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

CF: animate_weapon() fixes



This patch is already in the CVS tree.  I have not updated
common/loader.c in the CVS because it is a generated file.  From the
CHANGES file:

common/loader.l:  Fix handling of objects with no animation.  Fixes server
crash if object's archetype has an animation, but object doesn't.

common/loader.l: get_ob_diff():  Bugfix: Issue a "is_animated 0" line
if the object has an animation, but doesn't have FLAG_ANIMATE.

server/apply.c: manual_apply() and monster_apply_special():  Don't check
for FLAG_UNPAID if object is applied.  This should make the code more
robust if an unpaid item get's applied accidently.

server/apply.c: apply_special():  New optional flags AP_NO_MERGE and
AP_IGNORE_CURSE.  

server/monster.c: find_mon_throw_ob(); server/skills.c: find_throw_ob():
Bugfix:  Use AP_NO_MERGE flag to prevent unapplied object be merged with
other objects.  

server/spell_effect.c: animate_weapon:  Bugfixes: Correctly unapply
weapon.  Don't set FLAG_APPLIED directly on weapon in golem, but use
apply_special().  Don't call esrv_send_item() when caster is not a player
(fixes server crash if monster casts this spell).

-- 
Jan
diff -ru orig/crossfire-0.95.5-cvs3-patch23/common/loader.l crossfire-0.95.5-cvs3/common/loader.l
--- orig/crossfire-0.95.5-cvs3-patch23/common/loader.l	Mon May 15 22:29:08 2000
+++ crossfire-0.95.5-cvs3/common/loader.l	Fri Jun  9 13:22:27 2000
@@ -181,8 +181,13 @@
 
 ^other_arch{S}        op->other_arch=find_archetype(yval());
 ^animation{S}	    {	
-			op->animation_id = find_animation(yval());
-			SET_FLAG(op,FLAG_ANIMATE);
+			if (strcmp (yval(), "NONE") == 0) {
+			    op->animation_id = 0;
+			    CLEAR_FLAG (op, FLAG_ANIMATE);
+			} else {
+			    op->animation_id = find_animation (yval());
+			    SET_FLAG (op, FLAG_ANIMATE);
+			}
 		    }
 
 ^more{WS}$	    { /* We need to record that this is a multipart object,
@@ -619,8 +624,16 @@
       strcat(buf,buf2);
   }
   if (op->animation_id != op2->animation_id) {
-    sprintf(buf2,"animation %s\n", animations[GET_ANIM_ID(op)].name);
-    strcat(buf, buf2);
+    if (op->animation_id) {
+      sprintf(buf2,"animation %s\n", animations[GET_ANIM_ID(op)].name);
+      if ( ! QUERY_FLAG (op, FLAG_ANIMATE)) {
+        strcat (buf, buf2);
+        sprintf (buf2, "is_animated 0\n");
+      }
+    } else {
+      sprintf (buf2, "animation NONE\n");
+    }
+    strcat (buf, buf2);
   }
   if(op->stats.Str!=op2->stats.Str)
     save_long(buf,variable_const[V_STR],op->stats.Str);
diff -ru orig/crossfire-0.95.5-cvs3-patch23/include/define.h crossfire-0.95.5-cvs3/include/define.h
--- orig/crossfire-0.95.5-cvs3-patch23/include/define.h	Sun May 28 20:27:00 2000
+++ crossfire-0.95.5-cvs3/include/define.h	Fri Jun  9 12:28:18 2000
@@ -710,8 +710,19 @@
       safe_strcat(retbuf,")", len, maxlen); \
     }
 
-#define AP_APPLY		1
-#define AP_UNAPPLY		2
+/* Flags for apply_special() */
+enum apply_flag {
+  /* Basic flags, always use one of these */
+	AP_NULL			= 0,
+	AP_APPLY		= 1,
+	AP_UNAPPLY		= 2,
+
+        AP_BASIC_FLAGS		= 15,
+
+  /* Optional flags, for bitwise or with a basic flag */
+        AP_NO_MERGE		= 16,
+	AP_IGNORE_CURSE		= 32,
+};
 
 /* Cut off point of when an object is put on the active list or not */
 #define MIN_ACTIVE_SPEED	0.00001
diff -ru orig/crossfire-0.95.5-cvs3-patch23/server/apply.c crossfire-0.95.5-cvs3/server/apply.c
--- orig/crossfire-0.95.5-cvs3-patch23/server/apply.c	Mon May 29 18:31:26 2000
+++ crossfire-0.95.5-cvs3/server/apply.c	Fri Jun  9 12:44:23 2000
@@ -1654,7 +1654,7 @@
 
 int manual_apply (object *op, object *tmp, int aflag)
 {
-  if (QUERY_FLAG (tmp, FLAG_UNPAID)) {
+  if (QUERY_FLAG (tmp, FLAG_UNPAID) && ! QUERY_FLAG (tmp, FLAG_APPLIED)) {
     if (op->type == PLAYER) {
       new_draw_info (NDI_UNIQUE, 0, op, "You should pay for it first.");
       return 1;
@@ -1936,12 +1936,20 @@
 
 /* who is the object using the object.
  * op is the object they are using.
- * aflags is special flags (0 - normal/toggel, 1=always apply, 2=always unapply
- * (see define.h, AP_* values)
+ * aflags is special flags (0 - normal/toggle, AP_APPLY=always apply,
+ * AP_UNAPPLY=always unapply).
+ *
+ * Optional flags:
+ *   AP_NO_MERGE: don't merge an unapplied object with other objects
+ *   AP_IGNORE_CURSE: unapply cursed items
+ *
+ * Usage example:  apply_special (who, op, AP_UNAPPLY | AP_IGNORE_CURSE)
  *
  * apply_special() doesn't check for unpaid items.
  */
-int apply_special(object *who,object *op, int aflags) { /* wear/wield */
+int apply_special (object *who, object *op, int aflags)
+{ /* wear/wield */
+  int basic_flag = aflags & AP_BASIC_FLAGS;
   object *tmp;
   char buf[MAX_BUF];
   int i;
@@ -1955,10 +1963,11 @@
   if(op->env!=who)
     return 1;   /* op is not in inventory */
 
-  if(QUERY_FLAG(op,FLAG_APPLIED)) {
+  if (QUERY_FLAG(op,FLAG_APPLIED)) {
     /* always apply, so no reason to unapply */
-    if (aflags == AP_APPLY) return 0;
-    if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED))
+    if (basic_flag == AP_APPLY) return 0;
+    if ( ! (aflags & AP_IGNORE_CURSE)
+        && (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)))
     {
       new_draw_info_format(NDI_UNIQUE, 0, who,
 	"No matter how hard you try, you just can't\nremove %s.",
@@ -2040,20 +2049,23 @@
     }
     if (buf[0] != '\0')
       new_draw_info(NDI_UNIQUE, 0,who,buf);
-    del_tag = op->count;
-    tmp=merge_ob(op,NULL);
     fix_player(who);
-    if(who->type==PLAYER) {
-	  if (tmp) {  /* it was merged */
-              esrv_del_item (who->contr, del_tag);
-	      op = tmp;
-	  }
-          esrv_send_item(who, op);
+
+    if ( ! (aflags & AP_NO_MERGE)) {
+        tag_t del_tag = op->count;
+        tmp = merge_ob (op, NULL);
+        if (who->type == PLAYER) {
+            if (tmp) {  /* it was merged */
+                esrv_del_item (who->contr, del_tag);
+                op = tmp;
+            }
+            esrv_send_item (who, op);
+        }
     }
 
     return 0;
   }
-  if (aflags == AP_UNAPPLY) return 0;
+  if (basic_flag == AP_UNAPPLY) return 0;
   i=0;
   /* This goes through and checks to see if the player already has something
    * of that type applied - if so, unapply it.
@@ -2229,7 +2241,7 @@
 
 int monster_apply_special (object *who, object *op, int aflags)
 {
-  if (QUERY_FLAG (op, FLAG_UNPAID))
+  if (QUERY_FLAG (op, FLAG_UNPAID) && ! QUERY_FLAG (op, FLAG_APPLIED))
     return 1;
   return apply_special (who, op, aflags);
 }
diff -ru orig/crossfire-0.95.5-cvs3-patch23/server/c_object.c crossfire-0.95.5-cvs3/server/c_object.c
--- orig/crossfire-0.95.5-cvs3-patch23/server/c_object.c	Thu Jun  8 13:01:20 2000
+++ crossfire-0.95.5-cvs3/server/c_object.c	Fri Jun  9 12:07:37 2000
@@ -205,7 +205,7 @@
     return 0;
   }
   else {
-    int aflag=0;
+    enum apply_flag aflag = 0;
     object *inv;
 
     while (*params==' ') params++;
@@ -525,14 +525,9 @@
     if (! sack_can_hold (op, sack, tmp,(nrof?nrof:tmp->nrof)))
       return;
 
-    /* Small hack to avoid autojoining in apply_special(): */
     if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
-      int nrof = tmp->nrof, a;
-      tmp->nrof = 0;
-      a = apply_special(op,tmp,0);
-      tmp->nrof = nrof;
-      if (a)
-	  return;
+      if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
+          return;
     }
 
     /* we want to put some portion of the item into the container */
@@ -593,14 +588,9 @@
       return;
     }
 
-    /* Small hack to avoid autojoining in apply_special(): */
     if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
-      int nrof = tmp->nrof,a;
-      tmp->nrof = 0;
-      a = apply_special (op, tmp,0);
-      tmp->nrof = nrof;
-      if (a)		/* can't unapply it */
-	  return;
+      if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
+          return;		/* can't unapply it */
     }
 
     /* We are only dropping some of the items.  We split the current objec
diff -ru orig/crossfire-0.95.5-cvs3-patch23/server/monster.c crossfire-0.95.5-cvs3/server/monster.c
--- orig/crossfire-0.95.5-cvs3-patch23/server/monster.c	Sun May 28 20:27:01 2000
+++ crossfire-0.95.5-cvs3/server/monster.c	Fri Jun  9 12:15:35 2000
@@ -1410,7 +1410,7 @@
   if ( ! tmp)
     tmp = heaviest;
   if (tmp && QUERY_FLAG (tmp, FLAG_APPLIED)) {
-    if (monster_apply_special (op, tmp, AP_UNAPPLY)) {
+    if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE)) {
       LOG (llevError, "BUG: find_mon_throw_ob(): couldn't unapply\n");
       tmp = NULL;
     }
diff -ru orig/crossfire-0.95.5-cvs3-patch23/server/skills.c crossfire-0.95.5-cvs3/server/skills.c
--- orig/crossfire-0.95.5-cvs3-patch23/server/skills.c	Mon May 29 18:31:26 2000
+++ crossfire-0.95.5-cvs3/server/skills.c	Fri Jun  9 12:15:00 2000
@@ -1318,11 +1318,7 @@
           "The %s sticks to your hand!",query_name(tmp));
         tmp = NULL;
       } else {
-        tag_t tag = tmp->count;
-        player_apply (op, tmp, AP_UNAPPLY, 0);
-        if (was_destroyed (tmp, tag)) {
-          tmp = NULL;
-        } else if (QUERY_FLAG (tmp, FLAG_APPLIED)) {
+        if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE)) {
           LOG (llevError, "BUG: find_throw_ob(): couldn't unapply\n");
           tmp = NULL;
         }
diff -ru orig/crossfire-0.95.5-cvs3-patch23/server/spell_effect.c crossfire-0.95.5-cvs3/server/spell_effect.c
--- orig/crossfire-0.95.5-cvs3-patch23/server/spell_effect.c	Fri Jun  9 13:02:31 2000
+++ crossfire-0.95.5-cvs3/server/spell_effect.c	Fri Jun  9 13:52:25 2000
@@ -3056,7 +3056,8 @@
     op->contr->golem=tmp;
     op->contr->shoottype=range_scroll;
   } else {
-  /* if uncursed and animated by a pet(???), make the golem a pet */
+  /* If spell is cast by a pet, and the weapon is not cursed, make the animated
+   * weapon a pet. */
     if(QUERY_FLAG(op, FLAG_FRIENDLY)
        && !QUERY_FLAG(weapon,FLAG_CURSED)
        && !QUERY_FLAG(weapon,FLAG_DAMNED)){
@@ -3073,18 +3074,24 @@
   }
 
   /* ok, tailor the golem's characteristics based on the weapon */
-  tmp->stats.Str += weapon->stats.Str;
-  tmp->stats.Dex += weapon->stats.Dex;
-  tmp->stats.Con += weapon->stats.Con;
-  tmp->stats.Int += weapon->stats.Int;
-  tmp->stats.Wis += weapon->stats.Wis;
-  tmp->stats.Pow += weapon->stats.Pow;
-  tmp->stats.Cha += weapon->stats.Cha;
-  LOG(llevDebug, "animate_weapon: Str:%d  Dex:%d  Con:%d  Int:%d  Wis:%d  Pow:%d  Cha:%d.\n",
-      tmp->stats.Str, tmp->stats.Dex, tmp->stats.Con, tmp->stats.Int, tmp->stats.Wis, tmp->stats.Pow, tmp->stats.Cha);
+  if (spellnum == SP_STAFF_TO_SNAKE || spellnum == SP_ANIMATE_WEAPON) {
+    if (apply_special (op, weapon,
+                       AP_UNAPPLY | AP_IGNORE_CURSE | AP_NO_MERGE))
+    {
+      LOG (llevError, "BUG: animate_weapon(): can't unapply weapon\n");
+      return 0;
+    }
+    remove_ob (weapon);
+    insert_ob_in_ob (weapon, tmp);
+    if (op->type == PLAYER)
+      esrv_send_item(op, weapon);
+    SET_FLAG (tmp, FLAG_USE_WEAPON);
+    if (apply_special (tmp, weapon, AP_APPLY))
+      LOG (llevError, "BUG: animate_weapon(): golem can't apply weapon\n");
+  }
+
   /* modify weapon's animated wc */
   tmp->stats.wc = tmp->stats.wc
-    - weapon->stats.wc
     - SP_level_dam_adjust(op,caster,spellnum)
     - 5 * weapon->stats.Dex
     - 2 * weapon->stats.Str
@@ -3108,15 +3115,8 @@
   if(tmp->stats.dam<0) tmp->stats.dam=127;
   LOG(llevDebug,"animate_weapon: wc:%d  hp:%d  dam:%d.\n", tmp->stats.wc, tmp->stats.hp, tmp->stats.dam);
   /* attacktype */
-  if (weapon->attacktype) {
-    tmp->attacktype = weapon->attacktype;
-  } else {
+  if ( ! tmp->attacktype)
     tmp->attacktype = AT_PHYSICAL;
-  }
-  /* Set weapon's protection according to material and protected attribute */
-  tmp->protected = weapon->protected;
-  /* Set vulnerability according to weapon's material and vulnerability attribute */
-  tmp->vulnerable = weapon->vulnerable;
   for(i=0; i<NROFMATERIALS; i++)
     for(j=0; j<NROFATTACKS; j++)
       if(weapon->material & (1<<i)) {
@@ -3138,12 +3138,8 @@
     }
   }
   tmp->armour = 100 - (int)((100.0-(float)tmp->armour)/(30.0-2.0*(a>14?14.0:(float)a)));
-  /* If the weapon has a Slaying list, so does the golem */
-  if (tmp->slaying) {
-    free_string (tmp->slaying);
-    tmp->slaying = NULL;
-  }
-  if(weapon->slaying) tmp->slaying = add_string(weapon->slaying);
+  LOG (llevDebug, "animate_weapon: slaying %s\n",
+       tmp->slaying ? tmp->slaying : "nothing");
 
   /* Determine golem's speed */
   tmp->speed = ((weapon->last_sp>0.1)?weapon->last_sp:0.1) -
@@ -3163,26 +3159,13 @@
   switch(spellnum) {
 
   case SP_STAFF_TO_SNAKE:
-    /* now, remove object from op inv, insert into golem */
-    remove_ob(weapon);
-    /*    apply_special(op, weapon, AP_UNAPPLY);*/
-    insert_ob_in_ob(weapon,tmp);
-    fix_player(op);
-    esrv_send_item(op, weapon);
     new_draw_info(NDI_UNIQUE, 0,op,"Your staff becomes a serpent and leaps to the ground!");
     break;
 
   case SP_ANIMATE_WEAPON:
-    /* now, remove object from op inv, insert into golem */
-    remove_ob(weapon);
-    /*    apply_special(op, weapon, AP_UNAPPLY);*/
-    insert_ob_in_ob(weapon,tmp);
-    fix_player(op);
-    esrv_send_item(op, weapon);
-
     new_draw_info_format(NDI_UNIQUE, 0,op,"Your %s flies from your hand and hovers in mid-air!", weapon->name);
-    if(tmp->name) free_string(tmp->name);
     sprintf(buf, "animated %s", weapon->name);
+    if(tmp->name) free_string(tmp->name);
     tmp->name = add_string(buf);
 
     tmp->face = weapon->face;
@@ -3196,7 +3179,6 @@
       CLEAR_FLAG(tmp,FLAG_ANIMATE); 
     }
     update_ob_speed(tmp);
-    SET_FLAG(weapon,FLAG_APPLIED); /* so it can take acid damage */
     break;
 
   case SP_DANCING_SWORD: