Difference for server/skills.c from version 1.41 to 1.42


version 1.41 version 1.42
Line 1
 
Line 1
 /*  /*
  * static char *rcsid_skills_c =   * static char *rcsid_skills_c =
  *   "$Id: skills.c,v 1.41 2003/09/04 06:25:32 temitchell Exp $";   *   "$Id: skills.c,v 1.42 2003/09/13 05:02:12 mwedel Exp $";
  */   */
 /*  /*
     CrossFire, A Multiplayer game for X-windows      CrossFire, A Multiplayer game for X-windows
   
     Copyright (C) 2001 Mark Wedel & Crossfire Development Team      Copyright (C) 2003 Mark Wedel & Crossfire Development Team
     Copyright (C) 1992 Frank Tore Johansen      Copyright (C) 1992 Frank Tore Johansen
   
     This program is free software; you can redistribute it and/or modify      This program is free software; you can redistribute it and/or modify
Line 25
 
Line 25
     The authors can be reached via e-mail to crossfire-devel@real-time.com      The authors can be reached via e-mail to crossfire-devel@real-time.com
 */  */
   
 /* Initial coding: 6 Sep 1994, Nick Williams (njw@cs.city.ac.uk) */  
    
 /* Generalized code + added hiding and lockpicking skills, */  
 /* March 3, 1995, brian thomas (thomas@astro.psu.edu) */  
   
 /* Added more skills, fixed bug in stealing code */  
 /* April 21, 1995, brian thomas (thomas@astro.psu.edu) */  
    
 /* Added more skills, fixed bugs, see skills.h */  
 /* May/June, 1995, brian thomas (thomas@astro.psu.edu) */  
   
 /* July 95 Code re-vamped. Now we add the experience objects, all  
  * player activities which gain experience will bbe through the use  
  * of skillls. Thus, I added hand_weapons, missile_weapons, and   
  * remove_traps skills -b.t.   
  */  
   
 /* Aug 95 - Added more skills (disarm traps, spellcasting, praying).   
  * Also, hand_weapons is now "melee_weapons". b.t.   
  */  
   
 /* Oct 95 - changed the praying skill to accomodate MULTIPLE_GODS  
  * hack - b.t.  
  */  
   
 /* Dec 95 - modified the literacy and inscription (writing) skills. b.t.   
  */   
    
 /* Mar 96 - modified the stealing skill. Objects with type FLESH or  
  * w/o a type cannot be stolen by players. b.t.  
  */  
   
 /* Sept 96 - changed parsing of params through use_skill command, also  
  * added in throw skill -b.t. */  
   
 /* Oct 96 - altered hiding and stealing code for playbalance. -b.t. */  
   
 /* Sept 97 - yet another alteration to the stealing code. Lets allow  
  * multiple stealing, after having alerted the victim. But only subsequent  
  * steals made while we are unseen (in dark, invisible, hidden) will have  
  * any chance of success. Also, on each subsequent attempt, we raise the  
  * wisdom of the npc a bit, which makes it ultimately possible for the  
  * npc to detect the theif, regardless of the situation. -b.t. */  
   
 #include <global.h>  #include <global.h>
 #include <object.h>  #include <object.h>
 #ifndef __CEXTRACT__  #ifndef __CEXTRACT__
Line 79
 
