01 Dec, 2011, Liko wrote in the 1st comment:
Votes: 0
Hello,

I'm running into an issue were when a player is killed the players equipment is left on, its copied into his corpse, copied to the room, but he's left wearing it also.

I believe its something to do when its making the corpse or extracting the character. I've looked over it for hours and cannot spot it. Maybe more pairs of eyes can.

static void make_corpse(struct char_data *ch)
{
char buf2[MAX_NAME_LENGTH + 64];
struct obj_data *corpse, *o;
struct obj_data *money;
int i, x, y;

corpse = create_obj();

corpse->item_number = NOTHING;
IN_ROOM(corpse) = NOWHERE;
corpse->name = strdup("corpse");

snprintf(buf2, sizeof(buf2), "The corpse of %s is lying here.", GET_NAME(ch));
corpse->description = strdup(buf2);

snprintf(buf2, sizeof(buf2), "the corpse of %s", GET_NAME(ch));
corpse->short_description = strdup(buf2);

GET_OBJ_TYPE(corpse) = ITEM_CONTAINER;
for(x = y = 0; x < EF_ARRAY_MAX || y < TW_ARRAY_MAX; x++, y++) {
if (x < EF_ARRAY_MAX)
GET_OBJ_EXTRA_AR(corpse, x) = 0;
if (y < TW_ARRAY_MAX)
corpse->obj_flags.wear_flags[y] = 0;
}
SET_BIT_AR(GET_OBJ_WEAR(corpse), ITEM_WEAR_TAKE);
SET_BIT_AR(GET_OBJ_EXTRA(corpse), ITEM_NODONATE);
GET_OBJ_VAL(corpse, 0) = 0; /* You can't store stuff in a corpse */
GET_OBJ_VAL(corpse, 3) = 1; /* corpse identifier */
GET_OBJ_WEIGHT(corpse) = GET_WEIGHT(ch) + IS_CARRYING_W(ch);
GET_OBJ_RENT(corpse) = 100000;
if (IS_NPC(ch))
GET_OBJ_TIMER(corpse) = CONFIG_MAX_NPC_CORPSE_TIME;
else
GET_OBJ_TIMER(corpse) = CONFIG_MAX_PC_CORPSE_TIME;

/* transfer character's inventory to the corpse */
corpse->contains = ch->carrying;
for (o = corpse->contains; o != NULL; o = o->next_content)
o->in_obj = corpse;
object_list_new_owner(corpse, NULL);

/* transfer character's equipment to the corpse */
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i)) {
remove_otrigger(GET_EQ(ch, i), ch);
obj_to_obj(unequip_char(ch, i), corpse);
}

/* transfer gold */
if (GET_GOLD(ch) > 0) {
/* following 'if' clause added to fix gold duplication loophole. The above
* line apparently refers to the old "partially log in, kill the game
* character, then finish login sequence" duping bug. The duplication has
* been fixed (knock on wood) but the test below shall live on, for a
* while. -gg 3/3/2002 */
if (IS_NPC(ch) || ch->desc) {
money = create_money(GET_GOLD(ch) * CONFIG_GIL_MOD);
obj_to_obj(money, corpse);
}
GET_GOLD(ch) = 0;
}
ch->carrying = NULL;
IS_CARRYING_N(ch) = 0;
IS_CARRYING_W(ch) = 0;

obj_to_room(corpse, IN_ROOM(ch));
}


extract char_final.

