extract_char stuff.

From: George Greer (greerga@circlemud.org)
Date: 03/18/01


[ 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