Line 35
 #include <spells.h>  #include <spells.h>
 #include <book.h>  #include <book.h>
   
   /* adj_stealchance() - increased values indicate better attempts */
   static int adj_stealchance (object *op, object *victim, int roll) {
       object *equip;
   
       if(!op||!victim||!roll) return -1;
   
       if(op->type==PLAYER && op->body_used[BODY_ARMS] <=0) {
    new_draw_info(NDI_UNIQUE, 0,op,"But you have no free hands to steal with!");
    roll=-1;
       }
   
       /* ADJUSTMENTS */
   
       /* Its harder to steal from hostile beings! */
       if(!QUERY_FLAG(victim, FLAG_UNAGGRESSIVE)) roll = roll/2;
   
       /* Easier to steal from sleeping beings, or if the thief is
        * unseen */
       if(QUERY_FLAG(victim, FLAG_SLEEP))
    roll = roll*3;
       else if(op->invisible) 
    roll = roll*2;
   
       /* check stealing 'encumberance'. Having this equipment applied makes
        * it quite a bit harder to steal.
        */
       for(equip=op->inv;equip;equip=equip->below) {
    if(equip->type==WEAPON&&QUERY_FLAG(equip,FLAG_APPLIED)) {
        roll -= equip->weight/10000;
    }
    if(equip->type==BOW&&QUERY_FLAG(equip,FLAG_APPLIED))
        roll -= equip->weight/5000;
    if(equip->type==SHIELD&&QUERY_FLAG(equip,FLAG_APPLIED)) {
        roll -= equip->weight/2000;
    }
    if(equip->type==ARMOUR&&QUERY_FLAG(equip,FLAG_APPLIED))
        roll -= equip->weight/5000;
    if(equip->type==GLOVES&&QUERY_FLAG(equip,FLAG_APPLIED))
        roll -= equip->weight/100;
       }
       if(roll<0) roll=0;
       return roll;
   }
   
 /*   /*
  * When stealing: dependent on the intelligence/wisdom of whom you're   * When stealing: dependent on the intelligence/wisdom of whom you're
  * stealing from (op in attempt_steal), offset by your dexterity and   * stealing from (op in attempt_steal), offset by your dexterity and
Line 86
 
Line 86
  * or not.    * or not.
  */   */
   
 int attempt_steal(object* op, object* who)  static int attempt_steal(object* op, object* who, object *skill)
 {  {
     object *success=NULL, *tmp=NULL, *next;      object *success=NULL, *tmp=NULL, *next;
     int roll=0, chance=0, stats_value = get_weighted_skill_stats(who)*3;      int roll=0, chance=0, stats_value;
     int victim_lvl=op->level*3, thief_lvl = SK_level(who)*10;  
     rv_vector rv;      rv_vector rv;
   
       stats_value = ((who->stats.Dex + who->stats.Int) * 3) / 2;
   
     /* if the victim is aware of a thief in the area (FLAG_NO_STEAL set on them)      /* if the victim is aware of a thief in the area (FLAG_NO_STEAL set on them)
      * they will try to prevent stealing if they can. Only unseen theives will       * they will try to prevent stealing if they can. Only unseen theives will
      * have much chance of success.        * have much chance of success.
Line 127
 
Line 128
   
  if (QUERY_FLAG(tmp,FLAG_WAS_WIZ) || QUERY_FLAG(tmp, FLAG_APPLIED)    if (QUERY_FLAG(tmp,FLAG_WAS_WIZ) || QUERY_FLAG(tmp, FLAG_APPLIED)
      || !(tmp->type)       || !(tmp->type)
      || tmp->type == EXPERIENCE || tmp->type == ABILITY       || tmp->type == EXPERIENCE || tmp->type == SPELL
      || QUERY_FLAG(tmp,FLAG_STARTEQUIP)       || QUERY_FLAG(tmp,FLAG_STARTEQUIP)
      || QUERY_FLAG(tmp,FLAG_NO_STEAL)       || QUERY_FLAG(tmp,FLAG_NO_STEAL)
      || tmp->invisible ) continue;       || tmp->invisible ) continue;
   
  /* Okay, try stealing this item. Dependent on dexterity of thief,   /* Okay, try stealing this item. Dependent on dexterity of thief,
  * skill level, see the adj_stealroll fctn for more detail. */   * skill level, see the adj_stealroll fctn for more detail.
    */
   
  roll=die_roll(2, 100, who, PREFER_LOW)/2; /* weighted 1-100 */    roll=die_roll(2, 100, who, PREFER_LOW)/2; /* weighted 1-100 */
   
  if((chance=adj_stealchance(who,op,(stats_value+thief_lvl-victim_lvl)))==-1)   if((chance=adj_stealchance(who,op,(stats_value+skill->level * 10 - op->level * 3)))==-1)
      return 0;       return 0;
  else if (roll < chance ) {   else if (roll < chance ) {
      if (op->type == PLAYER)       if (op->type == PLAYER)
Line 168
 
Line 170
      * attempt to steal something heavy off them, they're bound to notice        * attempt to steal something heavy off them, they're bound to notice
      */       */
   
     if((roll>=SK_level(who))||!chance      if((roll>=skill->level) || !chance
       ||(tmp&&tmp->weight>(250*(random_roll(0, stats_value+thief_lvl-1, who, PREFER_LOW))))) {        ||(tmp && tmp->weight>(250*(random_roll(0, stats_value+skill->level * 10-1, who, PREFER_LOW))))) {
   
  /* victim figures out where the thief is! */   /* victim figures out where the thief is! */
  if(who->hide) make_visible(who);   if(who->hide) make_visible(who);
   
  if(op->type != PLAYER) {   if(op->type != PLAYER) {
   
      /* The unaggressives look after themselves 8) */       /* The unaggressives look after themselves 8) */
      if(who->type==PLAYER) {       if(who->type==PLAYER) {
  npc_call_help(op);   npc_call_help(op);
Line 184
 
Line 185
      }       }
      CLEAR_FLAG(op, FLAG_UNAGGRESSIVE);       CLEAR_FLAG(op, FLAG_UNAGGRESSIVE);
      /* all remaining npc items are guarded now. Set flag NO_STEAL        /* all remaining npc items are guarded now. Set flag NO_STEAL
       * on the victim. */        * on the victim.
         */
      SET_FLAG(op,FLAG_NO_STEAL);       SET_FLAG(op,FLAG_NO_STEAL);
  } else { /* stealing from another player */   } else { /* stealing from another player */
      char buf[MAX_BUF];       char buf[MAX_BUF];
Line 209
 
Line 211
     return success? 1:0;      return success? 1:0;
 }  }
   
 /* adj_stealchance() - increased values indicate better attempts */   
   
 int adj_stealchance (object *op, object *victim, int roll) {  
   object *equip;  
   int used_hands=0;  
   
   if(!op||!victim||!roll) return -1;  
   
   /* ADJUSTMENTS */  
   
   /* Its harder to steal from hostile beings! */  
   if(!QUERY_FLAG(victim, FLAG_UNAGGRESSIVE)) roll = roll/2;  
   
   /* Easier to steal from sleeping beings, or if the thief is   
    * unseen */  
   if(QUERY_FLAG(victim, FLAG_SLEEP))   
     roll = roll*3;  
   else if(op->invisible)    
     roll = roll*2;  
   
   /* check stealing 'encumberance'. Having this equipment applied makes  
    * it quite a bit harder to steal. */  
   for(equip=op->inv;equip;equip=equip->below) {   
     if(equip->type==WEAPON&&QUERY_FLAG(equip,FLAG_APPLIED)) {   
       roll -= equip->weight/10000;  
       used_hands++;  
     }  
     if(equip->type==BOW&&QUERY_FLAG(equip,FLAG_APPLIED))   
       roll -= equip->weight/5000;  
     if(equip->type==SHIELD&&QUERY_FLAG(equip,FLAG_APPLIED)) {   
       roll -= equip->weight/2000;  
       used_hands++;  
     }  
     if(equip->type==ARMOUR&&QUERY_FLAG(equip,FLAG_APPLIED))   
       roll -= equip->weight/5000;  
     if(equip->type==GLOVES&&QUERY_FLAG(equip,FLAG_APPLIED))   
       roll -= equip->weight/100;  
   }  
     
   if(roll<0) roll=0;  
   if(op->type==PLAYER && used_hands>=2) {  
     new_draw_info(NDI_UNIQUE, 0,op,"But you have no free hands to steal with!");  
     roll=-1;  
   }  
   
   return roll;  
 }  
   
 int steal(object* op, int dir)  int steal(object* op, int dir, object *skill)
 {  {
     object *tmp, *next;      object *tmp, *next;
     sint16 x, y;      sint16 x, y;
Line 289
 
Line 244
        */          */
       if (tmp->head) tmp=tmp->head;        if (tmp->head) tmp=tmp->head;
       if(tmp->type!=PLAYER&&!QUERY_FLAG(tmp, FLAG_MONSTER)) continue;        if(tmp->type!=PLAYER&&!QUERY_FLAG(tmp, FLAG_MONSTER)) continue;
       if (attempt_steal(tmp, op)) {        if (attempt_steal(tmp, op, skill)) {
    if(tmp->type==PLAYER) /* no xp for stealing from another player */     if(tmp->type==PLAYER) /* no xp for stealing from another player */
      return 0;       return 0;
    else return (calc_skill_exp(op,tmp));     else return (calc_skill_exp(op,tmp, skill));
       }        }
     }      }
     return 0;      return 0;
 }  }
   
   static int attempt_pick_lock (object *door, object *pl, object *skill)
   {
       int difficulty= pl->map->difficulty ? pl->map->difficulty : 0;
       int success = 0, number;        /* did we get anything? */
   
   
       /* Try to pick the lock on this item (doors only for now).
        * Dependent on dexterity/skill SK_level of the player and 
        * the map level difficulty.
        */
       number = (die_roll(2, 40, pl, PREFER_LOW)-2)/2;
       if (number < (pl->stats.Dex + skill->level - difficulty)) {
    remove_door(door);
    success = 1;
       } else if (door->inv && (door->inv->type==RUNE || door->inv->type==TRAP)) {  /* set off any traps? */
    spring_trap(door->inv,pl);       
       }
       return success;
   }
   
   
 /* Implementation by bt. (thomas@astro.psu.edu)  /* Implementation by bt. (thomas@astro.psu.edu)
  * monster implementation 7-7-95 by bt.   * monster implementation 7-7-95 by bt.
  */   */
   
 int pick_lock(object *pl, int dir)  int pick_lock(object *pl, int dir, object *skill)
 {  {
     char buf[MAX_BUF];  
     object *tmp;       object *tmp;
     int x = pl->x + freearr_x[dir];      int x = pl->x + freearr_x[dir];
     int y = pl->y + freearr_y[dir];      int y = pl->y + freearr_y[dir];
     int success = 0;  
   
     if(!dir) dir=pl->facing;      if(!dir) dir=pl->facing;
   
 /* For all the stacked objects at this point find a door*/  /* For all the stacked objects at this point find a door*/
   
     sprintf(buf, "There is no lock there.");  
     if (out_of_map(pl->map,x,y)) {      if (out_of_map(pl->map,x,y)) {
       new_draw_info(NDI_UNIQUE, 0,pl,buf);   new_draw_info(NDI_UNIQUE, 0,pl,"There is no lock there.");
       return 0;        return 0;
     }      }
   
     for(tmp=get_map_ob(pl->map,x,y); tmp; tmp=tmp->above) {      for(tmp=get_map_ob(pl->map,x,y); tmp; tmp=tmp->above)
       if(!tmp) continue;   if (tmp->type == DOOR || tmp->type == LOCKED_DOOR) break;
       switch(tmp->type) {   
         case DOOR:      if (!tmp) {
      if (!QUERY_FLAG(tmp, FLAG_NO_PASS)) {   new_draw_info(NDI_UNIQUE, 0,pl,"There is no lock there.");
  strcpy(buf,"The door has no lock!");   return 0;
      } else {  
  if (attempt_pick_lock(tmp, pl)) {   
      success = 1;  
      sprintf(buf, "you pick the lock.");  
  } else {  
      sprintf(buf, "you fail to pick the lock.");  
  }  
      }  
      break;  
         case LOCKED_DOOR:   
             sprintf(buf, "you can't pick that lock!");  
      break;  
     default:   
      break;  
       }  
     }      }
     new_draw_info(NDI_UNIQUE, 0,pl,buf);      if (tmp->type == LOCKED_DOOR) {
     if(success)   new_draw_info(NDI_UNIQUE, 0,pl, "You can't pick that lock!");
         return calc_skill_exp(pl,NULL);  
     else   
  return 0;   return 0;
 }        }      
   
 int attempt_pick_lock ( object *door, object *pl)      if (!QUERY_FLAG(tmp, FLAG_NO_PASS)) {
 {   new_draw_info(NDI_UNIQUE, 0,pl,"The door has no lock!");
     int bonus = SK_level(pl);   return 0;
     int difficulty= pl->map->difficulty ? pl->map->difficulty : 0;      }
     int dex = get_skill_stat1(pl) ? get_skill_stat1(pl) : 10;  
     int success = 0, number;        /* did we get anything? */  
   
   /* If has can_pass set, then its not locked! */  
    if(!QUERY_FLAG(door,FLAG_NO_PASS)) return 0;  
   
   /* Try to pick the lock on this item (doors only for now).   
    * Dependent on dexterity/skill SK_level of the player and    
    * the map level difficulty.   
    */  
   
     number = (die_roll(2, 40, pl, PREFER_LOW)-2)/2;       if (attempt_pick_lock(tmp, pl, skill)) {
     if (number < ((dex + bonus) - difficulty)) {    new_draw_info(NDI_UNIQUE, 0,pl,"You pick the lock.");
       remove_door(door);   return calc_skill_exp(pl,NULL, skill);
       success = 1;      } else {
     } else if (door->inv && (door->inv->type==RUNE || door->inv->type==TRAP)) {  /* set off any traps? */    new_draw_info(NDI_UNIQUE, 0,pl, "You fail to pick the lock.");
  spring_trap(door->inv,pl);           return 0;
     }       }
     return success;  
 }  }
   
   
 /* HIDE CODE. The user becomes undetectable (not just 'invisible') for  /* HIDE CODE. The user becomes undetectable (not just 'invisible') for
  * a short while (success and duration dependant on player SK_level,   * a short while (success and duration dependant on player SK_level,
  * dexterity, charisma, and map difficulty).    * dexterity, charisma, and map difficulty).
Line 383
 
Line 328
  * July 7, 1995 - made hiding possible for monsters. -b.t.   * July 7, 1995 - made hiding possible for monsters. -b.t.
  */    */
   
   static int attempt_hide(object *op, object *skill) {
       int number,difficulty=op->map->difficulty;
       int terrain = hideability(op);
   
       if(terrain<-10) /* not enough cover here */
    return 0;
   
       /*  Hiding success and duration dependant on skill level,
        *  op->stats.Dex, map difficulty and terrain.
        */
   
       number = (die_roll(2, 25, op, PREFER_LOW)-2)/2;
       if(!stand_near_hostile(op) && (number < (op->stats.Dex + skill->level + terrain - difficulty))) {
    op->invisible += 100;  /* set the level of 'hiddeness' */
    if(op->type==PLAYER)
        op->contr->tmp_invis=1;
    op->hide=1;
    return 1;
       }
       return 0;
   }
   
 /* patched this to take terrain into consideration */  /* patched this to take terrain into consideration */
   
 int hide(object *op) {  int hide(object *op, object *skill) {
   char buf[MAX_BUF];  
   int level= SK_level(op);  
   
 /* the preliminaries -- Can we really hide now? */  /* the preliminaries -- Can we really hide now? */
 /* this keeps monsters from using invisibilty spells and hiding */  /* this keeps monsters from using invisibilty spells and hiding */
   
   if (QUERY_FLAG(op, FLAG_MAKE_INVIS)) {    if (QUERY_FLAG(op, FLAG_MAKE_INVIS)) {
         sprintf(buf,"You don't need to hide while invisible!");   new_draw_info(NDI_UNIQUE, 0,op,"You don't need to hide while invisible!");
         new_draw_info(NDI_UNIQUE, 0,op,buf);  
         return 0;          return 0;
   } else if (!op->hide && op->invisible>0 && op->type == PLAYER) {     } else if (!op->hide && op->invisible>0 && op->type == PLAYER) {
         sprintf(buf,"Your attempt to hide breaks the invisibility spell!");    new_draw_info(NDI_UNIQUE, 0,op,"Your attempt to hide breaks the invisibility spell!");
         new_draw_info(NDI_UNIQUE, 0,op,buf);  
  make_visible(op);   make_visible(op);
         return 0;  
   }     }
    
   if(op->invisible>(50*level)) {      if(op->invisible>(50*skill->level)) {
        new_draw_info(NDI_UNIQUE,0,op,"You are as hidden as you can get.");          new_draw_info(NDI_UNIQUE,0,op,"You are as hidden as you can get.");
        return 0;         return 0;
   }    }
      
   if(attempt_hide(op)) {       if(attempt_hide(op, skill)) {
      new_draw_info(NDI_UNIQUE, 0,op,"You hide in the shadows.");       new_draw_info(NDI_UNIQUE, 0,op,"You hide in the shadows.");
      update_object(op,UP_OBJ_FACE);       update_object(op,UP_OBJ_FACE);
      return calc_skill_exp(op, NULL);   return calc_skill_exp(op, NULL, skill);
   }     }
   new_draw_info(NDI_UNIQUE,0,op,"You fail to conceal yourself.");    new_draw_info(NDI_UNIQUE,0,op,"You fail to conceal yourself.");
   return 0;     return 0;
 }  }
   
 int attempt_hide(object *op) {  
   int level = SK_level(op);  
   int success=0,number,difficulty=op->map->difficulty;  
   int dexterity = get_skill_stat1(op);   
   int terrain = hideability(op);  
   
   level = level>5?level/5:1;  
   
   /* first things... no hiding next to a hostile monster */  
   dexterity = dexterity ? dexterity : 15;  
   
   if(terrain<-10) /* not enough cover here */  
     return 0;  
   
 /*  Hiding success and duration dependant on SK_level,  
  *  dexterity, map difficulty and terrain.   
  */  
   
   number = (die_roll(2, 25, op, PREFER_LOW)-2)/2;  
   if(!stand_near_hostile(op) && number    
      && (number < (dexterity + level + terrain - difficulty )))   
   {  
     success = 1;  
     op->invisible += 100;  /* set the level of 'hiddeness' */  
     if(op->type==PLAYER)  
  op->contr->tmp_invis=1;  
     op->hide=1;  
   }  
   return success;  
 }  
   
 /* stop_jump() - End of jump. Clear flags, restore the map, and   /* stop_jump() - End of jump. Clear flags, restore the map, and
  * freeze the jumper a while to simulate the exhaustion   * freeze the jumper a while to simulate the exhaustion
  * of jumping.   * of jumping.
  */   */
   static void stop_jump(object *pl, int dist, int spaces) {
 static int stop_jump(object *pl, int dist, int spaces) {  
     /* int load=dist/(pl->speed*spaces); */   
   
     CLEAR_FLAG(pl,FLAG_FLYING);      CLEAR_FLAG(pl,FLAG_FLYING);
     insert_ob_in_map(pl,pl->map,pl,0);      insert_ob_in_map(pl,pl->map,pl,0);
     return 0;  
 }  }
   
   
 static int attempt_jump (object *pl, int dir, int spaces) {  static int attempt_jump (object *pl, int dir, int spaces, object *skill) {
     object *tmp;      object *tmp;
     int i,exp=0,dx=freearr_x[dir],dy=freearr_y[dir], mflags;      int i,exp=0,dx=freearr_x[dir],dy=freearr_y[dir], mflags;
     sint16 x, y;      sint16 x, y;
Line 484
 
Line 412
   
  mflags = get_map_flags(m, &m, x, y, &x, &y);   mflags = get_map_flags(m, &m, x, y, &x, &y);
   
   
  if (mflags & P_OUT_OF_MAP) {   if (mflags & P_OUT_OF_MAP) {
      (void) stop_jump(pl,i,spaces);       (void) stop_jump(pl,i,spaces);
      return 0;       return 0;
  }   }
  if (mflags & P_WALL) {   if (mflags & P_WALL) {
      new_draw_info(NDI_UNIQUE, 0,pl,"Your jump is blocked.");       new_draw_info(NDI_UNIQUE, 0,pl,"Your jump is blocked.");
      (void) stop_jump(pl,i,spaces);       stop_jump(pl,i,spaces);
      return 0;       return 0;
  }   }
   
Line 504
 
Line 431
     (pl->type==PLAYER && pl->contr->party_number==-1) ||      (pl->type==PLAYER && pl->contr->party_number==-1) ||
     (pl->type==PLAYER && tmp->type==PLAYER &&      (pl->type==PLAYER && tmp->type==PLAYER &&
      pl->contr->party_number!=tmp->contr->party_number))        pl->contr->party_number!=tmp->contr->party_number))
           exp = skill_attack(tmp,pl,pl->facing,"kicked"); /* pl makes an attack */    exp = skill_attack(tmp,pl,pl->facing,"kicked", skill); /* pl makes an attack */
  (void) stop_jump(pl,i,spaces);   stop_jump(pl,i,spaces);
  return exp;  /* note that calc_skill_exp() is already called by skill_attack() */    return exp;  /* note that calc_skill_exp() is already called by skill_attack() */
      }       }
      /* If the space has fly on set (no matter what the space is),       /* If the space has fly on set (no matter what the space is),
Line 518
 
Line 445
  pl->map = m;   pl->map = m;
  if (pl->contr)   if (pl->contr)
      esrv_map_scroll(&pl->contr->socket, dx, dy);       esrv_map_scroll(&pl->contr->socket, dx, dy);
  (void) stop_jump(pl,i,spaces);   stop_jump(pl,i,spaces);
  return calc_skill_exp(pl,NULL);   return calc_skill_exp(pl,NULL, skill);
      }       }
  }   }
  pl->x = x;   pl->x = x;
Line 528
 
Line 455
  if (pl->contr)   if (pl->contr)
      esrv_map_scroll(&pl->contr->socket, dx, dy);       esrv_map_scroll(&pl->contr->socket, dx, dy);
     }      }
     (void) stop_jump(pl,i,spaces);      stop_jump(pl,i,spaces);
     return calc_skill_exp(pl,NULL);      return calc_skill_exp(pl,NULL, skill);
 }  }
   
 /* jump() - this is both a new type of movement for player/monsters and  /* jump() - this is both a new type of movement for player/monsters and
  * an attack as well. -b.t.   * an attack as well.
    * Perhaps we should allow more spaces based on level, eg, level 50
    * jumper can jump several spaces?
  */    */
   
 int jump(object *pl, int dir)   int jump(object *pl, int dir, object *skill)
 {  {
     int spaces=0,stats;      int spaces=0,stats;
     int str = get_skill_stat1(pl);       int str = pl->stats.Str;
     int dex = get_skill_stat2(pl);      int dex = pl->stats.Dex;
   
     dex = dex ? dex : 15;      dex = dex ? dex : 15;
     str = str ? str : 10;       str = str ? str : 10;
   
     stats=str*str*str*dex;      stats=str*str*str*dex * skill->level;
   
     if(pl->carrying!=0) /* don't want div by zero !! */       if(pl->carrying!=0) /* don't want div by zero !! */
  spaces=(int) (stats/pl->carrying);   spaces=(int) (stats/pl->carrying);
Line 558
 
Line 487
  new_draw_info(NDI_UNIQUE, 0,pl,"You are carrying too much weight to jump.");   new_draw_info(NDI_UNIQUE, 0,pl,"You are carrying too much weight to jump.");
  return 0;   return 0;
     }      }
     return attempt_jump(pl,dir,spaces);      return attempt_jump(pl,dir,spaces, skill);
 }  }
   
   
