I found the answer to the second one. In my mud, I have fix_char on an update. When it would trigger, it would screw up players that had the exact same object worn in two different wear_locs. fix_char de_equip_char's the person, and then does this: ncarry = 0;
while ( (obj=ch->first_carrying) != NULL )
{
carry[ncarry++] = obj;
obj_from_char( obj );
}
Now, I can't seen ANY reason for this. fix_char is a minor function compared to save_char_obj, and this is not done in save_char_obj, so I see absolutely no reason to use it in fix_char. It is accompanied with this: for ( x = 0; x < ncarry; x++ )
obj_to_char( carry[x], ch );
to give it back to the player.
I tracked down the reason for this. de_equip_char is where on a character through a double array, using wear_loc and layer as indexes, the characters objects are saved in save_equipment, which is the double array of object_data pointers. So, we now have where everything is supposed to be, but just off of the character. The above code, when obj_from_char is applied, groups objects together if everything is the same. At this point, since wear_loc and layer have been reset after being de_equiped, they ARE the same, so it groups them. Now, we have one object, ch->first_carry, for example, with a 2 count, and 2 objects saved in save_equipment, each with a 1 count. So the code for fix_char is applied, the objects are given back, but are NOT seperated, since there is no way to know how to do this. Now, these objects are re-applied through re_equip_char. Here is the tricky part, when it gets to the first object in save_equipment(first first ring, for example), it has a pointer to an object with a 2 count. If detects this 2 count in the process of re-applying the object to the character, and seperates them, creating a third object(first ring in save_equipment, the clone of the first, and the second in save_equipment). This object is linked in to the characters list of objects carried. When the process loops through the next time, the call to get_eq_char returns the clone, instead of the one in save_equipment. The changes to put the object back on the character is applied to the clone instead of the second ring, and the second ring is left in the inventory.
This took me a while through gdb, but I am almost positive that this is the process for this bug. As far as I can tell, this should be a bug in stock SMAUG as well. If someone can test for me, that would be great. You need to:
Oinvoke one piece of armor twice(jewelry works best, since you can have them on the same layer)
Wear them both(left wrist and right wrist, for example)
Use the fixchar command on the character
If one of the objects is now in the players inventory, then I'm not crazy. I just want to confirm this is the issue. I remove the above code from my fixchar, and it seems to have solved the issue. If there is an actual reason for that bit of code, though, I would love to be enlightened about it. |