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

CF: Some owner fixes



This patch is already in the CVS tree.  It fixes explode_object() which
used op->owner directly and it fixes move_swarm_spell() which didn't
cast the spells with the correct skill and experience object pointers
set.  Furthermore, it might fix something in tailor_god_spell() (there
was some suspicious code which should now be at least more robust).

common/object.c:  Splitted set_owner() into set_owner_simple() and
set_owner().  copy_owner(): New function.
server/spell_util.c: explode_object(): Use copy_owner() instead of setting
skill and experience objects manually.  Bugfix: Don't use op->owner
directly (fixed by using the caster in call to SP_level_dam_adjust(),
not the owner, which was wrong anyway).
server/spell_util.c: fire_arch_from_position(): Use copy_owner() instead
of set_owner() if 'op' isn't the real owner but only a spell object
owned by somebody else.
server/spell_util.c: move_swarm_spell(): Use the swarm spell object as
the owner in call to fire_arch_from_position(), which now handles this
case correctly.
server/spell_util.c: fire_swarm(): Call tailor_god_spell().
server/gods.c: determine_god(): op->type==SWARM_SPELL is a spell.
server/gods.c: tailor_god_spell(): op->type==SWARM_SPELL is a spell.
Always abort function if we couldn't find a god.  Always add god's
attacktype if the spellop's attacktype has AT_GODPOWER.

*** orig/crossfire-0.95.5-cvs1-patch-pre13-urgent5/common/object.c	Thu Mar 16 08:06:57 2000
--- crossfire-0.95.5-cvs1/common/object.c	Mon May 22 13:53:17 2000
***************
*** 355,372 ****
  /*
   * Sets the owner of the first object to the second object.
   * Also checkpoints a backup id-scheme which detects freeing (and reusage)
   * of the owner object.
   * See also get_owner()
-  * The real purpose of setting an owner is so we know who kills something
-  * so we can properly credit EXP.
   */
  
! void set_owner(object *op, object *owner) {
! 
!     if(owner==NULL||op==NULL)
! 	return;
      /* next line added to allow objects which own objects */ 
      /* Add a check for ownercounts in here, as I got into an endless loop
       * with the fireball owning a poison cloud which then owned the
       * fireball.  I believe that was caused by one of the objects getting
       * freed and then another object replacing it.  Since the ownercounts
--- 355,368 ----
  /*
   * Sets the owner of the first object to the second object.
   * Also checkpoints a backup id-scheme which detects freeing (and reusage)
   * of the owner object.
   * See also get_owner()
   */
  
! static void set_owner_simple (object *op, object *owner)
! {
      /* next line added to allow objects which own objects */ 
      /* Add a check for ownercounts in here, as I got into an endless loop
       * with the fireball owning a poison cloud which then owned the
       * fireball.  I believe that was caused by one of the objects getting
       * freed and then another object replacing it.  Since the ownercounts
***************
*** 382,409 ****
  
      op->owner=owner;
  
      op->ownercount=owner->count;
      owner->refcount++;
  
  #ifdef ALLOW_SKILLS /* set the pointers in op to inherit owners skill, exp_obj */ 
!     if(owner->type==PLAYER&&owner->chosen_skill) {
! 	op->chosen_skill = owner->chosen_skill;
! 	op->exp_obj = owner->chosen_skill->exp_obj;
! 
! 	    /* unfortunately, we can't allow summoned monsters skill use
! 	     * because we will need the chosen_skill field to pick the
! 	     * right skill/stat modifiers for calc_skill_exp(). See
! 	     * hit_player() in server/attack.c -b.t. 
! 	     */
! 	if(QUERY_FLAG(op,FLAG_CAN_USE_SKILL))
! 	    CLEAR_FLAG(op,FLAG_CAN_USE_SKILL);
! 	if(QUERY_FLAG(op,FLAG_READY_SKILL))
! 	    CLEAR_FLAG(op,FLAG_READY_SKILL);
  
!     } else if(op->type!=PLAYER && QUERY_FLAG(op,FLAG_READY_SKILL))
! 	CLEAR_FLAG(op,FLAG_READY_SKILL);
  #endif
  }
  
  /*
   * Resets vital variables in an object
--- 378,447 ----
  
      op->owner=owner;
  
      op->ownercount=owner->count;
      owner->refcount++;
+ }
+ 
+ #ifdef ALLOW_SKILLS
+ static void set_skill_pointers (object *op, object *chosen_skill,
+ 	object *exp_obj)
+ {
+     op->chosen_skill = chosen_skill;
+     op->exp_obj = exp_obj;
+ 
+     /* unfortunately, we can't allow summoned monsters skill use
+      * because we will need the chosen_skill field to pick the
+      * right skill/stat modifiers for calc_skill_exp(). See
+      * hit_player() in server/attack.c -b.t.
+      */
+     CLEAR_FLAG (op, FLAG_CAN_USE_SKILL);
+     CLEAR_FLAG (op, FLAG_READY_SKILL);
+ }
+ #endif
+ 
+ /*
+  * Sets the owner and sets the skill and exp pointers to owner's current
+  * skill and experience objects.
+  */
+ void set_owner (object *op, object *owner)
+ {
+     if(owner==NULL||op==NULL)
+ 	return;
+     set_owner_simple (op, owner);
  
  #ifdef ALLOW_SKILLS /* set the pointers in op to inherit owners skill, exp_obj */ 
!     if (owner->type == PLAYER && owner->chosen_skill)
!         set_skill_pointers (op, owner->chosen_skill,
!                             owner->chosen_skill->exp_obj);
!     else if (op->type != PLAYER)
! 	CLEAR_FLAG (op, FLAG_READY_SKILL);
! #endif
! }
  
