All pastes #35622 Raw Edit

cavehippo

public text v1 · immutable
#35622 ·published 2006-01-03 17:28 UTC
rendered paste body
Index: common/living.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/common/living.c,v
retrieving revision 1.74
diff -C5 -r1.74 living.c
*** common/living.c     16 Nov 2005 08:16:00 -0000      1.74
--- common/living.c     3 Jan 2006 16:58:38 -0000
***************
*** 1357,1366 ****
--- 1357,1371 ----
       */
      if (op->move_type == 0) op->move_type = MOVE_WALK;
      else if (op->move_type & (MOVE_FLY_LOW | MOVE_FLY_HIGH)) op->move_type &= ~MOVE_WALK;

      update_ob_speed(op);
+
+     /* It is quite possible that a player's spell costing might have changed,
+      * so we will check that now.
+      */
+     if (op->type == PLAYER) esrv_update_spells(op->contr);
  }

  /*
   * Returns true if the given player is a legal class.
   * The function to add and remove class-bonuses to the stats doesn't
***************
*** 1560,1573 ****
            sprintf(buf,"You are now level %d in the %s skill.",op->level,op->name);
            if(who) new_draw_info(NDI_UNIQUE|NDI_RED, 0, who,buf);
        }
        player_lvl_adj(who,op); /* To decrease more levels */
      }
  }

-
-
  /*
   * Returns how much experience is needed for a player to become
   * the given level.  level should really never exceed max_level
   */

--- 1565,1578 ----
            sprintf(buf,"You are now level %d in the %s skill.",op->level,op->name);
            if(who) new_draw_info(NDI_UNIQUE|NDI_RED, 0, who,buf);
        }
        player_lvl_adj(who,op); /* To decrease more levels */
      }
+     /* check if the spell data has changed */
+     esrv_update_spells(who->contr);
  }

  /*
   * Returns how much experience is needed for a player to become
   * the given level.  level should really never exceed max_level
   */

Index: doc/Developers/protocol
===================================================================
RCS file: /cvsroot/crossfire/crossfire/doc/Developers/protocol,v
retrieving revision 1.14
diff -C5 -r1.14 protocol
*** doc/Developers/protocol     31 Aug 2005 21:53:08 -0000      1.14
--- doc/Developers/protocol     3 Jan 2006 16:58:55 -0000
***************
*** 519,528 ****
--- 519,601 ----
        <tag> is sent as plaintext numbers.  Tag of 0 means to delete
        all items on the space teh character is standing on.  This command
        only affects the inventory of the object.  To fully delete a
        container object, a delinv followed by a delitem should be issued.

+ S->C addspell <tag1> <level1> <casting time1> <mana1> <grace1> <damage1> <skill>
+       <path1> <name1> <display name1> <message1> <spell2 ....>
+       Tells the client to add the spell(s) listed to the list of spells
+       the client knows about. This will be sent at login, and again whenever
+       new spells are sent.
+
+       The fields are;
+       <tag> - (4 bytes - int) The ID number for the spell item. This is
+               going to be unique, for each spell and will be used to refer
+               to it henceforth.
+
+       <level> (2 bytes, signed int)
+               The level of the spell.
+
+       <casting time> (2 bytes, signed int)
+               The time it will take to cast the spell, in server ticks.
+
+       <mana>  (2 bytes, signed int)
+               The mana cost to cast the spell (may be zero)
+
+       <grace> (2 bytes, signed int)
+               The grace cost to cast the spell (may be zero)
+
+       <damage> (2 bytes, signed int)
+               The current damage done by the spell. Note that the meaning of
+               this number is to a large part spell dependent, what damage it
+               actually does will depend on how the spell works.
+
+       <skill> (1 byte, unsigned int)
+               The skill that the spell uses to be cast, if zero, no skill is
+               used in the casting of this spell.
+               The numbers are the same as for request_info skill_info
+
+       <path>  (4 bytes, unsigned integer)
+               The path that the spell belongs to.
+               The client should determine the effect of this by comparing
+               these values to both the spell_paths request_info data and the
+               stats info concerning attunement/repulsion, etc.
+
+       <name> (1 (non-zero) length byte, followed by that many bytes of ascii text)
+               This is the name of the spell, and should be sent to the server
+               in order to cast/invoke it.
+
+       <display name> (1 length byte (which may be zero) followed by that
+               many bytes of ascii text)
+               This is the name to display to the player regarding the spell.
+               If length is zero, then the <name> should be used instead.
+
+       <message> (2 length bytes (which may be zero) followed by that many
+               bytes of ascii text)
+               The description of the spell,
+
+ S->C updspell <flags><tag><vals>+
+
+       This updates some spell (of tag) with new values. The flags are 1 byte
+       andd etermine which values have been updated, and should be re-read.
+       Not all fields may be updated by this command, only those that can be
+       changed.
+
+       If new fields are added in future, they will extend the flags bitmask
+       and the order will remain the LSB order of the flags - that is, the
+       value associated with bit 1 set is sent first, then bit 2, etc.
+
+       The format of the values is same as the addspell command above.
+
+       Only one spell can be updated with the updspell command.  A spell
+       command should have been sent by the server before an updspell
+       command is set.
+
+ S->C delspell <tag>
+       Tells the client to remove its information about the spell Tag is a 4
+       byte value, the same as the one sent when the spell was added.
+
  ******************************************************************************
  COMMANDS RELATING TO THE PLAYER OBJECT/STATS

  S->C: player <tag><weight><face><name>
        All fields are the same as described in item above.  The only
***************
*** 551,560 ****
--- 624,636 ----

        -skill experience:  this is only set if exp64 is set.  This is sent
         as the skill level, followed by the skill exp (thus, 9 bytes +
         the stat type byte)

+       -spell paths: if spellmon is set in setup, the bitmask of attuned,
+        repelled and denied paths is sent. These are all 32bits
+
  ******************************************************************************
  COMMANDS RELATING TO IMAGE INFORMATION TRANSMISSION

  S->C: anim <num><flags><face1><face2>...
        Informs the client of an animation sequence.  The client is responsible
***************
*** 1165,1174 ****
--- 1241,1254 ----
        extendedTextInfos (0/1)
                Toggle sending from server of extended text informations.
                What lies in this extended info depended on what extended
                infos the client asked. See toggleextendedtext command for details.

+       spellmon (0/1)
+           If set to 1 the client has indicated that it wishes to be
+           sent the spell list and updated when it changes.
+
        All data in the setup command is in ascii text form.  options and
        values can not have whitepace - the client and server use whitspace
        to split the options and values.

        Currently (2001-05-28), the server only sends a setup in response to
***************
*** 1305,1318 ****
        that skill information.  Example:
        141:lockpicking
        142:hiding
        143:smithery



!


  ------------------------------------------------------------------------------

  Example Session:

--- 1385,1407 ----
        that skill information.  Example:
        141:lockpicking
        142:hiding
        143:smithery

+     spell_paths (no parameters)
+       This returns a list of all spell paths in the game, along with the
+       number associated with them. This should be used to parse spell_path
+       data in the stats command. The number is a bitmask but is sent as a
+       decimal value.
+
+       All data is sent in text format. Format is:

+       number:name

!       eg

+       16:missiles

  ------------------------------------------------------------------------------

  Example Session:

Index: include/funcpoint.h
===================================================================
RCS file: /cvsroot/crossfire/crossfire/include/funcpoint.h,v
retrieving revision 1.15
diff -C5 -r1.15 funcpoint.h
*** include/funcpoint.h 5 Dec 2005 23:34:03 -0000       1.15
--- include/funcpoint.h 3 Jan 2006 16:58:55 -0000
***************
*** 56,65 ****
--- 56,66 ----
  extern void   move_duplicator(object *);
  extern void trap_adjust(object *, int);
  extern void   esrv_send_item(object *, object *);
  extern void   esrv_del_item(player *, int);
  extern void   esrv_update_item(int, object *, object *);
