Difference for server/attack.c from version 1.36 to 1.37


version 1.36 version 1.37
Line 1
 
Line 1
 /*  /*
  * static char *rcsid_attack_c =   * static char *rcsid_attack_c =
  *   "$Id: attack.c,v 1.36 2001/05/29 04:41:53 mwedel Exp $";   *   "$Id: attack.c,v 1.37 2001/06/13 10:51:26 michtoen Exp $";
  */   */
 /*  /*
     CrossFire, A Multiplayer game for X-windows      CrossFire, A Multiplayer game for X-windows
Line 396
 
Line 396
     if (get_attack_mode (&op, &hitter, &simple_attack))      if (get_attack_mode (&op, &hitter, &simple_attack))
         goto error;          goto error;
   
       /* GROS: This is used to handle attack script */
       if (op->script_attack!=NULL)
       {
           guile_call_event(hitter, op, NULL, 0, NULL, base_dam, base_wc, op->script_attack, SCRIPT_FIX_ALL);
       };
       if (op->script_str_attack!=NULL)
       {
           guile_call_event_str(hitter, op, NULL, 0, NULL, base_dam, base_wc, op->script_str_attack, SCRIPT_FIX_ALL);
       };
       /* GROS: This is used to handle script_weapons with weapons. Only used for players */
       if (hitter->type==PLAYER)
       {
           if (hitter->current_weapon != NULL)
           {
                   if (guile_use_weapon_script(hitter, op, base_dam, base_wc))
                   {
                           return;
                   };
           };
       };
   
     op_tag = op->count;      op_tag = op->count;
     hitter_tag = hitter->count;      hitter_tag = hitter->count;
   
Line 616
 