void extract_char_final(struct char_data *ch)
{
struct char_data *k, *temp;
struct descriptor_data *d;
struct obj_data *obj;
int i;

if (IN_ROOM(ch) == NOWHERE) {
log("SYSERR: NOWHERE extracting char %s. (%s, extract_char_final)",
GET_NAME(ch), __FILE__);
exit(1);
}

/* We're booting the character of someone who has switched so first we need
* to stuff them back into their own body. This will set ch->desc we're
* checking below this loop to the proper value. */
if (!IS_NPC(ch) && !ch->desc) {
for (d = descriptor_list; d; d = d->next)
if (d->original == ch) {
do_return(d->character, NULL, 0, 0);
break;
}
}

if (ch->desc) {
/* This time we're extracting the body someone has switched into (not the
* body of someone switching as above) so we need to put the switcher back
* to their own body. If this body is not possessed, the owner won't have a
* body after the removal so dump them to the main menu. */
if (ch->desc->original)
do_return(ch, NULL, 0, 0);
else {
/* Now we boot anybody trying to log in with the same character, to help
* guard against duping. CON_DISCONNECT is used to close a descriptor
* without extracting the d->character associated with it, for being
* link-dead, so we want CON_CLOSE to clean everything up. If we're
* here, we know it's a player so no IS_NPC check required. */
for (d = descriptor_list; d; d = d->next) {
if (d == ch->desc)
continue;
if (d->character && GET_IDNUM(ch) == GET_IDNUM(d->character))
STATE(d) = CON_CLOSE;
}
STATE(ch->desc) = CON_MENU;
write_to_output(ch->desc, "%s", CONFIG_MENU);
}
}

/* On with the character's assets… */
if (ch->followers || ch->master)
die_follower(ch);

/* transfer objects to room, if any */
while (ch->carrying) {
obj = ch->carrying;
obj_from_char(obj);
obj_to_room(obj, IN_ROOM(ch));
}

/* transfer equipment to room, if any */
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i))
obj_to_room(unequip_char(ch, i), IN_ROOM(ch));

if (FIGHTING(ch))
stop_fighting(ch);

for (k = combat_list; k; k = temp) {
temp = k->next_fighting;
if (FIGHTING(k) == ch)
stop_fighting(k);
}
/* we can't forget the hunters either… */
for (temp = character_list; temp; temp = temp->next)
if (HUNTING(temp) == ch)
HUNTING(temp) = NULL;

char_from_room(ch);

if (IS_NPC(ch)) {
if (GET_MOB_RNUM(ch) != NOTHING) /* prototyped */
mob_index[GET_MOB_RNUM(ch)].number–;
clearMemory(ch);

if (SCRIPT(ch))
extract_script(ch, MOB_TRIGGER);

if (SCRIPT_MEM(ch))
extract_script_mem(SCRIPT_MEM(ch));
} else {
save_char(ch);
Crash_delete_crashfile(ch);
}

/* If there's a descriptor, they're in the menu now. */
if (IS_NPC(ch) || !ch->desc)
free_char(ch);
}
01 Dec, 2011, Liko wrote in the 2nd comment:
Votes: 0
Seems to fixed it. Changing the WEAR_NUM_FLAGS in structs.h to match extactly to the number of items fixed instead of items + 1
01 Dec, 2011, plamzi wrote in the 3rd comment:
Votes: 0
Hi,

My guess is the issue is not in the functions you pasted but rather in the function that calls make_corpse(). This looks like a Diku derivative so the name of the function could be raw_kill() in fight.c.

Edit: It's a bit odd that NUM_WEARS would have fixed this. I would expect that if the value was wrong, it would cause some equipment to be in corpse while other items to be still on the player after death, nothing duped…
01 Dec, 2011, Liko wrote in the 4th comment:
Votes: 0
plamzi said:
Hi,

My guess is the issue is not in the functions you pasted but rather in the function that calls make_corpse(). This looks like a Diku derivative so the name of the function could be raw_kill() in fight.c.

Edit: It's a bit odd that NUM_WEARS would have fixed this. I would expect that if the value was wrong, it would cause some equipment to be in corpse while other items to be still on the player after death, nothing duped…



Your correct after more testing it is not fixed.

Here is what calls make_corpse