+ extern void   esrv_update_spells(player *);
  extern void   set_darkness_map(mapstruct *m);
  extern void dragon_ability_gain(object *, int, int);
  extern void   weather_effect(const char *);
  extern object *       find_skill_by_number(object *, int);

Index: include/newclient.h
===================================================================
RCS file: /cvsroot/crossfire/crossfire/include/newclient.h,v
retrieving revision 1.11
diff -C5 -r1.11 newclient.h
*** include/newclient.h 13 Sep 2003 05:01:33 -0000      1.11
--- include/newclient.h 3 Jan 2006 16:58:55 -0000
***************
*** 97,106 ****
--- 97,109 ----
  #define CS_STAT_GRACE 23
  #define CS_STAT_MAXGRACE      24
  #define CS_STAT_FLAGS 25
  #define CS_STAT_WEIGHT_LIM    26
  #define CS_STAT_EXP64 28
+ #define CS_STAT_SPELL_ATTUNE  29
+ #define CS_STAT_SPELL_REPEL   30
+ #define CS_STAT_SPELL_DENY    31

  /* Start & end of resistances, inclusive. */
  #define CS_STAT_RESIST_START  100
  #define CS_STAT_RESIST_END    117
  #define CS_STAT_RES_PHYS      100
***************
*** 223,232 ****
--- 226,240 ----
  #define UPD_NAME      0x10
  #define UPD_ANIM      0x20
  #define UPD_ANIMSPEED 0x40
  #define UPD_NROF      0x80

