Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ SMAUG ➜ SMAUG coding ➜ New item types

New item types

It is now over 60 days since the last post. This thread is closed.     Refresh page


Pages: 1  2 3  

Posted by Isthiriel   (113 posts)  Bio
Date Reply #15 on Sat 18 Aug 2007 08:42 PM (UTC)
Message
Ok, an explanation on the uses (and abuses) of UNLINK.

SMAUG stores most objects (in the computer science sense... a struct in C) in doubly-linked lists.

A linked list is the name given to a bunch of objects where the first object has a pointer to the next, which in turn has a pointer to the next where no object in the list has a pointer to an earlier object in the list (this is important to avoid an infinite loop when attempting to traverse the list).

SMAUG's doubly-linked lists gives each object a pointer to the previous object (that is the object that points to the current object with its 'next' pointer). So it can be traversed either by following the next pointers forward, or the prev pointers backward.

Singly-linked lists are fairly easy to handle. If you want to do an insertion, you set the next pointer on the new object to the current list-head and the new object is the new head of the list.

Doubly-linked lists because you have to update three objects and four pointers (and you're usually trying to keep the number of temporary variables down) are more complicated, so the UNLINK and LINK macros are born.

LINK inserts the new object into a list specified by a head and a tail pointer.

For an empty list, new->next = NULL, new->prev = NULL, head = new, tail = new. Easy.
For a list containing item(s), we can do head- or tail- insertion, new->next = head, head->prev = new, head = new, new->prev = NULL.

So far, so good.

UNLINK has to find the object its handed in the list and then remove it from the list and repair all the references.

For an empty list, no work.
For a list containing the one item (to be removed), del->next = NULL, del->prev = NULL, head = NULL, tail = NULL.
For a list containing the item as the head, head = del->next, head->prev = NULL, del->next = NULL, del->prev = NULL.
(Ditto, but backwards for item-as-tail.)
For a list containing the item in the middle, del->prev->next = del->next, del->next->prev = del->prev, del->prev = NULL, del->next = NULL.


Taking this back to your code, the iteration follows the paf->next pointer to get the next affect in the list BUT you are calling UNLINK/LINK which both change what paf->next is actually pointing to. This is what I was trying to get across with my earlier post.

If your goal is to remove the affect from the gem and add it to the sword, then you should be able to use your code provided you cache the value of paf->next for the iteration.


IIRC, pIndexData is the prototype information? So you shouldn't be modifying (UNLINKing) it for a change to an instance. Personally, I'd destroy the gem once it has transferred its affects to the weapon. Though, that way you have to duplicate the affect from the gem pIndexData before applying it to the weapon.

Something like:

/*
 * gem_ob is the pointer to the gem object (sane variable names ftw!)
 * socketed_ob is the pointer to the socketed object receiving affects
 */
  separate_obj(gem_ob);
  for (paf = gem_ob->pIndexData->first_affect; paf; paf = paf->next) {
    /* paf is now iterating across the affects on the gem prototype, we want to copy this affect and apply it to socketed_ob */
/* Taken from SMAUG 1.8b mud.h: (tells us what we need to copy)
struct	affect_data
{
    AFFECT_DATA *	next;
    AFFECT_DATA *	prev;
    sh_int		type;
    int			duration;
    sh_int		location;
    int			modifier;
    EXT_BV		bitvector;
};
*/
    CREATE(new_paf, AFFECT_DATA, 1);
    new_paf->type = paf->type;
    new_paf->duration = paf->duration;
    new_paf->location = paf->location;
    new_paf->modifier = paf->modifier;
    xCLEAR_BITS(new_paf->bitvector);
    xSET_BITS(new_paf->bitvector, paf->bitvector);
    /* new_paf should now be a good copy of paf, so we can add it to the socketed_ob */
    LINK(new_paf, socketed_ob->first_affect, socketed_ob->last_affect, next, prev);
  }
  extract_obj(gem_ob); /* this destroys the gem? */
Top

Posted by Gohan_TheDragonball   USA  (183 posts)  Bio
Date Reply #16 on Sun 19 Aug 2007 02:24 AM (UTC)
Message
yeah sorry about that i usually remember to do that, was rewriting your code kind of quick. its your call where you want to pull the affects from, it is the same either way actually, as the permanent affects are in the first-obj->first_affect list anyways. i also did that way because its then just a simple unlink/link (simple being the idiot who told you to do it that way remembers to do it properly lol).

also nick already mentioned this but you haven't seemed to change it so ill restate that i really dont know why you are freeing a null string.

			if( !second_ob->sdesc1 || second_ob->sdesc1[0] == '\0' )
			{
				STRFREE( second_ob->sdesc1 );
				second_ob->sdesc1 = STRALLOC( buf1 );
			}

it just needs to be

			if( !second_ob->sdesc1 || second_ob->sdesc1[0] == '\0' )
				second_ob->sdesc1 = STRALLOC( buf1 );
Top

Posted by Orik   USA  (182 posts)  Bio
Date Reply #17 on Sun 19 Aug 2007 02:57 AM (UTC)

Amended on Sun 19 Aug 2007 03:20 AM (UTC) by Orik

Message
Thanks guys, It's working great now.

Thanks for the tutorial Isthiriel. I gave everyone credit in the comments.
Top

Posted by Nick Gammon   Australia  (23,169 posts)  Bio   Forum Administrator
Date Reply #18 on Sun 19 Aug 2007 04:18 AM (UTC)
Message
I was almost going to comment again, but he changed it to:


if( !second_ob->sdesc1 || second_ob->sdesc1[0] == '\0' )


Thus, the string isn't necessarily NULL, it might be present, but empty (maybe).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #19 on Sun 19 Aug 2007 05:46 AM (UTC)
Message
Strictly, shouldn't it be:
if (second_ob->sdesc1 && second_ob->sdesc1[0] == '\0') {
  STRFREE(second_ob->sdesc1);
}
if (!second_ob->sdesc1) { /* or == NULL for Correctness */
  second_ob->sdesc1 = STRALLOC(buf1);
}

Because otherwise you're leaking a byte everytime the function runs.
Top

Posted by Nick Gammon   Australia  (23,169 posts)  Bio   Forum Administrator
Date Reply #20 on Sun 19 Aug 2007 06:12 AM (UTC)
Message
Er, no I don't think so. The way it was written it did this:


  • If there is no description pointer, or
  • If there is a description pointer, and it was an empty string


Then:


  • Free the old description pointer (which would have no effect if the pointer was NULL) - however if it was the empty string it would be freed.


However the problem I see now is that if there is an existing description, however you want the new one to be different, then it won't be.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #21 on Sun 19 Aug 2007 08:36 AM (UTC)
Message
So STRFREE is null-checked?

Quote:
However the problem I see now is that if there is an existing description, however you want the new one to be different, then it won't be.


That's why it's repeated six times with else-ifs. It tries to put buf1 in each of the six sdesc slots, until it either succeeds (by finding an "empty" slot) or runs off the end.

And if that's SMAUG's standard idiom for it, then it badly needs at least some utility functions to clean it up and/or conversion to a linked-list structure.

... just because it's C doesn't mean you can't make it object-oriented :)
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #22 on Sun 19 Aug 2007 10:48 AM (UTC)
Message
Quote:
And if that's SMAUG's standard idiom for it, then it badly needs at least some utility functions to clean it up and/or conversion to a linked-list structure.

Groan. Don't get me started on places where SMAUG could use utility functions to make things cleaner, safer and easier to understand. #1 and #3 are just cosmetic (still important in my book) but I think everybody would agree that #2 is good no matter what...

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Orik   USA  (182 posts)  Bio
Date Reply #23 on Sun 19 Aug 2007 07:36 PM (UTC)

Amended on Sun 19 Aug 2007 08:04 PM (UTC) by Orik

Message
On to round 5 of this madness.

Everything is working except for the loading of the item.

It writes successfully in fwrite_fuss_object, but in fread_fuss_object it doesn't read it correctly. It just sets the Socket values back to 0. I copied the Item values code pretty much so here's what Sockets looks like in fread_fuss_object:


           if( !str_cmp( word, "Sockets" ) )
            {
               char *ln = fread_line( fp );
               int x1, x2, x3, x4, x5, x6;
               x1 = x2 = x3 = x4 = x5 = x6 = 0;

               sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );

               pObjIndex->socket[0] = x1;
               pObjIndex->socket[1] = x2;
               pObjIndex->socket[2] = x3;
               pObjIndex->socket[3] = x4;
               pObjIndex->socket[4] = x5;
               pObjIndex->socket[5] = x6;

               break;
            }


