ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/request.C
Revision: 1.22
Committed: Tue Sep 19 10:12:50 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.21: +11 -9 lines
Log Message:
indent

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4     Copyright (C) 2001 Mark Wedel
5     Copyright (C) 1992 Frank Tore Johansen
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 root 1.19 The author can be reached via e-mail to <crossfire@schmorp.de>
22 elmex 1.1 */
23    
24     /**
25     * \file
26     * Client handling.
27     *
28     * \date 2003-12-02
29     *
30     * This file implements all of the goo on the server side for handling
31     * clients. It's got a bunch of global variables for keeping track of
32     * each of the clients.
33     *
34     * Note: All functions that are used to process data from the client
35     * have the prototype of (char *data, int datalen, int client_num). This
36     * way, we can use one dispatch table.
37     *
38     * esrv_map_new starts updating the map
39     *
40     * esrv_map_setbelow allows filling in all of the faces for the map.
41     * if a face has not already been sent to the client, it is sent now.
42     *
43     * mapcellchanged, compactlayer, compactstack, perform the map compressing
44     * operations
45     *
46     * esrv_map_doneredraw finishes the map update, and ships across the
47     * map updates.
48     *
49     */
50    
51     #include <global.h>
52     #include <sproto.h>
53    
54     #include <newclient.h>
55     #include <newserver.h>
56     #include <living.h>
57     #include <commands.h>
58    
59     /* This block is basically taken from socket.c - I assume if it works there,
60     * it should work here.
61     */
62 root 1.16 #ifndef WIN32 /* ---win32 exclude unix headers */
63     # include <sys/types.h>
64     # include <sys/time.h>
65     # include <sys/socket.h>
66     # include <netinet/in.h>
67     # include <netdb.h>
68 elmex 1.1 #endif /* win32 */
69    
70     #ifdef HAVE_UNISTD_H
71 root 1.16 # include <unistd.h>
72 elmex 1.1 #endif
73    
74     #ifdef HAVE_SYS_TIME_H
75 root 1.16 # include <sys/time.h>
76 elmex 1.1 #endif
77    
78     #include "sounds.h"
79    
80     /**
81     * This table translates the attack numbers as used within the
82     * program to the value we use when sending STATS command to the
83     * client. If a value is -1, then we don't send that to the
84     * client.
85     */
86 root 1.16 short atnr_cs_stat[NROFATTACKS] = { CS_STAT_RES_PHYS,
87     CS_STAT_RES_MAG, CS_STAT_RES_FIRE, CS_STAT_RES_ELEC,
88     CS_STAT_RES_COLD, CS_STAT_RES_CONF, CS_STAT_RES_ACID,
89     CS_STAT_RES_DRAIN, -1 /* weaponmagic */ ,
90     CS_STAT_RES_GHOSTHIT, CS_STAT_RES_POISON,
91     CS_STAT_RES_SLOW, CS_STAT_RES_PARA, CS_STAT_TURN_UNDEAD,
92     CS_STAT_RES_FEAR, -1 /* Cancellation */ ,
93     CS_STAT_RES_DEPLETE, CS_STAT_RES_DEATH,
94     -1 /* Chaos */ , -1 /* Counterspell */ ,
95     -1 /* Godpower */ , CS_STAT_RES_HOLYWORD,
96     CS_STAT_RES_BLIND,
97     -1, /* Internal */
98     -1, /* life stealing */
99     -1 /* Disease - not fully done yet */
100 elmex 1.1 };
101    
102 root 1.2 static void
103 root 1.16 socket_map_scroll (NewSocket * ns, int dx, int dy)
104 root 1.2 {
105 root 1.16 struct Map newmap;
106     int x, y, mx, my;
107 root 1.2
108 root 1.16 {
109     char buf[MAXSOCKBUF];
110 root 1.2
111 root 1.16 sprintf (buf, "map_scroll %d %d", dx, dy);
112     Write_String_To_Socket (ns, buf, strlen (buf));
113     }
114 root 1.2
115 root 1.16 /* If we are using the Map1aCmd, we may in fact send
116     * head information that is outside the viewable map.
117     * So set the mx,my to the max value we want to
118     * look for. Removed code to do so - it caused extra
119     * complexities for the client, and probably doesn't make
120     * that much difference in bandwidth.
121     */
122     mx = ns->mapx;
123     my = ns->mapy;
124 root 1.2
125 root 1.16 if (ns->mapmode == Map1aCmd)
126     {
127     mx += MAX_HEAD_OFFSET;
128     my += MAX_HEAD_OFFSET;
129 root 1.2 }
130    
131 root 1.16 /* the x and y here are coordinates for the new map, i.e. if we moved
132     * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
133     * if the destination x or y coordinate is outside the viewable
134     * area, we clear the values - otherwise, the old values
135     * are preserved, and the check_head thinks it needs to clear them.
136     */
137     for (x = 0; x < mx; x++)
138     {
139     for (y = 0; y < my; y++)
140     {
141     if (x >= ns->mapx || y >= ns->mapy)
142     {
143     /* clear cells outside the viewable area */
144     memset (&newmap.cells[x][y], 0, sizeof (struct MapCell));
145 root 1.12 }
146 root 1.16 else if ((x + dx) < 0 || (x + dx) >= ns->mapx || (y + dy) < 0 || (y + dy) >= ns->mapy)
147     {
148     /* clear newly visible tiles within the viewable area */
149     memset (&(newmap.cells[x][y]), 0, sizeof (struct MapCell));
150 root 1.12 }
151 root 1.16 else
152     {
153     memcpy (&(newmap.cells[x][y]), &(ns->lastmap.cells[x + dx][y + dy]), sizeof (struct MapCell));
154 root 1.12 }
155     }
156 root 1.2 }
157    
158 root 1.16 memcpy (&(ns->lastmap), &newmap, sizeof (struct Map));
159 root 1.2
160 root 1.16 /* Make sure that the next "map1" command will be sent (even if it is
161     * empty).
162     */
163     ns->sent_scroll = 1;
164 root 1.2 }
165    
166 root 1.7 static void
167     clear_map (player *pl)
168     {
169 root 1.16 NewSocket & socket = pl->socket;
170 root 1.7
171     memset (&socket.lastmap, 0, sizeof (socket.lastmap));
172    
173     if (socket.newmapcmd == 1)
174     Write_String_To_Socket (&socket, "newmap", 6);
175    
176 root 1.16 socket.update_look = 1;
177 root 1.7 socket.look_position = 0;
178     }
179    
180 elmex 1.1 /** check for map change and send new map data */
181     static void
182     check_map_change (player *pl)
183     {
184 root 1.16 NewSocket & socket = pl->socket;
185 root 1.2 object *ob = pl->ob;
186 root 1.16 char buf[MAX_BUF]; /* eauugggh */
187 elmex 1.1
188 root 1.2 if (socket.current_map != ob->map)
189     {
190     socket.current_map = ob->map;
191 elmex 1.1
192 root 1.7 clear_map (pl);
193 elmex 1.1
194 root 1.2 if (socket.mapinfocmd)
195 elmex 1.1 {
196 root 1.16 if (ob->map && ob->map->path[0])
197 root 1.2 {
198     int flags = 0;
199 elmex 1.1
200 root 1.16 if (ob->map->tile_path[0])
201     flags |= 1;
202     if (ob->map->tile_path[1])
203     flags |= 2;
204     if (ob->map->tile_path[2])
205     flags |= 4;
206     if (ob->map->tile_path[3])
207     flags |= 8;
208 root 1.2
209     snprintf (buf, MAX_BUF, "mapinfo - spatial %d %d %d %d %d %s",
210 root 1.16 flags, socket.mapx / 2 - ob->x, socket.mapy / 2 - ob->y, ob->map->width, ob->map->height, ob->map->path);
211 root 1.2 }
212     else
213     snprintf (buf, MAX_BUF, "mapinfo current");
214 elmex 1.1
215 root 1.2 Write_String_To_Socket (&socket, buf, strlen (buf));
216 root 1.16 }
217 elmex 1.1 }
218 root 1.2 else if (socket.current_x != ob->x || socket.current_y != ob->y)
219     {
220 root 1.7 int dx = ob->x - socket.current_x;
221     int dy = ob->y - socket.current_y;
222    
223     if (socket.buggy_mapscroll && (abs (dx) > 8 || abs (dy) > 8))
224 root 1.16 clear_map (pl); // current (<= 1.9.1) clients have unchecked buffer overflows
225 root 1.7 else
226     {
227     socket_map_scroll (&socket, ob->x - socket.current_x, ob->y - socket.current_y);
228     socket.update_look = 1;
229     socket.look_position = 0;
230     }
231 root 1.2 }
232    
233     socket.current_x = ob->x;
234     socket.current_y = ob->y;
235 elmex 1.1 }
236    
237 root 1.16 void
238     ExtCmd (char *buf, int len, player *pl)
239 elmex 1.1 {
240 root 1.10 INVOKE_PLAYER (EXTCMD, pl, ARG_DATA (buf, len));
241 elmex 1.1 }
242    
243 root 1.16 void
244     MapInfoCmd (char *buf, int len, player *pl)
245 elmex 1.1 {
246     // <mapinfo tag spatial tile-path
247     // >mapinfo tag spatial flags x y w h hash
248 root 1.16
249 pippijn 1.15 char bigbuf[MAX_BUF], *token;
250 elmex 1.1
251     token = buf;
252     // copy token
253     if (!(buf = strchr (buf, ' ')))
254     return;
255    
256     *buf++ = 0;
257    
258     if (!strncmp (buf, "spatial ", 8))
259     {
260     buf += 8;
261    
262     // initial map and its origin
263 root 1.21 maptile *map = pl->ob->map;
264 elmex 1.1 sint16 dx, dy;
265     int mapx = pl->socket.mapx / 2 - pl->ob->x;
266     int mapy = pl->socket.mapy / 2 - pl->ob->y;
267 root 1.16 int max_distance = 8; // limit maximum path length to something generous
268 elmex 1.1
269     while (*buf && map && max_distance)
270     {
271     int dir = *buf++;
272    
273     switch (dir)
274     {
275 root 1.16 case '1':
276     dx = 0;
277     dy = -1;
278     map = get_map_from_coord (map, &dx, &dy);
279     map && (mapy -= map->height);
280     break;
281     case '2':
282     mapx += map->width;
283     dx = map->width;
284     dy = 0;
285     map = get_map_from_coord (map, &dx, &dy);
286     break;
287     case '3':
288     mapy += map->height;
289     dx = 0;
290     dy = map->height;
291     map = get_map_from_coord (map, &dx, &dy);
292     break;
293     case '4':
294     dx = -1;
295     dy = 0;
296     map = get_map_from_coord (map, &dx, &dy);
297     map && (mapx -= map->width);
298     break;
299 elmex 1.1 }
300    
301     --max_distance;
302     }
303    
304     if (!max_distance)
305     snprintf (bigbuf, MAX_BUF, "mapinfo %s error", token);
306 root 1.16 else if (map && map->path[0])
307 elmex 1.1 {
308     int flags = 0;
309    
310 root 1.16 if (map->tile_path[0])
311     flags |= 1;
312     if (map->tile_path[1])
313     flags |= 2;
314     if (map->tile_path[2])
315     flags |= 4;
316     if (map->tile_path[3])
317     flags |= 8;
318    
319     snprintf (bigbuf, MAX_BUF, "mapinfo %s spatial %d %d %d %d %d %s", token, flags, mapx, mapy, map->width, map->height, map->path);
320 elmex 1.1 }
321     else
322     snprintf (bigbuf, MAX_BUF, "mapinfo %s nomap", token);
323     }
324     else
325     snprintf (bigbuf, MAX_BUF, "mapinfo %s unsupported", token);
326 root 1.16
327 elmex 1.1 Write_String_To_Socket (&pl->socket, bigbuf, strlen (bigbuf));
328     }
329    
330     /** This is the Setup cmd - easy first implementation */
331 root 1.16 void
332     SetUp (char *buf, int len, NewSocket * ns)
333 elmex 1.1 {
334 root 1.16 int s, slen;
335     char *cmd, *param, cmdback[HUGE_BUF];
336    
337     /* run through the cmds of setup
338     * syntax is setup <cmdname1> <parameter> <cmdname2> <parameter> ...
339     *
340     * we send the status of the cmd back, or a FALSE is the cmd is the server unknown
341     * The client then must sort this out
342     */
343    
344     LOG (llevInfo, "Get SetupCmd:: %s\n", buf);
345     strcpy (cmdback, "setup");
346     for (s = 0; s < len;)
347     {
348 elmex 1.1
349 root 1.16 cmd = &buf[s];
350 root 1.12
351 root 1.16 /* find the next space, and put a null there */
352     for (; buf[s] && buf[s] != ' '; s++);
353     buf[s++] = 0;
354     while (buf[s] == ' ')
355     s++;
356    
357     if (s >= len)
358     break;
359    
360     param = &buf[s];
361 root 1.12
362 root 1.16 for (; buf[s] && buf[s] != ' '; s++);
363     buf[s++] = 0;
364     while (buf[s] == ' ')
365     s++;
366    
367     slen = strlen (cmdback);
368     safe_strcat (cmdback, " ", &slen, HUGE_BUF);
369     safe_strcat (cmdback, cmd, &slen, HUGE_BUF);
370     safe_strcat (cmdback, " ", &slen, HUGE_BUF);
371 root 1.12
372 root 1.16 if (!strcmp (cmd, "sound"))
373     {
374     ns->sound = atoi (param);
375     safe_strcat (cmdback, param, &slen, HUGE_BUF);
376     }
377     else if (!strcmp (cmd, "exp64"))
378     {
379     ns->exp64 = atoi (param);
380     safe_strcat (cmdback, param, &slen, HUGE_BUF);
381     }
382     else if (!strcmp (cmd, "spellmon"))
383     {
384     ns->monitor_spells = atoi (param);
385     safe_strcat (cmdback, param, &slen, HUGE_BUF);
386     }
387     else if (!strcmp (cmd, "darkness"))
388     {
389     ns->darkness = atoi (param);
390     safe_strcat (cmdback, param, &slen, HUGE_BUF);
391     }
392     else if (!strcmp (cmd, "map1cmd"))
393     {
394     if (atoi (param))
395     ns->mapmode = Map1Cmd;
396     /* if beyond this size, need to use map1cmd no matter what */
397     if (ns->mapx > 11 || ns->mapy > 11)
398     ns->mapmode = Map1Cmd;
399     safe_strcat (cmdback, ns->mapmode == Map1Cmd ? "1" : "0", &slen, HUGE_BUF);
400     }
401     else if (!strcmp (cmd, "map1acmd"))
402     {
403     if (atoi (param))
404     ns->mapmode = Map1aCmd;
405     /* if beyond this size, need to use map1acmd no matter what */
406     if (ns->mapx > 11 || ns->mapy > 11)
407     ns->mapmode = Map1aCmd;
408     safe_strcat (cmdback, ns->mapmode == Map1aCmd ? "1" : "0", &slen, HUGE_BUF);
409     }
410     else if (!strcmp (cmd, "newmapcmd"))
411     {
412     ns->newmapcmd = atoi (param);
413     safe_strcat (cmdback, param, &slen, HUGE_BUF);
414 elmex 1.1 // } else if (!strcmp(cmd,"plugincmd")) {
415     // ns->plugincmd = atoi(param);
416 root 1.16 // safe_strcat(cmdback, param, &slen, HUGE_BUF);
417     }
418     else if (!strcmp (cmd, "mapinfocmd"))
419     {
420     ns->mapinfocmd = atoi (param);
421     safe_strcat (cmdback, "1", &slen, HUGE_BUF);
422     }
423     else if (!strcmp (cmd, "extcmd"))
424     {
425     ns->extcmd = atoi (param);
426     safe_strcat (cmdback, "1", &slen, HUGE_BUF);
427     }
428     else if (!strcmp (cmd, "extmap"))
429     {
430     ns->extmap = atoi (param);
431     safe_strcat (cmdback, "1", &slen, HUGE_BUF);
432     }
433     else if (!strcmp (cmd, "facecache"))
434     {
435     ns->facecache = atoi (param);
436     safe_strcat (cmdback, param, &slen, HUGE_BUF);
437     }
438     else if (!strcmp (cmd, "faceset"))
439     {
440     char tmpbuf[20];
441     int q = atoi (param);
442    
443     if (is_valid_faceset (q))
444     ns->faceset = q;
445     sprintf (tmpbuf, "%d", ns->faceset);
446     safe_strcat (cmdback, tmpbuf, &slen, HUGE_BUF);
447     /* if the client is using faceset, it knows about image2 command */
448     ns->image2 = 1;
449     }
450     else if (!strcmp (cmd, "itemcmd"))
451     {
452     /* Version of the item protocol command to use. Currently,
453     * only supported versions are 1 and 2. Using a numeric
454     * value will make it very easy to extend this in the future.
455     */
456     char tmpbuf[20];
457     int q = atoi (param);
458    
459     if (q < 1 || q > 2)
460     {
461     strcpy (tmpbuf, "FALSE");
462     }
463     else
464     {
465     ns->itemcmd = q;
466     sprintf (tmpbuf, "%d", ns->itemcmd);
467     }
468     safe_strcat (cmdback, tmpbuf, &slen, HUGE_BUF);
469     }
470     else if (!strcmp (cmd, "mapsize"))
471     {
472     int x, y = 0;
473     char tmpbuf[MAX_BUF], *cp;
474    
475     x = atoi (param);
476     for (cp = param; *cp != 0; cp++)
477     if (*cp == 'x' || *cp == 'X')
478     {
479     y = atoi (cp + 1);
480     break;
481     }
482     if (x < 9 || y < 9 || x > MAP_CLIENT_X || y > MAP_CLIENT_Y)
483     {
484     sprintf (tmpbuf, " %dx%d", MAP_CLIENT_X, MAP_CLIENT_Y);
485     safe_strcat (cmdback, tmpbuf, &slen, HUGE_BUF);
486     }
487     else
488     {
489     ns->mapx = x;
490     ns->mapy = y;
491     /* better to send back what we are really using and not the
492     * param as given to us in case it gets parsed differently.
493     */
494     sprintf (tmpbuf, "%dx%d", x, y);
495     safe_strcat (cmdback, tmpbuf, &slen, HUGE_BUF);
496     /* If beyond this size and still using orig map command, need to
497     * go to map1cmd.
498     */
499     if ((x > 11 || y > 11) && ns->mapmode == Map0Cmd)
500     ns->mapmode = Map1Cmd;
501     }
502     }
503     else if (!strcmp (cmd, "extendedMapInfos"))
504     {
505     /* Added by tchize
506     * prepare to use the mapextended command
507     */
508     char tmpbuf[20];
509    
510     ns->ext_mapinfos = (atoi (param));
511     sprintf (tmpbuf, "%d", ns->ext_mapinfos);
512     safe_strcat (cmdback, tmpbuf, &slen, HUGE_BUF);
513     }
514     else if (!strcmp (cmd, "extendedTextInfos"))
515     {
516     /* Added by tchize
517     * prepare to use the extended text commands
518     * Client toggle this to non zero to get exttext
519     */
520     char tmpbuf[20];
521    
522     ns->has_readable_type = (atoi (param));
523     sprintf (tmpbuf, "%d", ns->has_readable_type);
524     safe_strcat (cmdback, tmpbuf, &slen, HUGE_BUF);
525     }
526     else
527     {
528     /* Didn't get a setup command we understood -
529     * report a failure to the client.
530     */
531     safe_strcat (cmdback, "FALSE", &slen, HUGE_BUF);
532     }
533     } /* for processing all the setup commands */
534     LOG (llevInfo, "SendBack SetupCmd:: %s\n", cmdback);
535     Write_String_To_Socket (ns, cmdback, strlen (cmdback));
536 elmex 1.1 }
537    
538     /**
539     * The client has requested to be added to the game.
540     * This is what takes care of it. We tell the client how things worked out.
541     * I am not sure if this file is the best place for this function. however,
542     * it either has to be here or init_sockets needs to be exported.
543     */
544 root 1.16 void
545     AddMeCmd (char *buf, int len, NewSocket * ns)
546 elmex 1.1 {
547 root 1.16 Settings oldsettings;
548    
549     oldsettings = settings;
550     if (ns->status != Ns_Add || add_player (ns))
551     {
552     Write_String_To_Socket (ns, "addme_failed", 12);
553     }
554     else
555     {
556     /* Basically, the add_player copies the socket structure into
557     * the player structure, so this one (which is from init_sockets)
558     * is not needed anymore. The write below should still work, as the
559     * stuff in ns is still relevant.
560     */
561     Write_String_To_Socket (ns, "addme_success", 13);
562     socket_info.nconns--;
563     ns->status = Ns_Avail;
564 elmex 1.1 }
565 root 1.16 settings = oldsettings;
566 elmex 1.1 }
567    
568     /** Reply to ExtendedInfos command */
569 root 1.16 void
570     ToggleExtendedInfos (char *buf, int len, NewSocket * ns)
571     {
572     char cmdback[MAX_BUF];
573     char command[50];
574     int info, nextinfo;
575    
576     cmdback[0] = '\0';
577     nextinfo = 0;
578 root 1.17
579 root 1.16 while (1)
580     {
581     /* 1. Extract an info */
582     info = nextinfo;
583 root 1.17
584 root 1.16 while ((info < len) && (buf[info] == ' '))
585     info++;
586 root 1.17
587 root 1.16 if (info >= len)
588     break;
589 root 1.17
590 root 1.16 nextinfo = info + 1;
591 root 1.17
592 root 1.16 while ((nextinfo < len) && (buf[nextinfo] != ' '))
593     nextinfo++;
594 root 1.17
595 root 1.16 if (nextinfo - info >= 49) /*Erroneous info asked */
596     continue;
597 root 1.17
598 root 1.16 strncpy (command, &(buf[info]), nextinfo - info);
599 root 1.17
600 root 1.16 /* 2. Interpret info */
601     if (!strcmp ("smooth", command))
602 root 1.17 /* Toggle smoothing */
603     ns->EMI_smooth = !ns->EMI_smooth;
604 root 1.16 else
605 root 1.17 /*bad value */;
606    
607 root 1.16 /*3. Next info */
608     }
609 root 1.17
610 root 1.16 strcpy (cmdback, "ExtendedInfoSet");
611 root 1.17
612 root 1.16 if (ns->EMI_smooth)
613     {
614     strcat (cmdback, " ");
615     strcat (cmdback, "smoothing");
616     }
617 root 1.17
618 root 1.16 Write_String_To_Socket (ns, cmdback, strlen (cmdback));
619 elmex 1.1 }
620 root 1.16
621 elmex 1.1 /*
622     #define MSG_TYPE_BOOK 1
623     #define MSG_TYPE_CARD 2
624     #define MSG_TYPE_PAPER 3
625     #define MSG_TYPE_SIGN 4
626     #define MSG_TYPE_MONUMENT 5
627     #define MSG_TYPE_SCRIPTED_DIALOG 6*/
628 root 1.16
629 elmex 1.1 /** Reply to ExtendedInfos command */
630 root 1.16 void
631     ToggleExtendedText (char *buf, int len, NewSocket * ns)
632     {
633     char cmdback[MAX_BUF];
634     char temp[10];
635     char command[50];
636     int info, nextinfo, i, flag;
637    
638     cmdback[0] = '\0';
639 root 1.17
640 root 1.16 nextinfo = 0;
641     while (1)
642     {
643     /* 1. Extract an info */
644     info = nextinfo;
645 root 1.17
646 root 1.16 while ((info < len) && (buf[info] == ' '))
647     info++;
648 root 1.17
649 root 1.16 if (info >= len)
650     break;
651 root 1.17
652 root 1.16 nextinfo = info + 1;
653 root 1.17
654 root 1.16 while ((nextinfo < len) && (buf[nextinfo] != ' '))
655     nextinfo++;
656 root 1.17
657 root 1.16 if (nextinfo - info >= 49) /*Erroneous info asked */
658     continue;
659 root 1.17
660 root 1.16 strncpy (command, &(buf[info]), nextinfo - info);
661     command[nextinfo - info] = '\0';
662     /* 2. Interpret info */
663     i = sscanf (command, "%d", &flag);
664 root 1.17
665 root 1.16 if ((i == 1) && (flag > 0) && (flag <= MSG_TYPE_LAST))
666     ns->supported_readables |= (1 << flag);
667     /*3. Next info */
668     }
669 root 1.17
670 root 1.16 /* Send resulting state */
671     strcpy (cmdback, "ExtendedTextSet");
672 root 1.17
673 root 1.16 for (i = 0; i <= MSG_TYPE_LAST; i++)
674     if (ns->supported_readables & (1 << i))
675     {
676     strcat (cmdback, " ");
677     snprintf (temp, sizeof (temp), "%d", i);
678     strcat (cmdback, temp);
679     }
680 root 1.17
681 root 1.16 Write_String_To_Socket (ns, cmdback, strlen (cmdback));
682 elmex 1.1 }
683    
684     /**
685     * A lot like the old AskSmooth (in fact, now called by AskSmooth).
686     * Basically, it makes no sense to wait for the client to request a
687     * a piece of data from us that we know the client wants. So
688     * if we know the client wants it, might as well push it to the
689     * client.
690     */
691 root 1.16 static void
692     SendSmooth (NewSocket * ns, uint16 face)
693     {
694     uint16 smoothface;
695     unsigned char reply[MAX_BUF];
696     SockList sl;
697    
698     /* If we can't find a face, return and set it so we won't try to send this
699     * again.
700     */
701     if ((!FindSmooth (face, &smoothface)) && (!FindSmooth (smooth_face->number, &smoothface)))
702     {
703    
704     LOG (llevError, "could not findsmooth for %d. Neither default (%s)\n", face, &smooth_face->name);
705     ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
706     return;
707     }
708    
709     if (!(ns->faces_sent[smoothface] & NS_FACESENT_FACE))
710     esrv_send_face (ns, smoothface, 0);
711    
712     ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
713    
714     sl.buf = reply;
715     strcpy ((char *) sl.buf, "smooth ");
716     sl.len = strlen ((char *) sl.buf);
717     SockList_AddShort (&sl, face);
718     SockList_AddShort (&sl, smoothface);
719     Send_With_Handling (ns, &sl);
720 elmex 1.1 }
721    
722     /**
723     * Tells client the picture it has to use
724     * to smooth a picture number given as argument.
725     */
726 root 1.16 void
727     AskSmooth (char *buf, int len, NewSocket * ns)
728     {
729     uint16 facenbr;
730 elmex 1.1
731 root 1.16 facenbr = atoi (buf);
732     SendSmooth (ns, facenbr);
733 elmex 1.1 }
734    
735    
736    
737    
738    
739     /**
740     * This handles the general commands from the client (ie, north, fire, cast,
741     * etc.)
742     */
743 root 1.16 void
744     PlayerCmd (char *buf, int len, player *pl)
745 elmex 1.1 {
746    
747 root 1.16 /* The following should never happen with a proper or honest client.
748     * Therefore, the error message doesn't have to be too clear - if
749     * someone is playing with a hacked/non working client, this gives them
750     * an idea of the problem, but they deserve what they get
751     */
752     if (pl->state != ST_PLAYING)
753     {
754     new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "You can not issue commands - state is not ST_PLAYING (%s)", buf);
755     return;
756     }
757     /* Check if there is a count. In theory, a zero count could also be
758     * sent, so check for that also.
759     */
760     if (atoi (buf) || buf[0] == '0')
761     {
762     pl->count = atoi ((char *) buf);
763     buf = strchr (buf, ' '); /* advance beyond the numbers */
764     if (!buf)
765     {
766 elmex 1.1 #ifdef ESRV_DEBUG
767 root 1.16 LOG (llevDebug, "PlayerCmd: Got count but no command.\n");
768 elmex 1.1 #endif
769 root 1.16 return;
770 root 1.12 }
771 root 1.16 buf++;
772 elmex 1.1 }
773 root 1.16 /* This should not happen anymore. */
774     if (pl->ob->speed_left < -1.0)
775     {
776     LOG (llevError, "Player has negative time - shouldn't do command.\n");
777     }
778     /* In c_new.c */
779     execute_newserver_command (pl->ob, (char *) buf);
780     /* Perhaps something better should be done with a left over count.
781     * Cleaning up the input should probably be done first - all actions
782     * for the command that issued the count should be done before any other
783     * commands.
784     */
785 elmex 1.1
786 root 1.16 pl->count = 0;
787 elmex 1.1
788     }
789    
790    
791     /**
792     * This handles the general commands from the client (ie, north, fire, cast,
793     * etc.). It is a lot like PlayerCmd above, but is called with the
794     * 'ncom' method which gives more information back to the client so it
795     * can throttle.
796     */
797 root 1.16 void
798     NewPlayerCmd (uint8 * buf, int len, player *pl)
799 elmex 1.1 {
800 root 1.16 int time, repeat;
801     short packet;
802     unsigned char command[MAX_BUF];
803     SockList sl;
804    
805     if (len < 7)
806     {
807     LOG (llevDebug, "Corrupt ncom command <%s> not long enough - discarding\n", buf);
808     return;
809     }
810    
811     packet = GetShort_String (buf);
812     repeat = GetInt_String (buf + 2);
813     /* -1 is special - no repeat, but don't update */
814     if (repeat != -1)
815     {
816     pl->count = repeat;
817     }
818     if ((len - 4) >= MAX_BUF)
819     len = MAX_BUF - 5;
820    
821     strncpy ((char *) command, (char *) buf + 6, len - 4);
822     command[len - 4] = '\0';
823    
824     /* The following should never happen with a proper or honest client.
825     * Therefore, the error message doesn't have to be too clear - if
826     * someone is playing with a hacked/non working client, this gives them
827     * an idea of the problem, but they deserve what they get
828     */
829     if (pl->state != ST_PLAYING)
830     {
831     new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "You can not issue commands - state is not ST_PLAYING (%s)", buf);
832     return;
833     }
834    
835     /* This should not happen anymore. */
836     if (pl->ob->speed_left < -1.0)
837     {
838     LOG (llevError, "Player has negative time - shouldn't do command.\n");
839     }
840     /* In c_new.c */
841     execute_newserver_command (pl->ob, (char *) command);
842     /* Perhaps something better should be done with a left over count.
843     * Cleaning up the input should probably be done first - all actions
844     * for the command that issued the count should be done before any other
845     * commands.
846     */
847     pl->count = 0;
848    
849     /* Send confirmation of command execution now */
850     sl.buf = command;
851     strcpy ((char *) sl.buf, "comc ");
852     sl.len = 5;
853     SockList_AddShort (&sl, packet);
854     if (FABS (pl->ob->speed) < 0.001)
855     time = MAX_TIME * 100;
856     else
857     time = (int) (MAX_TIME / FABS (pl->ob->speed));
858     SockList_AddInt (&sl, time);
859     Send_With_Handling (&pl->socket, &sl);
860 elmex 1.1 }
861    
862    
863     /** This is a reply to a previous query. */
864 root 1.16 void
865     ReplyCmd (char *buf, int len, player *pl)
866 elmex 1.1 {
867 root 1.16 /* This is to synthesize how the data would be stored if it
868     * was normally entered. A bit of a hack, and should be cleaned up
869     * once all the X11 code is removed from the server.
870     *
871     * We pass 13 to many of the functions because this way they
872     * think it was the carriage return that was entered, and the
873     * function then does not try to do additional input.
874     */
875     snprintf (pl->write_buf, sizeof (pl->write_buf), ":%s", buf);
876    
877     /* this avoids any hacking here */
878    
879     switch (pl->state)
880     {
881 root 1.12 case ST_PLAYING:
882 root 1.16 LOG (llevError, "Got reply message with ST_PLAYING input state\n");
883     break;
884 root 1.12
885     case ST_PLAY_AGAIN:
886 root 1.16 /* We can check this for return value (2==quit). Maybe we
887     * should, and do something appropriate?
888     */
889     receive_play_again (pl->ob, buf[0]);
890     break;
891 elmex 1.1
892 root 1.12 case ST_ROLL_STAT:
893 root 1.16 key_roll_stat (pl->ob, buf[0]);
894     break;
895 root 1.12
896     case ST_CHANGE_CLASS:
897 elmex 1.1
898 root 1.16 key_change_class (pl->ob, buf[0]);
899     break;
900 elmex 1.1
901 root 1.12 case ST_CONFIRM_QUIT:
902 root 1.16 key_confirm_quit (pl->ob, buf[0]);
903     break;
904 root 1.12
905     case ST_CONFIGURE:
906 root 1.16 LOG (llevError, "In client input handling, but into configure state\n");
907     pl->state = ST_PLAYING;
908     break;
909 root 1.12
910     case ST_GET_NAME:
911 root 1.16 receive_player_name (pl->ob, 13);
912     break;
913 root 1.12
914     case ST_GET_PASSWORD:
915     case ST_CONFIRM_PASSWORD:
916 root 1.16 receive_player_password (pl->ob, 13);
917     break;
918 root 1.12
919 root 1.16 case ST_GET_PARTY_PASSWORD: /* Get password for party */
920     receive_party_password (pl->ob, 13);
921     break;
922 elmex 1.1
923 root 1.12 default:
924 root 1.16 LOG (llevError, "Unknown input state: %d\n", pl->state);
925 elmex 1.1 }
926     }
927    
928     /**
929     * Client tells its version. If there is a mismatch, we close the
930     * socket. In real life, all we should care about is the client having
931     * something older than the server. If we assume the client will be
932     * backwards compatible, having it be a later version should not be a
933     * problem.
934     */
935 root 1.16 void
936     VersionCmd (char *buf, int len, NewSocket * ns)
937 elmex 1.1 {
938 root 1.16 char *cp;
939     char version_warning[256];
940    
941     if (!buf)
942     {
943     LOG (llevError, "CS: received corrupted version command\n");
944     return;
945 elmex 1.1 }
946    
947 root 1.16 ns->cs_version = atoi (buf);
948     ns->sc_version = ns->cs_version;
949     if (VERSION_CS != ns->cs_version)
950     {
951 elmex 1.1 #ifdef ESRV_DEBUG
952 root 1.16 LOG (llevDebug, "CS: csversion mismatch (%d,%d)\n", VERSION_CS, ns->cs_version);
953 elmex 1.1 #endif
954     }
955 root 1.16 cp = strchr (buf + 1, ' ');
956     if (!cp)
957     return;
958     ns->sc_version = atoi (cp);
959     if (VERSION_SC != ns->sc_version)
960     {
961 elmex 1.1 #ifdef ESRV_DEBUG
962 root 1.16 LOG (llevDebug, "CS: scversion mismatch (%d,%d)\n", VERSION_SC, ns->sc_version);
963 elmex 1.1 #endif
964     }
965 root 1.16 cp = strchr (cp + 1, ' ');
966     if (cp)
967     {
968     LOG (llevDebug, "CS: connection from client of type <%s>, ip %s\n", cp, ns->host);
969    
970     snprintf (ns->client, sizeof (ns->client), "%s", cp + 1);
971    
972     /* This is first implementation - i skip all beta DX clients with it
973     * Add later stuff here for other clients
974     */
975    
976     /* these are old dxclients */
977     /* Version 1024 added support for singular + plural name values -
978     * requiing this minimal value reduces complexity of that code, and it
979     * has been around for a long time.
980     */
981     if (!strcmp (" CF DX CLIENT", cp) || ns->sc_version < 1024)
982 root 1.12 {
983 root 1.16 sprintf (version_warning, "drawinfo %d %s", NDI_RED,
984     "**** VERSION WARNING ****\n**** CLIENT IS TOO OLD!! UPDATE THE CLIENT!! ****");
985     Write_String_To_Socket (ns, version_warning, strlen (version_warning));
986 root 1.12 }
987 elmex 1.1
988     }
989     }
990    
991     /** sound related functions. */
992 root 1.16
993     void
994     SetSound (char *buf, int len, NewSocket * ns)
995 elmex 1.1 {
996 root 1.16 ns->sound = atoi (buf);
997 elmex 1.1 }
998    
999     /** client wants the map resent */
1000    
1001 root 1.16 void
1002     MapRedrawCmd (char *buf, int len, player *pl)
1003 elmex 1.1 {
1004 root 1.16
1005 elmex 1.1 /* This function is currently disabled; just clearing the map state results in
1006     * display errors. It should clear the cache and send a newmap command.
1007     * Unfortunately this solution does not work because some client versions send
1008     * a mapredraw command after receiving a newmap command.
1009     */
1010     #if 0
1011 root 1.16 /* Okay, this is MAJOR UGLY. but the only way I know how to
1012     * clear the "cache"
1013     */
1014     memset (&pl->socket.lastmap, 0, sizeof (struct Map));
1015     draw_client_map (pl->ob);
1016 elmex 1.1 #endif
1017     }
1018    
1019     /**
1020     * Moves an object (typically, container to inventory).
1021     * syntax is: move (to) (tag) (nrof)
1022     */
1023 root 1.16 void
1024     MoveCmd (char *buf, int len, player *pl)
1025 elmex 1.1 {
1026 root 1.16 int vals[3], i;
1027 elmex 1.1
1028 root 1.16 /* A little funky here. We only cycle for 2 records, because
1029     * we obviously am not going to find a space after the third
1030     * record. Perhaps we should just replace this with a
1031     * sscanf?
1032     */
1033     for (i = 0; i < 2; i++)
1034     {
1035     vals[i] = atoi (buf);
1036     if (!(buf = strchr (buf, ' ')))
1037     {
1038     LOG (llevError, "Incomplete move command: %s\n", buf);
1039     return;
1040 root 1.12 }
1041 root 1.16 buf++;
1042 elmex 1.1 }
1043 root 1.16 vals[2] = atoi (buf);
1044 elmex 1.1
1045     /* LOG(llevDebug,"Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
1046 root 1.16 esrv_move_object (pl->ob, vals[0], vals[1], vals[2]);
1047 elmex 1.1 }
1048    
1049    
1050    
1051     /******************************************************************************
1052     *
1053     * Start of commands the server sends to the client.
1054     *
1055     ******************************************************************************/
1056    
1057     /**
1058     * Asks the client to query the user. This way, the client knows
1059     * it needs to send something back (vs just printing out a message)
1060     */
1061 root 1.16 void
1062     send_query (NewSocket * ns, uint8 flags, char *text)
1063 elmex 1.1 {
1064 root 1.16 char buf[MAX_BUF];
1065 elmex 1.1
1066 root 1.16 sprintf (buf, "query %d %s", flags, text ? text : "");
1067     Write_String_To_Socket (ns, buf, strlen (buf));
1068 elmex 1.1 }
1069    
1070     #define AddIfInt64(Old,New,Type) if (Old != New) {\
1071 root 1.12 Old = New; \
1072     SockList_AddChar(&sl, Type); \
1073     SockList_AddInt64(&sl, New); \
1074     }
1075 elmex 1.1
1076     #define AddIfInt(Old,New,Type) if (Old != New) {\
1077 root 1.12 Old = New; \
1078     SockList_AddChar(&sl, Type); \
1079     SockList_AddInt(&sl, New); \
1080     }
1081 elmex 1.1
1082     #define AddIfShort(Old,New,Type) if (Old != New) {\
1083 root 1.12 Old = New; \
1084     SockList_AddChar(&sl, Type); \
1085     SockList_AddShort(&sl, New); \
1086     }
1087 elmex 1.1
1088     #define AddIfFloat(Old,New,Type) if (Old != New) {\
1089 root 1.12 Old = New; \
1090     SockList_AddChar(&sl, Type); \
1091     SockList_AddInt(&sl,(long)(New*FLOAT_MULTI));\
1092     }
1093 elmex 1.1
1094     #define AddIfString(Old,New,Type) if (Old == NULL || strcmp(Old,New)) {\
1095 root 1.12 if (Old) free(Old);\
1096     Old = strdup_local(New);\
1097     SockList_AddChar(&sl, Type); \
1098     SockList_AddChar(&sl, ( char )strlen(New)); \
1099     strcpy((char*)sl.buf + sl.len, New); \
1100     sl.len += strlen(New); \
1101     }
1102 elmex 1.1
1103     /**
1104     * Sends a statistics update. We look at the old values,
1105     * and only send what has changed. Stat mapping values are in newclient.h
1106     * Since this gets sent a lot, this is actually one of the few binary
1107     * commands for now.
1108     */
1109 root 1.16 void
1110     esrv_update_stats (player *pl)
1111 elmex 1.1 {
1112 root 1.16 SockList sl;
1113     char buf[MAX_BUF];
1114     uint16 flags;
1115    
1116     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1117     strcpy ((char *) sl.buf, "stats ");
1118     sl.len = strlen ((char *) sl.buf);
1119 elmex 1.1
1120 root 1.16 if (pl->ob != NULL)
1121     {
1122     AddIfShort (pl->last_stats.hp, pl->ob->stats.hp, CS_STAT_HP);
1123     AddIfShort (pl->last_stats.maxhp, pl->ob->stats.maxhp, CS_STAT_MAXHP);
1124     AddIfShort (pl->last_stats.sp, pl->ob->stats.sp, CS_STAT_SP);
1125     AddIfShort (pl->last_stats.maxsp, pl->ob->stats.maxsp, CS_STAT_MAXSP);
1126     AddIfShort (pl->last_stats.grace, pl->ob->stats.grace, CS_STAT_GRACE);
1127     AddIfShort (pl->last_stats.maxgrace, pl->ob->stats.maxgrace, CS_STAT_MAXGRACE);
1128     AddIfShort (pl->last_stats.Str, pl->ob->stats.Str, CS_STAT_STR);
1129     AddIfShort (pl->last_stats.Int, pl->ob->stats.Int, CS_STAT_INT);
1130     AddIfShort (pl->last_stats.Pow, pl->ob->stats.Pow, CS_STAT_POW);
1131     AddIfShort (pl->last_stats.Wis, pl->ob->stats.Wis, CS_STAT_WIS);
1132     AddIfShort (pl->last_stats.Dex, pl->ob->stats.Dex, CS_STAT_DEX);
1133     AddIfShort (pl->last_stats.Con, pl->ob->stats.Con, CS_STAT_CON);
1134     AddIfShort (pl->last_stats.Cha, pl->ob->stats.Cha, CS_STAT_CHA);
1135     }
1136 root 1.22
1137 root 1.16 if (pl->socket.exp64)
1138     {
1139     uint8 s;
1140    
1141     for (s = 0; s < NUM_SKILLS; s++)
1142     {
1143     if (pl->last_skill_ob[s] && pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp)
1144     {
1145    
1146     /* Always send along the level if exp changes. This is only
1147     * 1 extra byte, but keeps processing simpler.
1148     */
1149     SockList_AddChar (&sl, (char) (s + CS_STAT_SKILLINFO));
1150     SockList_AddChar (&sl, (char) pl->last_skill_ob[s]->level);
1151     SockList_AddInt64 (&sl, pl->last_skill_ob[s]->stats.exp);
1152     pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
1153     }
1154     }
1155     }
1156 root 1.22
1157 root 1.16 if (pl->socket.exp64)
1158 root 1.22 AddIfInt64 (pl->last_stats.exp, pl->ob->stats.exp, CS_STAT_EXP64);
1159 root 1.16 else
1160 root 1.22 AddIfInt (pl->last_stats.exp, (int) pl->ob->stats.exp, CS_STAT_EXP);
1161    
1162 root 1.16 AddIfShort (pl->last_level, (char) pl->ob->level, CS_STAT_LEVEL);
1163     AddIfShort (pl->last_stats.wc, pl->ob->stats.wc, CS_STAT_WC);
1164     AddIfShort (pl->last_stats.ac, pl->ob->stats.ac, CS_STAT_AC);
1165     AddIfShort (pl->last_stats.dam, pl->ob->stats.dam, CS_STAT_DAM);
1166     AddIfFloat (pl->last_speed, pl->ob->speed, CS_STAT_SPEED);
1167     AddIfShort (pl->last_stats.food, pl->ob->stats.food, CS_STAT_FOOD);
1168     AddIfFloat (pl->last_weapon_sp, pl->weapon_sp, CS_STAT_WEAP_SP);
1169     AddIfInt (pl->last_weight_limit, (sint32) weight_limit[pl->ob->stats.Str], CS_STAT_WEIGHT_LIM);
1170     flags = 0;
1171 root 1.22
1172 root 1.16 if (pl->fire_on)
1173     flags |= SF_FIREON;
1174 root 1.22
1175 root 1.16 if (pl->run_on)
1176     flags |= SF_RUNON;
1177    
1178     AddIfShort (pl->last_flags, flags, CS_STAT_FLAGS);
1179 root 1.22
1180 root 1.16 if (pl->socket.sc_version < 1025)
1181 root 1.22 AddIfShort (pl->last_resist[ATNR_PHYSICAL], pl->ob->resist[ATNR_PHYSICAL], CS_STAT_ARMOUR);
1182 root 1.16 else
1183     {
1184     int i;
1185    
1186     for (i = 0; i < NROFATTACKS; i++)
1187     {
1188     /* Skip ones we won't send */
1189     if (atnr_cs_stat[i] == -1)
1190     continue;
1191     AddIfShort (pl->last_resist[i], pl->ob->resist[i], (char) atnr_cs_stat[i]);
1192     }
1193     }
1194 root 1.22
1195 root 1.16 if (pl->socket.monitor_spells)
1196     {
1197     AddIfInt (pl->last_path_attuned, pl->ob->path_attuned, CS_STAT_SPELL_ATTUNE);
1198     AddIfInt (pl->last_path_repelled, pl->ob->path_repelled, CS_STAT_SPELL_REPEL);
1199     AddIfInt (pl->last_path_denied, pl->ob->path_denied, CS_STAT_SPELL_DENY);
1200     }
1201 root 1.22
1202 root 1.16 rangetostring (pl->ob, buf); /* we want use the new fire & run system in new client */
1203     AddIfString (pl->socket.stats.range, buf, CS_STAT_RANGE);
1204     set_title (pl->ob, buf);
1205     AddIfString (pl->socket.stats.title, buf, CS_STAT_TITLE);
1206    
1207     /* Only send it away if we have some actual data */
1208     if (sl.len > 6)
1209     {
1210 elmex 1.1 #ifdef ESRV_DEBUG
1211 root 1.16 LOG (llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
1212 elmex 1.1 #endif
1213 root 1.16 Send_With_Handling (&pl->socket, &sl);
1214 elmex 1.1 }
1215 root 1.16 free (sl.buf);
1216 elmex 1.1 }
1217    
1218    
1219     /**
1220     * Tells the client that here is a player it should start using.
1221     */
1222 root 1.16 void
1223     esrv_new_player (player *pl, uint32 weight)
1224 elmex 1.1 {
1225 root 1.16 SockList sl;
1226    
1227     pl->last_weight = weight;
1228 elmex 1.1
1229 root 1.16 sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1230 elmex 1.1
1231 root 1.16 strcpy ((char *) sl.buf, "player ");
1232     sl.len = strlen ((char *) sl.buf);
1233     SockList_AddInt (&sl, pl->ob->count);
1234     SockList_AddInt (&sl, weight);
1235     SockList_AddInt (&sl, pl->ob->face->number);
1236 elmex 1.1
1237 root 1.16 SockList_AddChar (&sl, (char) strlen (pl->ob->name));
1238     strcpy ((char *) sl.buf + sl.len, pl->ob->name);
1239     sl.len += strlen (pl->ob->name);
1240    
1241     Send_With_Handling (&pl->socket, &sl);
1242     free (sl.buf);
1243     SET_FLAG (pl->ob, FLAG_CLIENT_SENT);
1244 elmex 1.1 }
1245    
1246    
1247     /**
1248     * Need to send an animation sequence to the client.
1249     * We will send appropriate face commands to the client if we haven't
1250     * sent them the face yet (this can become quite costly in terms of
1251     * how much we are sending - on the other hand, this should only happen
1252     * when the player logs in and picks stuff up.
1253     */
1254 root 1.16 void
1255     esrv_send_animation (NewSocket * ns, short anim_num)
1256 elmex 1.1 {
1257 root 1.16 SockList sl;
1258     int i;
1259 elmex 1.1
1260 root 1.16 /* Do some checking on the anim_num we got. Note that the animations
1261     * are added in contigous order, so if the number is in the valid
1262     * range, it must be a valid animation.
1263     */
1264     if (anim_num < 0 || anim_num > num_animations)
1265     {
1266     LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
1267     return;
1268     }
1269    
1270     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1271     strcpy ((char *) sl.buf, "anim ");
1272     sl.len = 5;
1273     SockList_AddShort (&sl, anim_num);
1274     SockList_AddShort (&sl, 0); /* flags - not used right now */
1275     /* Build up the list of faces. Also, send any information (ie, the
1276     * the face itself) down to the client.
1277     */
1278     for (i = 0; i < animations[anim_num].num_animations; i++)
1279     {
1280     if (!(ns->faces_sent[animations[anim_num].faces[i]] & NS_FACESENT_FACE))
1281     esrv_send_face (ns, animations[anim_num].faces[i], 0);
1282     SockList_AddShort (&sl, animations[anim_num].faces[i]); /* flags - not used right now */
1283     }
1284     Send_With_Handling (ns, &sl);
1285     free (sl.buf);
1286     ns->anims_sent[anim_num] = 1;
1287 elmex 1.1 }
1288    
1289    
1290     /******************************************************************************
1291     *
1292     * Start of map related commands.
1293     *
1294     ******************************************************************************/
1295    
1296     /**
1297     * This adds face_num to a map cell at x,y. If the client doesn't have
1298     * the face yet, we will also send it.
1299     */
1300 root 1.16 static void
1301     esrv_map_setbelow (NewSocket * ns, int x, int y, short face_num, struct Map *newmap)
1302 elmex 1.1 {
1303 root 1.16 if (newmap->cells[x][y].count >= MAP_LAYERS)
1304     {
1305     LOG (llevError, "Too many faces in map cell %d %d\n", x, y);
1306     return;
1307     abort ();
1308 elmex 1.1 }
1309 root 1.16 newmap->cells[x][y].faces[newmap->cells[x][y].count] = face_num;
1310     newmap->cells[x][y].count++;
1311     if (!(ns->faces_sent[face_num] & NS_FACESENT_FACE))
1312     esrv_send_face (ns, face_num, 0);
1313 elmex 1.1 }
1314    
1315 root 1.16 struct LayerCell
1316     {
1317 elmex 1.1 uint16 xy;
1318     short face;
1319     };
1320    
1321 root 1.16 struct MapLayer
1322     {
1323 elmex 1.1 int count;
1324     struct LayerCell lcells[MAP_CLIENT_X * MAP_CLIENT_Y];
1325     };
1326    
1327     /** Checkes if map cells have changed */
1328 root 1.16 static int
1329     mapcellchanged (NewSocket * ns, int i, int j, struct Map *newmap)
1330 elmex 1.1 {
1331     int k;
1332    
1333     if (ns->lastmap.cells[i][j].count != newmap->cells[i][j].count)
1334     return 1;
1335 root 1.16 for (k = 0; k < newmap->cells[i][j].count; k++)
1336     {
1337     if (ns->lastmap.cells[i][j].faces[k] != newmap->cells[i][j].faces[k])
1338     {
1339     return 1;
1340     }
1341 elmex 1.1 }
1342     return 0;
1343     }
1344    
1345     /**
1346     * Basically, what this does is pack the data into layers.
1347     * cnum is the client number, cur is the the buffer we put all of
1348     * this data into. we return the end of the data. layers is
1349     * how many layers of data we should back.
1350 root 1.16 */
1351     static uint8 *
1352     compactlayer (NewSocket * ns, unsigned char *cur, int numlayers, struct Map *newmap)
1353     {
1354     int x, y, k;
1355     int face;
1356     unsigned char *fcur;
1357     struct MapLayer layers[MAP_LAYERS];
1358    
1359     for (k = 0; k < MAP_LAYERS; k++)
1360     layers[k].count = 0;
1361     fcur = cur;
1362     for (x = 0; x < ns->mapx; x++)
1363     {
1364     for (y = 0; y < ns->mapy; y++)
1365     {
1366     if (!mapcellchanged (ns, x, y, newmap))
1367     continue;
1368     if (newmap->cells[x][y].count == 0)
1369     {
1370     *cur = x * ns->mapy + y; /* mark empty space */
1371     cur++;
1372     continue;
1373     }
1374     for (k = 0; k < newmap->cells[x][y].count; k++)
1375     {
1376     layers[k].lcells[layers[k].count].xy = x * ns->mapy + y;
1377     layers[k].lcells[layers[k].count].face = newmap->cells[x][y].faces[k];
1378     layers[k].count++;
1379 root 1.12 }
1380     }
1381 elmex 1.1 }
1382 root 1.16 /* If no data, return now. */
1383     if (fcur == cur && layers[0].count == 0)
1384     return cur;
1385     *cur = 255; /* mark end of explicitly cleared cells */
1386     cur++;
1387     /* First pack by layers. */
1388     for (k = 0; k < numlayers; k++)
1389     {
1390     if (layers[k].count == 0)
1391     break; /* once a layer is entirely empty, no layer below it can
1392     have anything in it either */
1393     /* Pack by entries in thie layer */
1394     for (x = 0; x < layers[k].count;)
1395     {
1396     fcur = cur;
1397     *cur = layers[k].lcells[x].face >> 8;
1398     cur++;
1399     *cur = layers[k].lcells[x].face & 0xFF;
1400     cur++;
1401     face = layers[k].lcells[x].face;
1402     /* Now, we back the redundant data into 1 byte xy pairings */
1403     for (y = x; y < layers[k].count; y++)
1404     {
1405     if (layers[k].lcells[y].face == face)
1406     {
1407     *cur = (uint8) layers[k].lcells[y].xy;
1408     cur++;
1409     layers[k].lcells[y].face = -1;
1410 root 1.12 }
1411     }
1412 root 1.16 *(cur - 1) = *(cur - 1) | 128; /* mark for end of xy's; 11*11 < 128 */
1413     /* forward over the now redundant data */
1414     while (x < layers[k].count && layers[k].lcells[x].face == -1)
1415     x++;
1416 root 1.12 }
1417 root 1.16 *fcur = *fcur | 128; /* mark for end of faces at this layer */
1418 elmex 1.1 }
1419 root 1.16 return cur;
1420 elmex 1.1 }
1421    
1422 root 1.16 static void
1423     esrv_map_doneredraw (NewSocket * ns, struct Map *newmap)
1424 elmex 1.1 {
1425 root 1.16 static long frames, bytes, tbytes, tframes;
1426     char *cur;
1427     SockList sl;
1428 elmex 1.1
1429    
1430 root 1.16 sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1431     strcpy ((char *) sl.buf, "map ");
1432     sl.len = strlen ((char *) sl.buf);
1433 elmex 1.1
1434 root 1.16 cur = (char *) compactlayer (ns, (unsigned char *) sl.buf + sl.len, MAP_LAYERS, newmap);
1435     sl.len = cur - (char *) sl.buf;
1436 elmex 1.1
1437     /* LOG(llevDebug, "Sending map command.\n");*/
1438    
1439 root 1.16 if (sl.len > (int) strlen ("map ") || ns->sent_scroll)
1440     {
1441     /* All of this is just accounting stuff */
1442     if (tframes > 100)
1443 root 1.18 tframes = tbytes = 0;
1444    
1445 root 1.16 tframes++;
1446     frames++;
1447     tbytes += sl.len;
1448     bytes += sl.len;
1449     memcpy (&ns->lastmap, newmap, sizeof (struct Map));
1450     Send_With_Handling (ns, &sl);
1451     ns->sent_scroll = 0;
1452 elmex 1.1 }
1453 root 1.18
1454 root 1.16 free (sl.buf);
1455 elmex 1.1 }
1456    
1457    
1458     /** Clears a map cell */
1459 root 1.16 static void
1460     map_clearcell (struct MapCell *cell, int face0, int face1, int face2, int count)
1461 elmex 1.1 {
1462 root 1.16 cell->faces[0] = face0;
1463     cell->faces[1] = face1;
1464     cell->faces[2] = face2;
1465     cell->count = count;
1466     cell->stat_hp = 0;
1467     cell->player = 0;
1468 elmex 1.1 }
1469    
1470     #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
1471     #define MAX_LAYERS 3
1472    
1473     /* Using a global really isn't a good approach, but saves the over head of
1474     * allocating and deallocating such a block of data each time run through,
1475     * and saves the space of allocating this in the socket object when we only
1476     * need it for this cycle. If the serve is ever threaded, this needs to be
1477     * re-examined.
1478     */
1479    
1480 root 1.16 static object *heads[MAX_HEAD_POS * MAX_HEAD_POS * MAX_LAYERS];
1481 elmex 1.1
1482     /**
1483     * Returns true if any of the heads for this
1484     * space is set. Returns false if all are blank - this is used
1485     * for empty space checking.
1486     */
1487 root 1.16 static inline int
1488     have_head (int ax, int ay)
1489     {
1490 elmex 1.1
1491 root 1.16 if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS] ||
1492     heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + 1] || heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + 2])
1493     return 1;
1494     return 0;
1495 elmex 1.1 }
1496    
1497     /**
1498     * check_head is a bit simplistic version of update_space below.
1499     * basically, it only checks the that the head on space ax,ay at layer
1500     * needs to get sent - if so, it adds the data, sending the head
1501     * if needed, and returning 1. If this no data needs to get
1502     * sent, it returns zero.
1503     */
1504 root 1.16 static int
1505     check_head (SockList & sl, NewSocket & ns, int ax, int ay, int layer)
1506 elmex 1.1 {
1507 root 1.16 short face_num;
1508 elmex 1.1
1509 root 1.16 if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer])
1510     face_num = heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]->face->number;
1511     else
1512     face_num = 0;
1513 elmex 1.1
1514 root 1.16 if (face_num != ns.lastmap.cells[ax][ay].faces[layer])
1515     {
1516     SockList_AddShort (&sl, face_num);
1517     if (face_num && !(ns.faces_sent[face_num] & NS_FACESENT_FACE))
1518     esrv_send_face (&ns, face_num, 0);
1519     heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer] = NULL;
1520     ns.lastmap.cells[ax][ay].faces[layer] = face_num;
1521     return 1;
1522 elmex 1.1 }
1523    
1524 root 1.16 return 0; /* No change */
1525 elmex 1.1 }
1526    
1527     /**
1528     * Removes the need to replicate the same code for each layer.
1529     * this returns true if this space is now in fact different than
1530     * it was.
1531     * sl is the socklist this data is going into.
1532     * ns is the socket we are working on - all the info we care
1533     * about is in this socket structure, so now need not pass the
1534     * entire player object.
1535     * mx and my are map coordinate offsets for map mp
1536     * sx and sy are the offsets into the socket structure that
1537     * holds the old values.
1538     * layer is the layer to update, with 2 being the floor and 0 the
1539     * top layer (this matches what the GET_MAP_FACE and GET_MAP_FACE_OBJ)
1540     * take. Interesting to note that before this function, the map1 function
1541     * numbers the spaces differently - I think this was a leftover from
1542     * the map command, where the faces stack up. Sinces that is no longer
1543     * the case, it seems to make more sense to have these layer values
1544     * actually match.
1545     */
1546    
1547 root 1.16 static int
1548 root 1.21 update_space (SockList * sl, NewSocket * ns, maptile *mp, int mx, int my, int sx, int sy, int layer)
1549 elmex 1.1 {
1550 root 1.16 object *ob, *head;
1551     uint16 face_num;
1552     int bx, by, i;
1553    
1554     /* If there is a multipart object stored away, treat that as more important.
1555     * If not, then do the normal processing.
1556     */
1557    
1558     head = heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer];
1559    
1560     /* Check to see if this head is part of the set of objects
1561     * we would normally send for this space. If so, then
1562     * don't use the head value. We need to do the check
1563     * here and not when setting up the heads[] value for two reasons -
1564     * 1) the heads[] values will get used even if the space is not visible.
1565     * 2) its possible the head is not on the same map as a part, and I'd
1566     * rather not need to do the map translation overhead.
1567     * 3) We need to do some extra checking to make sure that we will
1568     * otherwise send the image as this layer, eg, either it matches
1569     * the head value, or is not multipart.
1570     */
1571     if (head && !head->more)
1572     {
1573     for (i = 0; i < MAP_LAYERS; i++)
1574     {
1575     ob = GET_MAP_FACE_OBJ (mp, mx, my, i);
1576     if (!ob)
1577     continue;
1578    
1579     if (ob->head)
1580     ob = ob->head;
1581    
1582     if (ob == head)
1583     {
1584     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer] = NULL;
1585     head = NULL;
1586     break;
1587     }
1588     }
1589     }
1590    
1591     ob = head;
1592     if (!ob)
1593     ob = GET_MAP_FACE_OBJ (mp, mx, my, layer);
1594    
1595     /* If there is no object for this space, or if the face for the object
1596     * is the blank face, set the face number to zero.
1597     * else if we have the stored head object for this space, that takes
1598     * precedence over the other object for this space.
1599     * otherwise, we do special head processing
1600     */
1601     if (!ob || ob->face == blank_face)
1602     face_num = 0;
1603     else if (head)
1604     {
1605     /* if this is a head that had previously been stored */
1606     face_num = ob->face->number;
1607     }
1608     else
1609     {
1610     /* if the faces for the different parts of a multipart object
1611     * are the same, we only want to send the bottom right most
1612     * portion of the object. That info is in the tail_.. values
1613     * of the head. Note that for the head itself, ob->head will
1614     * be null, so we only do this block if we are working on
1615     * a tail piece.
1616     */
1617    
1618     /* tail_x and tail_y will only be set in the head object. If
1619     * this is the head object and these are set, we proceed
1620     * with logic to only send bottom right. Similarly, if
1621     * this is one of the more parts but the head has those values
1622     * set, we want to do the processing. There can be cases where
1623     * the head is not visible but one of its parts is, so we just
1624     * can always expect that ob->arch->tail_x will be true for all
1625     * object we may want to display.
1626     */
1627     if ((ob->arch->tail_x || ob->arch->tail_y) || (ob->head && (ob->head->arch->tail_x || ob->head->arch->tail_y)))
1628     {
1629    
1630     if (ob->head)
1631     head = ob->head;
1632     else
1633     head = ob;
1634    
1635     /* Basically figure out where the offset is from where we are right
1636     * now. the ob->arch->clone.{x,y} values hold the offset that this current
1637     * piece is from the head, and the tail is where the tail is from the
1638     * head. Note that bx and by will equal sx and sy if we are already working
1639     * on the bottom right corner. If ob is the head, the clone values
1640     * will be zero, so the right thing will still happen.
1641     */
1642     bx = sx + head->arch->tail_x - ob->arch->clone.x;
1643     by = sy + head->arch->tail_y - ob->arch->clone.y;
1644    
1645     /* I don't think this can ever happen, but better to check for it just
1646     * in case.
1647     */
1648     if (bx < sx || by < sy)
1649     {
1650     LOG (llevError, "update_space: bx (%d) or by (%d) is less than sx (%d) or sy (%d)\n", bx, by, sx, sy);
1651     face_num = 0;
1652     }
1653     /* single part object, multipart object with non merged faces,
1654     * of multipart object already at lower right.
1655     */
1656     else if (bx == sx && by == sy)
1657     {
1658     face_num = ob->face->number;
1659    
1660     /* if this face matches one stored away, clear that one away.
1661     * this code relies on the fact that the map1 commands
1662     * goes from 2 down to 0.
1663     */
1664     for (i = 0; i < MAP_LAYERS; i++)
1665     if (heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i] &&
1666     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i]->face->number == face_num)
1667     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i] = NULL;
1668     }
1669     else
1670     {
1671     /* If this head is stored away, clear it - otherwise,
1672     * there can be cases where a object is on multiple layers -
1673     * we only want to send it once.
1674     */
1675     face_num = head->face->number;
1676     for (i = 0; i < MAP_LAYERS; i++)
1677     if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] &&
1678     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i]->face->number == face_num)
1679     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] = NULL;
1680    
1681     /* First, try to put the new head on the same layer. If that is used up,
1682     * then find another layer.
1683     */
1684     if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + layer] == NULL)
1685     {
1686     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + layer] = head;
1687     }
1688     else
1689     for (i = 0; i < MAX_LAYERS; i++)
1690     {
1691 root 1.12 if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] == NULL ||
1692 root 1.16 heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] == head)
1693     {
1694     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] = head;
1695     }
1696     }
1697     face_num = 0; /* Don't send this object - we'll send the head later */
1698 root 1.12 }
1699 root 1.16 }
1700     else
1701     {
1702     /* In this case, we are already at the lower right or single part object,
1703     * so nothing special
1704     */
1705     face_num = ob->face->number;
1706    
1707     /* clear out any head entries that have the same face as this one */
1708     for (bx = 0; bx < layer; bx++)
1709     if (heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx] &&
1710     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx]->face->number == face_num)
1711     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx] = NULL;
1712     }
1713     } /* else not already head object or blank face */
1714    
1715     /* This is a real hack. Basically, if we have nothing to send for this layer,
1716     * but there is a head on the next layer, send that instead.
1717     * Without this, what happens is you can get the case where the player stands
1718     * on the same space as the head. However, if you have overlapping big objects
1719     * of the same type, what happens then is it doesn't think it needs to send
1720     * This tends to make stacking also work/look better.
1721     */
1722     if (!face_num && layer > 0 && heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1])
1723     {
1724     face_num = heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1]->face->number;
1725     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1] = NULL;
1726     }
1727    
1728     /* Another hack - because of heads and whatnot, this face may match one
1729     * we already sent for a lower layer. In that case, don't send
1730     * this one.
1731     */
1732     if (face_num && layer + 1 < MAP_LAYERS && ns->lastmap.cells[sx][sy].faces[layer + 1] == face_num)
1733     {
1734     face_num = 0;
1735     }
1736    
1737     /* We've gotten what face we want to use for the object. Now see if
1738     * if it has changed since we last sent it to the client.
1739     */
1740     if (ns->lastmap.cells[sx][sy].faces[layer] != face_num)
1741     {
1742     ns->lastmap.cells[sx][sy].faces[layer] = face_num;
1743     if (!(ns->faces_sent[face_num] & NS_FACESENT_FACE))
1744     esrv_send_face (ns, face_num, 0);
1745     SockList_AddShort (sl, face_num);
1746     return 1;
1747 elmex 1.1 }
1748 root 1.16 /* Nothing changed */
1749     return 0;
1750 elmex 1.1 }
1751    
1752     /**
1753     * This function is mainly a copy of update_space,
1754     * except it handles update of the smoothing updates,
1755     * not the face updates.
1756     * Removes the need to replicate the same code for each layer.
1757     * this returns true if this smooth is now in fact different
1758     * than it was.
1759     * sl is the socklist this data is going into.
1760     * ns is the socket we are working on - all the info we care
1761     * about is in this socket structure, so know need to pass the
1762     * entire player object.
1763     * mx and my are map coordinate offsets for map mp
1764     * sx and sy are the offsets into the socket structure that
1765     * holds the old values.
1766     * layer is the layer to update, with 2 being the floor and 0 the
1767     * top layer (this matches what the GET_MAP_FACE and GET_MAP_FACE_OBJ
1768     * take.
1769     */
1770    
1771 root 1.16 static inline int
1772 root 1.21 update_smooth (SockList * sl, NewSocket * ns, maptile *mp, int mx, int my, int sx, int sy, int layer)
1773 elmex 1.1 {
1774 root 1.16 object *ob;
1775     int smoothlevel; /* old face_num; */
1776 elmex 1.1
1777 root 1.16 ob = GET_MAP_FACE_OBJ (mp, mx, my, layer);
1778 elmex 1.1
1779 root 1.16 /* If there is no object for this space, or if the face for the object
1780     * is the blank face, set the smoothlevel to zero.
1781     */
1782     if (!ob || ob->face == blank_face || MAP_NOSMOOTH (mp))
1783     smoothlevel = 0;
1784     else
1785     {
1786     smoothlevel = ob->smoothlevel;
1787     if (smoothlevel && !(ns->faces_sent[ob->face->number] & NS_FACESENT_SMOOTH))
1788     SendSmooth (ns, ob->face->number);
1789     } /* else not already head object or blank face */
1790    
1791     /* We've gotten what face we want to use for the object. Now see if
1792     * if it has changed since we last sent it to the client.
1793     */
1794     if (smoothlevel > 255)
1795     smoothlevel = 255;
1796     else if (smoothlevel < 0)
1797     smoothlevel = 0;
1798     if (ns->lastmap.cells[sx][sy].smooth[layer] != smoothlevel)
1799     {
1800     ns->lastmap.cells[sx][sy].smooth[layer] = smoothlevel;
1801     SockList_AddChar (sl, (uint8) (smoothlevel & 0xFF));
1802     return 1;
1803 elmex 1.1 }
1804 root 1.16 /* Nothing changed */
1805     return 0;
1806 elmex 1.1 }
1807    
1808     /**
1809     * Returns the size of a data for a map square as returned by
1810     * mapextended. There are CLIENTMAPX*CLIENTMAPY*LAYERS entries
1811     * available.
1812     */
1813 root 1.16 int
1814     getExtendedMapInfoSize (NewSocket * ns)
1815     {
1816     int result = 0;
1817    
1818     if (ns->ext_mapinfos)
1819     {
1820     if (ns->EMI_smooth)
1821     result += 1; /*One byte for smoothlevel */
1822 elmex 1.1 }
1823 root 1.16 return result;
1824 elmex 1.1 }
1825 root 1.16
1826 elmex 1.1 /**
1827     * This function uses the new map1 protocol command to send the map
1828     * to the client. It is necessary because the old map command supports
1829     * a maximum map size of 15x15.
1830     * This function is much simpler than the old one. This is because
1831     * the old function optimized to send as few face identifiers as possible,
1832     * at the expense of sending more coordinate location (coordinates were
1833     * only 1 byte, faces 2 bytes, so this was a worthwhile savings). Since
1834     * we need 2 bytes for coordinates and 2 bytes for faces, such a trade off
1835     * maps no sense. Instead, we actually really only use 12 bits for coordinates,
1836     * and use the other 4 bits for other informatiion. For full documentation
1837     * of what we send, see the doc/Protocol file.
1838     * I will describe internally what we do:
1839     * the socket->lastmap shows how the map last looked when sent to the client.
1840     * in the lastmap structure, there is a cells array, which is set to the
1841     * maximum viewable size (As set in config.h).
1842     * in the cells, there are faces and a count value.
1843     * we use the count value to hold the darkness value. If -1, then this space
1844     * is not viewable.
1845     * we use faces[0] faces[1] faces[2] to hold what the three layers
1846     * look like.
1847     */
1848 root 1.16 void
1849     draw_client_map1 (object *pl)
1850 elmex 1.1 {
1851 root 1.16 int x, y, ax, ay, d, startlen, max_x, max_y, oldlen;
1852     sint16 nx, ny;
1853     int estartlen, eoldlen;
1854     SockList sl;
1855     SockList esl; /*For extended Map info */
1856     uint16 mask, emask;
1857     uint8 eentrysize;
1858     uint16 ewhatstart, ewhatflag;
1859     uint8 extendedinfos;
1860 root 1.21 maptile *m;
1861 root 1.16
1862     NewSocket & socket = pl->contr->socket;
1863    
1864     check_map_change (pl->contr);
1865    
1866     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1867     if (socket.mapmode == Map1Cmd)
1868     strcpy ((char *) sl.buf, "map1 ");
1869     else
1870     strcpy ((char *) sl.buf, "map1a ");
1871     sl.len = strlen ((char *) sl.buf);
1872     startlen = sl.len;
1873     /*Extendedmapinfo structure initialisation */
1874     if (socket.ext_mapinfos)
1875     {
1876     esl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1877     strcpy ((char *) esl.buf, "mapextended ");
1878     esl.len = strlen ((char *) esl.buf);
1879     extendedinfos = EMI_NOREDRAW;
1880     if (socket.EMI_smooth)
1881     extendedinfos |= EMI_SMOOTH;
1882     ewhatstart = esl.len;
1883     ewhatflag = extendedinfos; /*The EMI_NOREDRAW bit
1884     could need to be taken away */
1885     SockList_AddChar (&esl, extendedinfos);
1886     eentrysize = getExtendedMapInfoSize (&socket);
1887     SockList_AddChar (&esl, eentrysize);
1888     estartlen = esl.len;
1889     }
1890     else
1891     {
1892     /* suppress compiler warnings */
1893     ewhatstart = 0;
1894     ewhatflag = 0;
1895     estartlen = 0;
1896     }
1897     /* Init data to zero */
1898     memset (heads, 0, sizeof (object *) * MAX_HEAD_POS * MAX_HEAD_POS * MAX_LAYERS);
1899    
1900     /* x,y are the real map locations. ax, ay are viewport relative
1901     * locations.
1902     */
1903     ay = 0;
1904    
1905     /* We could do this logic as conditionals in the if statement,
1906     * but that started to get a bit messy to look at.
1907     */
1908     max_x = pl->x + (socket.mapx + 1) / 2;
1909     max_y = pl->y + (socket.mapy + 1) / 2;
1910     if (socket.mapmode == Map1aCmd)
1911     {
1912     max_x += MAX_HEAD_OFFSET;
1913     max_y += MAX_HEAD_OFFSET;
1914     }
1915 elmex 1.1
1916 root 1.16 for (y = pl->y - socket.mapy / 2; y < max_y; y++, ay++)
1917     {
1918     ax = 0;
1919     for (x = pl->x - socket.mapx / 2; x < max_x; x++, ax++)
1920     {
1921    
1922     emask = mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4;
1923    
1924     /* If this space is out of the normal viewable area, we only check
1925     * the heads value ax or ay will only be greater than what
1926     * the client wants if using the map1a command - this is because
1927     * if the map1a command is not used, max_x and max_y will be
1928     * set to lower values.
1929     */
1930     if (ax >= socket.mapx || ay >= socket.mapy)
1931     {
1932     int i, got_one;
1933 root 1.12
1934 root 1.16 oldlen = sl.len;
1935 root 1.12
1936 root 1.16 SockList_AddShort (&sl, mask);
1937 root 1.12
1938 root 1.16 if (check_head (sl, socket, ax, ay, 2))
1939     mask |= 0x4;
1940     if (check_head (sl, socket, ax, ay, 1))
1941     mask |= 0x2;
1942     if (check_head (sl, socket, ax, ay, 0))
1943     mask |= 0x1;
1944    
1945     /* If all we are doing is sending 0 (blank) faces, we don't
1946     * actually need to send that - just the coordinates
1947     * with no faces tells the client to blank out the
1948     * space.
1949     */
1950     got_one = 0;
1951     for (i = oldlen + 2; i < sl.len; i++)
1952     {
1953     if (sl.buf[i])
1954     got_one = 1;
1955 root 1.12 }
1956    
1957 root 1.16 if (got_one && (mask & 0xf))
1958     {
1959     sl.buf[oldlen + 1] = mask & 0xff;
1960     }
1961     else
1962     { /*either all faces blank, either no face at all */
1963     if (mask & 0xf) /*at least 1 face, we know it's blank, only send coordinates */
1964     sl.len = oldlen + 2;
1965 root 1.3 else
1966 root 1.16 sl.len = oldlen;
1967 root 1.12 }
1968 root 1.16 /*What concerns extendinfos, nothing to be done for now
1969     * (perhaps effects layer later)
1970     */
1971     continue; /* don't do processing below */
1972     }
1973    
1974     MapCell & lastcell = socket.lastmap.cells[ax][ay];
1975    
1976     d = pl->contr->blocked_los[ax][ay];
1977    
1978     /* If the coordinates are not valid, or it is too dark to see,
1979     * we tell the client as such
1980     */
1981     nx = x;
1982     ny = y;
1983     m = get_map_from_coord (pl->map, &nx, &ny);
1984     if (!m)
1985     {
1986     /* space is out of map. Update space and clear values
1987     * if this hasn't already been done. If the space is out
1988     * of the map, it shouldn't have a head
1989     */
1990     if (lastcell.count != -1)
1991     {
1992     SockList_AddShort (&sl, mask);
1993     map_clearcell (&lastcell, 0, 0, 0, -1);
1994 root 1.12 }
1995 root 1.16 }
1996     else if (d > 3)
1997     {
1998     int need_send = 0, count;
1999    
2000     /* This block deals with spaces that are not visible for whatever
2001     * reason. Still may need to send the head for this space.
2002     */
2003 root 1.12
2004 root 1.16 oldlen = sl.len;
2005 root 1.3
2006 root 1.16 SockList_AddShort (&sl, mask);
2007     if (lastcell.count != -1)
2008     need_send = 1;
2009     count = -1;
2010 root 1.3
2011 root 1.16 if (socket.mapmode == Map1aCmd && have_head (ax, ay))
2012     {
2013     /* Now check to see if any heads need to be sent */
2014 root 1.3
2015 root 1.16 if (check_head (sl, socket, ax, ay, 2))
2016     mask |= 0x4;
2017     if (check_head (sl, socket, ax, ay, 1))
2018     mask |= 0x2;
2019     if (check_head (sl, socket, ax, ay, 0))
2020     mask |= 0x1;
2021 root 1.3
2022 root 1.16 lastcell.count = count;
2023 root 1.8
2024 root 1.16 }
2025     else
2026     {
2027     struct MapCell *cell = &lastcell;
2028    
2029     /* properly clear a previously sent big face */
2030     if (cell->faces[0] != 0 || cell->faces[1] != 0 || cell->faces[2] != 0)
2031     need_send = 1;
2032     map_clearcell (&lastcell, 0, 0, 0, count);
2033     }
2034 root 1.3
2035 root 1.16 if ((mask & 0xf) || need_send)
2036     {
2037     sl.buf[oldlen + 1] = mask & 0xff;
2038     }
2039     else
2040     {
2041     sl.len = oldlen;
2042     }
2043     }
2044     else
2045     {
2046     /* In this block, the space is visible or there are head objects
2047     * we need to send.
2048     */
2049    
2050     /* Rather than try to figure out what everything that we might
2051     * need to send is, then form the packet after that,
2052     * we presume that we will in fact form a packet, and update
2053     * the bits by what we do actually send. If we send nothing,
2054     * we just back out sl.len to the old value, and no harm
2055     * is done.
2056     * I think this is simpler than doing a bunch of checks to see
2057     * what if anything we need to send, setting the bits, then
2058     * doing those checks again to add the real data.
2059     */
2060     oldlen = sl.len;
2061     mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4;
2062     eoldlen = esl.len;
2063     emask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4;
2064     SockList_AddShort (&sl, mask);
2065    
2066     if (socket.ext_mapinfos)
2067     SockList_AddShort (&esl, emask);
2068    
2069     unsigned char dummy;
2070     unsigned char *last_ext = &dummy;
2071    
2072     /* Darkness changed */
2073     if (lastcell.count != d && socket.darkness)
2074     {
2075     mask |= 0x8;
2076    
2077     if (socket.extmap)
2078     {
2079     *last_ext |= 0x80;
2080     last_ext = sl.buf + sl.len;
2081     SockList_AddChar (&sl, d);
2082     }
2083     else
2084     SockList_AddChar (&sl, 255 - 64 * d);
2085     }
2086 root 1.3
2087 root 1.16 lastcell.count = d;
2088 root 1.8
2089 root 1.16 if (socket.extmap)
2090     {
2091     uint8 stat_hp = 0;
2092     uint8 stat_width = 0;
2093     tag_t player = 0;
2094    
2095     // send hp information, if applicable
2096     if (object *op = GET_MAP_FACE_OBJ (m, nx, ny, 0))
2097     {
2098     if (op->head || op->invisible)
2099     ; // do not show
2100     else if (op->type == PLAYER
2101     || QUERY_FLAG (op, FLAG_MONSTER) || QUERY_FLAG (op, FLAG_ALIVE) || QUERY_FLAG (op, FLAG_GENERATOR))
2102     {
2103     if (op->stats.maxhp > 0 && (unsigned) op->stats.maxhp > (unsigned) op->stats.hp)
2104     {
2105     stat_hp = 255 - (op->stats.hp * 255 + 254) / op->stats.maxhp;
2106     stat_width = op->arch->tail_x;
2107     }
2108     }
2109 elmex 1.1
2110 root 1.16 if (op->type == PLAYER && op != pl)
2111     player = op->count;
2112     }
2113 root 1.12
2114 root 1.16 if (lastcell.stat_hp != stat_hp)
2115     {
2116     lastcell.stat_hp = stat_hp;
2117    
2118     mask |= 0x8;
2119     *last_ext |= 0x80;
2120     last_ext = sl.buf + sl.len;
2121     SockList_AddChar (&sl, 5);
2122     SockList_AddChar (&sl, stat_hp);
2123    
2124     if (stat_width > 1)
2125     {
2126     *last_ext |= 0x80;
2127     last_ext = sl.buf + sl.len;
2128     SockList_AddChar (&sl, 6);
2129     SockList_AddChar (&sl, stat_width);
2130     }
2131     }
2132 root 1.12
2133 root 1.20 if (lastcell.player != player)
2134 root 1.16 {
2135     lastcell.player = player;
2136    
2137     mask |= 0x8;
2138     *last_ext |= 0x80;
2139     last_ext = sl.buf + sl.len;
2140     SockList_AddChar (&sl, 0x47);
2141     SockList_AddChar (&sl, 4);
2142     SockList_AddInt (&sl, player);
2143     }
2144     }
2145 root 1.12
2146 root 1.16 /* Floor face */
2147     if (update_space (&sl, &socket, m, nx, ny, ax, ay, 2))
2148     mask |= 0x4;
2149    
2150     if (socket.EMI_smooth)
2151     if (update_smooth (&esl, &socket, m, nx, ny, ax, ay, 2))
2152     emask |= 0x4;
2153    
2154     /* Middle face */
2155     if (update_space (&sl, &socket, m, nx, ny, ax, ay, 1))
2156     mask |= 0x2;
2157    
2158     if (socket.EMI_smooth)
2159     if (update_smooth (&esl, &socket, m, nx, ny, ax, ay, 1))
2160     emask |= 0x2;
2161    
2162     if (nx == pl->x && ny == pl->y && pl->invisible & (pl->invisible < 50 ? 4 : 1))
2163     {
2164     if (lastcell.faces[0] != pl->face->number)
2165     {
2166     lastcell.faces[0] = pl->face->number;
2167     mask |= 0x1;
2168     if (!(socket.faces_sent[pl->face->number] & NS_FACESENT_FACE))
2169     esrv_send_face (&socket, pl->face->number, 0);
2170     SockList_AddShort (&sl, pl->face->number);
2171 root 1.12 }
2172     }
2173 root 1.16 /* Top face */
2174     else
2175     {
2176     if (update_space (&sl, &socket, m, nx, ny, ax, ay, 0))
2177     mask |= 0x1;
2178     if (socket.EMI_smooth)
2179     if (update_smooth (&esl, &socket, m, nx, ny, ax, ay, 0))
2180     {
2181     emask |= 0x1;
2182     }
2183     }
2184     /* Check to see if we are in fact sending anything for this
2185     * space by checking the mask. If so, update the mask.
2186     * if not, reset the len to that from before adding the mask
2187     * value, so we don't send those bits.
2188     */
2189     if (mask & 0xf)
2190     {
2191     sl.buf[oldlen + 1] = mask & 0xff;
2192     }
2193     else
2194     {
2195     sl.len = oldlen;
2196 root 1.12 }
2197 root 1.16 if (emask & 0xf)
2198     {
2199     esl.buf[eoldlen + 1] = emask & 0xff;
2200 root 1.12 }
2201 root 1.16 else
2202     {
2203     esl.len = eoldlen;
2204 root 1.12 }
2205 root 1.16 } /* else this is a viewable space */
2206     } /* for x loop */
2207     } /* for y loop */
2208    
2209     /* Verify that we in fact do need to send this */
2210     if (socket.ext_mapinfos)
2211     {
2212     if (!(sl.len > startlen || socket.sent_scroll))
2213     {
2214     /* No map data will follow, so don't say the client
2215     * it doesn't need draw!
2216     */
2217     ewhatflag &= (~EMI_NOREDRAW);
2218     esl.buf[ewhatstart + 1] = ewhatflag & 0xff;
2219     }
2220 root 1.18
2221 root 1.16 if (esl.len > estartlen)
2222 root 1.18 Send_With_Handling (&socket, &esl);
2223    
2224 root 1.16 free (esl.buf);
2225     }
2226 root 1.18
2227 root 1.16 if (sl.len > startlen || socket.sent_scroll)
2228     {
2229     Send_With_Handling (&socket, &sl);
2230     socket.sent_scroll = 0;
2231 elmex 1.1 }
2232 root 1.18
2233 root 1.16 free (sl.buf);
2234 elmex 1.1 }
2235    
2236     /**
2237     * Draws client map.
2238     */
2239 root 1.16 void
2240     draw_client_map (object *pl)
2241 elmex 1.1 {
2242 root 1.16 int i, j;
2243     sint16 ax, ay, nx, ny; /* ax and ay goes from 0 to max-size of arrays */
2244     New_Face *face, *floor;
2245     New_Face *floor2;
2246     int d, mflags;
2247     struct Map newmap;
2248 root 1.21 maptile *m, *pm;
2249 root 1.16
2250     if (pl->type != PLAYER)
2251     {
2252     LOG (llevError, "draw_client_map called with non player/non eric-server\n");
2253     return;
2254     }
2255    
2256     pm = pl->map;
2257    
2258     /* If player is just joining the game, he isn't here yet, so the map
2259     * can get swapped out. If so, don't try to send them a map. All will
2260     * be OK once they really log in.
2261     */
2262     if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
2263     return;
2264    
2265     memset (&newmap, 0, sizeof (struct Map));
2266    
2267     for (j = (pl->y - pl->contr->socket.mapy / 2); j < (pl->y + (pl->contr->socket.mapy + 1) / 2); j++)
2268     {
2269     for (i = (pl->x - pl->contr->socket.mapx / 2); i < (pl->x + (pl->contr->socket.mapx + 1) / 2); i++)
2270     {
2271     ax = i;
2272     ay = j;
2273     m = pm;
2274     mflags = get_map_flags (m, &m, ax, ay, &ax, &ay);
2275     if (mflags & P_OUT_OF_MAP)
2276     continue;
2277     if (mflags & P_NEED_UPDATE)
2278     update_position (m, ax, ay);
2279     /* If a map is visible to the player, we don't want to swap it out
2280     * just to reload it. This should really call something like
2281     * swap_map, but this is much more efficient and 'good enough'
2282     */
2283     if (mflags & P_NEW_MAP)
2284     m->timeout = 50;
2285     }
2286     }
2287     /* do LOS after calls to update_position */
2288     if (pl->contr->do_los)
2289     {
2290     update_los (pl);
2291     pl->contr->do_los = 0;
2292     }
2293    
2294     if (pl->contr->socket.mapmode == Map1Cmd || pl->contr->socket.mapmode == Map1aCmd)
2295     {
2296     /* Big maps need a different drawing mechanism to work */
2297     draw_client_map1 (pl);
2298     return;
2299     }
2300    
2301     if (pl->invisible & (pl->invisible < 50 ? 4 : 1))
2302     {
2303     esrv_map_setbelow (&pl->contr->socket, pl->contr->socket.mapx / 2, pl->contr->socket.mapy / 2, pl->face->number, &newmap);
2304     }
2305    
2306     /* j and i are the y and x coordinates of the real map (which is
2307     * basically some number of spaces around the player)
2308     * ax and ay are values from within the viewport (ie, 0, 0 is upper
2309     * left corner) and are thus disconnected from the map values.
2310     * Subtract 1 from the max values so that we properly handle cases where
2311     * player has specified an even map. Otherwise, we try to send them too
2312     * much, ie, if mapx is 10, we would try to send from -5 to 5, which is actually
2313     * 11 spaces. Now, we would send from -5 to 4, which is properly. If mapx is
2314     * odd, this still works fine.
2315     */
2316     ay = 0;
2317     for (j = pl->y - pl->contr->socket.mapy / 2; j <= pl->y + (pl->contr->socket.mapy - 1) / 2; j++, ay++)
2318     {
2319     ax = 0;
2320     for (i = pl->x - pl->contr->socket.mapx / 2; i <= pl->x + (pl->contr->socket.mapx - 1) / 2; i++, ax++)
2321     {
2322    
2323     d = pl->contr->blocked_los[ax][ay];
2324     /* note the out_of_map and d>3 checks are both within the same
2325     * negation check.
2326     */
2327     nx = i;
2328     ny = j;
2329     m = get_map_from_coord (pm, &nx, &ny);
2330     if (m && d < 4)
2331     {
2332     face = GET_MAP_FACE (m, nx, ny, 0);
2333     floor2 = GET_MAP_FACE (m, nx, ny, 1);
2334     floor = GET_MAP_FACE (m, nx, ny, 2);
2335    
2336     /* If all is blank, send a blank face. */
2337     if ((!face || face == blank_face) && (!floor2 || floor2 == blank_face) && (!floor || floor == blank_face))
2338     {
2339     esrv_map_setbelow (&pl->contr->socket, ax, ay, blank_face->number, &newmap);
2340     }
2341     else
2342     { /* actually have something interesting */
2343 root 1.12 /* send the darkness mask, if any. */
2344 root 1.16 if (d && pl->contr->socket.darkness)
2345     esrv_map_setbelow (&pl->contr->socket, ax, ay, dark_faces[d - 1]->number, &newmap);
2346    
2347     if (face && face != blank_face)
2348     esrv_map_setbelow (&pl->contr->socket, ax, ay, face->number, &newmap);
2349     if (floor2 && floor2 != blank_face)
2350     esrv_map_setbelow (&pl->contr->socket, ax, ay, floor2->number, &newmap);
2351     if (floor && floor != blank_face)
2352     esrv_map_setbelow (&pl->contr->socket, ax, ay, floor->number, &newmap);
2353     }
2354     } /* Is a valid space */
2355 root 1.12 }
2356 elmex 1.1 }
2357 root 1.16 esrv_map_doneredraw (&pl->contr->socket, &newmap);
2358 elmex 1.1
2359 root 1.16 check_map_change (pl->contr);
2360 elmex 1.1 }
2361    
2362    
2363     /*****************************************************************************/
2364 root 1.16
2365 elmex 1.1 /* GROS: The following one is used to allow a plugin to send a generic cmd to*/
2366 root 1.16
2367 elmex 1.1 /* a player. Of course, the client need to know the command to be able to */
2368 root 1.16
2369 elmex 1.1 /* manage it ! */
2370 root 1.16
2371 elmex 1.1 /*****************************************************************************/
2372 root 1.16 void
2373     send_plugin_custom_message (object *pl, char *buf)
2374 elmex 1.1 {
2375 root 1.16 cs_write_string (&pl->contr->socket, buf, strlen (buf));
2376 elmex 1.1 }
2377    
2378     /**
2379     * This sends the skill number to name mapping. We ignore
2380     * the params - we always send the same info no matter what.
2381     */
2382 root 1.16 void
2383     send_skill_info (NewSocket * ns, char *params)
2384 elmex 1.1 {
2385 root 1.16 SockList sl;
2386     int i;
2387 elmex 1.1
2388 root 1.16 sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2389     strcpy ((char *) sl.buf, "replyinfo skill_info\n");
2390     for (i = 1; i < NUM_SKILLS; i++)
2391     {
2392     sprintf ((char *) sl.buf + strlen ((char *) sl.buf), "%d:%s\n", i + CS_STAT_SKILLINFO, &skill_names[i]);
2393     }
2394     sl.len = strlen ((char *) sl.buf);
2395     if (sl.len >= MAXSOCKBUF)
2396     {
2397     LOG (llevError, "Buffer overflow in send_skill_info!\n");
2398     fatal (0);
2399 elmex 1.1 }
2400 root 1.16 Send_With_Handling (ns, &sl);
2401     free (sl.buf);
2402 elmex 1.1 }
2403    
2404     /**
2405     * This sends the spell path to name mapping. We ignore
2406     * the params - we always send the same info no matter what.
2407     */
2408 root 1.16 void
2409     send_spell_paths (NewSocket * ns, char *params)
2410     {
2411     SockList sl;
2412     int i;
2413    
2414     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2415     strcpy ((char *) sl.buf, "replyinfo spell_paths\n");
2416     for (i = 0; i < NRSPELLPATHS; i++)
2417     sprintf ((char *) sl.buf + strlen ((char *) sl.buf), "%d:%s\n", 1 << i, spellpathnames[i]);
2418     sl.len = strlen ((char *) sl.buf);
2419     if (sl.len >= MAXSOCKBUF)
2420     {
2421     LOG (llevError, "Buffer overflow in send_spell_paths!\n");
2422     fatal (0);
2423 elmex 1.1 }
2424 root 1.16 Send_With_Handling (ns, &sl);
2425     free (sl.buf);
2426 elmex 1.1 }
2427    
2428     /**
2429     * This looks for any spells the player may have that have changed their stats.
2430     * it then sends an updspell packet for each spell that has changed in this way
2431     */
2432 root 1.16 void
2433     esrv_update_spells (player *pl)
2434     {
2435     SockList sl;
2436     int flags = 0;
2437     object *spell;
2438    
2439     if (!pl->socket.monitor_spells)
2440     return;
2441     for (spell = pl->ob->inv; spell != NULL; spell = spell->below)
2442     {
2443     if (spell->type == SPELL)
2444     {
2445     /* check if we need to update it */
2446     if (spell->last_sp != SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA))
2447     {
2448     spell->last_sp = SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA);
2449     flags |= UPD_SP_MANA;
2450     }
2451     if (spell->last_grace != SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE))
2452     {
2453     spell->last_grace = SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE);
2454     flags |= UPD_SP_GRACE;
2455     }
2456     if (spell->last_eat != spell->stats.dam + SP_level_dam_adjust (pl->ob, spell))
2457     {
2458     spell->last_eat = spell->stats.dam + SP_level_dam_adjust (pl->ob, spell);
2459     flags |= UPD_SP_DAMAGE;
2460     }
2461     if (flags != 0)
2462     {
2463     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2464     strcpy ((char *) sl.buf, "updspell ");
2465     sl.len = strlen ((char *) sl.buf);
2466     SockList_AddChar (&sl, flags);
2467     SockList_AddInt (&sl, spell->count);
2468     if (flags & UPD_SP_MANA)
2469     SockList_AddShort (&sl, spell->last_sp);
2470     if (flags & UPD_SP_GRACE)
2471     SockList_AddShort (&sl, spell->last_grace);
2472     if (flags & UPD_SP_DAMAGE)
2473     SockList_AddShort (&sl, spell->last_eat);
2474     flags = 0;
2475     Send_With_Handling (&pl->socket, &sl);
2476     free (sl.buf);
2477 root 1.12 }
2478     }
2479 elmex 1.1 }
2480     }
2481    
2482 root 1.16 void
2483     esrv_remove_spell (player *pl, object *spell)
2484     {
2485     SockList sl;
2486    
2487     if (!pl->socket.monitor_spells)
2488     return;
2489     if (!pl || !spell || spell->env != pl->ob)
2490     {
2491     LOG (llevError, "Invalid call to esrv_remove_spell");
2492     return;
2493     }
2494     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2495     strcpy ((char *) sl.buf, "delspell ");
2496     sl.len = strlen ((char *) sl.buf);
2497     SockList_AddInt (&sl, spell->count);
2498     Send_With_Handling (&pl->socket, &sl);
2499     free (sl.buf);
2500 elmex 1.1 }
2501    
2502     /* appends the spell *spell to the Socklist we will send the data to. */
2503 root 1.16 static void
2504     append_spell (player *pl, SockList * sl, object *spell)
2505     {
2506     int len, i, skill = 0;
2507    
2508     if (!(spell->name))
2509     {
2510     LOG (llevError, "item number %d is a spell with no name.\n", spell->count);
2511     return;
2512     }
2513     SockList_AddInt (sl, spell->count);
2514     SockList_AddShort (sl, spell->level);
2515     SockList_AddShort (sl, spell->casting_time);
2516     /* store costs and damage in the object struct, to compare to later */
2517     spell->last_sp = SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA);
2518     spell->last_grace = SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE);
2519     spell->last_eat = spell->stats.dam + SP_level_dam_adjust (pl->ob, spell);
2520     /* send the current values */
2521     SockList_AddShort (sl, spell->last_sp);
2522     SockList_AddShort (sl, spell->last_grace);
2523     SockList_AddShort (sl, spell->last_eat);
2524 elmex 1.1
2525 root 1.16 /* figure out which skill it uses, if it uses one */
2526     if (spell->skill)
2527     {
2528     for (i = 1; i < NUM_SKILLS; i++)
2529     if (!strcmp (spell->skill, skill_names[i]))
2530     {
2531     skill = i + CS_STAT_SKILLINFO;
2532     break;
2533     }
2534 elmex 1.1 }
2535 root 1.16 SockList_AddChar (sl, skill);
2536 elmex 1.1
2537 root 1.16 SockList_AddInt (sl, spell->path_attuned);
2538     SockList_AddInt (sl, (spell->face) ? spell->face->number : 0);
2539 elmex 1.1
2540 root 1.16 len = strlen (spell->name);
2541     SockList_AddChar (sl, (char) len);
2542     memcpy (sl->buf + sl->len, spell->name, len);
2543     sl->len += len;
2544    
2545     if (!spell->msg)
2546     {
2547     SockList_AddShort (sl, 0);
2548     }
2549     else
2550     {
2551     len = strlen (spell->msg);
2552     SockList_AddShort (sl, len);
2553     memcpy (sl->buf + sl->len, spell->msg, len);
2554     sl->len += len;
2555 elmex 1.1 }
2556     }
2557    
2558     /**
2559     * This tells the client to add the spell *ob, if *ob is NULL, then add
2560     * all spells in the player's inventory.
2561     */
2562 root 1.16 void
2563     esrv_add_spells (player *pl, object *spell)
2564     {
2565     SockList sl;
2566    
2567     if (!pl)
2568     {
2569     LOG (llevError, "esrv_add_spells, tried to add a spell to a NULL player");
2570     return;
2571     }
2572     if (!pl->socket.monitor_spells)
2573     return;
2574     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2575     strcpy ((char *) sl.buf, "addspell ");
2576     sl.len = strlen ((char *) sl.buf);
2577     if (!spell)
2578     {
2579     for (spell = pl->ob->inv; spell != NULL; spell = spell->below)
2580     {
2581     /* were we to simply keep appending data here, we could exceed
2582     * MAXSOCKBUF if the player has enough spells to add, we know that
2583     * append_spells will always append 19 data bytes, plus 4 length
2584     * bytes and 3 strings (because that is the spec) so we need to
2585     * check that the length of those 3 strings, plus the 23 bytes,
2586     * won't take us over the length limit for the socket, if it does,
2587     * we need to send what we already have, and restart packet formation
2588     */
2589     /* Seeing crashes by overflowed buffers. Quick arithemetic seems
2590     * to show add_spell is 26 bytes + 2 strings. However, the overun
2591     * is hundreds of bytes off, so correcting 22 vs 26 doesn't seem
2592     * like it will fix this
2593     */
2594     if (spell->type != SPELL)
2595     continue;
2596     if (sl.len >= (MAXSOCKBUF - (26 + strlen (spell->name) + (spell->msg ? strlen (spell->msg) : 0))))
2597     {
2598     Send_With_Handling (&pl->socket, &sl);
2599     strcpy ((char *) sl.buf, "addspell ");
2600     sl.len = strlen ((char *) sl.buf);
2601     }
2602     append_spell (pl, &sl, spell);
2603     }
2604     }
2605     else if (spell->type != SPELL)
2606     {
2607     LOG (llevError, "Asked to send a non-spell object as a spell");
2608     return;
2609     }
2610     else
2611     append_spell (pl, &sl, spell);
2612     if (sl.len >= MAXSOCKBUF)
2613     {
2614     LOG (llevError, "Buffer overflow in esrv_add_spells!\n");
2615     fatal (0);
2616     }
2617     /* finally, we can send the packet */
2618     Send_With_Handling (&pl->socket, &sl);
2619     free (sl.buf);
2620 elmex 1.1 }