Line 572
 
Line 501
  * - b.t. (thomas@astro.psu.edu)    * - b.t. (thomas@astro.psu.edu)
  */   */
   
 int skill_ident(object *pl) {  static int do_skill_detect_curse(object *pl, object *skill) {
   char buf[MAX_BUF];  
   int success=0;  
   
  if(!pl->chosen_skill) /* should'nt happen... */   
  return 0;  
   
  if(pl->type != PLAYER) return 0;  /* only players will skill-identify */  
   
     sprintf(buf, "You look at the objects nearby...");  
     new_draw_info(NDI_UNIQUE, 0,pl,buf);     
   
  switch (pl->chosen_skill->stats.sp) {  
     case SK_SMITH:   
         success += do_skill_ident(pl,WEAPON) + do_skill_ident(pl,ARMOUR)  
      + do_skill_ident(pl,BRACERS) + do_skill_ident(pl,CLOAK)  
      + do_skill_ident(pl,BOOTS) + do_skill_ident(pl,SHIELD)  
      + do_skill_ident(pl,GIRDLE) + do_skill_ident(pl,HELMET)   
      + do_skill_ident(pl,GLOVES);  
  break;  
     case SK_BOWYER:  
  success += do_skill_ident(pl,BOW) + do_skill_ident(pl,ARROW);  
                 break;  
     case SK_ALCHEMY:  
                 success += do_skill_ident(pl,POTION) + do_skill_ident(pl,POISON)  
      + do_skill_ident(pl,AMULET) + do_skill_ident(pl,CONTAINER)  
      + do_skill_ident(pl,DRINK) + do_skill_ident(pl,INORGANIC);  
  break;  
            case SK_WOODSMAN:    
                 success += do_skill_ident(pl,FOOD) + do_skill_ident(pl,DRINK)   
      + do_skill_ident(pl,FLESH);  
                 break;   
            case SK_JEWELER:  
                 success += do_skill_ident(pl,GEM) + do_skill_ident(pl,RING);  
                 break;   
     case SK_LITERACY:  
                 success += do_skill_ident(pl,SPELLBOOK)   
      + do_skill_ident(pl,SCROLL) + do_skill_ident(pl,BOOK);  
  break;  
            case SK_THAUMATURGY:  
                 success += do_skill_ident(pl,WAND) + do_skill_ident(pl,ROD)   
      + do_skill_ident(pl,HORN);  
                 break;  
     case SK_DET_CURSE:  
                 success = do_skill_detect_curse(pl);  
                 if(success)   
                    new_draw_info(NDI_UNIQUE, 0,pl,"...and discover cursed items!");  
                 break;     
     case SK_DET_MAGIC:  
  success = do_skill_detect_magic(pl);  
  if(success)  
                   new_draw_info(NDI_UNIQUE, 0,pl,  
        "...and discover items imbued with mystic forces!");  
  break;  
     default:  
  LOG(llevError,"Error: bad call to skill_ident()");  
  return 0;  
  break;  
  }   
  if(!success) {  
  sprintf(buf,"...and learn nothing more.");  
     new_draw_info(NDI_UNIQUE, 0,pl,buf);  
  }  
   
         return success;  
 }  
    
 int do_skill_detect_curse(object *pl) {  
 object *tmp;  object *tmp;
 int success=0;  int success=0;
    
 /* check the player inventory - stop after 1st success or   
  * run out of unidented items   
  */   
     for(tmp=pl->inv;tmp;tmp=tmp->below)      for(tmp=pl->inv;tmp;tmp=tmp->below)
         if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_KNOWN_CURSED)          if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_KNOWN_CURSED)
             && (QUERY_FLAG(tmp,FLAG_CURSED) || QUERY_FLAG(tmp,FLAG_DAMNED)) ) {              && (QUERY_FLAG(tmp,FLAG_CURSED) || QUERY_FLAG(tmp,FLAG_DAMNED)) &&
        tmp->item_power < skill->level) {
                 SET_FLAG(tmp,FLAG_KNOWN_CURSED);                  SET_FLAG(tmp,FLAG_KNOWN_CURSED);
  esrv_update_item(UPD_FLAGS, pl, tmp);   esrv_update_item(UPD_FLAGS, pl, tmp);
                 success+=calc_skill_exp(pl,tmp);   success+= calc_skill_exp(pl,tmp, skill);
         }          }
     return success;      return success;
 }  }
   
 int do_skill_detect_magic(object *pl) {  static int do_skill_detect_magic(object *pl, object *skill) {
 object *tmp;  object *tmp;
 int success=0;  int success=0;
   
 /* check the player inventory - stop after 1st success or  
  * run out of unidented items  
  */  
     for(tmp=pl->inv;tmp;tmp=tmp->below)      for(tmp=pl->inv;tmp;tmp=tmp->below)
         if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL)          if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL)
      && (is_magical(tmp)) ) {        && (is_magical(tmp)) && tmp->item_power < skill->level) {
             SET_FLAG(tmp,FLAG_KNOWN_MAGICAL);              SET_FLAG(tmp,FLAG_KNOWN_MAGICAL);
  esrv_update_item(UPD_FLAGS, pl, tmp);   esrv_update_item(UPD_FLAGS, pl, tmp);
  success+=calc_skill_exp(pl,tmp);   success+=calc_skill_exp(pl,tmp, skill);
  }   }
     return success;      return success;
 }  }
   
 /* Helper function for do_skill_ident, so that we can loop  /* Helper function for do_skill_ident, so that we can loop
 over inventory AND objects on the ground conveniently.  */   * over inventory AND objects on the ground conveniently. 
 int do_skill_ident2(object *tmp,object *pl, int obj_class)    */
   int do_skill_ident2(object *tmp,object *pl, int obj_class, object *skill)
 {  {
    int success=0,chance;      int success=0,chance, ip;
   int skill_value = SK_level(pl) + get_weighted_skill_stats(pl);      int skill_value = skill->level * pl->stats.Int?pl->stats.Int:10;
   
  if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_NO_SKILL_IDENT)    if(!QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_NO_SKILL_IDENT)
     && need_identify(tmp)          && need_identify(tmp) && !tmp->invisible && tmp->type==obj_class) {
     && !tmp->invisible && tmp->type==obj_class) {    ip = tmp->magic;
    if (tmp->item_power > ip) ip=tmp->item_power;
   
  chance = die_roll(3, 10, pl, PREFER_LOW)-3 +   chance = die_roll(3, 10, pl, PREFER_LOW)-3 +
  rndm(0, (tmp->magic ? tmp->magic*5 : 1)-1);    rndm(0, (tmp->magic ? tmp->magic*5 : 1)-1);
  if(skill_value >= chance) {   if(skill_value >= chance) {
Line 701
 
Line 561
      if (tmp->map)       if (tmp->map)
  esrv_send_item(pl, tmp);   esrv_send_item(pl, tmp);
    }     }
            success += calc_skill_exp(pl,tmp);             success += calc_skill_exp(pl,tmp, skill);
         } else           } else
    SET_FLAG(tmp, FLAG_NO_SKILL_IDENT);     SET_FLAG(tmp, FLAG_NO_SKILL_IDENT);
           }
    return success;
   }
   
   /* do_skill_ident() - workhorse for skill_ident() -b.t.
    */
   static int do_skill_ident(object *pl, int obj_class, object *skill) {
       object *tmp;
       int success=0;
   
       for(tmp=pl->inv;tmp;tmp=tmp->below)
    success+=do_skill_ident2(tmp,pl,obj_class, skill);
    /*  check the ground */
   
       for(tmp=get_map_ob(pl->map,pl->x,pl->y);tmp;tmp=tmp->above)
    success+=do_skill_ident2(tmp,pl,obj_class, skill);
     
       return success;
   } 
   
   int skill_ident(object *pl, object *skill) {
       int success=0;
   
       if(pl->type != PLAYER) return 0;  /* only players will skill-identify */
   
       new_draw_info(NDI_UNIQUE, 0,pl,"You look at the objects nearby...");
   
       switch (skill->subtype) {
    case SK_SMITHERY:
        success += do_skill_ident(pl,WEAPON, skill) + do_skill_ident(pl,ARMOUR, skill)
        + do_skill_ident(pl,BRACERS,skill) + do_skill_ident(pl,CLOAK,skill)
        + do_skill_ident(pl,BOOTS,skill) + do_skill_ident(pl,SHIELD,skill)
        + do_skill_ident(pl,GIRDLE,skill) + do_skill_ident(pl,HELMET,skill)
        + do_skill_ident(pl,GLOVES,skill);
        break;
   
    case SK_BOWYER:
        success += do_skill_ident(pl,BOW,skill) + do_skill_ident(pl,ARROW,skill);
        break;
   
    case SK_ALCHEMY:
        success += do_skill_ident(pl,POTION,skill) + do_skill_ident(pl,POISON,skill)
        + do_skill_ident(pl,AMULET,skill) + do_skill_ident(pl,CONTAINER,skill)
        + do_skill_ident(pl,DRINK,skill) + do_skill_ident(pl,INORGANIC,skill);
        break;
   
    case SK_WOODSMAN: 
        success += do_skill_ident(pl,FOOD,skill) + do_skill_ident(pl,DRINK,skill)
        + do_skill_ident(pl,FLESH,skill);
        break;
   
    case SK_JEWELER:
        success += do_skill_ident(pl,GEM,skill) + do_skill_ident(pl,RING,skill);
        break;
   
    case SK_LITERACY:
        success += do_skill_ident(pl,SPELLBOOK,skill)
        + do_skill_ident(pl,SCROLL,skill) + do_skill_ident(pl,BOOK,skill);
        break;
   
    case SK_THAUMATURGY:
        success += do_skill_ident(pl,WAND,skill) + do_skill_ident(pl,ROD,skill)
        + do_skill_ident(pl,HORN,skill);
        break;
   
    case SK_DET_CURSE:
        success = do_skill_detect_curse(pl,skill);
        if(success)
    new_draw_info(NDI_UNIQUE, 0,pl,"...and discover cursed items!");
        break;   
   
    case SK_DET_MAGIC:
        success = do_skill_detect_magic(pl,skill);
        if(success)
    new_draw_info(NDI_UNIQUE, 0,pl,
          "...and discover items imbued with mystic forces!");
        break;
   
    default:
        LOG(llevError,"Error: bad call to skill_ident()");
        return 0;
        break;
       }
       if(!success) {
    new_draw_info(NDI_UNIQUE, 0,pl,"...and learn nothing more.");
         }          }
  return success;   return success;
 }  }
 /* do_skill_ident() - workhorse for skill_ident() -b.t. */  
 /*  Sept 95. I put in a probability for identification of artifacts.  
  *  highly magical artifacts will be more difficult to ident -b.t.  
  */  
 int do_skill_ident(object *pl, int obj_class) {  
   object *tmp;  
   int success=0;   
 /* check the player inventory */  
     for(tmp=pl->inv;tmp;tmp=tmp->below)  
  success+=do_skill_ident2(tmp,pl,obj_class);  
  /*  check the ground */  
  for(tmp=get_map_ob(pl->map,pl->x,pl->y);tmp;tmp=tmp->above)  
  success+=do_skill_ident2(tmp,pl,obj_class);  
        
     return success;  
 }    
   
 /* players using this skill can 'charm' a monster --  /* players using this skill can 'charm' a monster --
  * into working for them. It can only be used on    * into working for them. It can only be used on
Line 730
 
Line 660
  * -b.t. (thomas@astro.psu.edu)   * -b.t. (thomas@astro.psu.edu)
  */   */
   
 int use_oratory(object *pl, int dir) {  int use_oratory(object *pl, int dir, object *skill) {
     int x=pl->x+freearr_x[dir],y=pl->y+freearr_y[dir],chance;      sint16 x=pl->x+freearr_x[dir],y=pl->y+freearr_y[dir];
     int stat1 = get_skill_stat1(pl);      int mflags,chance;
     object *tmp;      object *tmp;
       mapstruct *m;
    
     if(pl->type!=PLAYER) return 0; /* only players use this skill */       if(pl->type!=PLAYER) return 0; /* only players use this skill */
     if(out_of_map(pl->map,x,y)) return 0;      m = pl->map;
       mflags =get_map_flags(m, &m, x,y, &x, &y);
       if (mflags & P_OUT_OF_MAP) return 0;
   
       /* Save some processing - we have the flag already anyways
        */
       if (!(mflags & P_IS_ALIVE)) {
    new_draw_info(NDI_UNIQUE, 0, pl, "There is nothing to orate to.");
    return 0;
       }
   
     for(tmp=get_map_ob(pl->map,x,y);tmp;tmp=tmp->above) {       for(tmp=get_map_ob(m,x,y);tmp;tmp=tmp->above) {
        if(!tmp) return 0;          /* can't persuade players - return because there is nothing else
  if(!QUERY_FLAG(tmp,FLAG_MONSTER)) continue;   
         /* can't persude players - return because there is nothing else  
  * on that space to charm.  Same for multi space monsters and   * on that space to charm.  Same for multi space monsters and
  * special monsters - we don't allow them to be charmed, and there   * special monsters - we don't allow them to be charmed, and there
  * is no reason to do further processing since they should be the   * is no reason to do further processing since they should be the
Line 751
 
Line 689
        if(tmp->more || tmp->head) return 0;         if(tmp->more || tmp->head) return 0;
  if(tmp->msg) return 0;   if(tmp->msg) return 0;
   
    if(QUERY_FLAG(tmp,FLAG_MONSTER)) break;
       }
   
       if (!tmp) {
    new_draw_info(NDI_UNIQUE, 0, pl, "There is nothing to orate to.");
    return 0;
       }
   
  new_draw_info_format(NDI_UNIQUE,    new_draw_info_format(NDI_UNIQUE,
  0,pl, "You orate to the %s.",query_name(tmp));   0,pl, "You orate to the %s.",query_name(tmp));
Line 763
 
Line 708
     "Too bad the %s isn't listening!\n",query_name(tmp));      "Too bad the %s isn't listening!\n",query_name(tmp));
  return 0;    return 0;
  }   }
   
  /* it's already allied! */    /* it's already allied! */
         if(QUERY_FLAG(tmp,FLAG_FRIENDLY)&&(tmp->move_type==PETMOVE)){            if(QUERY_FLAG(tmp,FLAG_FRIENDLY)&&(tmp->move_type==PETMOVE)){ 
      if(get_owner(tmp)==pl) {       if(get_owner(tmp)==pl) {
  new_draw_info(NDI_UNIQUE, 0,pl,    new_draw_info(NDI_UNIQUE, 0,pl,
        "Your follower loves your speach.\n");         "Your follower loves your speach.\n");
  return 0;   return 0;
      } else if(SK_level(pl)>tmp->level) { /* you steal the follower! */   } else if (skill->level > tmp->level) {
        /* you steal the follower.  Perhaps we should really look at the
         * level of the owner above?
         */
      set_owner(tmp,pl);        set_owner(tmp,pl);
                 new_draw_info_format(NDI_UNIQUE, 0,pl,                   new_draw_info_format(NDI_UNIQUE, 0,pl,
  "You convince the %s to follow you instead!\n",   "You convince the %s to follow you instead!\n",
Line 778
 
Line 727
  * be used by a couple players to gets lots of exp.   * be used by a couple players to gets lots of exp.
  */   */
  return 0;   return 0;
    } else {
        /* In this case, you can't steal it from the other player */
        return 0;
      }       }
  } /* Creature was already a pet of someone */   } /* Creature was already a pet of someone */
   
  chance=SK_level(pl)*2+(stat1-2*tmp->stats.Int)/2;      chance=skill->level*2+(pl->stats.Cha-2*tmp->stats.Int)/2;
   
  /* Ok, got a 'sucker' lets try to make them a follower */   /* Ok, got a 'sucker' lets try to make them a follower */
        if(chance>0 && tmp->level<(random_roll(0, chance-1, pl, PREFER_HIGH)-1)) {         if(chance>0 && tmp->level<(random_roll(0, chance-1, pl, PREFER_HIGH)-1)) {
Line 790
 
Line 742
  query_name(tmp));   query_name(tmp));
   
      set_owner(tmp,pl);       set_owner(tmp,pl);
      SET_FLAG(tmp,FLAG_MONSTER);  
      tmp->stats.exp = 0;       tmp->stats.exp = 0;
      add_friendly_object(tmp);       add_friendly_object(tmp);
      SET_FLAG(tmp,FLAG_FRIENDLY);       SET_FLAG(tmp,FLAG_FRIENDLY);
      tmp->move_type = PETMOVE;       tmp->move_type = PETMOVE;
      return calc_skill_exp(pl,tmp);   return calc_skill_exp(pl,tmp, skill);
  }   }
  /* Charm failed.  Creature may be angry now */   /* Charm failed.  Creature may be angry now */
        else if((SK_level(pl)+((stat1-10)/2)) <      else if((skill->level+((pl->stats.Cha-10)/2)) < random_roll(1, 2*tmp->level, pl, PREFER_LOW)) {
  random_roll(1, 2*tmp->level, pl, PREFER_LOW)) {  
      new_draw_info_format(NDI_UNIQUE, 0,pl,        new_draw_info_format(NDI_UNIQUE, 0,pl,
    "Your speach angers the %s!\n",query_name(tmp));      "Your speach angers the %s!\n",query_name(tmp));
      if(QUERY_FLAG(tmp,FLAG_FRIENDLY)) {       if(QUERY_FLAG(tmp,FLAG_FRIENDLY)) {
Line 809
 
Line 759
      }       }
      CLEAR_FLAG(tmp,FLAG_UNAGGRESSIVE);       CLEAR_FLAG(tmp,FLAG_UNAGGRESSIVE);
  }   }
     } /* For loop cyclign through the objects on this space */  
     return 0; /* Fall through - if we get here, we didn't charm anything */      return 0; /* Fall through - if we get here, we didn't charm anything */
 }  }
   
Line 823
 
Line 772
  * of anything better! -b.t.    * of anything better! -b.t.
  */   */
   
 int singing(object *pl, int dir) {  int singing(object *pl, int dir, object *skill) {
     int i,exp = 0,stat1=get_skill_stat1(pl),chance;      int i,exp = 0,chance, mflags;
     object *tmp;      object *tmp;
       mapstruct *m;
       sint16  x, y;
   
     if(pl->type!=PLAYER) return 0;    /* only players use this skill */      if(pl->type!=PLAYER) return 0;    /* only players use this skill */
   
     new_draw_info_format(NDI_UNIQUE,0,pl, "You sing");      new_draw_info_format(NDI_UNIQUE,0,pl, "You sing");
     for(i=dir;i<(dir+MIN(SK_level(pl),SIZEOFFREE));i++) {      for(i=dir;i<(dir+MIN(skill->level,SIZEOFFREE));i++) {
  if (out_of_map(pl->map,pl->x+freearr_x[i],pl->y+freearr_y[i]))   x = pl->x+freearr_x[i];
  continue;   y = pl->y+freearr_y[i];
         for(tmp=get_map_ob(pl->map,pl->x+freearr_x[i],pl->y+freearr_y[i]);   m = pl->map;
    tmp;tmp=tmp->above) {  
             if(!tmp) return 0;   mflags =get_map_flags(m, &m, x,y, &x, &y);
      if(!QUERY_FLAG(tmp,FLAG_MONSTER)) continue;   if (mflags & P_OUT_OF_MAP) continue;
    if (!(mflags & P_IS_ALIVE)) continue;
   
    for(tmp=get_map_ob(m, x, y); tmp;tmp=tmp->above)
        if(QUERY_FLAG(tmp,FLAG_MONSTER)) break;
      /* can't affect players */       /* can't affect players */
             if(tmp->type==PLAYER) break;              if(tmp->type==PLAYER) break;
   
      /* Only the head listens to music - not other parts.  head   /* Whole bunch of checks to see if this is a type of monster that would
       * is only set if an object has extra parts.  This is also   * listen to singing.
       * necessary since the other parts may not have appropriate  
       * skills/flags set.  
       */        */
      if (tmp->head) break;   if (tmp && QUERY_FLAG(tmp, FLAG_MONSTER) &&
        !QUERY_FLAG(tmp, FLAG_NO_STEAL) &&     /* Been charmed or abused before */
      /* the following monsters can't be calmed */       !QUERY_FLAG(tmp, FLAG_SPLITTING) &&     /* no ears */
        !QUERY_FLAG(tmp, FLAG_HITBACK) &&     /* was here before */
      if(QUERY_FLAG(tmp,FLAG_SPLITTING) /* have no ears! */        (tmp->level <= skill->level) &&
         || QUERY_FLAG(tmp,FLAG_HITBACK)) break;        (!tmp->head) &&
        !QUERY_FLAG(tmp, FLAG_UNDEAD) &&
 /*     if(tmp->stats.Int>0) break; *//* is too smart */       !QUERY_FLAG(tmp,FLAG_UNAGGRESSIVE) &&   /* already calm */
      if(tmp->level>SK_level(pl)) break; /* too powerfull */       !QUERY_FLAG(tmp,FLAG_FRIENDLY)) {     /* already calm */
      if(QUERY_FLAG(tmp,FLAG_UNDEAD)) break; /* undead dont listen! */   
   
      if(QUERY_FLAG(tmp,FLAG_UNAGGRESSIVE) /* already calm */  
         ||QUERY_FLAG(tmp,FLAG_FRIENDLY))   
  break;   
   
      /* stealing isn't really related (although, maybe it should       /* stealing isn't really related (although, maybe it should
       * be).  This is mainly to prevent singing to the same monster        * be).  This is mainly to prevent singing to the same monster
       * over and over again and getting exp for it.        * over and over again and getting exp for it.
       */        */
      chance=SK_level(pl)*2+(stat1-5-tmp->stats.Int)/2;       chance=skill->level*2+(pl->stats.Cha-5-tmp->stats.Int)/2;
      if(chance && tmp->level*2<random_roll(0, chance-1, pl, PREFER_HIGH)) {       if(chance && tmp->level*2<random_roll(0, chance-1, pl, PREFER_HIGH)) {
  SET_FLAG(tmp,FLAG_UNAGGRESSIVE);   SET_FLAG(tmp,FLAG_UNAGGRESSIVE);
  new_draw_info_format(NDI_UNIQUE, 0,pl,   new_draw_info_format(NDI_UNIQUE, 0,pl,
                    "You calm down the %s\n",query_name(tmp));                     "You calm down the %s\n",query_name(tmp));
  tmp->stats.Int = 1; /* this prevents re-pacification */  
  /* Give exp only if they are not aware */   /* Give exp only if they are not aware */
  if(!QUERY_FLAG(tmp,FLAG_NO_STEAL))   if(!QUERY_FLAG(tmp,FLAG_NO_STEAL))
      exp += calc_skill_exp(pl,tmp);       exp += calc_skill_exp(pl,tmp, skill);
  SET_FLAG(tmp,FLAG_NO_STEAL);   SET_FLAG(tmp,FLAG_NO_STEAL);
      } else {        } else {
                  new_draw_info_format(NDI_UNIQUE, 0,pl,                   new_draw_info_format(NDI_UNIQUE, 0,pl,
                  "Too bad the %s isn't listening!\n",query_name(tmp));                   "Too bad the %s isn't listening!\n",query_name(tmp));
    SET_FLAG(tmp,FLAG_NO_STEAL);
      }       }
  }   }
     }      }
     return exp;      return exp;
 }  }
   
 /* The FIND_TRAPS skill. This routine is taken mostly from the   /* The find_traps skill (aka, search).  Checks for traps
  * command_search loop. It seemed easier to have a separate command,   * on the spaces or in certain objects
  * rather than overhaul the existing code - this makes sure things   
  * still work for those people who don't want to have skill code   
  * implemented.  
  */   */
   
 int find_traps (object *pl) {    int find_traps (object *pl, object *skill) { 
    object *tmp,*tmp2;     object *tmp,*tmp2;
    int i,expsum=0;      int i,expsum=0, mflags;
   /*First we search all around us for runes and traps*/      sint16 x,y;
       mapstruct *m;
   
       /* First we search all around us for runes and traps, which are
        * all type RUNE
        */
   
    for(i=0;i<9;i++) {      for(i=0;i<9;i++) {
    x = pl->x+freearr_x[i];
    y = pl->y+freearr_y[i];
    m = pl->map;
   
    mflags =get_map_flags(m, &m, x,y, &x, &y);
    if (mflags & P_OUT_OF_MAP) continue;
   
         /*  Check everything in the square for trapness */          /*  Check everything in the square for trapness */
         if(out_of_map(pl->map,pl->x + freearr_x[i],pl->y + freearr_y[i])) continue;          for(tmp = get_map_ob(m, x, y); tmp!=NULL;tmp=tmp->above) {
         for(tmp = get_map_ob(pl->map, pl->x + freearr_x[i], pl->y +freearr_y[i]);  
             tmp!=NULL;tmp=tmp->above) {  
   
             /*  And now we'd better do an inventory traversal of each              /*  And now we'd better do an inventory traversal of each
                 of these objects' inventory */               * of these objects' inventory
         * We can narrow this down a bit - no reason to search through
         * the players inventory or monsters for that matter.
         */
        if (tmp->type != PLAYER && !QUERY_FLAG(tmp, FLAG_MONSTER)) {
             for(tmp2=tmp->inv;tmp2!=NULL;tmp2=tmp2->below)              for(tmp2=tmp->inv;tmp2!=NULL;tmp2=tmp2->below)
                 if(tmp2->type==RUNE || tmp2->type==TRAP)                    if(tmp2->type==RUNE || tmp2->type==TRAP) 
    if(trap_see(pl,tmp2)) {      if(trap_see(pl,tmp2)) {
  trap_show(tmp2,tmp);    trap_show(tmp2,tmp);
   if(tmp2->stats.Cha>1) {     if(tmp2->stats.Cha>1) {
      if (!tmp2->owner || tmp2->owner->type!=PLAYER)       if (!tmp2->owner || tmp2->owner->type!=PLAYER)
  expsum += calc_skill_exp(pl,tmp2);       expsum += calc_skill_exp(pl,tmp2, skill);
      /* do the following so calc_skill_exp will know   
       * how much xp to award for disarming  
       */  
      tmp2->stats.exp = tmp2->stats.Cha * tmp2->level;   
      tmp2->stats.Cha = 1; /* unhide the trap */        tmp2->stats.Cha = 1; /* unhide the trap */
  }   }
    }     }
             if(tmp->type==RUNE || tmp->type==TRAP)         }
    if(trap_see(pl,tmp)) {               if((tmp->type==RUNE || tmp->type == TRAP) && trap_see(pl,tmp)) {
  trap_show(tmp,tmp);    trap_show(tmp,tmp);
   if(tmp->stats.Cha>1) {    if(tmp->stats.Cha>1) {
      if (!tmp->owner || tmp->owner->type!=PLAYER)       if (!tmp->owner || tmp->owner->type!=PLAYER)
  expsum += calc_skill_exp(pl,tmp);   expsum += calc_skill_exp(pl,tmp, skill);
      /* do the following so calc_skill_exp will know   
       * how much xp to award for disarming  
       */  
      tmp->stats.exp = tmp->stats.Cha * tmp->level;   
      tmp->stats.Cha = 1; /* unhide the trap */        tmp->stats.Cha = 1; /* unhide the trap */
  }   }
               }                }
     }      }
    }     }
       new_draw_info(NDI_BLACK, 0, pl, "You search the area.");
    return expsum;     return expsum;
 }    } 
   
   /* remove_trap() - This skill will disarm any previously discovered trap
    * the algorithm is based (almost totally) on the old command_disarm() - b.t.
    */
   
   int remove_trap (object *op, int dir, object *skill) {
       object *tmp,*tmp2;
       int i,success=0,mflags;
       mapstruct *m;
       sint16 x,y;
   
       for(i=0;i<9;i++) {
    x = op->x + freearr_x[i];
    y = op->y + freearr_y[i];
    m = op->map;
   
    mflags =get_map_flags(m, &m, x,y, &x, &y);
    if (mflags & P_OUT_OF_MAP) continue;
   
    /* Check everything in the square for trapness */
    for(tmp = get_map_ob(m,x,y);tmp!=NULL;tmp=tmp->above) {
        /* And now we'd better do an inventory traversal of each
         * of these objects inventory.  Like above, only
         * do this for interesting objects.
         */
   
        if (tmp->type != PLAYER && !QUERY_FLAG(tmp, FLAG_MONSTER)) {
    for(tmp2=tmp->inv;tmp2!=NULL;tmp2=tmp2->below)
        if((tmp2->type==RUNE || tmp2->type == TRAP) && tmp2->stats.Cha<=1) {
    trap_show(tmp2,tmp);
    if(trap_disarm(op,tmp2,1, skill) && (!tmp2->owner || tmp2->owner->type!=PLAYER)) {
        tmp->stats.exp = tmp->stats.Cha * tmp->level;
        success += calc_skill_exp(op,tmp2, skill);
    }
        }
        }
        if((tmp->type==RUNE || tmp->type==TRAP) && tmp->stats.Cha<=1) {
    trap_show(tmp,tmp);
    if (trap_disarm(op,tmp,1,skill) && (!tmp->owner || tmp->owner->type!=PLAYER)) {
        tmp->stats.exp = tmp->stats.Cha * tmp->level;
        success += calc_skill_exp(op,tmp,skill);
    }
        }
    }
       }
       return success;
   }
   
   
 /* pray() - when this skill is called from do_skill(), it allows  /* pray() - when this skill is called from do_skill(), it allows
  * the player to regain lost grace points at a faster rate. -b.t.   * the player to regain lost grace points at a faster rate. -b.t.
  * This always returns 0 - return value is used by calling function   * This always returns 0 - return value is used by calling function
Line 944
 
Line 944
  * give infinite exp by returning true in any cases.   * give infinite exp by returning true in any cases.
  */   */
   
 int pray (object *pl) {  int pray (object *pl, object *skill) {
     char buf[MAX_BUF];      char buf[MAX_BUF];
     object *tmp;      object *tmp;
   
     if(pl->type!=PLAYER) return 0;      if(pl->type!=PLAYER) return 0;
   
     strcpy(buf,"You pray.");      strcpy(buf,"You pray.");
   
     /* Check all objects - we could stop at floor objects,      /* Check all objects - we could stop at floor objects,
      * but if someone buries an altar, I don't see a problem with       * but if someone buries an altar, I don't see a problem with
      * going through all the objects, and it shouldn't be much slower       * going through all the objects, and it shouldn't be much slower
Line 960
 
Line 961
  /* Only if the altar actually belongs to someone do you get special benefits */   /* Only if the altar actually belongs to someone do you get special benefits */
  if(tmp && tmp->type==HOLY_ALTAR && tmp->other_arch) {   if(tmp && tmp->type==HOLY_ALTAR && tmp->other_arch) {
      sprintf(buf,"You pray over the %s.",tmp->name);       sprintf(buf,"You pray over the %s.",tmp->name);
      pray_at_altar(pl,tmp);       pray_at_altar(pl,tmp, skill);
      break;  /* Only pray at one altar */       break;  /* Only pray at one altar */
  }   }
     }      }
Line 970
 
Line 971
     if(pl->stats.grace < pl->stats.maxgrace) {      if(pl->stats.grace < pl->stats.maxgrace) {
  pl->stats.grace++;   pl->stats.grace++;
  pl->last_grace = -1;   pl->last_grace = -1;
     } else return 0;      }
   
     /* Is this really right?  This will basically increase food  
      * consumption, hp & sp regeneration, and everything else that  
      * do_some_living does.  
      */  
     do_some_living(pl);  
     return 0;      return 0;
 }  }
   