It's setting the values back at 0. When I savearea and check the file to see if it saved, it'll say

"Sockets 1 1 2 0 0 0"

That means that i had 1 blue, 1 red, 2 yellow sockets. It shows it directly in the area file after a savearea. Then when I reboot or shutdown and start again, the file loads as

"Sockets 0 0 0 0 0 0"

So for some odd reason, the socket value isn't carrying over.

**EDIT**
Ok, I've found out that it loads with the socket values, but when I oinvoke and ostat the sword it shows no values. Then when I savearea it saves to "Sockets 0 0 0 0 0 0"

do_ostat

   ch_printf_color( ch, "&cSocketed Slots : &BBlue &z(&w%d/&W%d&z) &RRed &z(&w%d/&W%d&z) &YYellow &z&z(&w%d/&W%d&z)&w\r\n",
                    obj->pIndexData->usocket[0], obj->pIndexData->socket[0], 
                                        obj->pIndexData->usocket[1], obj->pIndexData->socket[1],
                    obj->pIndexData->usocket[2], obj->pIndexData->socket[2]);


it shows "Socketed Slots : Blue (0/0) Red (0/0) Yellow (0/0)"

when it should show
"Socketed Slots : Blue (0/1) Red (0/1) Yellow (0/2)"

I'm guessing it's going to be in db.c create_object function. hmm..