! /* Set the owner to clone's current owner and set the skill and experience
!  * objects to clone's objects (typically those objects that where the owner's
!  * current skill and experience objects at the time when clone's owner was
!  * set - not the owner's current skill and experience objects).
!  *
!  * Use this function if player created an object (e.g. fire bullet, swarm
!  * spell), and this object creates further objects whose kills should be
!  * accounted for the player's original skill, even if player has changed
!  * skills meanwhile.
!  */
! void copy_owner (object *op, object *clone)
! {
!     object *owner = get_owner (clone);
!     if (owner == NULL)
!       return;
!     set_owner_simple (op, owner);
! 
! #ifdef ALLOW_SKILLS
!     if (clone->chosen_skill)
!         set_skill_pointers (op, clone->chosen_skill, clone->exp_obj);
!     else if (op->type != PLAYER)
! 	CLEAR_FLAG (op, FLAG_READY_SKILL);
  #endif
  }
  
  /*
   * Resets vital variables in an object
*** orig/crossfire-0.95.5-cvs1-patch-pre13-urgent5/server/gods.c	Mon May 15 22:35:14 2000
--- crossfire-0.95.5-cvs1/server/gods.c	Mon May 22 13:26:44 2000
***************
*** 287,297 ****
  
  char *determine_god(object *op) {
      int godnr = -1;
  
      /* spells */