Line 637
 {  {
     object *container, *hitter;      object *container, *hitter;
     int hit_something;      int hit_something;
       int sretval = 0; /* GROS - Needed for script return value */
     tag_t victim_tag, hitter_tag;      tag_t victim_tag, hitter_tag;
     sint16 victim_x, victim_y;      sint16 victim_x, victim_y;
   
Line 639
 
Line 661
     victim_y = victim->y;      victim_y = victim->y;
     victim_tag = victim->count;      victim_tag = victim->count;
     hitter_tag = hitter->count;      hitter_tag = hitter->count;
   
       /* GROS: Handling script_attack event for thrown items */
       if (op->script_attack!=NULL)
       {
           sretval = guile_call_event(hitter, op ,victim, 0, NULL, op->stats.dam, op->stats.wc, op->script_attack, SCRIPT_FIX_ALL);
       }
       else
       {
         if (op->script_str_attack!=NULL)
         {
           sretval = guile_call_event_str(hitter, op ,victim, 0, NULL, op->stats.dam, op->stats.wc, op->script_str_attack, SCRIPT_FIX_ALL);
         }
         else
         {
     hit_something = attack_ob_simple (victim, hitter, op->stats.dam,      hit_something = attack_ob_simple (victim, hitter, op->stats.dam,
                                       op->stats.wc);                                        op->stats.wc);
         };
       };
   
     /* Arrow attacks door, rune of summoning is triggered, demon is put on      /* Arrow attacks door, rune of summoning is triggered, demon is put on
      * arrow, move_apply() calls this function, arrow sticks in demon,       * arrow, move_apply() calls this function, arrow sticks in demon,
      * attack_ob_simple() returns, and we've got an arrow that still exists       * attack_ob_simple() returns, and we've got an arrow that still exists
Line 963
 
Line 1002
     return dam;      return dam;
 }  }
   
   /* GROS: This code comes from hit_player. It has been made external to
    * allow script procedures to "kill" objects in a combat-like fashion.
    * It was initially used by (kill-object) developed for the Collector's
    * Sword. Note that nothing has been changed from the original version
    * of the following code.
    */
   int kill_object(object *op,int dam, object *hitter, int type)
   {
       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);
       int body_attack = op && op->head;   /* Did we hit op's head? */
       int simple_attack;
       tag_t op_tag, hitter_tag;
       int battleg=0;    /* true if op standing on battleground */
       int killed_script_rtn = 0;
       object *owner=NULL;
   
       /* GROS: Handling for the death event */
       if(op->script_death!=NULL)
       {
           killed_script_rtn = guile_call_event(hitter, op ,NULL, type, NULL, 0,0, op->script_death, SCRIPT_FIX_ALL);
           if (killed_script_rtn)
                   return;
       }
      else
       {
           if (op->script_str_death!=NULL)
           {
                   killed_script_rtn = guile_call_event_str(hitter, op ,NULL, type, NULL, 0,0, op->script_str_death, SCRIPT_FIX_ALL);
                   if (killed_script_rtn)
                           return;
           };
       };
   
   /* Object has been killed.  Lets clean it up */
   if (op->stats.hp<0) {
       maxdam+=op->stats.hp+1;
   
       if(QUERY_FLAG(op,FLAG_BLOCKSVIEW))
           update_all_los(op->map); /* makes sure los will be recalculated */
   
       if(op->type==DOOR)
       {
           op->speed = 0.1;
           update_ob_speed(op);
           op->speed_left= -0.05;
           return maxdam;
       };
       if(QUERY_FLAG (op, FLAG_FRIENDLY) && op->type != PLAYER)
       {
           remove_friendly_object(op);
           if (get_owner (op) != NULL && op->owner->type == PLAYER)
                   op->owner->contr->golem=NULL;
           else
                   LOG (llevError, "BUG: hit_player(): Encountered golem "
                   "without owner.\n");
           remove_ob(op);
           free_object(op);
           return maxdam;
       };
   
   /* Now lets start dealing with experience we get for killing something */
   
       owner=get_owner(hitter);
       if(owner==NULL)
           owner=hitter;
   
   /* is the victim (op) standing on battleground? */
       if (op_on_battleground(op, NULL, NULL)) battleg=1;
   
   /* Player killed something */
       if(owner->type==PLAYER)
       {
           Log_Kill(owner->name,
                   query_name(op),op->type,
                   (owner!=hitter) ? query_name(hitter) : NULL,
                   (owner!=hitter) ? hitter->type : 0);
   
           /* This appears to be doing primitive filtering to only
            * display the more interesting monsters.
            */
           if ( owner->level/2<op->level || op->stats.exp>1000)
           {
                   if(owner!=hitter)
                   {
                           (void) sprintf(buf,"You killed %s with %s.",query_name(op)
                                   ,query_name(hitter));
                           old_hitter = hitter;
                           owner->exp_obj=hitter->exp_obj;
                   }
                   else
                   {
                           (void) sprintf(buf,"You killed %s.",query_name(op));
                   }
                   play_sound_map(owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS);
                   new_draw_info(NDI_BLACK, 0,owner,buf);
           }/* message should be displayed */
   
           /* If a player kills another player with melee, not on
            * battleground, the "killer" looses 1 luck. Since this is
            * not reversible, it's actually quite a pain IMHO. -AV */
           if(op->type == PLAYER && hitter != op && !battleg)
                   change_luck(hitter, -1);
       } /* was a player that hit this creature */
   
   /* Pet killed something. */
       if(get_owner(hitter)!=NULL)
       {
           (void) sprintf(buf,"%s killed %s with %s%s.",hitter->owner->name,
                   query_name(op),query_name(hitter), battleg? " (duel)":"");
           old_hitter = hitter;
           owner->exp_obj=hitter->exp_obj;
           hitter=hitter->owner;
       }
       else
           (void) sprintf(buf,"%s killed %s%s.",hitter->name,op->name,
                   battleg? " (duel)":"");
   
   /* If you didn't kill yourself, and your not the wizard */
       if(hitter!=op&&!QUERY_FLAG(op, FLAG_WAS_WIZ))
       {
           int exp=op->stats.exp;
   
           if(!settings.simple_exp && hitter->level>op->level)
                   exp=(exp*(op->level+1))/MAX(hitter->level+1, 1);
   
   /* new exp system in here. Try to insure the right skill is modifying gained exp */
           if(hitter->type==PLAYER && !old_hitter)
                   exp = calc_skill_exp(hitter,op);
           /* case for attack spells, summoned monsters killing */
           if (old_hitter && hitter->type==PLAYER) {
                   object *old_skill = hitter->chosen_skill;
   
           hitter->chosen_skill=old_hitter->chosen_skill;
           exp = calc_skill_exp(hitter,op);
           hitter->chosen_skill = old_skill;
       };
   
   /* Really don't give much experience for killing other players */
       if (op->type==PLAYER)
       {
           if (battleg)
           {
                   new_draw_info(NDI_UNIQUE, 0,hitter, "Your foe has fallen!");
                   new_draw_info(NDI_UNIQUE, 0,hitter, "VICTORY!!!");
           }
           else
                   exp = MIN(5000000, MAX(0, exp/10));
       }
   
   /* Don't know why this is set this way - doesn't make
    * sense to just divide everything by two for no reason.
    */
       if (!settings.simple_exp)
           exp=exp/2;
   
   /* if op is standing on "battleground" (arena), no way to gain
    * exp by killing him */
       if (battleg) exp = 0;
       if(hitter->type!=PLAYER || hitter->contr->party_number<=0)
       {
           add_exp(hitter,exp);
       }
       else
       {
           int shares=0,count=0;
           player *pl;
           int no=hitter->contr->party_number;
   #ifdef PARTY_KILL_LOG
           add_kill_to_party(no,query_name(hitter),query_name(op),exp);
   #endif
           for(pl=first_player;pl!=NULL;pl=pl->next)
           {
                   if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map))
                   {
                           count++;
                           shares+=(pl->ob->level+4);
                   }
           }
           if(count==1 || shares>exp)
                   add_exp(hitter,exp);
           else
           {
                   int share=exp/shares,given=0,nexp;
                   for(pl=first_player;pl!=NULL;pl=pl->next)
                   {
                           if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map))
                           {
                                   nexp=(pl->ob->level+4)*share;
                                   add_exp(pl->ob,nexp);
                                   given+=nexp;
                           }
                   }
                   exp-=given;
                   add_exp(hitter,exp); /* give any remainder to the player */
           }
       }
   }
       if(op->type!=PLAYER)
       {
           new_draw_info(NDI_ALL, 10, NULL, buf);
           if(QUERY_FLAG(op,FLAG_FRIENDLY))
           {
                   object *owner = get_owner(op);
                   if(owner!= NULL && owner->type == PLAYER)
                   {
                           sprintf(buf,"Your pet, the %s, is killed by %s.",
                                   op->name,hitter->name);
                           play_sound_player_only(owner->contr, SOUND_PET_IS_KILLED,0,0);
                           new_draw_info(NDI_UNIQUE, 0,owner,buf);
                   }
                   remove_friendly_object(op);
           }
           remove_ob(op);
           free_object(op);
       }
   /* Player has been killed! */
       else
       {
           new_draw_info(NDI_ALL, 1, NULL, buf);
           if(hitter->type==PLAYER)
           {
                   sprintf(buf,"%s the %s",hitter->name,hitter->contr->title);
                   strncpy(op->contr->killer,buf,BIG_NAME);
           }
           else
           {
                   strncpy(op->contr->killer,hitter->name,BIG_NAME);
                   op->contr->killer[BIG_NAME-1]='\0';
           }
       };
   };
       return -1;
   };
   
 /* This isn't used just for players, but in fact most objects.  /* This isn't used just for players, but in fact most objects.
  * op is the object to be hit, dam is the amount of damage, hitter   * op is the object to be hit, dam is the amount of damage, hitter
  * is what is hitting the object, and type is the attacktype.   * is what is hitting the object, and type is the attacktype.
Line 981
 
Line 1256
     int simple_attack;      int simple_attack;
     tag_t op_tag, hitter_tag;      tag_t op_tag, hitter_tag;
     int battleg=0;    /* true if op standing on battleground */      int battleg=0;    /* true if op standing on battleground */
       int rtn_kill = 0;
   
     if (get_attack_mode (&op, &hitter, &simple_attack))      if (get_attack_mode (&op, &hitter, &simple_attack))
         return 0;          return 0;