+ /* The flag values sent by the updspell command */
+ #define UPD_SP_MANA   0x01
+ #define UPD_SP_GRACE  0x02
+ #define UPD_SP_DAMAGE 0x04
+
  #define SOUND_NORMAL  0
  #define SOUND_SPELL   1

  /* Contains the base information we use to make up a packet we want to send. */
  typedef struct SockList {
Index: include/newserver.h
===================================================================
RCS file: /cvsroot/crossfire/crossfire/include/newserver.h,v
retrieving revision 1.34
diff -C5 -r1.34 newserver.h
*** include/newserver.h 28 Oct 2005 18:19:53 -0000      1.34
--- include/newserver.h 3 Jan 2006 16:58:55 -0000
***************
*** 121,130 ****
--- 121,131 ----
      uint32  image2:1;     /* Client wants image2/face2 commands */
      uint32  update_look:1;  /* If true, we need to send the look window */
      uint32  can_write:1;    /* Can we write to this socket? */
      uint32  has_readable_type:1; /* If true client accept additional text information
                                      used to arrange text in books, scrolls, or scripted dialogs */
+     uint32  monitor_spells:1; /* Client wishes to be informed when their spell list changes */
      uint32  supported_readables; /* each bit is a readable supported by client */
      uint32  cs_version, sc_version; /* versions of the client */
      enum MapMode mapmode;   /* Type of map commands the client wants. */
      uint16  look_position;  /* start of drawing of look window */
      uint8   mapx, mapy;           /* How large a map the client wants */
Index: include/player.h
===================================================================
RCS file: /cvsroot/crossfire/crossfire/include/player.h,v
retrieving revision 1.43
diff -C5 -r1.43 player.h
*** include/player.h    1 Oct 2005 17:46:04 -0000       1.43
--- include/player.h    3 Jan 2006 16:58:58 -0000
***************
*** 146,165 ****
      uint32    has_hit:1;          /* If set, weapon_sp instead of speed will count */
      uint32    name_changed:1;     /* If true, the player has set a name. */
      uint32    peaceful:1;         /* If set, won't attack friendly creatures */
      uint32    hidden:1;           /* If True, player (DM) is hidden from view */
      uint32    explore:1;          /* if True, player is in explore mode */
!       uint32  no_shout:1;             /* if True, player is *not* able to use shout command */

      object    *last_skill_ob[NUM_SKILLS];     /* the exp object */
      sint64    last_skill_exp[NUM_SKILLS];     /* shadow register. if != exp. obj update client */

      float     weapon_sp;          /* Penalties to speed when fighting w speed >ws/10*/
      float     last_weapon_sp;     /* if diff than weapon_sp, update client */
      uint16    last_flags;         /* fire/run on flags for last tick */
      sint32    last_weight;        /* Last weight as sent to client; -1 means do not send weight */
      sint32    last_weight_limit;  /* Last weight limit transmitted to client */
      living    orig_stats;         /* Permanent real stats of player */
      living    last_stats;         /* Last stats as sent to client */
      float     last_speed;         /* Last speed as sent to client */
      sint16    last_resist[NROFATTACKS];       /* last resist values sent to client */
      int               Swap_First;         /* First stat player has selected to swap */
--- 146,168 ----
      uint32    has_hit:1;          /* If set, weapon_sp instead of speed will count */
      uint32    name_changed:1;     /* If true, the player has set a name. */
      uint32    peaceful:1;         /* If set, won't attack friendly creatures */
      uint32    hidden:1;           /* If True, player (DM) is hidden from view */
      uint32    explore:1;          /* if True, player is in explore mode */
!     uint32    no_shout:1;         /* if True, player is *not* able to use shout command */

      object    *last_skill_ob[NUM_SKILLS];     /* the exp object */
      sint64    last_skill_exp[NUM_SKILLS];     /* shadow register. if != exp. obj update client */

      float     weapon_sp;          /* Penalties to speed when fighting w speed >ws/10*/
      float     last_weapon_sp;     /* if diff than weapon_sp, update client */
      uint16    last_flags;         /* fire/run on flags for last tick */
      sint32    last_weight;        /* Last weight as sent to client; -1 means do not send weight */
      sint32    last_weight_limit;  /* Last weight limit transmitted to client */
+     uint32    last_path_attuned;  /* Last spell attunment sent to client */
+     uint32    last_path_repelled; /* Last spell repelled sent to client */
+     uint32    last_path_denied;   /* Last spell denied sent to client */
      living    orig_stats;         /* Permanent real stats of player */
      living    last_stats;         /* Last stats as sent to client */
      float     last_speed;         /* Last speed as sent to client */
      sint16    last_resist[NROFATTACKS];       /* last resist values sent to client */
      int               Swap_First;         /* First stat player has selected to swap */
Index: include/sockproto.h
===================================================================
RCS file: /cvsroot/crossfire/crossfire/include/sockproto.h,v
retrieving revision 1.22
diff -C5 -r1.22 sockproto.h
*** include/sockproto.h 7 Dec 2005 18:25:54 -0000       1.22
--- include/sockproto.h 3 Jan 2006 16:58:58 -0000
***************
*** 90,97 ****
--- 90,101 ----
  void draw_client_map1(object *pl);
  void draw_client_map(object *pl);
  void esrv_map_scroll(NewSocket *ns, int dx, int dy);
  void send_plugin_custom_message(object *pl, char *buf);
  void send_skill_info(NewSocket *ns, char *params);
+ void send_spell_paths (NewSocket *ns, char *params);
+ void esrv_update_spells(player *pl);
+ void esrv_remove_spell(player *pl, object *spell);
+ void esrv_add_spells(player *pl, object *spell);
  /* sounds.c */
  void play_sound_player_only(player *pl, short soundnum, sint8 x, sint8 y);
  void play_sound_map(mapstruct *map, int x, int y, short sound_num);
Index: include/sproto.h
===================================================================
RCS file: /cvsroot/crossfire/crossfire/include/sproto.h,v
retrieving revision 1.158
diff -C5 -r1.158 sproto.h
*** include/sproto.h    1 Jan 2006 13:03:02 -0000       1.158
--- include/sproto.h    3 Jan 2006 16:59:06 -0000
***************
*** 788,798 ****
  void init_spells(void);
  void dump_spells(void);
  void spell_effect(object *spob, int x, int y, mapstruct *map, object *originator);
  int min_casting_level(object *caster, object *spell);
  int caster_level(object *caster, object *spell);
! int SP_level_spellpoint_cost(object *caster, object *spell, int flags);
  int SP_level_dam_adjust(object *caster, object *spob);
  int SP_level_duration_adjust(object *caster, object *spob);
  int SP_level_range_adjust(object *caster, object *spob);
  object *check_spell_known(object *op, const char *name);
  object *lookup_spell_by_name(object *op, const char *spname);
--- 788,798 ----
  void init_spells(void);
  void dump_spells(void);
  void spell_effect(object *spob, int x, int y, mapstruct *map, object *originator);
  int min_casting_level(object *caster, object *spell);
  int caster_level(object *caster, object *spell);
! sint16 SP_level_spellpoint_cost(object *caster, object *spell, int flags);
  int SP_level_dam_adjust(object *caster, object *spob);
  int SP_level_duration_adjust(object *caster, object *spob);
  int SP_level_range_adjust(object *caster, object *spob);
  object *check_spell_known(object *op, const char *name);
  object *lookup_spell_by_name(object *op, const char *spname);
Index: server/apply.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/server/apply.c,v
retrieving revision 1.154
diff -C5 -r1.154 apply.c
*** server/apply.c      1 Jan 2006 20:36:07 -0000       1.154
--- server/apply.c      3 Jan 2006 16:59:20 -0000
***************
*** 1732,1741 ****
--- 1732,1742 ----
      }

      new_draw_info_format (NDI_UNIQUE, 0, op,
              "Type 'bind cast %s", spell->name);
      new_draw_info (NDI_UNIQUE, 0, op, "to store the spell in a key.");
