Crossfire Mailing List Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: CF: Wizard Crashes



On Fri, May 26, 2000 at 12:24:23PM +0200, Jan Echternach wrote:
> Thanks for the server logs.  This is fixed by the attached patch.  The
> patch is already applied to the CVS tree.

The patch triggered other bugs in that area:  Two functions called
add_friendly_object() without setting FLAG_FRIENDLY.  I fixed these
bugs and some more that I have found while trying to crash the server
on /Lake_Country/Mwizard/Mwizard6 and /Lake_Country/Mwizard/Mwizard6
maps (however, the server didn't crash - I can't reproduce the wizard
problems).

I have also added handling of magic missiles to move_apply().  That
should get rid of many debugging messages.

From the CHANGES file:

* server/attack.c: hit_map(), hit_player(); server/spell_effect.c:
move_cone(); server/rune.c: spring_trap(); server/spell_util.c:
move_missile(): Bugfix: Added missing was_destroyed() calls.
* server/rune.c: spring_trap(): Bugfix: Call trap_show() before the rune
has a chance to be destroyed.
* server/attack.c: hit_map(), hit_player(): Check for freed objects
right at the beginning of the function.  Removed check that hitter has
a name from hit_player().
* server/spell_util.c: move_cone(): Bugfix: Remove cone objects in
inventories from active list, this fixes the cone without map problem when
a flower was hit with ice and put into an icecube.
* server/spell_util.c: move_missile(): Bugfix: Don't call hit_map() while
missile is removed from the map.
* server/apply.c: manual_apply(): Handle MMISSILE.