void raw_kill(struct char_data * ch, struct char_data * killer)
{
if (FIGHTING(ch))
stop_fighting(ch);

while (ch->affected)
affect_remove(ch, ch->affected);

/* To make ordinary commands work in scripts. welcor*/
GET_POS(ch) = POS_STANDING;

if (killer) {
if (death_mtrigger(ch, killer))
death_cry(ch);
} else
death_cry(ch);

if (killer)
autoquest_trigger_check(killer, ch, NULL, AQ_MOB_KILL);

update_pos(ch);

make_corpse(ch);
extract_char(ch);

if (killer) {
autoquest_trigger_check(killer, NULL, NULL, AQ_MOB_SAVE);
autoquest_trigger_check(killer, NULL, NULL, AQ_ROOM_CLEAR);
}
}
01 Dec, 2011, David Haley wrote in the 5th comment:
Votes: 0
This is not nearly enough information because there are a lot of helper functions that aren't shown. That said… make_corpse only calls obj_to_obj for ch's equipment to the corpse, it never calls obj_from_char to remove it from the character. So it would be in both linked lists. This is assuming that obj_to_obj is only responsible for adding objects.

Where does extract_char_final come in? The player is being killed and reused, not extracted completely.

Is this stock code or a snippet or something you wrote or what?
01 Dec, 2011, Rarva.Riendf wrote in the 6th comment:
Votes: 0
/* transfer character's inventory to the corpse */
corpse->contains = ch->carrying;
for (o = corpse->contains; o != NULL; o = o->next_content)
o->in_obj = corpse; // when you do this you do begin to have fields that makes no sense (obj can be in inentory and wear as well
object_list_new_owner(corpse, NULL); // maybe this is to fix what is above but we have no idea

/* transfer character's equipment to the corpse */ //this is only needed because you did not do it when you shoudl have (ie, above)
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i)) {
remove_otrigger(GET_EQ(ch, i), ch);
obj_to_obj(unequip_char(ch, i), corpse);
}


should be replaced by something looking like this

OBJ_DATA *obj, *obj_next;
for (obj = ch->carrying;obj ;obj = obj_next) {
obj_next = obj->next_content;
obj_from_char(obj); //this is what does all the unequip etc etc etc and ensure the player does not have anything left referenced to the object
if (IS_SET(obj->extra_flags,ITEM_ROT_DEATH)) {
obj->timer = number_range(5, 10);
REMOVE_BIT(obj->extra_flags,ITEM_ROT_DEATH);
}
REMOVE_BIT(obj->extra_flags,ITEM_VIS_DEATH);

if (IS_SET( obj->extra_flags, ITEM_INVENTORY )) {
extract_obj(obj);
continue;
}
obj_to_obj(obj, corpse); //put the object in the corpse
}
01 Dec, 2011, plamzi wrote in the 7th comment:
Votes: 0
David, Rarva,

This is Diku and I have very similar code transferring the inventory fine. First it moves the pointer to the top item, then it makes sure that all top-level items point to the corpse item instead of the player, then it nulls ch->carrying. I think the problem is elsewhere.

Liko, can you put a debug message when a player is killed, and another debug message in save_char? If the killed character is not saved successfully after he/she was stripped, then that can cause duping when they re-enter and their saved items file gets reloaded.
01 Dec, 2011, Rarva.Riendf wrote in the 8th comment:
Votes: 0
Ok, seemed like an overly complicated code to me though, for such a simple thing, removing items from a char and putting it in an object.

Diku or whatever kind of code, this is all you should have to type.
obj_from_char(obj);
obj_to_obj(obj, corpse);

Only way you are sure you did everything properly each time is to go to a single entry point for doing this. obj_from_char should handle the unequip thing as well.
Makes code a lot easier to maintain as well, just saying.
01 Dec, 2011, Liko wrote in the 9th comment:
Votes: 0
I think the simple solution is that I need to write a death script that doesn't force the player to log out when they die. I believe that is kinda lame anyway. It's stock and I don't like it. I believe that is how I'll fix it.
01 Dec, 2011, Hades_Kane wrote in the 10th comment:
Votes: 0
I would just take a look at the ROM death function, that ought to help a lot, and has none of that other non sense.
01 Dec, 2011, David Haley wrote in the 11th comment:
Votes: 0
Plamzi, if this is straight Diku, then as I said, he is not calling the functions correctly.