!     if((op->type==FBULLET||op->type==CONE||op->type==FBALL)&&op->title) {
  	if(lookup_god_by_name(op->title)>=0) return op->title;
      }
  
      if(op->type!= PLAYER && QUERY_FLAG(op,FLAG_ALIVE)) {
  	if(!op->title) {
--- 287,299 ----
  
  char *determine_god(object *op) {
      int godnr = -1;
  
      /* spells */
!     if ((op->type == FBULLET || op->type == CONE || op->type == FBALL
!          || op->type == SWARM_SPELL) && op->title) 
!     {
  	if(lookup_god_by_name(op->title)>=0) return op->title;
      }
  
      if(op->type!= PLAYER && QUERY_FLAG(op,FLAG_ALIVE)) {
  	if(!op->title) {
***************
*** 639,657 ****
      object *god=find_god(determine_god(caster));
      int caster_is_spell=0; 
  
      if(caster->type==FBULLET
         ||caster->type==CONE
!        ||caster->type==FBALL) caster_is_spell=1; 
  
!     if(!caster_is_spell)
!         if(!god||(spellop->attacktype&AT_HOLYWORD&&!god->race)) {
!           new_draw_info(NDI_UNIQUE, 0, caster,
!             "This prayer is useless unless you worship an appropriate god");
!           free_object(spellop);
!           return 0;
!         }
  
      /* either holy word or godpower attacks will set the slaying field */
      if(spellop->attacktype&AT_HOLYWORD||spellop->attacktype&AT_GODPOWER) { 
           if(spellop->slaying) free_string(spellop->slaying);
           if(!caster_is_spell)
--- 641,662 ----
      object *god=find_god(determine_god(caster));
      int caster_is_spell=0; 
  
      if(caster->type==FBULLET
         ||caster->type==CONE
!        ||caster->type==FBALL
!        ||caster->type==SWARM_SPELL) caster_is_spell=1;
  
!     if ( ! god || (spellop->attacktype & AT_HOLYWORD && ! god->race)) {
!         if ( ! caster_is_spell)
!             new_draw_info(NDI_UNIQUE, 0, caster,
!               "This prayer is useless unless you worship an appropriate god");
!         else
!             LOG (llevError, "BUG: tailor_god_spell(): no god\n");
!         free_object(spellop);
!         return 0;
!     }
  
      /* either holy word or godpower attacks will set the slaying field */
      if(spellop->attacktype&AT_HOLYWORD||spellop->attacktype&AT_GODPOWER) { 
           if(spellop->slaying) free_string(spellop->slaying);
           if(!caster_is_spell)
***************
*** 659,672 ****
  	 else if(caster->slaying) 
  	    spellop->slaying = add_string(caster->slaying);
      }
  
      /* only the godpower attacktype adds the god's attack onto the spell */
!     if((spellop->attacktype&AT_GODPOWER)&&!caster_is_spell) 
           spellop->attacktype=spellop->attacktype|god->attacktype;
  
!     /* a little cosmetic for fun, we tack on the god's name to the spell */
      if(spellop->attacktype&AT_HOLYWORD||spellop->attacktype&AT_GODPOWER) { 
           if(spellop->title) 
  	   free_string(spellop->title);
           spellop->title=add_string(god->name);
           if(spellop->title){
--- 664,677 ----
  	 else if(caster->slaying) 
  	    spellop->slaying = add_string(caster->slaying);
      }
  
      /* only the godpower attacktype adds the god's attack onto the spell */
!     if(spellop->attacktype & AT_GODPOWER)
           spellop->attacktype=spellop->attacktype|god->attacktype;
  
!     /* tack on the god's name to the spell */
      if(spellop->attacktype&AT_HOLYWORD||spellop->attacktype&AT_GODPOWER) { 
           if(spellop->title) 
  	   free_string(spellop->title);
           spellop->title=add_string(god->name);
           if(spellop->title){
*** orig/crossfire-0.95.5-cvs1-patch-pre13-urgent5/server/spell_util.c	Mon May 15 22:35:15 2000
--- crossfire-0.95.5-cvs1/server/spell_util.c	Mon May 22 13:41:23 2000
***************
*** 974,985 ****
  /*  peterm  added a type field to fire_arch.  Needed it for making
      fireball etall level dependent.
      Later added a ball-lightning firing routine.
   * dir is direction, at is spell we are firing.  Type is index of spell
   * array.  If magic is 1, then add magical attacktype to spell.
!  * op is the owner of the spell (player who gets exp), caster is the
!  * casting object.
   */
  
  int fire_arch (object *op, object *caster, int dir, archetype *at, int type,
  	int magic)
  {
--- 976,987 ----
  /*  peterm  added a type field to fire_arch.  Needed it for making
      fireball etall level dependent.
      Later added a ball-lightning firing routine.
   * dir is direction, at is spell we are firing.  Type is index of spell
   * array.  If magic is 1, then add magical attacktype to spell.
!  * op is either the owner of the spell (player who gets exp) or the
!  * casting object owned by the owner.  caster is the casting object.
   */
  
  int fire_arch (object *op, object *caster, int dir, archetype *at, int type,
  	int magic)
  {
***************
*** 1003,1013 ****
    tmp->stats.sp=type;
    tmp->stats.dam=SP_PARAMETERS[type].bdam+SP_level_dam_adjust(op,caster,type);
    tmp->stats.hp=SP_PARAMETERS[type].bdur+SP_level_strength_adjust(op,caster,type);
    tmp->x=x, tmp->y=y;
    tmp->direction=dir;
!   set_owner(tmp,op);
    tmp->level = casting_level (caster, type);
  #ifdef MULTIPLE_GODS /* needed for AT_HOLYWORD,AT_GODPOWER stuff */
    if(tmp->attacktype&AT_HOLYWORD||tmp->attacktype&AT_GODPOWER) {
  	      if(!tailor_god_spell(tmp,op)) return 0; 
    } else /* Ugly else going across endif */
--- 1005,1018 ----
    tmp->stats.sp=type;
    tmp->stats.dam=SP_PARAMETERS[type].bdam+SP_level_dam_adjust(op,caster,type);
    tmp->stats.hp=SP_PARAMETERS[type].bdur+SP_level_strength_adjust(op,caster,type);
    tmp->x=x, tmp->y=y;
    tmp->direction=dir;
!   if (get_owner (op) != NULL)
!     copy_owner (tmp, op);
!   else
!     set_owner (tmp, op);
    tmp->level = casting_level (caster, type);
  #ifdef MULTIPLE_GODS /* needed for AT_HOLYWORD,AT_GODPOWER stuff */
    if(tmp->attacktype&AT_HOLYWORD||tmp->attacktype&AT_GODPOWER) {
  	      if(!tailor_god_spell(tmp,op)) return 0; 
    } else /* Ugly else going across endif */
***************
*** 1411,1421 ****
    }
    insert_ob_in_map(op,op->map);
  }
  
  int explode_object(object *op) {
!   object *tmp, *victim, *owner, *env;
  
    if(out_of_map(op->map,op->x,op->y))  /*  peterm:  check for out of map obj's.*/
      {
        return 0;
      }
--- 1416,1426 ----
    }
    insert_ob_in_map(op,op->map);
  }
  
  int explode_object(object *op) {
!   object *tmp, *victim, *env;
  
    if(out_of_map(op->map,op->x,op->y))  /*  peterm:  check for out of map obj's.*/
      {
        return 0;
      }
***************
*** 1450,1470 ****
    /*  peterm:  hack added to make fireballs and other explosions level
     *  dependent:
     */
  
    /*  op->stats.sp stores the spell which made this object here. */
!   if(op->owner)
!       tmp->stats.dam += SP_level_dam_adjust(op->owner,op->owner,op->stats.sp);
    if(op->attacktype&AT_MAGIC)
      tmp->attacktype|=AT_MAGIC;
!   if((owner = get_owner(op)) != (object *) NULL) {
!     set_owner(tmp,owner);
!     if(op->chosen_skill && (op->chosen_skill != tmp->chosen_skill)){
!           tmp->exp_obj = op->exp_obj;
!           tmp->chosen_skill = op->chosen_skill;
!     }
!   }
    if(op->stats.hp)
      tmp->stats.hp=op->stats.hp;
    tmp->stats.maxhp=op->count; /* Unique ID */
    tmp->x=env->x,tmp->y=env->y;
  
--- 1455,1468 ----
    /*  peterm:  hack added to make fireballs and other explosions level
     *  dependent:
     */
  
    /*  op->stats.sp stores the spell which made this object here. */
!   tmp->stats.dam += SP_level_dam_adjust(op,op,op->stats.sp);
    if(op->attacktype&AT_MAGIC)
      tmp->attacktype|=AT_MAGIC;
!   copy_owner (tmp, op);
    if(op->stats.hp)
      tmp->stats.hp=op->stats.hp;
    tmp->stats.maxhp=op->count; /* Unique ID */
    tmp->x=env->x,tmp->y=env->y;
  
***************
*** 1787,1799 ****
  
  void move_swarm_spell(object *op)
  {
      sint16 x,y;
      int di;
-     object *owner = get_owner (op);
  
!     if(op->stats.hp == 0 || owner == NULL) {
  	remove_ob(op);
  	free_object(op);
  	return;
      }
      op->stats.hp--;
--- 1785,1796 ----
  
  void move_swarm_spell(object *op)
  {
      sint16 x,y;
      int di;
  
!     if(op->stats.hp == 0 || get_owner (op) == NULL) {
  	remove_ob(op);
  	free_object(op);
  	return;
      }
      op->stats.hp--;
***************
*** 1806,1816 ****
     y = op->y + freearr_y[absdir(op->direction +di)];
  
     /*  for level dependence, we need to know what spell is fired.  */
     /*  that's stored in op->stats.sp  by fire_swarm  */
     if ( ! wall (op->map, x, y))
!        fire_arch_from_position (owner, op, x, y, op->direction, op->other_arch,
                                  op->stats.sp, op->magic);
  }
  
  
  
--- 1803,1813 ----
     y = op->y + freearr_y[absdir(op->direction +di)];
  
     /*  for level dependence, we need to know what spell is fired.  */
     /*  that's stored in op->stats.sp  by fire_swarm  */
     if ( ! wall (op->map, x, y))
!        fire_arch_from_position (op, op, x, y, op->direction, op->other_arch,
                                  op->stats.sp, op->magic);
  }
  
  
  
***************
*** 1837,1846 ****
    tmp->x=op->x;
    tmp->y=op->y;	    
    set_owner(tmp,op);       /* needed so that if swarm elements kill, caster gets xp.*/
    tmp->level=casting_level(caster, spell_type);   /*needed later, to get level dep. right.*/
    tmp->stats.sp=spell_type;  /* needed later, see move_swarm_spell */
    tmp->magic = magic;
    tmp->stats.hp=n;	    /* n in swarm*/
    tmp->other_arch=swarm_type;  /* the archetype of the things to be fired*/
    tmp->direction=dir; 
    tmp->invisible=1;
--- 1834,1850 ----
    tmp->x=op->x;
    tmp->y=op->y;	    
    set_owner(tmp,op);       /* needed so that if swarm elements kill, caster gets xp.*/
    tmp->level=casting_level(caster, spell_type);   /*needed later, to get level dep. right.*/
    tmp->stats.sp=spell_type;  /* needed later, see move_swarm_spell */
+ #ifdef MULTIPLE_GODS
+   tmp->attacktype = swarm_type->clone.attacktype;
+   if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER) {
+     if ( ! tailor_god_spell (tmp, op))
+       return;
+   }
+ #endif 
    tmp->magic = magic;
    tmp->stats.hp=n;	    /* n in swarm*/
    tmp->other_arch=swarm_type;  /* the archetype of the things to be fired*/
    tmp->direction=dir; 
    tmp->invisible=1;
*** orig/crossfire-0.95.5-cvs1-patch-pre13-urgent5/include/libproto.h	Fri Apr  2 21:10:04 1999
--- crossfire-0.95.5-cvs1/include/libproto.h	Mon May 22 13:30:37 2000
***************
*** 313,322 ****
--- 314,324 ----
  extern void set_max_time ( long t );
  extern void set_monster_check_apply ( type_func_ob_ob addr );
  extern void set_move_creator ( type_func_ob addr );
  extern void set_move_teleporter ( type_func_ob addr );
  extern void set_owner ( object *op, object *owner );
+ extern void copy_owner ( object *op, object *clone );
  extern void set_process_active_maps ( type_func_void addr );
  extern void set_remove_friendly_object ( type_func_ob addr );
  extern void set_ring_bonus ( object *op, int bonus );
  extern void set_trap_adjust ( type_func_ob_int addr );
  extern void set_update_buttons ( type_func_map addr );

-- 
Jan
-
[you can put yourself on the announcement list only or unsubscribe altogether
by sending an email stating your wishes to crossfire-request@ifi.uio.no]