-- 
Jan
diff -ru orig/crossfire-0.95.5-cvs2-patch14/server/spell_effect.c crossfire-0.95.5-cvs2/server/spell_effect.c
--- orig/crossfire-0.95.5-cvs2-patch14/server/spell_effect.c	Fri May 26 11:26:52 2000
+++ crossfire-0.95.5-cvs2/server/spell_effect.c	Fri May 26 12:53:26 2000
@@ -3043,6 +3043,7 @@
   /* if animated by a player, give the player control of the golem */
   if(op->type==PLAYER) {
     CLEAR_FLAG(tmp, FLAG_MONSTER);
+    SET_FLAG(tmp, FLAG_FRIENDLY);
     tmp->stats.exp=0;
     add_friendly_object(tmp);
     tmp->type=GOLEM;
diff -ru orig/crossfire-0.95.5-cvs2-patch14/server/spell_util.c crossfire-0.95.5-cvs2/server/spell_util.c
--- orig/crossfire-0.95.5-cvs2-patch14/server/spell_util.c	Fri May 26 11:26:52 2000
+++ crossfire-0.95.5-cvs2/server/spell_util.c	Fri May 26 12:50:03 2000
@@ -822,6 +822,7 @@
   tmp=arch_to_object(at);
   if(op->type==PLAYER) {
     CLEAR_FLAG(tmp, FLAG_MONSTER);
+    SET_FLAG(tmp, FLAG_FRIENDLY);
     tmp->stats.exp=0;
     add_friendly_object(tmp);
     tmp->type=GOLEM;
diff -ru orig/crossfire-0.95.5-cvs2-patch15/server/attack.c crossfire-0.95.5-cvs2/server/attack.c
--- orig/crossfire-0.95.5-cvs2-patch15/server/attack.c	Fri May 26 12:54:04 2000
+++ crossfire-0.95.5-cvs2/server/attack.c	Fri May 26 13:16:46 2000
@@ -169,9 +169,17 @@
 int hit_map(object *op,int dir,int type) {
   object *tmp,*next=NULL;
   int retflag=0;  /* added this flag..  will return 1 if it hits a monster */
+  tag_t tag;
+
+  if (QUERY_FLAG (op, FLAG_FREED)) {
+    LOG (llevError, "BUG: hit_map(): free object\n");
+    return 0;
+  }
   
   if (op->head) op=op->head;
 
+  tag = op->count;
+
   if (!op->map) {
     LOG(llevDebug,"hit_map called, but %s has no map", op->name);
     return 0;
@@ -214,6 +222,8 @@
     else if(QUERY_FLAG(tmp,FLAG_ALIVE)) {
       hit_player(tmp,op->stats.dam,op,type);
       retflag |=1;
+      if (was_destroyed (op, tag))
+        break;
     } /* It is possible the object has been relocated to know longer be
        * on the map (ie, in an icecube.)  If we no longer have a map,
        * just ignore.
@@ -697,6 +707,13 @@
     char buf[MAX_BUF];
     object *old_hitter=NULL; /* this is used in case of servant monsters */ 
     int maxdam=0,ndam,attacktype=1,attacknum,magic=(type & AT_MAGIC);
+    tag_t hitter_tag;
+
+    if (QUERY_FLAG (op, FLAG_FREED) || QUERY_FLAG (hitter, FLAG_FREED)) {
+        LOG (llevError, "BUG: hit_player(): freed object\n");
+        return 0;
+    }
+    hitter_tag = hitter->count;
 
     if(op->head!=NULL) {
 	if(op->head==op) {
@@ -727,18 +744,15 @@
 	op=op->head;
     }
 
-    if(op->type==DOOR && op->inv && op->inv->type==RUNE)
+    if(op->type==DOOR && op->inv && op->inv->type==RUNE) {
 	spring_trap(op->inv,hitter);
+        if (was_destroyed (hitter, hitter_tag))
+            return 0;
+    }
 
     /* If its already dead, or we're the wizard, don't attack it - no point */
     if(QUERY_FLAG(op,FLAG_WIZ)||!QUERY_FLAG(op,FLAG_ALIVE)||op->stats.hp<0)
 	return 0;
-
-    /* If its already dead, or we're the wizard, don't attack it - no point */
-    if(hitter->name==NULL) {
-	LOG(llevDebug, "hit_player: hitter has no name\n");
-	return 0;
-    }
 
 #ifdef ATTACK_DEBUG
     LOG(llevDebug,"hit player: attacktype %d, dam %d\n", type, dam);
diff -ru orig/crossfire-0.95.5-cvs2-patch15/server/spell_util.c crossfire-0.95.5-cvs2/server/spell_util.c
--- orig/crossfire-0.95.5-cvs2-patch15/server/spell_util.c	Fri May 26 13:35:24 2000
+++ crossfire-0.95.5-cvs2/server/spell_util.c	Fri May 26 13:30:57 2000
@@ -1094,6 +1094,14 @@
 
 void move_cone(object *op) {
     int i;
+    tag_t tag;
+
+    if (op->env) {
+        /* handle flowers in icecubes */
+        op->speed = 0;
+        update_ob_speed (op);
+        return;
+    }
 
     /* if no map then hit_map will crash so just ignore object */
     if (! op->map) {
@@ -1118,7 +1126,10 @@
     /* Hit map returns 1 if it hits a monster.  If it does, set
      * food to 1, which will stop the cone from progressing.
      */
+    tag = op->count;
     op->stats.food |= hit_map(op,0,op->attacktype);
+    if (was_destroyed (op, tag))
+        return;
 
     if((op->stats.hp-=2)<0) {
 	if(op->stats.exp) {
diff -ru orig/crossfire-0.95.5-cvs2-patch16/server/apply.c crossfire-0.95.5-cvs2/server/apply.c
--- orig/crossfire-0.95.5-cvs2-patch16/server/apply.c	Fri May 26 11:26:51 2000
+++ crossfire-0.95.5-cvs2/server/apply.c	Fri May 26 14:07:11 2000
@@ -1093,6 +1093,17 @@
     apply_altar (trap, victim, originator);
     return;
 
+  case MMISSILE:
+    if (QUERY_FLAG (victim, FLAG_ALIVE)) {
+      tag_t trap_tag = trap->count;
+      hit_player (victim, trap->stats.dam, trap, AT_MAGIC);
+      if ( ! was_destroyed (trap, trap_tag)) {
+          remove_ob (trap);
+          free_object (trap);
+      }
+    }
+    return;
+
   case ARROW:
     if(QUERY_FLAG(victim, FLAG_ALIVE)&&trap->speed) {
       tag_t trap_tag = trap->count;
diff -ru orig/crossfire-0.95.5-cvs2-patch16/server/rune.c crossfire-0.95.5-cvs2/server/rune.c
--- orig/crossfire-0.95.5-cvs2-patch16/server/rune.c	Fri May 26 11:26:52 2000
+++ crossfire-0.95.5-cvs2/server/rune.c	Fri May 26 13:54:12 2000
@@ -185,9 +185,10 @@
 void rune_attack(object *op,object *victim)
 {
     if(victim) {
+         tag_t tag = victim->count;
 	 hit_player(victim,op->stats.dam,op,op->attacktype);
-	 if (QUERY_FLAG (victim, FLAG_FREED))
-		return;
+         if (was_destroyed (victim, tag))
+                return;
 	 /*  if there's a disease in the needle, put it in the player */
 	 if(op->randomitems!=NULL) create_treasure(op->randomitems,op,GT_INVENTORY,
 		(victim->map?victim->map->difficulty:1),0);
@@ -207,22 +208,35 @@
 void spring_trap(object *trap,object *victim)
 {  int spell_in_rune;
    object *env;
+   tag_t trap_tag = trap->count;
+
   trap->stats.hp--;  /*decrement detcount */
   /*  get the spell number from the name in the slaying field, and set
       that as the spell to be cast. */
   if((spell_in_rune=look_up_spell_by_name(NULL,trap->slaying))!=-1) trap->stats.sp=spell_in_rune;
   if(victim) if(victim->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,victim,trap->msg);
-  if(!trap->stats.sp) rune_attack(trap,victim); 
-  else {  /*  This is necessary if the trap is inside something else */
+  /*  Flash an image of the trap on the map so the poor sod
+   *   knows what hit him.  */
+  for (env = trap; env->env != NULL; env = env->env)
+    ;
+  trap_show(trap,env);  
+
+  if ( ! trap->stats.sp)
+  {
+    rune_attack(trap,victim); 
+    if (was_destroyed (trap, trap_tag))
+      return;
+  }
+  else
+  {
+    /* This is necessary if the trap is inside something else */
     remove_ob(trap);
     trap->x=victim->x;trap->y=victim->y;
     insert_ob_in_map(trap,victim->map,trap);
+    if (was_destroyed (trap, trap_tag))
+      return;
     cast_spell(trap,trap,trap->direction,trap->stats.sp,1,spellNormal,NULL);
   }
-  /*  Flash an image of the trap on the map so the poor sod
-   *   knows what hit him.  */
-  for(env=trap;env!=NULL&&env->env!=NULL;env=env->env);
-  trap_show(trap,env);  
 
   if(!trap->stats.hp) {
     trap->type=98;  /* make the trap impotent */
diff -ru orig/crossfire-0.95.5-cvs2-patch16/server/spell_util.c crossfire-0.95.5-cvs2/server/spell_util.c
--- orig/crossfire-0.95.5-cvs2-patch16/server/spell_util.c	Fri May 26 14:18:33 2000
+++ crossfire-0.95.5-cvs2/server/spell_util.c	Fri May 26 14:07:44 2000
@@ -1403,25 +1403,37 @@
 void move_missile(object *op) {
   int i;
   object *owner;
+  sint16 new_x, new_y;
 
-  remove_ob(op);
   owner = get_owner(op);
-  if (owner == (object *) NULL) {
+  if (owner == NULL) {
+    remove_ob(op);
     free_object(op);
     return;
   }
 
-  op->x+=DIRX(op),op->y+=DIRY(op);
-  if(!op->direction||wall(op->map,op->x,op->y)||
-     blocks_view(op->map,op->x,op->y)) {
-    free_object(op);
+  new_x = op->x + DIRX(op);
+  new_y = op->y + DIRY(op);
+
+  if (blocked (op->map, new_x, new_y)) {
+    tag_t tag = op->count;
+    hit_map (op, op->direction, AT_MAGIC);
+    if ( ! was_destroyed (op, tag)) {
+      remove_ob (op);
+      free_object(op);
+    }
     return;
   }
-  if(blocked(op->map,op->x,op->y)) {
-    hit_map(op,0,AT_MAGIC);
+
+  remove_ob(op);
+  if ( ! op->direction || wall (op->map, new_x, new_y)
+      || blocks_view (op->map, new_x, new_y))
+  {
     free_object(op);
     return;
   }
+  op->x = new_x;
+  op->y = new_y;
   i=find_dir(op->map,op->x,op->y,get_owner(op));
   if(i&&i!=op->direction){
     op->direction=absdir(op->direction+((op->direction-i+8)%8<4?-1:1));