+     esrv_add_spells(op->contr, tmp);
  }

  /**
   * Erases spell from player's inventory.
   */
***************
*** 1753,1762 ****
--- 1754,1764 ----
      }

      new_draw_info_format (NDI_UNIQUE|NDI_NAVY, 0, op,
                          "You lose knowledge of %s.", spell);
      player_unready_range_ob(op->contr, spob);
+     esrv_remove_spell(op->contr, spob);
      remove_ob(spob);
      free_object(spob);
  }

  /**
Index: server/login.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/server/login.c,v
retrieving revision 1.56
diff -C5 -r1.56 login.c
*** server/login.c      11 Dec 2005 19:11:32 -0000      1.56
--- server/login.c      3 Jan 2006 16:59:26 -0000
***************
*** 709,718 ****
--- 709,719 ----
      /* Do this after checking for death - no reason sucking up bandwidth if
       * the data isn't needed.
       */
      esrv_new_player(op->contr,op->weight+op->carrying);
      esrv_send_inventory(op, op);
+     esrv_add_spells(op->contr, NULL);

      CLEAR_FLAG(op, FLAG_FRIENDLY);

      /* can_use_shield is a new flag.  However, the can_use.. seems to largely come
       * from the class, and not race.  I don't see any way to get the class information
Index: server/spell_util.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/server/spell_util.c,v
retrieving revision 1.102
diff -C5 -r1.102 spell_util.c
*** server/spell_util.c 5 Dec 2005 23:34:04 -0000       1.102
--- server/spell_util.c 3 Jan 2006 16:59:42 -0000
***************
*** 231,241 ****
   * spell is the spell object.
   * Note that it is now possible for a spell to cost both grace and
   * mana.  In that case, we return which ever value is higher.
   */