Line 1122
 
Line 1398
  tear_down_wall(op);   tear_down_wall(op);
  return maxdam; /* nothing more to do for wall */   return maxdam; /* nothing more to do for wall */
     }      }
    /* Start of creature kill processing */
   
     /* Object has been killed.  Lets clean it up */          rtn_kill = kill_object(op, dam, hitter, type);
     if(op->stats.hp<0) {          if (rtn_kill != -1)
  object *owner=NULL;          {
  maxdam+=op->stats.hp+1;                  return rtn_kill;
  if(QUERY_FLAG(op,FLAG_BLOCKSVIEW))          };
      update_all_los(op->map); /* makes sure los will be recalculated */  
   
  if(op->type==DOOR) {  
      op->speed = 0.1;  
      update_ob_speed(op);  
      op->speed_left= -0.05;  
      return maxdam;  
  }  
  if(QUERY_FLAG (op, FLAG_FRIENDLY) && op->type != PLAYER) {  
      remove_friendly_object(op);  
      if (op->type == GOLEM && get_owner (op) != NULL && op->owner->type == PLAYER)  
  op->owner->contr->golem=NULL;  
 #if 0  
      else  
  LOG (llevError, "BUG: hit_player(): Encountered golem "  
       "without owner.\n");  
 #endif  
      remove_ob(op);  
      free_object(op);  
      return maxdam;  
  }  
   
  /* Now lets start dealing with experience we get for killing something */  
  owner=get_owner(hitter);  
  if(owner==NULL)  
      owner=hitter;  
    
  /* is the victim (op) standing on battleground? */  
  if (op_on_battleground(op, NULL, NULL)) battleg=1;  
    
  /* Player killed something */  
  if(owner->type==PLAYER) {  
      Log_Kill(owner->name,  
       query_name(op),op->type,  
       (owner!=hitter) ? query_name(hitter) : NULL,  
       (owner!=hitter) ? hitter->type : 0);  
   
      /* This appears to be doing primitive filtering to only  
       * display the more interesting monsters.  
       */  
      if ( owner->level/2<op->level || op->stats.exp>1000) {  
  if(owner!=hitter) {  
      (void) sprintf(buf,"You killed %s with %s.",query_name(op)  
         ,query_name(hitter));  
      old_hitter = hitter;  
      owner->exp_obj=hitter->exp_obj;   
  } else {  
  (void) sprintf(buf,"You killed %s.",query_name(op));  
  }  
  play_sound_map(owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS);  
  new_draw_info(NDI_BLACK, 0,owner,buf);  
      }/* message should be displayed */  
   
      /* If a player kills another player with melee, not on  
                battleground, the "killer" looses 1 luck. Since this is  
                not reversible, it's actually quite a pain IMHO. -AV */   
      if(op->type == PLAYER && hitter != op && !battleg)  
        change_luck(hitter, -1);  
  } /* was a player that hit this creature */  
    
  /* Pet killed something. */  
  if(get_owner(hitter)!=NULL) {  
      (void) sprintf(buf,"%s killed %s with %s%s.",hitter->owner->name,  
  query_name(op),query_name(hitter), battleg? " (duel)":"");  
      old_hitter = hitter;  
      owner->exp_obj=hitter->exp_obj;  
      hitter=hitter->owner;  
  }  
  else  
    (void) sprintf(buf,"%s killed %s%s.",hitter->name,op->name,  
  battleg? " (duel)":"");  
    
  /* If you didn't kill yourself, and your not the wizard */  
  if(hitter!=op&&!QUERY_FLAG(op, FLAG_WAS_WIZ)) {  
      int exp=op->stats.exp;  
   
      if(!settings.simple_exp && hitter->level>op->level)  
  exp=(exp*(op->level+1))/MAX(hitter->level+1, 1);  
   
 /* new exp system in here. Try to insure the right skill is modifying gained exp */   
      if(hitter->type==PLAYER && !old_hitter)   
  exp = calc_skill_exp(hitter,op);   
      /* case for attack spells, summoned monsters killing */   
      if (old_hitter && hitter->type==PLAYER) {   
  object *old_skill = hitter->chosen_skill;   
   
  hitter->chosen_skill=old_hitter->chosen_skill;  
  exp = calc_skill_exp(hitter,op);   
  hitter->chosen_skill = old_skill;  
      }  
   
      /* Really don't give much experience for killing other players */  
      if (op->type==PLAYER) {  
        if (battleg) {  
  new_draw_info(NDI_UNIQUE, 0,hitter, "Your foe has fallen!");  
  new_draw_info(NDI_UNIQUE, 0,hitter, "VICTORY!!!");  
        }  
        else  
  exp = MIN(5000000, MAX(0, exp/10));  
      }  
   
      /* Don't know why this is set this way - doesn't make  
       * sense to just divide everything by two for no reason.  
       */  
      if (!settings.simple_exp)  
  exp=exp/2;  
        
      /* if op is standing on "battleground" (arena), no way to gain  
       * exp by killing him */  
      if (battleg) exp = 0;  
            
      if(hitter->type!=PLAYER || hitter->contr->party_number<=0) {  /* End of creature kill processing */
  add_exp(hitter,exp);  
      } else {  
  int shares=0,count=0;  
  player *pl;  
  int no=hitter->contr->party_number;  
 #ifdef PARTY_KILL_LOG  
  add_kill_to_party(no,query_name(hitter),query_name(op),exp);  
 #endif  
  for(pl=first_player;pl!=NULL;pl=pl->next) {  
      if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map)) {  
  count++;  
  shares+=(pl->ob->level+4);  
      }  
  }  
  if(count==1 || shares>exp)  
      add_exp(hitter,exp);  
  else {  
      int share=exp/shares,given=0,nexp;  
      for(pl=first_player;pl!=NULL;pl=pl->next) {  
  if(pl->ob->contr->party_number==no && (pl->ob->map == hitter->map)) {  
      nexp=(pl->ob->level+4)*share;  
      add_exp(pl->ob,nexp);  
      given+=nexp;  
  }  
      }  
      exp-=given;  
      add_exp(hitter,exp); /* give any remainder to the player */  
  }  
      }  
  }  
  if(op->type!=PLAYER) {  
      new_draw_info(NDI_ALL, 10, NULL, buf);  
      if(QUERY_FLAG(op,FLAG_FRIENDLY)) {  
  object *owner = get_owner(op);  
  if(owner!= NULL && owner->type == PLAYER) {  
      sprintf(buf,"Your pet, the %s, is killed by %s.",  
  op->name,hitter->name);  
      play_sound_player_only(owner->contr, SOUND_PET_IS_KILLED,0,0);  
      new_draw_info(NDI_UNIQUE, 0,owner,buf);  
  }  
  remove_friendly_object(op);  
      }  
      remove_ob(op);  
      free_object(op);  
  }  
  /* Player has been killed! */  
  else {  
      new_draw_info(NDI_ALL, 1, NULL, buf);  
      if(hitter->type==PLAYER) {  
  sprintf(buf,"%s the %s",hitter->name,hitter->contr->title);  
  strncpy(op->contr->killer,buf,BIG_NAME);  
      } else {  
  strncpy(op->contr->killer,hitter->name,BIG_NAME);  
  op->contr->killer[BIG_NAME-1]='\0';  
      }  
  }  
     } /* End of creature kill processing */  
   
     /* Used to be ghosthit removal - we now use the ONE_HIT flag.  Note      /* Used to be ghosthit removal - we now use the ONE_HIT flag.  Note
      * that before if the player was immune to ghosthit, the monster        * that before if the player was immune to ghosthit, the monster


Legend:
line(s) removed in v.1.36 
line(s) changed
 line(s) added in v.1.37

File made using version 1.98 of cvs2html by leaf at 2011-07-21 17:25