create_object

   obj->socket[0] = pObjIndex->socket[0];
   obj->socket[1] = pObjIndex->socket[1];
   obj->socket[2] = pObjIndex->socket[2];

   obj->usocket[0] = 0;
   obj->usocket[1] = 0;
   obj->usocket[2] = 0;
Top

Posted by Orik   USA  (182 posts)  Bio
Date Reply #24 on Tue 21 Aug 2007 12:20 AM (UTC)
Message
So when I set

obj->socket[0] = 1;
obj->socket[1] = 2;
obj->socket[2] = 3;

It was able to load as 1, 2, and 3. When I set it back to

  obj->socket[0] = pObjIndex->socket[0];
   obj->socket[1] = pObjIndex->socket[1];
   obj->socket[2] = pObjIndex->socket[2];


It showed 0 again on oinvoking. The area file still read that it was what it was supposed to be, it just loaded as 0's.

I then added 3 more value types in all the respective areas and added the 3 new value types in create_object and when I loaded, set the new value types, savea, checked file, was still correct, shutdown, checked file again, was correct, booted up, correct, oinvoke, the three new value types were 0 on the object even though they were correct in the area file.

Gah, this is annoying.
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #25 on Tue 21 Aug 2007 08:05 AM (UTC)
Message
Hmm. Not really enough information to work from.

I assume you're running some version of SmaugFuss?

Have you tried examining sscanf's return value?

I might be able to help more with the complete listings of fread_fuss_object, fwrite_fuss_object and create_object :-/ (Is there any way to attach files to posts here?)
Top

Posted by Orik   USA  (182 posts)  Bio
Date Reply #26 on Tue 21 Aug 2007 07:20 PM (UTC)
Message
I am using Smaugfuss1.8.

I'll get more detailed information when I get home from work. I'll check out sscanf as well.

Top

Posted by Orik   USA  (182 posts)  Bio
Date Reply #27 on Wed 22 Aug 2007 12:22 AM (UTC)
Message
maximum is 6000 chars. I'll post my code.
fread_fuss_object
Here's my sockets.

            if( !str_cmp( word, "Sockets" ) )^M
            {^M
               char *ln = fread_line( fp );^M
               int x1, x2, x3, x4, x5, x6;^M
               x1 = x2 = x3 = x4 = x5 = x6 = 0;^M
^M
               sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );^M
^M
               pObjIndex->socket[0] = x1;^M
               pObjIndex->socket[1] = x2;^M
               pObjIndex->socket[2] = x3;^M
               pObjIndex->socket[3] = x4;^M
               pObjIndex->socket[4] = x5;^M
               pObjIndex->socket[5] = x6;^M
^M
               break;^M
            }^M
            KEY( "Socketable", pObjIndex->socket_item, fread_number( fp ) );^M
            KEY( "Socket1", pObjIndex->sdesc1, fread_string( fp ) );^M
            KEY( "Socket2", pObjIndex->sdesc2, fread_string( fp ) );^M
            KEY( "Socket3", pObjIndex->sdesc3, fread_string( fp ) );^M
            KEY( "Socket4", pObjIndex->sdesc4, fread_string( fp ) );^M
            KEY( "Socket5", pObjIndex->sdesc5, fread_string( fp ) );^M
            KEY( "Socket6", pObjIndex->sdesc6, fread_string( fp ) );^M

Here's Values

         case 'V':
            if( !str_cmp( word, "Values" ) )
            {
               char *ln = fread_line( fp );
               int x1, x2, x3, x4, x5, x6;
               x1 = x2 = x3 = x4 = x5 = x6 = 0;

               sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );

               pObjIndex->value[0] = x1;
               pObjIndex->value[1] = x2;
               pObjIndex->value[2] = x3;
               pObjIndex->value[3] = x4;
               pObjIndex->value[4] = x5;
               pObjIndex->value[5] = x6;

               break;
            }

Here's used sockets


                 case 'U':^M
                        if( !str_cmp( word, "Used Sockets" ) )^M
            {^M
               char *ln = fread_line( fp );^M
               int x1, x2, x3, x4, x5, x6;^M
               x1 = x2 = x3 = x4 = x5 = x6 = 0;^M
^M
               sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 );^M
