Difference for server/attack.c from version 1.59 to 1.60


version 1.59 version 1.60
Line 1
 
Line 1
 /*  /*
  * static char *rcsid_attack_c =   * static char *rcsid_attack_c =
  *   "$Id: attack.c,v 1.59 2001/11/28 04:44:42 michtoen Exp $";   *   "$Id: attack.c,v 1.60 2001/12/14 10:31:34 darth_bob Exp $";
  */   */
 /*  /*
     CrossFire, A Multiplayer game for X-windows      CrossFire, A Multiplayer game for X-windows
Line 953
 
Line 953
     }      }
 }  }
   
 /* This returns the amount of damage hitter does to op with the appropriate  /* This returns the amount of damage hitter does to op with the
  * attacktype.  Only 1 attacktype should be set at a time.  This doesn't   * appropriate attacktype.  Only 1 attacktype should be set at a time.
  * damage the player, but returns how much it should take.  However, it will   * This doesn't damage the player, but returns how much it should
  * do other effects (paralyzation, slow, etc.)   * take.  However, it will do other effects (paralyzation, slow, etc.)
  * Note - changed for PR code - we now pass the attack number and not   * Note - changed for PR code - we now pass the attack number and not
  * the attacktype.  Makes it easier for the PR code.   * the attacktype.  Makes it easier for the PR code.  */
  */  
   
 int hit_player_attacktype(object *op, object *hitter, int dam,   int hit_player_attacktype(object *op, object *hitter, int dam,
  uint32 attacknum, int magic) {   uint32 attacknum, int magic) {
      
     int does_slay=0;      int doesnt_slay = 1;
     int level_diff;       /* for special attacktypes (paralyze, etc) */  
     uint32 attacktype=1<<attacknum;  
   
     /* Catch anyone that may be trying to send us a bitmask instead of the number */      /* Catch anyone that may be trying to send us a bitmask instead of the number */
     if (attacknum>=NROFATTACKS) {      if ((attacknum >= NROFATTACKS) || (attacknum < 0)) {
  LOG(llevError, "hit_player_attacktype: Invalid attacknumber passed: %x\n", attacknum);   LOG(llevError, "hit_player_attacktype: Invalid attacknumber passed: %x\n", attacknum);
  return 0;   return 0;
     }      }
   
     if (!attacktype) {  
  LOG(llevError,"hit_player_attacktype called without an attacktype\n");  
  return 0;  
     }  
     if (dam < 0) {      if (dam < 0) {
  LOG(llevError,"hit_player_attacktype called with negative damage: %d\n", dam);   LOG(llevError,"hit_player_attacktype called with negative damage: %d\n", dam);
  return 0;   return 0;
     }      }
   
     /* AT_INTERNAL is supposed to do exactly dam.  Put a case here so      /* AT_INTERNAL is supposed to do exactly dam.  Put a case here so
      * people can't mess with that or it otherwise get confused.       * people can't mess with that or it otherwise get confused.  */
      */      if (attacknum == ATNR_INTERNAL) return dam;
     if (attacktype & AT_INTERNAL) return dam;  
   
     if (hitter->slaying) {      if (hitter->slaying) {
  if (((op->race !=NULL && strstr(hitter->slaying,op->race)) ||        if(
    (op->arch && op->arch->name!=NULL && strstr(op->arch->name, hitter->slaying)))) {   ((op->race != NULL) &&
      does_slay=1;     strstr(hitter->slaying, op->race)
      ) ||
    (op->arch &&
      (op->arch->name != NULL) &&
      strstr(op->arch->name, hitter->slaying))
    ) {
    doesnt_slay = 0;
      dam*=3;       dam*=3;
  }   }
     }      }
   
     /* Adjust the damage for resistance. Note that neg. values increase damage. */      /* Adjust the damage for resistance. Note that neg. values increase damage. */
     if (op->resist[attacknum] || 1) {      if(1) { // if (op->resist[attacknum] || 1) { // This is a nop!
       /* basically:  dam = dam*(100-op->resist[attacknum])/100;        /* basically:  dam = dam*(100-op->resist[attacknum])/100;
        * in case 0>dam>1, we try to "simulate" a float value-effect */         * in case 0>dam>1, we try to "simulate" a float value-effect */
       dam = dam*(100-op->resist[attacknum]);        dam *= (100-op->resist[attacknum]);
       if (dam >= 100)        if (dam >= 100)
  dam /= 100;   dam /= 100;
       else        else
  dam = (dam > (random_roll(0, 99, op, PREFER_LOW))) ? 1 : 0;   dam = (dam > (random_roll(0, 99, op, PREFER_LOW))) ? 1 : 0;
         // why not simulate for all values?
         // dam = (dam / 100) + (((dam % 100) > (random_roll(0, 99, op, PREFER_LOW))) ? 1 : 0)
     }      }
   
     /* Special hack.  By default, if immune to something, you shouldn't need      /* Special hack.  By default, if immune to something, you
      * to worry.  However, acid is an exception, since it can still damage       * shouldn't need to worry.  However, acid is an exception, since
      * your items.  Only include attacktypes if special processing is needed       * it can still damage your items.  Only include attacktypes if
      */       * special processing is needed */
     if ((op->resist[attacknum]>=100) && !does_slay && !(attacktype & AT_ACID))     
  return 0;      if ((op->resist[attacknum] >= 100) &&
    doesnt_slay &&
    (attacknum != ATNR_ACID))
         return 0; // why do we carefully propagate dam everywhere else?
   
     /* Keep this in order - makes things easier to find */      /* Keep this in order - makes things easier to find */
   
     if (attacktype & AT_PHYSICAL) {      switch(attacknum) {
       case ATNR_PHYSICAL:
  /*  here also check for diseases */   /*  here also check for diseases */
  check_physically_infect(op,hitter);   check_physically_infect(op,hitter);
    break;
   
     /* Don't need to do anything for magic, fire, electricity, cold */   /* Don't need to do anything for:
     } else if (attacktype &        magic,
       (AT_CONFUSION|AT_POISON|AT_SLOW|AT_PARALYZE|AT_FEAR|AT_CANCELLATION|        fire,
        AT_DEPLETE|AT_BLIND)) {        electricity,
  /* Give bonus/penalty for saving throw. */        cold */
  int save_adj=op->resist[attacknum]/10;  
       case ATNR_CONFUSION:
       case ATNR_POISON:
       case ATNR_SLOW:
       case ATNR_PARALYZE:
       case ATNR_FEAR:
       case ATNR_CANCELLATION:
       case AT_DEPLETE:
       case AT_BLIND: {
         /* chance for inflicting a special attack depends on the          /* chance for inflicting a special attack depends on the
     difference between attacker's and defender's level */      difference between attacker's and defender's level */
         level_diff = MIN(110, MAX(0, op->level - hitter->level));   int level_diff = MIN(110, MAX(0, op->level - hitter->level));
   
  /* First, only creatures/players with speed can be affected.   /* First, only creatures/players with speed can be affected.
  * Second, just getting hit doesn't mean it always affects you.   * Second, just getting hit doesn't mean it always affects
  * Third, you still get a saving through against the effect.   * you.  Third, you still get a saving through against the
  */   * effect.  */
         if (op->speed && (QUERY_FLAG(op, FLAG_MONSTER) || op->type==PLAYER) &&          if (op->speed &&
           !(rndm(0, (attacktype&AT_SLOW?6:3)-1)) &&       (QUERY_FLAG(op, FLAG_MONSTER) || op->type==PLAYER) &&
    ((random_roll(1, 20, op, PREFER_LOW)+save_adj)  < savethrow[level_diff])) {       !(rndm(0, (attacknum == ATNR_SLOW?6:3)-1)) &&
        ((random_roll(1, 20, op, PREFER_LOW) +
          op->resist[attacknum]/10) < savethrow[level_diff])) {
   
      switch(attacknum) {
      /* Player has been hit by something */       /* Player has been hit by something */
      if (attacktype & AT_CONFUSION) confuse_player(op,hitter,dam);     case AT_CONFUSION:
      else if (attacktype & AT_POISON) poison_player(op,hitter,dam);       confuse_player(op,hitter,dam);
      else if (attacktype & AT_SLOW) slow_player(op,hitter,dam);       break;
      else if (attacktype & AT_PARALYZE) paralyze_player(op,hitter,dam);     case AT_POISON:
      else if (attacktype & AT_FEAR) SET_FLAG(op, FLAG_SCARED);       poison_player(op,hitter,dam);
      else if (attacktype & AT_CANCELLATION) cancellation(op);       break;
      else if (attacktype & AT_DEPLETE) drain_stat(op);     case AT_SLOW:
      else if (attacktype & AT_BLIND && !QUERY_FLAG(op,FLAG_UNDEAD) &&       slow_player(op,hitter,dam);
  !QUERY_FLAG(op,FLAG_GENERATOR)) blind_player(op,hitter,dam);       break;
      case AT_PARALYZE:
        paralyze_player(op,hitter,dam);
        break;
      case AT_FEAR:
        SET_FLAG(op, FLAG_SCARED);
        break;
      case AT_CANCELLATION:
        cancellation(op);
        break;
      case AT_DEPLETE:
        drain_stat(op);
        break;
      case AT_BLIND:
        if(!QUERY_FLAG(op,FLAG_UNDEAD) &&
    !QUERY_FLAG(op,FLAG_GENERATOR))
          blind_player(op,hitter,dam);
        break;
  }   }
  dam=0; /* These are all effects and don't do real damage */  
     }      }
     else if (attacktype & AT_ACID) {   dam = 0; /* These are all effects and don't do real damage */
  object *tmp;   } break;
       case ATNR_ACID:
         {
  int flag=0;   int flag=0;
   
  /* Items only get corroded if you're not on a battleground and if   /* Items only get corroded if you're not on a battleground and
          * your acid resistance is below 50%. */           * if your acid resistance is below 50%. */
  if (!op_on_battleground(op, NULL, NULL) && (op->resist[ATNR_ACID]<50)) {   if (!op_on_battleground(op, NULL, NULL) &&
        (op->resist[ATNR_ACID] < 50))
      {
        object *tmp;
      for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) {       for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) {
   
  if(!QUERY_FLAG(tmp,FLAG_APPLIED)||tmp->resist[ATNR_ACID]>=10)   if(!QUERY_FLAG(tmp, FLAG_APPLIED) ||
    continue;  /* >= 10% acid res. on itmes will protect these */      (tmp->resist[ATNR_ACID] >= 10))
      /* >= 10% acid res. on itmes will protect these */
      continue;
   
  if(!(tmp->material&M_IRON))   if(!(tmp->material&M_IRON))
      continue;       continue;
  if(tmp->magic< -4) /* Let's stop at -5 */   if(tmp->magic< -4) /* Let's stop at -5 */
      continue;       continue;
   
  if(tmp->type==RING|| /* removed boots and gloves from exlusion list in PR */   if(tmp->type==RING ||
     tmp->type==GIRDLE||tmp->type==AMULET||tmp->type==WAND||      /* removed boots and gloves from exclusion list in
     tmp->type==ROD||tmp->type==HORN)                        PR */
       tmp->type==GIRDLE ||
       tmp->type==AMULET ||
       tmp->type==WAND ||
       tmp->type==ROD ||
       tmp->type==HORN)
  continue; /* To avoid some strange effects */   continue; /* To avoid some strange effects */
   
  /* High damage acid has better chance of corroding objects */   /* High damage acid has better chance of corroding
  if(rndm(0, dam+4)>random_roll(0, 39, op, PREFER_HIGH)+2*tmp->magic) {                     objects */
    if(rndm(0, dam+4) >
       random_roll(0, 39, op, PREFER_HIGH)+2*tmp->magic) {
      if(op->type==PLAYER) {       if(op->type==PLAYER) {
  /* Make this more visible */   /* Make this more visible */
  new_draw_info_format(NDI_UNIQUE|NDI_RED,0, op,   new_draw_info_format(NDI_UNIQUE|NDI_RED,0, op,
Line 1088
 
Line 1133
  esrv_send_item(op, tmp);   esrv_send_item(op, tmp);
  }   }
      }       }
      if(flag) fix_player(op); /* Something was corroded */       if(flag)
          fix_player(op); /* Something was corroded */
  }   }
     }      }
     else if (attacktype & AT_DRAIN) {        break;
       case ATNR_DRAIN:
         {
  /* rate is the proportion of exp drained.  High rate means   /* rate is the proportion of exp drained.  High rate means
  * not much is drained, low rate means a lot is drained.   * not much is drained, low rate means a lot is drained.
  */   */
  int rate = 50;   int rate;
   
  if (op->resist[ATNR_DRAIN]>0) rate *= (100+op->resist[ATNR_DRAIN])/100;  
  else if (op->resist[ATNR_DRAIN]<0) rate /= (100 - op->resist[ATNR_DRAIN])/100;  
   
  /* full protection has no effect.  Nothing else in this function needs   if(op->resist[ATNR_DRAIN] > 0)
  * to get done, so just return.     rate = 50 + op->resist[ATNR_DRAIN] / 2;
  */   else if(op->resist[ATNR_DRAIN] < 0)
  if (!rate) return 0;     rate = 5000 / (100 - op->resist[ATNR_DRAIN]);
   
    /* full protection has no effect.  Nothing else in this
    * function needs to get done, so just return.  */
    if(!rate)
      return 0;
   
  if(op->stats.exp<=rate) {   if(op->stats.exp<=rate) {
      if(op->type==GOLEM)       if(op->type==GOLEM)
  dam=999; /* It's force is "sucked" away. 8) */   dam = 999; /* Its force is "sucked" away. 8) */
      else /* If we can't drain, lets try to do physical damage */       else
          /* If we can't drain, lets try to do physical damage */
  dam=hit_player_attacktype(op, hitter, dam, ATNR_PHYSICAL, magic);   dam=hit_player_attacktype(op, hitter, dam, ATNR_PHYSICAL, magic);
  } else {   } else {
      if(hitter->stats.hp<hitter->stats.maxhp &&       if(hitter->stats.hp<hitter->stats.maxhp &&
Line 1124
 
Line 1175
      }       }
      dam=0; /* Drain is an effect */       dam=0; /* Drain is an effect */
  }   }
     } else if (attacktype & AT_TURN_UNDEAD) {        } break;
       case ATNR_TURN_UNDEAD:
         {
  if (QUERY_FLAG(op,FLAG_UNDEAD)) {   if (QUERY_FLAG(op,FLAG_UNDEAD)) {
      object *owner=get_owner(hitter)==NULL?hitter:get_owner(hitter);       object *owner=get_owner(hitter)==NULL?hitter:get_owner(hitter);
             object *god = find_god (determine_god (owner));              object *god = find_god (determine_god (owner));
             int div = 1;              int div = 1;
   
      /* if undead are not an enemy of your god, you turn them at half       /* if undead are not an enemy of your god, you turn them
              * strength */               * at half strength */
             if ( ! god || ! god->slaying              if ( ! god || ! god->slaying
                 || strstr (god->slaying, undead_name) == NULL)                  || strstr (god->slaying, undead_name) == NULL)
                 div = 2;                  div = 2;
      /* Give a bonus if you resist turn unded */       /* Give a bonus if you resist turn undead */
      if (op->level <       if (op->level * div <
  (turn_bonus[owner->stats.Wis]+owner->level + (op->resist[ATNR_TURN_UNDEAD]/100)) / div)   (turn_bonus[owner->stats.Wis]+owner->level +
    (op->resist[ATNR_TURN_UNDEAD]/100)))
      SET_FLAG(op, FLAG_SCARED);       SET_FLAG(op, FLAG_SCARED);
  }   }
  else dam=0; /*don't damage non undead - should we damage undead? */   else
      dam = 0; /* don't damage non undead - should we damage
     } else if (attacktype & AT_DEATH) {                        undead? */
         } break;
       case ATNR_DEATH:
         {
  deathstrike_player(op, hitter, &dam);   deathstrike_player(op, hitter, &dam);
         } break;
     } else if (attacktype & AT_CHAOS) {      case ATNR_CHAOS:
          LOG(llevError,"%s was hit by %s with non-specific chaos.\n",        {
       query_name(op),query_name(hitter));   LOG(llevError,
        "%s was hit by %s with non-specific chaos.\n",
        query_name(op),
        query_name(hitter));
          dam=0;           dam=0;
         } break;
     } else if (attacktype & AT_COUNTERSPELL) {      case ATNR_COUNTERSPELL:
          LOG(llevError,"%s was hit by %s with counterspell attack.\n",        {
       query_name(op),query_name(hitter));   LOG(llevError,
  dam=0; /* This should never happen.  Counterspell is handled seperately       "%s was hit by %s with counterspell attack.\n",
  * and filtered out.  If this does happen, Counterspell has no       query_name(op),
  * effect on anything but spells, so it does no damage. */       query_name(hitter));
    dam = 0;
     } else if (attacktype & AT_HOLYWORD) {   /* This should never happen.  Counterspell is handled
    * seperately and filtered out.  If this does happen,
    * Counterspell has no effect on anything but spells, so it
    * does no damage. */
         }  break;
         case ATNR_HOLYWORD:
    {
       /* Holyword only affects a limited range of creatures */        /* Holyword only affects a limited range of creatures */
       /* Affects enemies of your god (*3 for slaying applied above) *        /* Affects enemies of your god (*3 for slaying applied above) *
        * Affects undead even if not enemies, unless they are friends *         * Affects undead even if not enemies, unless they are friends *
Line 1173
 
Line 1239
  /* As with turn undead above, give a bonus on the saving throw */   /* As with turn undead above, give a bonus on the saving throw */
  if((op->level+(op->resist[ATNR_HOLYWORD]/100))<owner->level+turn_bonus[owner->stats.Wis])   if((op->level+(op->resist[ATNR_HOLYWORD]/100))<owner->level+turn_bonus[owner->stats.Wis])
      SET_FLAG(op, FLAG_SCARED);       SET_FLAG(op, FLAG_SCARED);
    } break;
     }      }
     return dam;      return dam;
 }  }


Legend:
line(s) removed in v.1.59 
line(s) changed
 line(s) added in v.1.60

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