Line 987
 
Line 982
  * the level of the user. - b.t. thomas@astro.psu.edu    * the level of the user. - b.t. thomas@astro.psu.edu
  */    */
   
 /* July 95 I commented out 'factor' - this should now be handled by   void meditate (object *pl, object *skill) {
  * get_skill_time() -b.t. */  
   
 /* Sept 95. Now meditation is level dependant (score). User may  
  * meditate w/ more armour on as they get higher level   
  * Probably a better way to do this is based on overall encumberance   
  * -b.t.  
  */   
   
 void meditate (object *pl) {  
   object *tmp;    object *tmp;
   int lvl = pl->level;   
   /* int factor = 10/(1+(pl->level/10)+(pl->stats.Int/15)+(pl->stats.Wis/15)); */   
   
     if(pl->type!=PLAYER) return; /* players only */      if(pl->type!=PLAYER) return; /* players only */
   
     /* check if pl has removed encumbering armour and weapons */       /* check if pl has removed encumbering armour and weapons */
       if(QUERY_FLAG(pl,FLAG_READY_WEAPON) && (skill->level<6)) {
     if(QUERY_FLAG(pl,FLAG_READY_WEAPON) && (lvl<6)) {   
         new_draw_info(NDI_UNIQUE,0,pl,           new_draw_info(NDI_UNIQUE,0,pl,
    "You can't concentrate while wielding a weapon!\n");      "You can't concentrate while wielding a weapon!\n");
  return;   return;
     } else {      } else {
  for(tmp=pl->inv;tmp;tmp=tmp->below)   for(tmp=pl->inv;tmp;tmp=tmp->below)
           if(( (tmp->type==ARMOUR && lvl<12)             if (( (tmp->type==ARMOUR && skill->level<12)
  || (tmp->type==HELMET && lvl<10)    || (tmp->type==HELMET && skill->level<10)
  || (tmp->type==SHIELD && lvl<6)    || (tmp->type==SHIELD && skill->level<6)
  || (tmp->type==BOOTS && lvl<4)    || (tmp->type==BOOTS && skill->level<4)
  || (tmp->type==GLOVES && lvl<2) )   || (tmp->type==GLOVES && skill->level<2) )
        && QUERY_FLAG(tmp,FLAG_APPLIED)) {         && QUERY_FLAG(tmp,FLAG_APPLIED)) {
          new_draw_info(NDI_UNIQUE,0,pl,            new_draw_info(NDI_UNIQUE,0,pl,
    "You can't concentrate while wearing so much armour!\n");      "You can't concentrate while wearing so much armour!\n");
Line 1032
 
Line 1015
      */       */
    
         new_draw_info(NDI_UNIQUE,0,pl, "You meditate.");           new_draw_info(NDI_UNIQUE,0,pl, "You meditate.");
      /*   pl->speed_left -= (int) FABS(factor); */   
   
  if(pl->stats.sp < pl->stats.maxsp) {   if(pl->stats.sp < pl->stats.maxsp) {
     pl->stats.sp++;      pl->stats.sp++;
Line 1040
 
Line 1022
  } else if (pl->stats.hp < pl->stats.maxhp)  {   } else if (pl->stats.hp < pl->stats.maxhp)  {
     pl->stats.hp++;      pl->stats.hp++;
     pl->last_heal = -1;      pl->last_heal = -1;
  } else return;  
    
  do_some_living(pl);   
 }  
   
 /* write_on_item() - wrapper for write_note and write_scroll */  
   
 int write_on_item (object *pl,char *params) {  
     object *item;  
     char *string=params;  
     int msgtype;  
   
     if(pl->type!=PLAYER) return 0;  
     if (!params) {  
  params="";  
  string=params;  
     }  
   
     /* Need to be able to read before we can write! */  
   
     if(!find_skill(pl,SK_LITERACY)) {  
  new_draw_info(NDI_UNIQUE,0,pl,  
     "You must learn to read before you can write!");  
  return 0;  
     }  
   
     /* if skill name occurs at begining of the string  
      * we have to reset pointer to miss it and trailing space(s)  
      */  
     /*  
      * GROS: Bugfix here. if you type  
      * use_skill inscription bla  
      * params will contain "bla" only, so looking for the skill name  
      * shouldn't be done anymore.  
      */  
 /*  if(lookup_skill_by_name(params)>=0){  
  for(i=strcspn(string," ");i>0;i--) string++;  
  for(i=strspn(string," ");i>0;i--) string++;  
     }  
 */  
     /* if there is a message then it goes in a book and no message means  
      * write active spell into the scroll  
      */  
     msgtype = (string[0]!='\0') ? BOOK : SCROLL;  
   
     /* find an item of correct type to write on */  
     if ( !(item = find_marked_object(pl))){  
  new_draw_info(NDI_UNIQUE,0,pl,"You don't have anything marked.");  
  return 0;  
     }  
   
     if(item) {  
  if(QUERY_FLAG(item,FLAG_UNPAID)) {  
      new_draw_info(NDI_UNIQUE,0,pl,  
  "You had better pay for that before you write on it.");  
      return 0;  
  }  
  switch(msgtype) {  
      case SCROLL:  
  return write_scroll(pl,item);  
  break;  
      case BOOK: {   
  return write_note(pl,item,string);  
  break;  
      }  
      default:  
  break;  
  }  
     }      }
     new_draw_info_format(NDI_UNIQUE,0,pl,"You have no %s to write on",  
  msgtype==BOOK ? "book" : "scroll");  
     return 0;  
 }  }
   
 /* write_note() - this routine allows players to inscribe messages in   /* write_note() - this routine allows players to inscribe messages in
  * ordinary 'books' (anything that is type BOOK). b.t.   * ordinary 'books' (anything that is type BOOK). b.t.
  */   */
   
 int write_note(object *pl, object *item, char *msg) {  static int write_note(object *pl, object *item, char *msg, object *skill) {
   char buf[BOOK_BUF];     char buf[BOOK_BUF];
   object *newBook = NULL;    object *newBook = NULL;
   event *evt;    event *evt;
Line 1129
 
Line 1040
   if(!msg) {     if(!msg) {
   new_draw_info(NDI_UNIQUE,0,pl,"No message to write!");    new_draw_info(NDI_UNIQUE,0,pl,"No message to write!");
  new_draw_info_format(NDI_UNIQUE,0,pl,"Usage: use_skill %s <message>",   new_draw_info_format(NDI_UNIQUE,0,pl,"Usage: use_skill %s <message>",
    skills[SK_INSCRIPTION].name);        skill->skill);
  return 0;   return 0;
   }    }
   if (strcasestr_local(msg, "endmsg")) {    if (strcasestr_local(msg, "endmsg")) {
Line 1137
 
Line 1048
  return 0;   return 0;
   }    }
   /* GROS: Handle for plugin book writing (trigger) event */    /* GROS: Handle for plugin book writing (trigger) event */
   if ((evt = find_event(item, EVENT_TRIGGER)) != NULL)      if ((evt = find_event(item, EVENT_TRIGGER)) != NULL) {
   {  
     CFParm CFP;      CFParm CFP;
     int k, l, m;      int k, l, m;
     k = EVENT_TRIGGER;      k = EVENT_TRIGGER;
Line 1155
 
Line 1065
     CFP.Value[8] = &l;      CFP.Value[8] = &l;
     CFP.Value[9] = evt->hook;      CFP.Value[9] = evt->hook;
     CFP.Value[10]= evt->options;      CFP.Value[10]= evt->options;
     if (findPlugin(evt->plugin)>=0)   if (findPlugin(evt->plugin)>=0) {
     {  
         ((PlugList[findPlugin(evt->plugin)].eventfunc) (&CFP));          ((PlugList[findPlugin(evt->plugin)].eventfunc) (&CFP));
         return strlen(msg);          return strlen(msg);
     }      }
Line 1164
 
Line 1073
   
   buf[0] = 0;    buf[0] = 0;
   if(!book_overflow(item->msg,msg,BOOK_BUF)) { /* add msg string to book */    if(!book_overflow(item->msg,msg,BOOK_BUF)) { /* add msg string to book */
     if(item->msg) {   if(item->msg)
       strcpy(buf,item->msg);        strcpy(buf,item->msg);
    if (item->nrof < 2)  
         free_string(item->msg);  
     }  
     strcat(buf,msg);      strcat(buf,msg);
     strcat(buf,"\n"); /* new msg needs a LF */      strcat(buf,"\n"); /* new msg needs a LF */
     if(item->nrof > 1) {      if(item->nrof > 1) {
Line 1177
 
Line 1084
       decrease_ob(item);        decrease_ob(item);
       esrv_send_item(pl, item);        esrv_send_item(pl, item);
       newBook->nrof = 1;        newBook->nrof = 1;
        if (newBook->msg) free_string(newBook->msg);
       newBook->msg = add_string(buf);        newBook->msg = add_string(buf);
       newBook = insert_ob_in_ob(newBook, pl);        newBook = insert_ob_in_ob(newBook, pl);
       esrv_send_item(pl, newBook);        esrv_send_item(pl, newBook);
     } else {      } else {
        if (item->msg) free_string(item->msg);
       item->msg=add_string(buf);         item->msg=add_string(buf);
       esrv_send_item(pl, item);       /* This shouldn't be necessary - the object hasn't changed in any visible way */
   /*     esrv_send_item(pl, item);*/
     }      }
     new_draw_info_format(NDI_UNIQUE,0,pl, "You write in the %s.",query_short_name(item));      new_draw_info_format(NDI_UNIQUE,0,pl, "You write in the %s.",query_short_name(item));
     return strlen(msg);      return strlen(msg);
   } else    } else
     new_draw_info_format(NDI_UNIQUE,0,pl, "Your message won't fit in the %s!",query_short_name(item));       new_draw_info_format(NDI_UNIQUE,0,pl, "Your message won't fit in the %s!",query_short_name(item));
   
   return 0;    return 0;
 }  }
   
Line 1197
 
Line 1108
  * that is attempted. -b.t. thomas@astro.psu.edu   * that is attempted. -b.t. thomas@astro.psu.edu
  */   */
   
 int write_scroll (object *pl, object *scroll) {  static int write_scroll (object *pl, object *scroll, object *skill) {
     int success=0,confused=0,chosen_spell=-1,stat1=get_skill_stat1(pl);      int success=0,confused=0;
     object *newScroll;      object *newscroll, *chosen_spell, *tmp;
   
     /* this is a sanity check */      /* this is a sanity check */
     if (scroll->type!=SCROLL) {      if (scroll->type!=SCROLL) {
Line 1208
 
Line 1119
     }      }
   
     /* Check if we are ready to attempt inscription */      /* Check if we are ready to attempt inscription */
     chosen_spell=pl->contr->chosen_spell;      chosen_spell=pl->contr->ranges[range_magic];
     if(chosen_spell<0) {      if(!chosen_spell) {
  new_draw_info(NDI_UNIQUE,0,pl,   new_draw_info(NDI_UNIQUE,0,pl,
      "You need a spell readied in order to inscribe!");        "You need a spell readied in order to inscribe!");
  return 0;    return 0;
     }      }
     if(spells[chosen_spell].scroll_chance==0) { /* Tried to write non-scroll spell */      if(chosen_spell->stats.grace > pl->stats.grace) {
        new_draw_info_format(NDI_UNIQUE,0,pl,"The spell %s cannot be inscribed.",  
  spells[chosen_spell].name);  
  return 0;  
     }  
     if(spells[chosen_spell].cleric && spells[chosen_spell].sp>pl->stats.grace) {  
        new_draw_info_format(NDI_UNIQUE,0,pl,         new_draw_info_format(NDI_UNIQUE,0,pl,
       "You don't have enough grace to write a scroll of %s."        "You don't have enough grace to write a scroll of %s.",
        ,spells[chosen_spell].name);        chosen_spell->name);
  return 0;   return 0;
     }      }
     else if(spells[chosen_spell].sp>pl->stats.sp) {      if(chosen_spell->stats.sp > pl->stats.sp) {
        new_draw_info_format(NDI_UNIQUE,0,pl,         new_draw_info_format(NDI_UNIQUE,0,pl,
       "You don't have enough mana to write a scroll of %s."        "You don't have enough mana to write a scroll of %s.",
        ,spells[chosen_spell].name);        chosen_spell->name);
  return 0;   return 0;
     }      }
   
Line 1236
 
Line 1142
      * accidently read it while trying to write the new one.  give player       * accidently read it while trying to write the new one.  give player
      * a 50% chance to overwrite spell at their own level       * a 50% chance to overwrite spell at their own level
      */       */
     if(scroll->stats.sp &&      if((scroll->stats.sp || scroll->inv) &&
        random_roll(0, scroll->level*2, pl, PREFER_LOW)>SK_level(pl)) {         random_roll(0, scroll->level*2, pl, PREFER_LOW)>skill->level) {
          new_draw_info_format(NDI_UNIQUE,0,pl,           new_draw_info_format(NDI_UNIQUE,0,pl,
  "Oops! You accidently read it while trying to write on it.");   "Oops! You accidently read it while trying to write on it.");
  manual_apply(pl,scroll,0);   manual_apply(pl,scroll,0);
  change_skill(pl,SK_INSCRIPTION);  
  return 0;   return 0;
     }      }
   
     /* ok, we are ready to try inscription */      /* ok, we are ready to try inscription */
   
     if(QUERY_FLAG(pl,FLAG_CONFUSED)) confused = 1;      if(QUERY_FLAG(pl,FLAG_CONFUSED)) confused = 1;
   
     /* Lost mana/grace no matter what */      /* Lost mana/grace no matter what */
     if (spells[chosen_spell].cleric)      pl->stats.grace-=chosen_spell->stats.grace;
  pl->stats.grace-=spells[chosen_spell].sp;      pl->stats.sp-=chosen_spell->stats.sp;
     else  
  pl->stats.sp-=spells[chosen_spell].sp;  
   
     if (random_roll(0, spells[chosen_spell].level*4-1, pl, PREFER_LOW) <      if (random_roll(0, chosen_spell->level*4-1, pl, PREFER_LOW) < skill->level) {
  SK_level(pl)) {   if (scroll->nrof > 1) {
  newScroll = get_object();       newscroll = get_object();
  copy_object(scroll, newScroll);       copy_object(scroll, newscroll);
  decrease_ob(scroll);   decrease_ob(scroll);
  newScroll->nrof = 1;       newscroll->nrof = 1;
   
  if(!confused) {  
      newScroll->level= (SK_level(pl)>spells[chosen_spell].level ?   
  SK_level(pl) : spells[chosen_spell].level);  
  } else {   } else {
  /* a  confused scribe gets a random spell */        newscroll = scroll;
      do  
  chosen_spell=rndm(0, NROFREALSPELLS-1);  
      while (spells[chosen_spell].scroll_chance==0);  
   
      newScroll->level=SK_level(pl)>spells[chosen_spell].level ?   
         spells[chosen_spell].level :  
         (random_roll(1, SK_level(pl), pl, PREFER_HIGH));  
  }   }
   
  if(newScroll->stats.sp==chosen_spell)    if(!confused) {
      new_draw_info(NDI_UNIQUE,0,pl, "You overwrite the scroll.");       newscroll->level= MAX(skill->level, chosen_spell->level);
  else {   
      new_draw_info(NDI_UNIQUE,0,pl,       new_draw_info(NDI_UNIQUE,0,pl,
  "You succeed in writing a new scroll.");   "You succeed in writing a new scroll.");
      newScroll->stats.sp=chosen_spell;    } else {
        chosen_spell = find_random_spell_in_ob(pl, NULL);
        if (!chosen_spell) return 0;
   
        newscroll->level= MAX(skill->level, chosen_spell->level);
        new_draw_info(NDI_UNIQUE,0,pl,
    "In your confused state, you write down some odd spell.");
    }
   
    if (newscroll->inv) {
        remove_ob(newscroll->inv);
        free_object(newscroll->inv);
  }   }
    tmp = get_object();
    copy_object(chosen_spell, tmp);
    insert_ob_in_ob(newscroll, tmp);
   
  /* wait until finished manipulating the scroll before inserting it */   /* wait until finished manipulating the scroll before inserting it */
  newScroll=insert_ob_in_ob(newScroll,pl);   if (newscroll != scroll)
  esrv_send_item(pl, newScroll);       newscroll=insert_ob_in_ob(newscroll,pl);
  success = calc_skill_exp(pl,newScroll);   esrv_send_item(pl, newscroll);
    success = calc_skill_exp(pl,newscroll, skill);
  if(!confused) success *= 2;   if(!confused) success *= 2;
  return success;    return success;
   
     } else { /* Inscription has failed */      } else { /* Inscription has failed */
   
  if(spells[chosen_spell].level>SK_level(pl) || confused){ /*backfire!*/   if(chosen_spell->level>skill->level || confused) { /*backfire!*/
           new_draw_info(NDI_UNIQUE,0,pl,            new_draw_info(NDI_UNIQUE,0,pl,
  "Ouch! Your attempt to write a new scroll strains your mind!");   "Ouch! Your attempt to write a new scroll strains your mind!");
     if(random_roll(0, 1, pl, PREFER_LOW)==1)         if(random_roll(0, 1, pl, PREFER_LOW)==1)   
  drain_specific_stat(pl,4);    drain_specific_stat(pl,4);
       else {         else {
          confuse_player(pl,pl,99);           confuse_player(pl,pl,99);
 /* return (-3*calc_skill_exp(pl,newScroll));*/   return (-30*chosen_spell->level);
  return (-30*spells[chosen_spell].level);  
       }        }
  } else if(random_roll(0, stat1-1, pl, PREFER_HIGH) < 15) {    } else if(random_roll(0, pl->stats.Int-1, pl, PREFER_HIGH) < 15) {
           new_draw_info(NDI_UNIQUE,0,pl,            new_draw_info(NDI_UNIQUE,0,pl,
  "Your attempt to write a new scroll rattles your mind!");   "Your attempt to write a new scroll rattles your mind!");
     confuse_player(pl,pl,99);      confuse_player(pl,pl,99);
  } else   } else
           new_draw_info(NDI_UNIQUE,0,pl,"You fail to write a new scroll.");            new_draw_info(NDI_UNIQUE,0,pl,"You fail to write a new scroll.");
     }      }
 /*    return (-1*calc_skill_exp(pl,newScroll));*/      return 0;
     return (-10*spells[chosen_spell].level);  
 }  }
   
 /* remove_trap() - This skill will disarm any previously discovered trap   /* write_on_item() - wrapper for write_note and write_scroll */
  * the algorithm is based (almost totally) on the old command_disarm() - b.t.   int write_on_item (object *pl,char *params, object *skill) {
  */       object *item;
       char *string=params;
       int msgtype;
       archetype *skat;
   
 int remove_trap (object *op, int dir) {      if(pl->type!=PLAYER) return 0;
   object *tmp,*tmp2;  
   int i,x,y,success=0;      
   
    for(i=0;i<9;i++) {      if (!params) {
       x = op->x + freearr_x[i];   params="";
       y = op->y + freearr_y[i];   string=params;
       if(out_of_map(op->map,x,y))      }
  continue;      skat = get_archetype_by_type_subtype(SKILL, SK_LITERACY);
   
   /*  Check everything in the square for trapness */      /* Need to be able to read before we can write! */
    for(tmp = get_map_ob(op->map,x,y);tmp!=NULL;tmp=tmp->above) {      if(!find_skill_by_name(pl,skat->clone.skill)) {
    new_draw_info(NDI_UNIQUE,0,pl,
       "You must learn to read before you can write!");
    return 0;
       }
   
       /* And now we'd better do an inventory traversal of each      /* if there is a message then it goes in a book and no message means
        * of these objects' inventory */       * write active spell into the scroll
        */
       msgtype = (string[0]!='\0') ? BOOK : SCROLL;
   
       for(tmp2=tmp->inv;tmp2!=NULL;tmp2=tmp2->below)      /* find an item of correct type to write on */
          if((tmp2->type==RUNE || tmp2->type==TRAP)&&tmp2->stats.Cha<=1) {      if ( !(item = find_marked_object(pl))){
               trap_show(tmp2,tmp);   new_draw_info(NDI_UNIQUE,0,pl,"You don't have any marked item to write on.");
               if(trap_disarm(op,tmp2,1) && (!tmp2->owner || tmp2->owner->type!=PLAYER))   return 0;
     success += calc_skill_exp(op,tmp2);  
          }           }
   
       if((tmp->type==RUNE || tmp->type==TRAP)&&tmp->stats.Cha<=1) {      if(QUERY_FLAG(item,FLAG_UNPAID)) {
          trap_show(tmp,tmp);   new_draw_info(NDI_UNIQUE,0,pl,
          if (trap_disarm(op,tmp,1) && (!tmp->owner || tmp->owner->type!=PLAYER))         "You had better pay for that before you write on it.");
     success += calc_skill_exp(op,tmp);   return 0;
       }    
     }      }
       if (msgtype != item->type) {
    new_draw_info_format(NDI_UNIQUE,0,pl,"You have no %s to write on",
                            msgtype==BOOK ? "book" : "scroll");
    return 0;
   }    }
    
    return success;      if (msgtype == SCROLL) {
    return write_scroll(pl,item, skill);
       } else if (msgtype == BOOK) {
    return write_note(pl,item,string, skill);
       }
       return 0;
 }  }
   
 int skill_throw (object *op, object *part, int dir, char *params) {  
   
     object *throw_ob;  
   
     if(op->type==PLAYER)   
  throw_ob =  find_throw_ob(op,params);  
     else  
  throw_ob = find_mon_throw_ob(op);  
   
     return do_throw(op,part, throw_ob,dir);  
 }  
   
 /* find_throw_ob() - if we request an object, then  /* find_throw_ob() - if we request an object, then
  * we search for it in the inventory of the owner (you've   * we search for it in the inventory of the owner (you've
Line 1373
 
Line 1280
  * 'throwable' (ie not applied cursed obj, worn, etc).   * 'throwable' (ie not applied cursed obj, worn, etc).
  */   */
   
 object *find_throw_ob( object *op, char *request ) {  static object *find_throw_ob( object *op, char *request ) {
   object *tmp;    object *tmp;
         
   if(!op) { /* safety */    if(!op) { /* safety */
Line 1385
 
Line 1292
   for(tmp=op->inv;tmp;tmp=tmp->below) {    for(tmp=op->inv;tmp;tmp=tmp->below) {
        /* can't toss invisible or inv-locked items */         /* can't toss invisible or inv-locked items */
       if(tmp->invisible||QUERY_FLAG(tmp,FLAG_INV_LOCKED)) continue;        if(tmp->invisible||QUERY_FLAG(tmp,FLAG_INV_LOCKED)) continue;
       if(!request||!strcmp(query_name(tmp),request)   if(!request || !strcmp(query_name(tmp),request) || !strcmp(tmp->name,request))
           ||!strcmp(tmp->name,request)) break;       break;
   }    }
    
   /* this should prevent us from throwing away    /* this should prevent us from throwing away
    * cursed items, worn armour, etc. Only weapons     * cursed items, worn armour, etc. Only weapons
    * can be thrown from 'hand'.  */       * can be thrown from 'hand'. 
   if(tmp) {       */
       if (!tmp) return NULL;
   
     if (QUERY_FLAG(tmp,FLAG_APPLIED)) {      if (QUERY_FLAG(tmp,FLAG_APPLIED)) {
       if(tmp->type!=WEAPON) {        if(tmp->type!=WEAPON) {
         new_draw_info_format(NDI_UNIQUE, 0,op,          new_draw_info_format(NDI_UNIQUE, 0,op,
Line 1409
 
Line 1318
         }          }
       }        }
     } else if (QUERY_FLAG(tmp, FLAG_UNPAID)) {      } else if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
  new_draw_info_format(NDI_UNIQUE, 0, op, "You should pay for the %s"   new_draw_info_format(NDI_UNIQUE, 0, op, "You should pay for the %s first.", query_name(tmp));
      " first.", query_name(tmp));  
  tmp = NULL;   tmp = NULL;
     }      }
   }  
   
   if (tmp && QUERY_FLAG (tmp, FLAG_INV_LOCKED)) {    if (tmp && QUERY_FLAG (tmp, FLAG_INV_LOCKED)) {
     LOG (llevError, "BUG: find_throw_ob(): object is locked\n");      LOG (llevError, "BUG: find_throw_ob(): object is locked\n");
     tmp=NULL;      tmp=NULL;
   }    }
   
   return tmp;    return tmp;
 }  }
   
Line 1428
 
Line 1334
  * This combination  becomes the 'thrown object'. -b.t.   * This combination  becomes the 'thrown object'. -b.t.
  */   */
   
 object *make_throw_ob (object *orig) {  static object *make_throw_ob (object *orig) {
   object *toss_item=NULL;      object *toss_item;
   
       if(!orig) return NULL;
   
   if(orig) {  
     toss_item=get_object();      toss_item=get_object();
     if (QUERY_FLAG (orig, FLAG_APPLIED)) {      if (QUERY_FLAG (orig, FLAG_APPLIED)) {
       LOG (llevError, "BUG: make_throw_ob(): ob is applied\n");        LOG (llevError, "BUG: make_throw_ob(): ob is applied\n");
Line 1442
 
Line 1349
     toss_item->type = THROWN_OBJ;      toss_item->type = THROWN_OBJ;
     CLEAR_FLAG(toss_item,FLAG_CHANGING);      CLEAR_FLAG(toss_item,FLAG_CHANGING);
     toss_item->stats.dam = 0; /* default damage */      toss_item->stats.dam = 0; /* default damage */
 #ifdef DEBUG_THROW  
     LOG(llevDebug," inserting %s(%d) in toss_item(%d)\n",  
         orig->name,orig->count,toss_item->count);  
 #endif   
     insert_ob_in_ob(orig,toss_item);      insert_ob_in_ob(orig,toss_item);
   }  
   
   return toss_item;    return toss_item;
 }  }
   
   
 /* do_throw() - op throws any object toss_item. This code  /* do_throw() - op throws any object toss_item. This code
  * was borrowed from fire_bow (see above).   * was borrowed from fire_bow.
  * Returns 1 if skill was successfully used, 0 if not   * Returns 1 if skill was successfully used, 0 if not
  */   */
   
 int do_throw(object *op, object *part, object *toss_item, int dir) {  static int do_throw(object *op, object *part, object *toss_item, int dir, object *skill) {
     object *throw_ob=toss_item, *left=NULL;      object *throw_ob=toss_item, *left=NULL;
     tag_t left_tag;      tag_t left_tag;
     int eff_str = 0,maxc,str=op->stats.Str,dam=0;      int eff_str = 0,maxc,str=op->stats.Str,dam=0;
Line 1479
 
Line 1380
  return 0;   return 0;
     }      }
    
   
     /* Because throwing effectiveness must be reduced by the      /* Because throwing effectiveness must be reduced by the
      * encumbrance of the thrower and weight of the object. THus,       * encumbrance of the thrower and weight of the object. THus,
      * we use the concept of 'effective strength' as defined below.        * we use the concept of 'effective strength' as defined below.
Line 1554
 
Line 1454
      */       */
   
     if((throw_ob = get_split_ob(throw_ob, 1))==NULL) {      if((throw_ob = get_split_ob(throw_ob, 1))==NULL) {
 #ifdef DEBUG_THROW  
  LOG(llevDebug," get_splt_ob faild to split throw ob %s\n",left->name);  
 #endif  
  throw_ob = left;   throw_ob = left;
  remove_ob(left);   remove_ob(left);
  if (op->type==PLAYER)   if (op->type==PLAYER)
Line 1570
 
Line 1467
     }      }
   
     /* special case: throwing powdery substances like dust, dirt */      /* special case: throwing powdery substances like dust, dirt */
     if(QUERY_FLAG(throw_ob,FLAG_DUST)) {       if(throw_ob->type == POTION && throw_ob->subtype == POT_DUST) {
  cast_dust(op,throw_ob,dir);    cast_dust(op,throw_ob,dir);
  return 1;   return 1;
     }      }
Line 1579
 
Line 1476
      * If unsuccessfull at making the "thrown_obj", we just reinsert       * If unsuccessfull at making the "thrown_obj", we just reinsert
      * the original object back into inventory and exit       * the original object back into inventory and exit
      */       */
     if((toss_item = make_throw_ob(throw_ob)))      if((toss_item = make_throw_ob(throw_ob))) {
  throw_ob = toss_item;   throw_ob = toss_item;
    if (throw_ob->skill) free_string(throw_ob->skill);
    throw_ob->skill = add_string(skill->skill);
       }
     else {      else {
  insert_ob_in_ob(throw_ob,op);   insert_ob_in_ob(throw_ob,op);
  return 0;   return 0;
Line 1618
 
Line 1518
            
     /* replace 25 with a call to clone.arch wc? messes up w/ NPC */      /* replace 25 with a call to clone.arch wc? messes up w/ NPC */
     throw_ob->stats.wc = 25 - dex_bonus[op->stats.Dex?dex_bonus[op->stats.Dex]:0]      throw_ob->stats.wc = 25 - dex_bonus[op->stats.Dex?dex_bonus[op->stats.Dex]:0]
  - thaco_bonus[eff_str] - SK_level(op);   - thaco_bonus[eff_str] - skill->level;
    
   
     /* the properties of objects which are meant to be thrown (ie dart,      /* the properties of objects which are meant to be thrown (ie dart,
Line 1663
 
Line 1563
     if(throw_ob->stats.wc>30) throw_ob->stats.wc=30;      if(throw_ob->stats.wc>30) throw_ob->stats.wc=30;
   
     /* how long to pause the thrower. Higher values mean less pause */      /* how long to pause the thrower. Higher values mean less pause */
     pause_f = ((2*eff_str)/3)+20+SK_level(op);      pause_f = ((2*eff_str)/3)+20+skill->level;
   
     /* Put a lower limit on this */      /* Put a lower limit on this */
     if (pause_f < 10) pause_f=10;      if (pause_f < 10) pause_f=10;
Line 1719
 
Line 1619
     move_arrow(throw_ob);      move_arrow(throw_ob);
     return 1;      return 1;
 }  }
   
   int skill_throw (object *op, object *part, int dir, char *params, object *skill) {
       object *throw_ob;
   
       if(op->type==PLAYER)
    throw_ob =  find_throw_ob(op,params);
       else
    throw_ob = find_mon_throw_ob(op);
   
       return do_throw(op,part, throw_ob,dir, skill);
   }
   


Legend:
line(s) removed in v.1.41 
line(s) changed
 line(s) added in v.1.42

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