We also know that this works in straight Diku, so obviously, something has been done here to break things, or this isn't actually straight Diku… :wink:
01 Dec, 2011, Ssolvarain wrote in the 12th comment:
Votes: 0
David Haley said:
or this isn't actually straight Diku… :wink:


SSJDIKUUUUUUUUUUUUUUUUUU
01 Dec, 2011, Kober wrote in the 13th comment:
Votes: 0
It's from the TBAMud or some circle codebase
02 Dec, 2011, David Haley wrote in the 14th comment:
Votes: 0
That's the forum section, yes, and it's a derivative of Diku, yes, but I'd be pretty surprised if a stock, standard codebase had an item duplication bug during such a common event as character death. So I'm trying to work out where this code is from and who touched it.
02 Dec, 2011, Hades_Kane wrote in the 15th comment:
Votes: 0
Is forcing a character quit upon death a stock feature?

Mind you, I haven't played a ton of different codebases, but I personally have never run into that.
03 Dec, 2011, Sharmair wrote in the 16th comment:
Votes: 0
Hades_Kane said:
Is forcing a character quit upon death a stock feature?

Mind you, I haven't played a ton of different codebases, but I personally have never run into that.

With circleMUD it is stock. You are not disconnected though, circleMUD has this menu when you
log on and you get when you quit. When you die, you are placed at the menu. The menu has
options for leaving, entering the game and normaly some other options like reading the MUD
story, changing password etc. (I don't really see the need for the menu myself, but that is their
way).
03 Dec, 2011, Hades_Kane wrote in the 17th comment:
Votes: 0
Sharmair said:
Hades_Kane said:
Is forcing a character quit upon death a stock feature?

Mind you, I haven't played a ton of different codebases, but I personally have never run into that.

With circleMUD it is stock. You are not disconnected though, circleMUD has this menu when you
log on and you get when you quit. When you die, you are placed at the menu. The menu has
options for leaving, entering the game and normaly some other options like reading the MUD
story, changing password etc. (I don't really see the need for the menu myself, but that is their
way).


That just seems odd.. thanks for the clarification :p
04 Dec, 2011, Liko wrote in the 18th comment:
Votes: 0
David Haley said:
That's the forum section, yes, and it's a derivative of Diku, yes, but I'd be pretty surprised if a stock, standard codebase had an item duplication bug during such a common event as character death. So I'm trying to work out where this code is from and who touched it.


Actually, Yes it is stock for TBA Mud.


Hades_Kane said:
Is forcing a character quit upon death a stock feature?

Mind you, I haven't played a ton of different codebases, but I personally have never run into that.


Yes, it is.


But,

What I finally did to finally fix the issue was rewrite how the mud handle when a character lost in combat.
Now it outlines like this
A) Character Lost
B) Remove Equipment
C) Place all their gold and inventory in their corpse.
D) Apply losing penalty.
E) End Combat
D) Transfer User to Death Room.

So instead of it Extracting the Player it just loads it into their corpse then applies the rest of combat.

But for mobs, it does still extract NPCS.
05 Dec, 2011, David Haley wrote in the 19th comment:
Votes: 0
If you are truly saying that stock tbaMUD comes with such a huge and glaring bug, then it should be reported to the people who maintain the codebase…
05 Dec, 2011, Liko wrote in the 20th comment:
Votes: 0
David Haley said:
If you are truly saying that stock tbaMUD comes with such a huge and glaring bug, then it should be reported to the people who maintain the codebase…


I'm in the process of doing so.
0.0/27