! int SP_level_spellpoint_cost(object *caster, object *spell, int flags)
  {
      int sp, grace, level = caster_level(caster, spell);

      if (settings.spellpoint_level_depend == TRUE) {
        if (spell->stats.sp && spell->stats.maxsp) {
--- 231,241 ----
   * spell is the spell object.
   * Note that it is now possible for a spell to cost both grace and
   * mana.  In that case, we return which ever value is higher.
   */

! sint16 SP_level_spellpoint_cost(object *caster, object *spell, int flags)
  {
      int sp, grace, level = caster_level(caster, spell);

      if (settings.spellpoint_level_depend == TRUE) {
        if (spell->stats.sp && spell->stats.maxsp) {
Index: socket/init.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/socket/init.c,v
retrieving revision 1.43
diff -C5 -r1.43 init.c
*** socket/init.c       7 Dec 2005 18:25:56 -0000       1.43
--- socket/init.c       3 Jan 2006 16:59:47 -0000
***************
*** 107,116 ****
--- 107,117 ----
      ns->image2 = 0;
      ns->sound = 0;
      ns->ext2 = 0;
      ns->ext_title_flag = 1;
      ns->exp64 = 0;
+     ns->monitor_spells = 0;
      ns->mapmode = Map0Cmd;
      ns->darkness = 1;
      ns->status = Ns_Add;
      ns->comment = NULL;
      ns->old_mode = 0;
Index: socket/loop.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/socket/loop.c,v
retrieving revision 1.37
diff -C5 -r1.37 loop.c
*** socket/loop.c       11 Dec 2005 19:11:32 -0000      1.37
--- socket/loop.c       3 Jan 2006 16:59:47 -0000
***************
*** 162,171 ****
--- 162,172 ----
            break;
        }
      if (!strcmp(buf, "image_info")) send_image_info(ns, params);
      else if (!strcmp(buf,"image_sums")) send_image_sums(ns, params);
      else if (!strcmp(buf,"skill_info")) send_skill_info(ns, params);
+     else if (!strcmp(buf,"spell_paths")) send_spell_paths(ns, params);
      else Write_String_To_Socket(ns, bigbuf, len);
  }

  /**
   * Handles old socket format.
Index: socket/request.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/socket/request.c,v
retrieving revision 1.75
diff -C5 -r1.75 request.c
*** socket/request.c    10 Dec 2005 14:27:10 -0000      1.75
--- socket/request.c    3 Jan 2006 16:59:55 -0000
***************
*** 153,163 ****
            strcat(cmdback, param);
        }
        else if (!strcmp(cmd,"exp64")) {
            ns->exp64 = atoi(param);
            strcat(cmdback, param);
!       } else if (!strcmp(cmd,"darkness")) {
            ns->darkness = atoi(param);
            strcat(cmdback, param);
        } else if (!strcmp(cmd,"map1cmd")) {
            if (atoi(param)) ns->mapmode = Map1Cmd;
            /* if beyond this size, need to use map1cmd no matter what */
--- 153,166 ----
            strcat(cmdback, param);
        }
        else if (!strcmp(cmd,"exp64")) {
            ns->exp64 = atoi(param);
            strcat(cmdback, param);
!       } else if (!strcmp(cmd, "spellmon")) {
!           ns->monitor_spells = atoi(param);
!           strcat(cmdback, param);
!       }  else if (!strcmp(cmd,"darkness")) {
            ns->darkness = atoi(param);
            strcat(cmdback, param);
        } else if (!strcmp(cmd,"map1cmd")) {
            if (atoi(param)) ns->mapmode = Map1Cmd;
            /* if beyond this size, need to use map1cmd no matter what */
***************
*** 833,843 ****
            /* Skip ones we won't send */
            if (atnr_cs_stat[i]==-1) continue;
            AddIfShort(pl->last_resist[i], pl->ob->resist[i], ( char )atnr_cs_stat[i]);
        }
      }
!
      rangetostring(pl->ob, buf); /* we want use the new fire & run system in new client */
      AddIfString(pl->socket.stats.range, buf, CS_STAT_RANGE);
      set_title(pl->ob, buf);
      AddIfString(pl->socket.stats.title, buf, CS_STAT_TITLE);

--- 836,850 ----
            /* Skip ones we won't send */
            if (atnr_cs_stat[i]==-1) continue;
            AddIfShort(pl->last_resist[i], pl->ob->resist[i], ( char )atnr_cs_stat[i]);
        }
      }