^M
               pObjIndex->usocket[0] = x1;^M
               pObjIndex->usocket[1] = x2;^M
               pObjIndex->usocket[2] = x3;^M
               pObjIndex->usocket[3] = x4;^M
               pObjIndex->usocket[4] = x5;^M
               pObjIndex->usocket[5] = x6;^M
^M
               break;^M
            }^M
Top

Posted by Orik   USA  (182 posts)  Bio
Date Reply #28 on Wed 22 Aug 2007 12:48 AM (UTC)
Message
fwrite_fuss_project

   val0 = pObjIndex->value[0];^M
   val1 = pObjIndex->value[1];^M
   val2 = pObjIndex->value[2];^M
   val3 = pObjIndex->value[3];^M
   val4 = pObjIndex->value[4];^M
   val5 = pObjIndex->value[5];^M
^M
   sock0 = pObjIndex->socket[0];^M
   sock1 = pObjIndex->socket[1];^M
   sock2 = pObjIndex->socket[2];^M
   sock3 = pObjIndex->socket[3];^M
   sock4 = pObjIndex->socket[4];^M
   sock5 = pObjIndex->socket[5];^M
^M
   usock0 = pObjIndex->usocket[0];^M
   usock1 = pObjIndex->usocket[1];^M
   usock2 = pObjIndex->usocket[2];^M
   usock3 = pObjIndex->usocket[3];^M
   usock4 = pObjIndex->usocket[4];^M
   usock5 = pObjIndex->usocket[5];^M

further down:

   fprintf( fpout, "Values   %d %d %d %d %d %d\n", val0, val1, val2, val3, val4, val5 );^M
   fprintf( fpout, "Socketable       %d\n", pObjIndex->socket_item );^M
   fprintf( fpout, "Sockets   %d %d %d %d %d %d\n", sock0, sock1, sock2, sock3, sock4, sock5 );^M
   fprintf( fpout, "Used Sockets   %d %d %d %d %d %d\n", usock0, usock1, usock2, usock3, usock4, usock5 );^M
   fprintf( fpout, "Stats    %d %d %d %d %d\n", pObjIndex->weight,
            pObjIndex->cost, pObjIndex->rent ? pObjIndex->rent : ( int )( pObjIndex->cost / 10 ),
            pObjIndex->level, pObjIndex->layers );
^M
   if( pObjIndex->sdesc1 && pObjIndex->sdesc1[0] != '\0' )^M
      fprintf( fpout, "Socket1     %s~\n", pObjIndex->sdesc1 );^M
   if( pObjIndex->sdesc2 && pObjIndex->sdesc2[0] != '\0' )^M
      fprintf( fpout, "Socket2     %s~\n", pObjIndex->sdesc2 );^M
   if( pObjIndex->sdesc3 && pObjIndex->sdesc3[0] != '\0' )^M
      fprintf( fpout, "Socket3     %s~\n", pObjIndex->sdesc3 );^M
   if( pObjIndex->sdesc4 && pObjIndex->sdesc4[0] != '\0' )^M
      fprintf( fpout, "Socket4     %s~\n", pObjIndex->sdesc4 );^M
   if( pObjIndex->sdesc5 && pObjIndex->sdesc5[0] != '\0' )^M
      fprintf( fpout, "Socket5     %s~\n", pObjIndex->sdesc5 );^M
   if( pObjIndex->sdesc6 && pObjIndex->sdesc6[0] != '\0' )^M
      fprintf( fpout, "Socket6     %s~\n", pObjIndex->sdesc6 );^M
^M
Top

Posted by Orik   USA  (182 posts)  Bio
Date Reply #29 on Wed 22 Aug 2007 12:53 AM (UTC)
Message
Create_object

   obj->wear_flags = pObjIndex->wear_flags;
   obj->value[0] = pObjIndex->value[0];^M
   obj->value[1] = pObjIndex->value[1];^M
   obj->value[2] = pObjIndex->value[2];^M
   obj->value[3] = pObjIndex->value[3];^M
   obj->value[4] = pObjIndex->value[4];^M
   obj->value[5] = pObjIndex->value[5];^M
^M
   obj->socket[0] = pObjIndex->socket[0];^M
   obj->socket[1] = pObjIndex->socket[1];^M
   obj->socket[2] = pObjIndex->socket[2];^M
^M
   obj->usocket[0] = 0;^M
   obj->usocket[1] = 0;^M
   obj->usocket[2] = 0;^M
^M
   obj->weight = pObjIndex->weight;
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


102,202 views.

This is page 2, subject is 3 pages long:  [Previous page]  1  2 3  [Next page]

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.