[ Doh, take 3, it was originally a 204-line patch. It's now missing the handler.h prototype for e_p_c, and the #defines for {PLR,MOB}_NOTDEADYET. ] Here's what I'm using for the 'extracting a dead character in the middle of a loop' fix. Can anyone think of cases that this will either break or that will break this? You have 16 hours. :) Index: act.offensive.c =================================================================== RCS file: /home/circledb/.cvs/circle/src/act.offensive.c,v retrieving revision 1.23 diff -u -p -r1.23 act.offensive.c --- act.offensive.c 2001/01/26 00:50:43 1.23 +++ act.offensive.c 2001/03/14 03:40:50 @@ -207,10 +207,6 @@ ACMD(do_backstab) } -/* - * Ordering followers is crash-ridden due to character extraction during - * the command execution. It's been disabled until it can be made safer. - */ ACMD(do_order) { char name[MAX_INPUT_LENGTH], message[MAX_INPUT_LENGTH]; @@ -223,7 +219,7 @@ ACMD(do_order) if (!*name || !*message) send_to_char("Order who to do what?\r\n", ch); - else if (!(vict = get_char_vis(ch, name, NULL, FIND_CHAR_ROOM)) /* && !is_abbrev(name, "followers") */) + else if (!(vict = get_char_vis(ch, name, NULL, FIND_CHAR_ROOM)) && !is_abbrev(name, "followers")) send_to_char("That person isn't here.\r\n", ch); else if (ch == vict) send_to_char("You obviously suffer from skitzofrenia.\r\n", ch); Index: comm.c =================================================================== RCS file: /home/circledb/.cvs/circle/src/comm.c,v retrieving revision 1.87 diff -u -p -r1.87 comm.c --- comm.c 2001/03/07 09:41:46 1.87 +++ comm.c 2001/03/14 03:14:14 @@ -822,6 +822,9 @@ void heartbeat(int pulse) } if (!(pulse % PULSE_USAGE)) record_usage(); + + /* Every pulse! Don't want them to stink the place up... */ + extract_pending_chars(); } Index: fight.c =================================================================== RCS file: /home/circledb/.cvs/circle/src/fight.c,v retrieving revision 1.19 diff -u -p -r1.19 fight.c --- fight.c 1999/05/10 00:05:46 1.19 +++ fight.c 2001/03/18 13:00:42 @@ -640,10 +640,14 @@ int skill_message(int dam, struct char_d int damage(struct char_data * ch, struct char_data * victim, int dam, int attacktype) { if (GET_POS(victim) <= POS_DEAD) { + /* This is "normal"-ish now with delayed extraction. -gg 3/15/2001 */ + if (PLR_FLAGGED(victim, PLR_NOTDEADYET) || MOB_FLAGGED(victim, MOB_NOTDEADYET)) + return (-1); + log("SYSERR: Attempt to damage corpse '%s' in room #%d by '%s'.", GET_NAME(victim), GET_ROOM_VNUM(IN_ROOM(victim)), GET_NAME(ch)); die(victim); - return (0); /* -je, 7/7/92 */ + return (-1); /* -je, 7/7/92 */ } /* peaceful rooms */ Index: handler.c =================================================================== RCS file: /home/circledb/.cvs/circle/src/handler.c,v retrieving revision 1.25 diff -u -p -r1.25 handler.c --- handler.c 2001/03/07 09:44:56 1.25 +++ handler.c 2001/03/18 13:07:36 @@ -20,6 +20,9 @@ #include "interpreter.h" #include "spells.h" +/* local vars */ +int extractions_pending = 0; + /* external vars */ extern struct char_data *combat_list; extern struct room_data *world; @@ -844,9 +847,8 @@ void update_char_objects(struct char_dat } - /* Extract a ch completely from the world, and leave his stuff behind */ -void extract_char(struct char_data * ch) +void extract_char_final(struct char_data *ch) { struct char_data *k, *temp; struct descriptor_data *d; @@ -854,7 +856,7 @@ void extract_char(struct char_data * ch) int i; if (ch->in_room == NOWHERE) { - log("SYSERR: NOWHERE extracting char %s. (%s, extract_char)", + log("SYSERR: NOWHERE extracting char %s. (%s, extract_char_final)", GET_NAME(ch), __FILE__); exit(1); } @@ -945,6 +947,61 @@ void extract_char(struct char_data * ch) } } + +/* + * Q: Why do we do this? + * A: Because trying to iterate over the character + * list with 'ch = ch->next' does bad things if + * the current character happens to die. The + * trivial workaround of 'vict = next_vict' + * doesn't work if the _next_ person in the list + * gets killed, for example, by an area spell. + * + * Q: Why do we leave them on the character_list? + * A: Because code doing 'vict = vict->next' would + * get really confused otherwise. + */ +void extract_char(struct char_data *ch) +{ + if (IS_NPC(ch)) + SET_BIT(MOB_FLAGS(ch), MOB_NOTDEADYET); + else + SET_BIT(PLR_FLAGS(ch), PLR_NOTDEADYET); + + extractions_pending++; +} + + +/* + * I'm not particularly pleased with the MOB/PLR + * hoops that have to be jumped through but it + * hardly calls for a completely new variable. + * Ideally it would be its own list, but that + * would change the '->next' pointer, potentially + * confusing some code. Ugh. -gg 3/15/2001 + */ +void extract_pending_chars(void) +{ + struct char_data *vict, *next_vict; + + if (extractions_pending < 0) + log("SYSERR: Negative (%d) extractions pending.", extractions_pending); + + for (vict = character_list; vict && extractions_pending; vict = next_vict) { + next_vict = vict->next; + + if (MOB_FLAGGED(vict, MOB_NOTDEADYET)) + REMOVE_BIT(MOB_FLAGS(vict), MOB_NOTDEADYET); + else if (PLR_FLAGGED(vict, PLR_NOTDEADYET)) + REMOVE_BIT(PLR_FLAGS(vict), PLR_NOTDEADYET); + else + continue; + + extract_char_final(vict); + extractions_pending--; + } + extractions_pending = 0; +} /* *********************************************************************** -- +---------------------------------------------------------------+ | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html | | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html | +---------------------------------------------------------------+
This archive was generated by hypermail 2b30 : 12/04/01 PST