!     if (pl->socket.monitor_spells) {
!       AddIfInt(pl->last_path_attuned, pl->ob->path_attuned, CS_STAT_SPELL_ATTUNE);
!       AddIfInt(pl->last_path_repelled, pl->ob->path_repelled, CS_STAT_SPELL_REPEL);
!       AddIfInt(pl->last_path_denied, pl->ob->path_denied, CS_STAT_SPELL_DENY);
!     }
      rangetostring(pl->ob, buf); /* we want use the new fire & run system in new client */
      AddIfString(pl->socket.stats.range, buf, CS_STAT_RANGE);
      set_title(pl->ob, buf);
      AddIfString(pl->socket.stats.title, buf, CS_STAT_TITLE);

***************
*** 1929,1933 ****
--- 1936,2100 ----
        fatal(0);
      }
      Send_With_Handling(ns, &sl);
      free(sl.buf);
  }
+
+ /**
+  * This sends the spell path to name mapping.  We ignore
+  * the params - we always send the same info no matter what.
+  */
+ void send_spell_paths (NewSocket *ns, char *params) {
+     SockList sl;
+     int i;
+
+     sl.buf = malloc(MAXSOCKBUF);
+     strcpy(sl.buf,"replyinfo spell_paths\n");
+     for(i=0; i<NRSPELLPATHS; i++)
+       sprintf(sl.buf + strlen(sl.buf), "%d:%s\n", 1<<i, spellpathnames[i]);
+     sl.len = strlen(sl.buf);
+     if (sl.len > MAXSOCKBUF) {
+       LOG(llevError,"Buffer overflow in send_spell_paths!\n");
+       fatal(0);
+     }
+     Send_With_Handling(ns, &sl);
+     free(sl.buf);
+ }
+
+ /**
+  * This looks for any spells the player may have that have changed their stats.
+  * it then sends an updspell packet for each spell that has changed in this way
+  */
+ void esrv_update_spells(player *pl) {
+     SockList sl;
+     int flags=0;
+     object *spell;
+     if (!pl->socket.monitor_spells) return;
+     for (spell=pl->ob->inv; spell!=NULL; spell=spell->below) {
+       if (spell->type == SPELL) {
+           /* check if we need to update it*/
+           if (spell->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
+               spell->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
+               flags |= UPD_SP_MANA;
+           }
+           if (spell->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
+               spell->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
+               flags |= UPD_SP_GRACE;
+           }
+           if (spell->last_eat != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
+               spell->last_eat = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
+               flags |= UPD_SP_DAMAGE;
+           }
+           if (flags !=0) {
+               sl.buf = malloc(MAXSOCKBUF);
+               strcpy(sl.buf,"updspell ");
+               sl.len=strlen((char*)sl.buf);
+               SockList_AddChar(&sl, flags);
+               SockList_AddInt(&sl, spell->count);
+               if (flags & UPD_SP_MANA) SockList_AddShort(&sl, spell->last_sp);
+               if (flags & UPD_SP_GRACE) SockList_AddShort(&sl, spell->last_grace);
+               if (flags & UPD_SP_DAMAGE) SockList_AddShort(&sl, spell->last_eat);
+               flags = 0;
+               Send_With_Handling(&pl->socket, &sl);
+               free(sl.buf);
+           }
+       }
+     }
+ }
+
+ void esrv_remove_spell(player *pl, object *spell) {
+     if (!pl->socket.monitor_spells) return;
+     if (!pl || !spell || spell->env != pl->ob) {
+       LOG(llevError, "Invalid call to esrv_remove_spell");
+       return;
+     }
+     SockList sl;
+     sl.buf = malloc(MAXSOCKBUF);
+     strcpy(sl.buf,"delspell ");
+     sl.len=strlen((char*)sl.buf);
+     SockList_AddInt(&sl, spell->count);
+     Send_With_Handling(&pl->socket, &sl);
+     free(sl.buf);
+ }