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);
+ }