ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/request.C
Revision: 1.21
Committed: Sat Sep 16 22:24:13 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.20: +5 -5 lines
Log Message:
mapstruct => maptile
removed many ytypedefs in favor of structure tags

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     if (pl->socket.exp64)
1137     {
1138     uint8 s;
1139    
1140     for (s = 0; s < NUM_SKILLS; s++)
1141     {
1142     if (pl->last_skill_ob[s] && pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp)
1143     {
1144    
1145     /* Always send along the level if exp changes. This is only
1146     * 1 extra byte, but keeps processing simpler.
1147     */
1148     SockList_AddChar (&sl, (char) (s + CS_STAT_SKILLINFO));
1149     SockList_AddChar (&sl, (char) pl->last_skill_ob[s]->level);
1150     SockList_AddInt64 (&sl, pl->last_skill_ob[s]->stats.exp);
1151     pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
1152     }
1153     }
1154     }
1155     if (pl->socket.exp64)
1156     {
1157     AddIfInt64 (pl->last_stats.exp, pl->ob->stats.exp, CS_STAT_EXP64);
1158     }
1159     else
1160     {
1161     AddIfInt (pl->last_stats.exp, (int) pl->ob->stats.exp, CS_STAT_EXP);
1162     }
1163     AddIfShort (pl->last_level, (char) pl->ob->level, CS_STAT_LEVEL);
1164     AddIfShort (pl->last_stats.wc, pl->ob->stats.wc, CS_STAT_WC);
1165     AddIfShort (pl->last_stats.ac, pl->ob->stats.ac, CS_STAT_AC);
1166     AddIfShort (pl->last_stats.dam, pl->ob->stats.dam, CS_STAT_DAM);
1167     AddIfFloat (pl->last_speed, pl->ob->speed, CS_STAT_SPEED);
1168     AddIfShort (pl->last_stats.food, pl->ob->stats.food, CS_STAT_FOOD);
1169     AddIfFloat (pl->last_weapon_sp, pl->weapon_sp, CS_STAT_WEAP_SP);
1170     AddIfInt (pl->last_weight_limit, (sint32) weight_limit[pl->ob->stats.Str], CS_STAT_WEIGHT_LIM);
1171     flags = 0;
1172     if (pl->fire_on)
1173     flags |= SF_FIREON;
1174     if (pl->run_on)
1175     flags |= SF_RUNON;
1176    
1177     AddIfShort (pl->last_flags, flags, CS_STAT_FLAGS);
1178     if (pl->socket.sc_version < 1025)
1179     {
1180     AddIfShort (pl->last_resist[ATNR_PHYSICAL], pl->ob->resist[ATNR_PHYSICAL], CS_STAT_ARMOUR);
1181     }
1182     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     if (pl->socket.monitor_spells)
1195     {
1196     AddIfInt (pl->last_path_attuned, pl->ob->path_attuned, CS_STAT_SPELL_ATTUNE);
1197     AddIfInt (pl->last_path_repelled, pl->ob->path_repelled, CS_STAT_SPELL_REPEL);
1198     AddIfInt (pl->last_path_denied, pl->ob->path_denied, CS_STAT_SPELL_DENY);
1199     }
1200     rangetostring (pl->ob, buf); /* we want use the new fire & run system in new client */
1201     AddIfString (pl->socket.stats.range, buf, CS_STAT_RANGE);
1202     set_title (pl->ob, buf);
1203     AddIfString (pl->socket.stats.title, buf, CS_STAT_TITLE);
1204    
1205     /* Only send it away if we have some actual data */
1206     if (sl.len > 6)
1207     {
1208 elmex 1.1 #ifdef ESRV_DEBUG
1209 root 1.16 LOG (llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
1210 elmex 1.1 #endif
1211 root 1.16 Send_With_Handling (&pl->socket, &sl);
1212 elmex 1.1 }
1213 root 1.16 free (sl.buf);
1214 elmex 1.1 }
1215    
1216    
1217     /**
1218     * Tells the client that here is a player it should start using.
1219     */
1220 root 1.16 void
1221     esrv_new_player (player *pl, uint32 weight)
1222 elmex 1.1 {
1223 root 1.16 SockList sl;
1224    
1225     pl->last_weight = weight;
1226 elmex 1.1
1227 root 1.16 sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1228 elmex 1.1
1229 root 1.16 strcpy ((char *) sl.buf, "player ");
1230     sl.len = strlen ((char *) sl.buf);
1231     SockList_AddInt (&sl, pl->ob->count);
1232     SockList_AddInt (&sl, weight);
1233     SockList_AddInt (&sl, pl->ob->face->number);
1234 elmex 1.1
1235 root 1.16 SockList_AddChar (&sl, (char) strlen (pl->ob->name));
1236     strcpy ((char *) sl.buf + sl.len, pl->ob->name);
1237     sl.len += strlen (pl->ob->name);
1238    
1239     Send_With_Handling (&pl->socket, &sl);
1240     free (sl.buf);
1241     SET_FLAG (pl->ob, FLAG_CLIENT_SENT);
1242 elmex 1.1 }
1243    
1244    
1245     /**
1246     * Need to send an animation sequence to the client.
1247     * We will send appropriate face commands to the client if we haven't
1248     * sent them the face yet (this can become quite costly in terms of
1249     * how much we are sending - on the other hand, this should only happen
1250     * when the player logs in and picks stuff up.
1251     */
1252 root 1.16 void
1253     esrv_send_animation (NewSocket * ns, short anim_num)
1254 elmex 1.1 {
1255 root 1.16 SockList sl;
1256     int i;
1257 elmex 1.1
1258 root 1.16 /* Do some checking on the anim_num we got. Note that the animations
1259     * are added in contigous order, so if the number is in the valid
1260     * range, it must be a valid animation.
1261     */
1262     if (anim_num < 0 || anim_num > num_animations)
1263     {
1264     LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
1265     return;
1266     }
1267    
1268     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1269     strcpy ((char *) sl.buf, "anim ");
1270     sl.len = 5;
1271     SockList_AddShort (&sl, anim_num);
1272     SockList_AddShort (&sl, 0); /* flags - not used right now */
1273     /* Build up the list of faces. Also, send any information (ie, the
1274     * the face itself) down to the client.
1275     */
1276     for (i = 0; i < animations[anim_num].num_animations; i++)
1277     {
1278     if (!(ns->faces_sent[animations[anim_num].faces[i]] & NS_FACESENT_FACE))
1279     esrv_send_face (ns, animations[anim_num].faces[i], 0);
1280     SockList_AddShort (&sl, animations[anim_num].faces[i]); /* flags - not used right now */
1281     }
1282     Send_With_Handling (ns, &sl);
1283     free (sl.buf);
1284     ns->anims_sent[anim_num] = 1;
1285 elmex 1.1 }
1286    
1287    
1288     /******************************************************************************
1289     *
1290     * Start of map related commands.
1291     *
1292     ******************************************************************************/
1293    
1294     /**
1295     * This adds face_num to a map cell at x,y. If the client doesn't have
1296     * the face yet, we will also send it.
1297     */
1298 root 1.16 static void
1299     esrv_map_setbelow (NewSocket * ns, int x, int y, short face_num, struct Map *newmap)
1300 elmex 1.1 {
1301 root 1.16 if (newmap->cells[x][y].count >= MAP_LAYERS)
1302     {
1303     LOG (llevError, "Too many faces in map cell %d %d\n", x, y);
1304     return;
1305     abort ();
1306 elmex 1.1 }
1307 root 1.16 newmap->cells[x][y].faces[newmap->cells[x][y].count] = face_num;
1308     newmap->cells[x][y].count++;
1309     if (!(ns->faces_sent[face_num] & NS_FACESENT_FACE))
1310     esrv_send_face (ns, face_num, 0);
1311 elmex 1.1 }
1312    
1313 root 1.16 struct LayerCell
1314     {
1315 elmex 1.1 uint16 xy;
1316     short face;
1317     };
1318    
1319 root 1.16 struct MapLayer
1320     {
1321 elmex 1.1 int count;
1322     struct LayerCell lcells[MAP_CLIENT_X * MAP_CLIENT_Y];
1323     };
1324    
1325     /** Checkes if map cells have changed */
1326 root 1.16 static int
1327     mapcellchanged (NewSocket * ns, int i, int j, struct Map *newmap)
1328 elmex 1.1 {
1329     int k;
1330    
1331     if (ns->lastmap.cells[i][j].count != newmap->cells[i][j].count)
1332     return 1;
1333 root 1.16 for (k = 0; k < newmap->cells[i][j].count; k++)
1334     {
1335     if (ns->lastmap.cells[i][j].faces[k] != newmap->cells[i][j].faces[k])
1336     {
1337     return 1;
1338     }
1339 elmex 1.1 }
1340     return 0;
1341     }
1342    
1343     /**
1344     * Basically, what this does is pack the data into layers.
1345     * cnum is the client number, cur is the the buffer we put all of
1346     * this data into. we return the end of the data. layers is
1347     * how many layers of data we should back.
1348 root 1.16 */
1349     static uint8 *
1350     compactlayer (NewSocket * ns, unsigned char *cur, int numlayers, struct Map *newmap)
1351     {
1352     int x, y, k;
1353     int face;
1354     unsigned char *fcur;
1355     struct MapLayer layers[MAP_LAYERS];
1356    
1357     for (k = 0; k < MAP_LAYERS; k++)
1358     layers[k].count = 0;
1359     fcur = cur;
1360     for (x = 0; x < ns->mapx; x++)
1361     {
1362     for (y = 0; y < ns->mapy; y++)
1363     {
1364     if (!mapcellchanged (ns, x, y, newmap))
1365     continue;
1366     if (newmap->cells[x][y].count == 0)
1367     {
1368     *cur = x * ns->mapy + y; /* mark empty space */
1369     cur++;
1370     continue;
1371     }
1372     for (k = 0; k < newmap->cells[x][y].count; k++)
1373     {
1374     layers[k].lcells[layers[k].count].xy = x * ns->mapy + y;
1375     layers[k].lcells[layers[k].count].face = newmap->cells[x][y].faces[k];
1376     layers[k].count++;
1377 root 1.12 }
1378     }
1379 elmex 1.1 }
1380 root 1.16 /* If no data, return now. */
1381     if (fcur == cur && layers[0].count == 0)
1382     return cur;
1383     *cur = 255; /* mark end of explicitly cleared cells */
1384     cur++;
1385     /* First pack by layers. */
1386     for (k = 0; k < numlayers; k++)
1387     {
1388     if (layers[k].count == 0)
1389     break; /* once a layer is entirely empty, no layer below it can
1390     have anything in it either */
1391     /* Pack by entries in thie layer */
1392     for (x = 0; x < layers[k].count;)
1393     {
1394     fcur = cur;
1395     *cur = layers[k].lcells[x].face >> 8;
1396     cur++;
1397     *cur = layers[k].lcells[x].face & 0xFF;
1398     cur++;
1399     face = layers[k].lcells[x].face;
1400     /* Now, we back the redundant data into 1 byte xy pairings */
1401     for (y = x; y < layers[k].count; y++)
1402     {
1403     if (layers[k].lcells[y].face == face)
1404     {
1405     *cur = (uint8) layers[k].lcells[y].xy;
1406     cur++;
1407     layers[k].lcells[y].face = -1;
1408 root 1.12 }
1409     }
1410 root 1.16 *(cur - 1) = *(cur - 1) | 128; /* mark for end of xy's; 11*11 < 128 */
1411     /* forward over the now redundant data */
1412     while (x < layers[k].count && layers[k].lcells[x].face == -1)
1413     x++;
1414 root 1.12 }
1415 root 1.16 *fcur = *fcur | 128; /* mark for end of faces at this layer */
1416 elmex 1.1 }
1417 root 1.16 return cur;
1418 elmex 1.1 }
1419    
1420 root 1.16 static void
1421     esrv_map_doneredraw (NewSocket * ns, struct Map *newmap)
1422 elmex 1.1 {
1423 root 1.16 static long frames, bytes, tbytes, tframes;
1424     char *cur;
1425     SockList sl;
1426 elmex 1.1
1427    
1428 root 1.16 sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1429     strcpy ((char *) sl.buf, "map ");
1430     sl.len = strlen ((char *) sl.buf);
1431 elmex 1.1
1432 root 1.16 cur = (char *) compactlayer (ns, (unsigned char *) sl.buf + sl.len, MAP_LAYERS, newmap);
1433     sl.len = cur - (char *) sl.buf;
1434 elmex 1.1
1435     /* LOG(llevDebug, "Sending map command.\n");*/
1436    
1437 root 1.16 if (sl.len > (int) strlen ("map ") || ns->sent_scroll)
1438     {
1439     /* All of this is just accounting stuff */
1440     if (tframes > 100)
1441 root 1.18 tframes = tbytes = 0;
1442    
1443 root 1.16 tframes++;
1444     frames++;
1445     tbytes += sl.len;
1446     bytes += sl.len;
1447     memcpy (&ns->lastmap, newmap, sizeof (struct Map));
1448     Send_With_Handling (ns, &sl);
1449     ns->sent_scroll = 0;
1450 elmex 1.1 }
1451 root 1.18
1452 root 1.16 free (sl.buf);
1453 elmex 1.1 }
1454    
1455    
1456     /** Clears a map cell */
1457 root 1.16 static void
1458     map_clearcell (struct MapCell *cell, int face0, int face1, int face2, int count)
1459 elmex 1.1 {
1460 root 1.16 cell->faces[0] = face0;
1461     cell->faces[1] = face1;
1462     cell->faces[2] = face2;
1463     cell->count = count;
1464     cell->stat_hp = 0;
1465     cell->player = 0;
1466 elmex 1.1 }
1467    
1468     #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
1469     #define MAX_LAYERS 3
1470    
1471     /* Using a global really isn't a good approach, but saves the over head of
1472     * allocating and deallocating such a block of data each time run through,
1473     * and saves the space of allocating this in the socket object when we only
1474     * need it for this cycle. If the serve is ever threaded, this needs to be
1475     * re-examined.
1476     */
1477    
1478 root 1.16 static object *heads[MAX_HEAD_POS * MAX_HEAD_POS * MAX_LAYERS];
1479 elmex 1.1
1480     /**
1481     * Returns true if any of the heads for this
1482     * space is set. Returns false if all are blank - this is used
1483     * for empty space checking.
1484     */
1485 root 1.16 static inline int
1486     have_head (int ax, int ay)
1487     {
1488 elmex 1.1
1489 root 1.16 if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS] ||
1490     heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + 1] || heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + 2])
1491     return 1;
1492     return 0;
1493 elmex 1.1 }
1494    
1495     /**
1496     * check_head is a bit simplistic version of update_space below.
1497     * basically, it only checks the that the head on space ax,ay at layer
1498     * needs to get sent - if so, it adds the data, sending the head
1499     * if needed, and returning 1. If this no data needs to get
1500     * sent, it returns zero.
1501     */
1502 root 1.16 static int
1503     check_head (SockList & sl, NewSocket & ns, int ax, int ay, int layer)
1504 elmex 1.1 {
1505 root 1.16 short face_num;
1506 elmex 1.1
1507 root 1.16 if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer])
1508     face_num = heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]->face->number;
1509     else
1510     face_num = 0;
1511 elmex 1.1
1512 root 1.16 if (face_num != ns.lastmap.cells[ax][ay].faces[layer])
1513     {
1514     SockList_AddShort (&sl, face_num);
1515     if (face_num && !(ns.faces_sent[face_num] & NS_FACESENT_FACE))
1516     esrv_send_face (&ns, face_num, 0);
1517     heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer] = NULL;
1518     ns.lastmap.cells[ax][ay].faces[layer] = face_num;
1519     return 1;
1520 elmex 1.1 }
1521    
1522 root 1.16 return 0; /* No change */
1523 elmex 1.1 }
1524    
1525     /**
1526     * Removes the need to replicate the same code for each layer.
1527     * this returns true if this space is now in fact different than
1528     * it was.
1529     * sl is the socklist this data is going into.
1530     * ns is the socket we are working on - all the info we care
1531     * about is in this socket structure, so now need not pass the
1532     * entire player object.
1533     * mx and my are map coordinate offsets for map mp
1534     * sx and sy are the offsets into the socket structure that
1535     * holds the old values.
1536     * layer is the layer to update, with 2 being the floor and 0 the
1537     * top layer (this matches what the GET_MAP_FACE and GET_MAP_FACE_OBJ)
1538     * take. Interesting to note that before this function, the map1 function
1539     * numbers the spaces differently - I think this was a leftover from
1540     * the map command, where the faces stack up. Sinces that is no longer
1541     * the case, it seems to make more sense to have these layer values
1542     * actually match.
1543     */
1544    
1545 root 1.16 static int
1546 root 1.21 update_space (SockList * sl, NewSocket * ns, maptile *mp, int mx, int my, int sx, int sy, int layer)
1547 elmex 1.1 {
1548 root 1.16 object *ob, *head;
1549     uint16 face_num;
1550     int bx, by, i;
1551    
1552     /* If there is a multipart object stored away, treat that as more important.
1553     * If not, then do the normal processing.
1554     */
1555    
1556     head = heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer];
1557    
1558     /* Check to see if this head is part of the set of objects
1559     * we would normally send for this space. If so, then
1560     * don't use the head value. We need to do the check
1561     * here and not when setting up the heads[] value for two reasons -
1562     * 1) the heads[] values will get used even if the space is not visible.
1563     * 2) its possible the head is not on the same map as a part, and I'd
1564     * rather not need to do the map translation overhead.
1565     * 3) We need to do some extra checking to make sure that we will
1566     * otherwise send the image as this layer, eg, either it matches
1567     * the head value, or is not multipart.
1568     */
1569     if (head && !head->more)
1570     {
1571     for (i = 0; i < MAP_LAYERS; i++)
1572     {
1573     ob = GET_MAP_FACE_OBJ (mp, mx, my, i);
1574     if (!ob)
1575     continue;
1576    
1577     if (ob->head)
1578     ob = ob->head;
1579    
1580     if (ob == head)
1581     {
1582     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer] = NULL;
1583     head = NULL;
1584     break;
1585     }
1586     }
1587     }
1588    
1589     ob = head;
1590     if (!ob)
1591     ob = GET_MAP_FACE_OBJ (mp, mx, my, layer);
1592    
1593     /* If there is no object for this space, or if the face for the object
1594     * is the blank face, set the face number to zero.
1595     * else if we have the stored head object for this space, that takes
1596     * precedence over the other object for this space.
1597     * otherwise, we do special head processing
1598     */
1599     if (!ob || ob->face == blank_face)
1600     face_num = 0;
1601     else if (head)
1602     {
1603     /* if this is a head that had previously been stored */
1604     face_num = ob->face->number;
1605     }
1606     else
1607     {
1608     /* if the faces for the different parts of a multipart object
1609     * are the same, we only want to send the bottom right most
1610     * portion of the object. That info is in the tail_.. values
1611     * of the head. Note that for the head itself, ob->head will
1612     * be null, so we only do this block if we are working on
1613     * a tail piece.
1614     */
1615    
1616     /* tail_x and tail_y will only be set in the head object. If
1617     * this is the head object and these are set, we proceed
1618     * with logic to only send bottom right. Similarly, if
1619     * this is one of the more parts but the head has those values
1620     * set, we want to do the processing. There can be cases where
1621     * the head is not visible but one of its parts is, so we just
1622     * can always expect that ob->arch->tail_x will be true for all
1623     * object we may want to display.
1624     */
1625     if ((ob->arch->tail_x || ob->arch->tail_y) || (ob->head && (ob->head->arch->tail_x || ob->head->arch->tail_y)))
1626     {
1627    
1628     if (ob->head)
1629     head = ob->head;
1630     else
1631     head = ob;
1632    
1633     /* Basically figure out where the offset is from where we are right
1634     * now. the ob->arch->clone.{x,y} values hold the offset that this current
1635     * piece is from the head, and the tail is where the tail is from the
1636     * head. Note that bx and by will equal sx and sy if we are already working
1637     * on the bottom right corner. If ob is the head, the clone values
1638     * will be zero, so the right thing will still happen.
1639     */
1640     bx = sx + head->arch->tail_x - ob->arch->clone.x;
1641     by = sy + head->arch->tail_y - ob->arch->clone.y;
1642    
1643     /* I don't think this can ever happen, but better to check for it just
1644     * in case.
1645     */
1646     if (bx < sx || by < sy)
1647     {
1648     LOG (llevError, "update_space: bx (%d) or by (%d) is less than sx (%d) or sy (%d)\n", bx, by, sx, sy);
1649     face_num = 0;
1650     }
1651     /* single part object, multipart object with non merged faces,
1652     * of multipart object already at lower right.
1653     */
1654     else if (bx == sx && by == sy)
1655     {
1656     face_num = ob->face->number;
1657    
1658     /* if this face matches one stored away, clear that one away.
1659     * this code relies on the fact that the map1 commands
1660     * goes from 2 down to 0.
1661     */
1662     for (i = 0; i < MAP_LAYERS; i++)
1663     if (heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i] &&
1664     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i]->face->number == face_num)
1665     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i] = NULL;
1666     }
1667     else
1668     {
1669     /* If this head is stored away, clear it - otherwise,
1670     * there can be cases where a object is on multiple layers -
1671     * we only want to send it once.
1672     */
1673     face_num = head->face->number;
1674     for (i = 0; i < MAP_LAYERS; i++)
1675     if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] &&
1676     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i]->face->number == face_num)
1677     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] = NULL;
1678    
1679     /* First, try to put the new head on the same layer. If that is used up,
1680     * then find another layer.
1681     */
1682     if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + layer] == NULL)
1683     {
1684     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + layer] = head;
1685     }
1686     else
1687     for (i = 0; i < MAX_LAYERS; i++)
1688     {
1689 root 1.12 if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] == NULL ||
1690 root 1.16 heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] == head)
1691     {
1692     heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] = head;
1693     }
1694     }
1695     face_num = 0; /* Don't send this object - we'll send the head later */
1696 root 1.12 }
1697 root 1.16 }
1698     else
1699     {
1700     /* In this case, we are already at the lower right or single part object,
1701     * so nothing special
1702     */
1703     face_num = ob->face->number;
1704    
1705     /* clear out any head entries that have the same face as this one */
1706     for (bx = 0; bx < layer; bx++)
1707     if (heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx] &&
1708     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx]->face->number == face_num)
1709     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx] = NULL;
1710     }
1711     } /* else not already head object or blank face */
1712    
1713     /* This is a real hack. Basically, if we have nothing to send for this layer,
1714     * but there is a head on the next layer, send that instead.
1715     * Without this, what happens is you can get the case where the player stands
1716     * on the same space as the head. However, if you have overlapping big objects
1717     * of the same type, what happens then is it doesn't think it needs to send
1718     * This tends to make stacking also work/look better.
1719     */
1720     if (!face_num && layer > 0 && heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1])
1721     {
1722     face_num = heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1]->face->number;
1723     heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1] = NULL;
1724     }
1725    
1726     /* Another hack - because of heads and whatnot, this face may match one
1727     * we already sent for a lower layer. In that case, don't send
1728     * this one.
1729     */
1730     if (face_num && layer + 1 < MAP_LAYERS && ns->lastmap.cells[sx][sy].faces[layer + 1] == face_num)
1731     {
1732     face_num = 0;
1733     }
1734    
1735     /* We've gotten what face we want to use for the object. Now see if
1736     * if it has changed since we last sent it to the client.
1737     */
1738     if (ns->lastmap.cells[sx][sy].faces[layer] != face_num)
1739     {
1740     ns->lastmap.cells[sx][sy].faces[layer] = face_num;
1741     if (!(ns->faces_sent[face_num] & NS_FACESENT_FACE))
1742     esrv_send_face (ns, face_num, 0);
1743     SockList_AddShort (sl, face_num);
1744     return 1;
1745 elmex 1.1 }
1746 root 1.16 /* Nothing changed */
1747     return 0;
1748 elmex 1.1 }
1749    
1750     /**
1751     * This function is mainly a copy of update_space,
1752     * except it handles update of the smoothing updates,
1753     * not the face updates.
1754     * Removes the need to replicate the same code for each layer.
1755     * this returns true if this smooth is now in fact different
1756     * than it was.
1757     * sl is the socklist this data is going into.
1758     * ns is the socket we are working on - all the info we care
1759     * about is in this socket structure, so know need to pass the
1760     * entire player object.
1761     * mx and my are map coordinate offsets for map mp
1762     * sx and sy are the offsets into the socket structure that
1763     * holds the old values.
1764     * layer is the layer to update, with 2 being the floor and 0 the
1765     * top layer (this matches what the GET_MAP_FACE and GET_MAP_FACE_OBJ
1766     * take.
1767     */
1768    
1769 root 1.16 static inline int
1770 root 1.21 update_smooth (SockList * sl, NewSocket * ns, maptile *mp, int mx, int my, int sx, int sy, int layer)
1771 elmex 1.1 {
1772 root 1.16 object *ob;
1773     int smoothlevel; /* old face_num; */
1774 elmex 1.1
1775 root 1.16 ob = GET_MAP_FACE_OBJ (mp, mx, my, layer);
1776 elmex 1.1
1777 root 1.16 /* If there is no object for this space, or if the face for the object
1778     * is the blank face, set the smoothlevel to zero.
1779     */
1780     if (!ob || ob->face == blank_face || MAP_NOSMOOTH (mp))
1781     smoothlevel = 0;
1782     else
1783     {
1784     smoothlevel = ob->smoothlevel;
1785     if (smoothlevel && !(ns->faces_sent[ob->face->number] & NS_FACESENT_SMOOTH))
1786     SendSmooth (ns, ob->face->number);
1787     } /* else not already head object or blank face */
1788    
1789     /* We've gotten what face we want to use for the object. Now see if
1790     * if it has changed since we last sent it to the client.
1791     */
1792     if (smoothlevel > 255)
1793     smoothlevel = 255;
1794     else if (smoothlevel < 0)
1795     smoothlevel = 0;
1796     if (ns->lastmap.cells[sx][sy].smooth[layer] != smoothlevel)
1797     {
1798     ns->lastmap.cells[sx][sy].smooth[layer] = smoothlevel;
1799     SockList_AddChar (sl, (uint8) (smoothlevel & 0xFF));
1800     return 1;
1801 elmex 1.1 }
1802 root 1.16 /* Nothing changed */
1803     return 0;
1804 elmex 1.1 }
1805    
1806     /**
1807     * Returns the size of a data for a map square as returned by
1808     * mapextended. There are CLIENTMAPX*CLIENTMAPY*LAYERS entries
1809     * available.
1810     */
1811 root 1.16 int
1812     getExtendedMapInfoSize (NewSocket * ns)
1813     {
1814     int result = 0;
1815    
1816     if (ns->ext_mapinfos)
1817     {
1818     if (ns->EMI_smooth)
1819     result += 1; /*One byte for smoothlevel */
1820 elmex 1.1 }
1821 root 1.16 return result;
1822 elmex 1.1 }
1823 root 1.16
1824 elmex 1.1 /**
1825     * This function uses the new map1 protocol command to send the map
1826     * to the client. It is necessary because the old map command supports
1827     * a maximum map size of 15x15.
1828     * This function is much simpler than the old one. This is because
1829     * the old function optimized to send as few face identifiers as possible,
1830     * at the expense of sending more coordinate location (coordinates were
1831     * only 1 byte, faces 2 bytes, so this was a worthwhile savings). Since
1832     * we need 2 bytes for coordinates and 2 bytes for faces, such a trade off
1833     * maps no sense. Instead, we actually really only use 12 bits for coordinates,
1834     * and use the other 4 bits for other informatiion. For full documentation
1835     * of what we send, see the doc/Protocol file.
1836     * I will describe internally what we do:
1837     * the socket->lastmap shows how the map last looked when sent to the client.
1838     * in the lastmap structure, there is a cells array, which is set to the
1839     * maximum viewable size (As set in config.h).
1840     * in the cells, there are faces and a count value.
1841     * we use the count value to hold the darkness value. If -1, then this space
1842     * is not viewable.
1843     * we use faces[0] faces[1] faces[2] to hold what the three layers
1844     * look like.
1845     */
1846 root 1.16 void
1847     draw_client_map1 (object *pl)
1848 elmex 1.1 {
1849 root 1.16 int x, y, ax, ay, d, startlen, max_x, max_y, oldlen;
1850     sint16 nx, ny;
1851     int estartlen, eoldlen;
1852     SockList sl;
1853     SockList esl; /*For extended Map info */
1854     uint16 mask, emask;
1855     uint8 eentrysize;
1856     uint16 ewhatstart, ewhatflag;
1857     uint8 extendedinfos;
1858 root 1.21 maptile *m;
1859 root 1.16
1860     NewSocket & socket = pl->contr->socket;
1861    
1862     check_map_change (pl->contr);
1863    
1864     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1865     if (socket.mapmode == Map1Cmd)
1866     strcpy ((char *) sl.buf, "map1 ");
1867     else
1868     strcpy ((char *) sl.buf, "map1a ");
1869     sl.len = strlen ((char *) sl.buf);
1870     startlen = sl.len;
1871     /*Extendedmapinfo structure initialisation */
1872     if (socket.ext_mapinfos)
1873     {
1874     esl.buf = (unsigned char *) malloc (MAXSOCKBUF);
1875     strcpy ((char *) esl.buf, "mapextended ");
1876     esl.len = strlen ((char *) esl.buf);
1877     extendedinfos = EMI_NOREDRAW;
1878     if (socket.EMI_smooth)
1879     extendedinfos |= EMI_SMOOTH;
1880     ewhatstart = esl.len;
1881     ewhatflag = extendedinfos; /*The EMI_NOREDRAW bit
1882     could need to be taken away */
1883     SockList_AddChar (&esl, extendedinfos);
1884     eentrysize = getExtendedMapInfoSize (&socket);
1885     SockList_AddChar (&esl, eentrysize);
1886     estartlen = esl.len;
1887     }
1888     else
1889     {
1890     /* suppress compiler warnings */
1891     ewhatstart = 0;
1892     ewhatflag = 0;
1893     estartlen = 0;
1894     }
1895     /* Init data to zero */
1896     memset (heads, 0, sizeof (object *) * MAX_HEAD_POS * MAX_HEAD_POS * MAX_LAYERS);
1897    
1898     /* x,y are the real map locations. ax, ay are viewport relative
1899     * locations.
1900     */
1901     ay = 0;
1902    
1903     /* We could do this logic as conditionals in the if statement,
1904     * but that started to get a bit messy to look at.
1905     */
1906     max_x = pl->x + (socket.mapx + 1) / 2;
1907     max_y = pl->y + (socket.mapy + 1) / 2;
1908     if (socket.mapmode == Map1aCmd)
1909     {
1910     max_x += MAX_HEAD_OFFSET;
1911     max_y += MAX_HEAD_OFFSET;
1912     }
1913 elmex 1.1
1914 root 1.16 for (y = pl->y - socket.mapy / 2; y < max_y; y++, ay++)
1915     {
1916     ax = 0;
1917     for (x = pl->x - socket.mapx / 2; x < max_x; x++, ax++)
1918     {
1919    
1920     emask = mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4;
1921    
1922     /* If this space is out of the normal viewable area, we only check
1923     * the heads value ax or ay will only be greater than what
1924     * the client wants if using the map1a command - this is because
1925     * if the map1a command is not used, max_x and max_y will be
1926     * set to lower values.
1927     */
1928     if (ax >= socket.mapx || ay >= socket.mapy)
1929     {
1930     int i, got_one;
1931 root 1.12
1932 root 1.16 oldlen = sl.len;
1933 root 1.12
1934 root 1.16 SockList_AddShort (&sl, mask);
1935 root 1.12
1936 root 1.16 if (check_head (sl, socket, ax, ay, 2))
1937     mask |= 0x4;
1938     if (check_head (sl, socket, ax, ay, 1))
1939     mask |= 0x2;
1940     if (check_head (sl, socket, ax, ay, 0))
1941     mask |= 0x1;
1942    
1943     /* If all we are doing is sending 0 (blank) faces, we don't
1944     * actually need to send that - just the coordinates
1945     * with no faces tells the client to blank out the
1946     * space.
1947     */
1948     got_one = 0;
1949     for (i = oldlen + 2; i < sl.len; i++)
1950     {
1951     if (sl.buf[i])
1952     got_one = 1;
1953 root 1.12 }
1954    
1955 root 1.16 if (got_one && (mask & 0xf))
1956     {
1957     sl.buf[oldlen + 1] = mask & 0xff;
1958     }
1959     else
1960     { /*either all faces blank, either no face at all */
1961     if (mask & 0xf) /*at least 1 face, we know it's blank, only send coordinates */
1962     sl.len = oldlen + 2;
1963 root 1.3 else
1964 root 1.16 sl.len = oldlen;
1965 root 1.12 }
1966 root 1.16 /*What concerns extendinfos, nothing to be done for now
1967     * (perhaps effects layer later)
1968     */
1969     continue; /* don't do processing below */
1970     }
1971    
1972     MapCell & lastcell = socket.lastmap.cells[ax][ay];
1973    
1974     d = pl->contr->blocked_los[ax][ay];
1975    
1976     /* If the coordinates are not valid, or it is too dark to see,
1977     * we tell the client as such
1978     */
1979     nx = x;
1980     ny = y;
1981     m = get_map_from_coord (pl->map, &nx, &ny);
1982     if (!m)
1983     {
1984     /* space is out of map. Update space and clear values
1985     * if this hasn't already been done. If the space is out
1986     * of the map, it shouldn't have a head
1987     */
1988     if (lastcell.count != -1)
1989     {
1990     SockList_AddShort (&sl, mask);
1991     map_clearcell (&lastcell, 0, 0, 0, -1);
1992 root 1.12 }
1993 root 1.16 }
1994     else if (d > 3)
1995     {
1996     int need_send = 0, count;
1997    
1998     /* This block deals with spaces that are not visible for whatever
1999     * reason. Still may need to send the head for this space.
2000     */
2001 root 1.12
2002 root 1.16 oldlen = sl.len;
2003 root 1.3
2004 root 1.16 SockList_AddShort (&sl, mask);
2005     if (lastcell.count != -1)
2006     need_send = 1;
2007     count = -1;
2008 root 1.3
2009 root 1.16 if (socket.mapmode == Map1aCmd && have_head (ax, ay))
2010     {
2011     /* Now check to see if any heads need to be sent */
2012 root 1.3
2013 root 1.16 if (check_head (sl, socket, ax, ay, 2))
2014     mask |= 0x4;
2015     if (check_head (sl, socket, ax, ay, 1))
2016     mask |= 0x2;
2017     if (check_head (sl, socket, ax, ay, 0))
2018     mask |= 0x1;
2019 root 1.3
2020 root 1.16 lastcell.count = count;
2021 root 1.8
2022 root 1.16 }
2023     else
2024     {
2025     struct MapCell *cell = &lastcell;
2026    
2027     /* properly clear a previously sent big face */
2028     if (cell->faces[0] != 0 || cell->faces[1] != 0 || cell->faces[2] != 0)
2029     need_send = 1;
2030     map_clearcell (&lastcell, 0, 0, 0, count);
2031     }
2032 root 1.3
2033 root 1.16 if ((mask & 0xf) || need_send)
2034     {
2035     sl.buf[oldlen + 1] = mask & 0xff;
2036     }
2037     else
2038     {
2039     sl.len = oldlen;
2040     }
2041     }
2042     else
2043     {
2044     /* In this block, the space is visible or there are head objects
2045     * we need to send.
2046     */
2047    
2048     /* Rather than try to figure out what everything that we might
2049     * need to send is, then form the packet after that,
2050     * we presume that we will in fact form a packet, and update
2051     * the bits by what we do actually send. If we send nothing,
2052     * we just back out sl.len to the old value, and no harm
2053     * is done.
2054     * I think this is simpler than doing a bunch of checks to see
2055     * what if anything we need to send, setting the bits, then
2056     * doing those checks again to add the real data.
2057     */
2058     oldlen = sl.len;
2059     mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4;
2060     eoldlen = esl.len;
2061     emask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4;
2062     SockList_AddShort (&sl, mask);
2063    
2064     if (socket.ext_mapinfos)
2065     SockList_AddShort (&esl, emask);
2066    
2067     unsigned char dummy;
2068     unsigned char *last_ext = &dummy;
2069    
2070     /* Darkness changed */
2071     if (lastcell.count != d && socket.darkness)
2072     {
2073     mask |= 0x8;
2074    
2075     if (socket.extmap)
2076     {
2077     *last_ext |= 0x80;
2078     last_ext = sl.buf + sl.len;
2079     SockList_AddChar (&sl, d);
2080     }
2081     else
2082     SockList_AddChar (&sl, 255 - 64 * d);
2083     }
2084 root 1.3
2085 root 1.16 lastcell.count = d;
2086 root 1.8
2087 root 1.16 if (socket.extmap)
2088     {
2089     uint8 stat_hp = 0;
2090     uint8 stat_width = 0;
2091     tag_t player = 0;
2092    
2093     // send hp information, if applicable
2094     if (object *op = GET_MAP_FACE_OBJ (m, nx, ny, 0))
2095     {
2096     if (op->head || op->invisible)
2097     ; // do not show
2098     else if (op->type == PLAYER
2099     || QUERY_FLAG (op, FLAG_MONSTER) || QUERY_FLAG (op, FLAG_ALIVE) || QUERY_FLAG (op, FLAG_GENERATOR))
2100     {
2101     if (op->stats.maxhp > 0 && (unsigned) op->stats.maxhp > (unsigned) op->stats.hp)
2102     {
2103     stat_hp = 255 - (op->stats.hp * 255 + 254) / op->stats.maxhp;
2104     stat_width = op->arch->tail_x;
2105     }
2106     }
2107 elmex 1.1
2108 root 1.16 if (op->type == PLAYER && op != pl)
2109     player = op->count;
2110     }
2111 root 1.12
2112 root 1.16 if (lastcell.stat_hp != stat_hp)
2113     {
2114     lastcell.stat_hp = stat_hp;
2115    
2116     mask |= 0x8;
2117     *last_ext |= 0x80;
2118     last_ext = sl.buf + sl.len;
2119     SockList_AddChar (&sl, 5);
2120     SockList_AddChar (&sl, stat_hp);
2121    
2122     if (stat_width > 1)
2123     {
2124     *last_ext |= 0x80;
2125     last_ext = sl.buf + sl.len;
2126     SockList_AddChar (&sl, 6);
2127     SockList_AddChar (&sl, stat_width);
2128     }
2129     }
2130 root 1.12
2131 root 1.20 if (lastcell.player != player)
2132 root 1.16 {
2133     lastcell.player = player;
2134    
2135     mask |= 0x8;
2136     *last_ext |= 0x80;
2137     last_ext = sl.buf + sl.len;
2138     SockList_AddChar (&sl, 0x47);
2139     SockList_AddChar (&sl, 4);
2140     SockList_AddInt (&sl, player);
2141     }
2142     }
2143 root 1.12
2144 root 1.16 /* Floor face */
2145     if (update_space (&sl, &socket, m, nx, ny, ax, ay, 2))
2146     mask |= 0x4;
2147    
2148     if (socket.EMI_smooth)
2149     if (update_smooth (&esl, &socket, m, nx, ny, ax, ay, 2))
2150     emask |= 0x4;
2151    
2152     /* Middle face */
2153     if (update_space (&sl, &socket, m, nx, ny, ax, ay, 1))
2154     mask |= 0x2;
2155    
2156     if (socket.EMI_smooth)
2157     if (update_smooth (&esl, &socket, m, nx, ny, ax, ay, 1))
2158     emask |= 0x2;
2159    
2160     if (nx == pl->x && ny == pl->y && pl->invisible & (pl->invisible < 50 ? 4 : 1))
2161     {
2162     if (lastcell.faces[0] != pl->face->number)
2163     {
2164     lastcell.faces[0] = pl->face->number;
2165     mask |= 0x1;
2166     if (!(socket.faces_sent[pl->face->number] & NS_FACESENT_FACE))
2167     esrv_send_face (&socket, pl->face->number, 0);
2168     SockList_AddShort (&sl, pl->face->number);
2169 root 1.12 }
2170     }
2171 root 1.16 /* Top face */
2172     else
2173     {
2174     if (update_space (&sl, &socket, m, nx, ny, ax, ay, 0))
2175     mask |= 0x1;
2176     if (socket.EMI_smooth)
2177     if (update_smooth (&esl, &socket, m, nx, ny, ax, ay, 0))
2178     {
2179     emask |= 0x1;
2180     }
2181     }
2182     /* Check to see if we are in fact sending anything for this
2183     * space by checking the mask. If so, update the mask.
2184     * if not, reset the len to that from before adding the mask
2185     * value, so we don't send those bits.
2186     */
2187     if (mask & 0xf)
2188     {
2189     sl.buf[oldlen + 1] = mask & 0xff;
2190     }
2191     else
2192     {
2193     sl.len = oldlen;
2194 root 1.12 }
2195 root 1.16 if (emask & 0xf)
2196     {
2197     esl.buf[eoldlen + 1] = emask & 0xff;
2198 root 1.12 }
2199 root 1.16 else
2200     {
2201     esl.len = eoldlen;
2202 root 1.12 }
2203 root 1.16 } /* else this is a viewable space */
2204     } /* for x loop */
2205     } /* for y loop */
2206    
2207     /* Verify that we in fact do need to send this */
2208     if (socket.ext_mapinfos)
2209     {
2210     if (!(sl.len > startlen || socket.sent_scroll))
2211     {
2212     /* No map data will follow, so don't say the client
2213     * it doesn't need draw!
2214     */
2215     ewhatflag &= (~EMI_NOREDRAW);
2216     esl.buf[ewhatstart + 1] = ewhatflag & 0xff;
2217     }
2218 root 1.18
2219 root 1.16 if (esl.len > estartlen)
2220 root 1.18 Send_With_Handling (&socket, &esl);
2221    
2222 root 1.16 free (esl.buf);
2223     }
2224 root 1.18
2225 root 1.16 if (sl.len > startlen || socket.sent_scroll)
2226     {
2227     Send_With_Handling (&socket, &sl);
2228     socket.sent_scroll = 0;
2229 elmex 1.1 }
2230 root 1.18
2231 root 1.16 free (sl.buf);
2232 elmex 1.1 }
2233    
2234     /**
2235     * Draws client map.
2236     */
2237 root 1.16 void
2238     draw_client_map (object *pl)
2239 elmex 1.1 {
2240 root 1.16 int i, j;
2241     sint16 ax, ay, nx, ny; /* ax and ay goes from 0 to max-size of arrays */
2242     New_Face *face, *floor;
2243     New_Face *floor2;
2244     int d, mflags;
2245     struct Map newmap;
2246 root 1.21 maptile *m, *pm;
2247 root 1.16
2248     if (pl->type != PLAYER)
2249     {
2250     LOG (llevError, "draw_client_map called with non player/non eric-server\n");
2251     return;
2252     }
2253    
2254     pm = pl->map;
2255    
2256     /* If player is just joining the game, he isn't here yet, so the map
2257     * can get swapped out. If so, don't try to send them a map. All will
2258     * be OK once they really log in.
2259     */
2260     if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
2261     return;
2262    
2263     memset (&newmap, 0, sizeof (struct Map));
2264    
2265     for (j = (pl->y - pl->contr->socket.mapy / 2); j < (pl->y + (pl->contr->socket.mapy + 1) / 2); j++)
2266     {
2267     for (i = (pl->x - pl->contr->socket.mapx / 2); i < (pl->x + (pl->contr->socket.mapx + 1) / 2); i++)
2268     {
2269     ax = i;
2270     ay = j;
2271     m = pm;
2272     mflags = get_map_flags (m, &m, ax, ay, &ax, &ay);
2273     if (mflags & P_OUT_OF_MAP)
2274     continue;
2275     if (mflags & P_NEED_UPDATE)
2276     update_position (m, ax, ay);
2277     /* If a map is visible to the player, we don't want to swap it out
2278     * just to reload it. This should really call something like
2279     * swap_map, but this is much more efficient and 'good enough'
2280     */
2281     if (mflags & P_NEW_MAP)
2282     m->timeout = 50;
2283     }
2284     }
2285     /* do LOS after calls to update_position */
2286     if (pl->contr->do_los)
2287     {
2288     update_los (pl);
2289     pl->contr->do_los = 0;
2290     }
2291    
2292     if (pl->contr->socket.mapmode == Map1Cmd || pl->contr->socket.mapmode == Map1aCmd)
2293     {
2294     /* Big maps need a different drawing mechanism to work */
2295     draw_client_map1 (pl);
2296     return;
2297     }
2298    
2299     if (pl->invisible & (pl->invisible < 50 ? 4 : 1))
2300     {
2301     esrv_map_setbelow (&pl->contr->socket, pl->contr->socket.mapx / 2, pl->contr->socket.mapy / 2, pl->face->number, &newmap);
2302     }
2303    
2304     /* j and i are the y and x coordinates of the real map (which is
2305     * basically some number of spaces around the player)
2306     * ax and ay are values from within the viewport (ie, 0, 0 is upper
2307     * left corner) and are thus disconnected from the map values.
2308     * Subtract 1 from the max values so that we properly handle cases where
2309     * player has specified an even map. Otherwise, we try to send them too
2310     * much, ie, if mapx is 10, we would try to send from -5 to 5, which is actually
2311     * 11 spaces. Now, we would send from -5 to 4, which is properly. If mapx is
2312     * odd, this still works fine.
2313     */
2314     ay = 0;
2315     for (j = pl->y - pl->contr->socket.mapy / 2; j <= pl->y + (pl->contr->socket.mapy - 1) / 2; j++, ay++)
2316     {
2317     ax = 0;
2318     for (i = pl->x - pl->contr->socket.mapx / 2; i <= pl->x + (pl->contr->socket.mapx - 1) / 2; i++, ax++)
2319     {
2320    
2321     d = pl->contr->blocked_los[ax][ay];
2322     /* note the out_of_map and d>3 checks are both within the same
2323     * negation check.
2324     */
2325     nx = i;
2326     ny = j;
2327     m = get_map_from_coord (pm, &nx, &ny);
2328     if (m && d < 4)
2329     {
2330     face = GET_MAP_FACE (m, nx, ny, 0);
2331     floor2 = GET_MAP_FACE (m, nx, ny, 1);
2332     floor = GET_MAP_FACE (m, nx, ny, 2);
2333    
2334     /* If all is blank, send a blank face. */
2335     if ((!face || face == blank_face) && (!floor2 || floor2 == blank_face) && (!floor || floor == blank_face))
2336     {
2337     esrv_map_setbelow (&pl->contr->socket, ax, ay, blank_face->number, &newmap);
2338     }
2339     else
2340     { /* actually have something interesting */
2341 root 1.12 /* send the darkness mask, if any. */
2342 root 1.16 if (d && pl->contr->socket.darkness)
2343     esrv_map_setbelow (&pl->contr->socket, ax, ay, dark_faces[d - 1]->number, &newmap);
2344    
2345     if (face && face != blank_face)
2346     esrv_map_setbelow (&pl->contr->socket, ax, ay, face->number, &newmap);
2347     if (floor2 && floor2 != blank_face)
2348     esrv_map_setbelow (&pl->contr->socket, ax, ay, floor2->number, &newmap);
2349     if (floor && floor != blank_face)
2350     esrv_map_setbelow (&pl->contr->socket, ax, ay, floor->number, &newmap);
2351     }
2352     } /* Is a valid space */
2353 root 1.12 }
2354 elmex 1.1 }
2355 root 1.16 esrv_map_doneredraw (&pl->contr->socket, &newmap);
2356 elmex 1.1
2357 root 1.16 check_map_change (pl->contr);
2358 elmex 1.1 }
2359    
2360    
2361     /*****************************************************************************/
2362 root 1.16
2363 elmex 1.1 /* GROS: The following one is used to allow a plugin to send a generic cmd to*/
2364 root 1.16
2365 elmex 1.1 /* a player. Of course, the client need to know the command to be able to */
2366 root 1.16
2367 elmex 1.1 /* manage it ! */
2368 root 1.16
2369 elmex 1.1 /*****************************************************************************/
2370 root 1.16 void
2371     send_plugin_custom_message (object *pl, char *buf)
2372 elmex 1.1 {
2373 root 1.16 cs_write_string (&pl->contr->socket, buf, strlen (buf));
2374 elmex 1.1 }
2375    
2376     /**
2377     * This sends the skill number to name mapping. We ignore
2378     * the params - we always send the same info no matter what.
2379     */
2380 root 1.16 void
2381     send_skill_info (NewSocket * ns, char *params)
2382 elmex 1.1 {
2383 root 1.16 SockList sl;
2384     int i;
2385 elmex 1.1
2386 root 1.16 sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2387     strcpy ((char *) sl.buf, "replyinfo skill_info\n");
2388     for (i = 1; i < NUM_SKILLS; i++)
2389     {
2390     sprintf ((char *) sl.buf + strlen ((char *) sl.buf), "%d:%s\n", i + CS_STAT_SKILLINFO, &skill_names[i]);
2391     }
2392     sl.len = strlen ((char *) sl.buf);
2393     if (sl.len >= MAXSOCKBUF)
2394     {
2395     LOG (llevError, "Buffer overflow in send_skill_info!\n");
2396     fatal (0);
2397 elmex 1.1 }
2398 root 1.16 Send_With_Handling (ns, &sl);
2399     free (sl.buf);
2400 elmex 1.1 }
2401    
2402     /**
2403     * This sends the spell path to name mapping. We ignore
2404     * the params - we always send the same info no matter what.
2405     */
2406 root 1.16 void
2407     send_spell_paths (NewSocket * ns, char *params)
2408     {
2409     SockList sl;
2410     int i;
2411    
2412     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2413     strcpy ((char *) sl.buf, "replyinfo spell_paths\n");
2414     for (i = 0; i < NRSPELLPATHS; i++)
2415     sprintf ((char *) sl.buf + strlen ((char *) sl.buf), "%d:%s\n", 1 << i, spellpathnames[i]);
2416     sl.len = strlen ((char *) sl.buf);
2417     if (sl.len >= MAXSOCKBUF)
2418     {
2419     LOG (llevError, "Buffer overflow in send_spell_paths!\n");
2420     fatal (0);
2421 elmex 1.1 }
2422 root 1.16 Send_With_Handling (ns, &sl);
2423     free (sl.buf);
2424 elmex 1.1 }
2425    
2426     /**
2427     * This looks for any spells the player may have that have changed their stats.
2428     * it then sends an updspell packet for each spell that has changed in this way
2429     */
2430 root 1.16 void
2431     esrv_update_spells (player *pl)
2432     {
2433     SockList sl;
2434     int flags = 0;
2435     object *spell;
2436    
2437     if (!pl->socket.monitor_spells)
2438     return;
2439     for (spell = pl->ob->inv; spell != NULL; spell = spell->below)
2440     {
2441     if (spell->type == SPELL)
2442     {
2443     /* check if we need to update it */
2444     if (spell->last_sp != SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA))
2445     {
2446     spell->last_sp = SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA);
2447     flags |= UPD_SP_MANA;
2448     }
2449     if (spell->last_grace != SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE))
2450     {
2451     spell->last_grace = SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE);
2452     flags |= UPD_SP_GRACE;
2453     }
2454     if (spell->last_eat != spell->stats.dam + SP_level_dam_adjust (pl->ob, spell))
2455     {
2456     spell->last_eat = spell->stats.dam + SP_level_dam_adjust (pl->ob, spell);
2457     flags |= UPD_SP_DAMAGE;
2458     }
2459     if (flags != 0)
2460     {
2461     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2462     strcpy ((char *) sl.buf, "updspell ");
2463     sl.len = strlen ((char *) sl.buf);
2464     SockList_AddChar (&sl, flags);
2465     SockList_AddInt (&sl, spell->count);
2466     if (flags & UPD_SP_MANA)
2467     SockList_AddShort (&sl, spell->last_sp);
2468     if (flags & UPD_SP_GRACE)
2469     SockList_AddShort (&sl, spell->last_grace);
2470     if (flags & UPD_SP_DAMAGE)
2471     SockList_AddShort (&sl, spell->last_eat);
2472     flags = 0;
2473     Send_With_Handling (&pl->socket, &sl);
2474     free (sl.buf);
2475 root 1.12 }
2476     }
2477 elmex 1.1 }
2478     }
2479    
2480 root 1.16 void
2481     esrv_remove_spell (player *pl, object *spell)
2482     {
2483     SockList sl;
2484    
2485     if (!pl->socket.monitor_spells)
2486     return;
2487     if (!pl || !spell || spell->env != pl->ob)
2488     {
2489     LOG (llevError, "Invalid call to esrv_remove_spell");
2490     return;
2491     }
2492     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2493     strcpy ((char *) sl.buf, "delspell ");
2494     sl.len = strlen ((char *) sl.buf);
2495     SockList_AddInt (&sl, spell->count);
2496     Send_With_Handling (&pl->socket, &sl);
2497     free (sl.buf);
2498 elmex 1.1 }
2499    
2500     /* appends the spell *spell to the Socklist we will send the data to. */
2501 root 1.16 static void
2502     append_spell (player *pl, SockList * sl, object *spell)
2503     {
2504     int len, i, skill = 0;
2505    
2506     if (!(spell->name))
2507     {
2508     LOG (llevError, "item number %d is a spell with no name.\n", spell->count);
2509     return;
2510     }
2511     SockList_AddInt (sl, spell->count);
2512     SockList_AddShort (sl, spell->level);
2513     SockList_AddShort (sl, spell->casting_time);
2514     /* store costs and damage in the object struct, to compare to later */
2515     spell->last_sp = SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA);
2516     spell->last_grace = SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE);
2517     spell->last_eat = spell->stats.dam + SP_level_dam_adjust (pl->ob, spell);
2518     /* send the current values */
2519     SockList_AddShort (sl, spell->last_sp);
2520     SockList_AddShort (sl, spell->last_grace);
2521     SockList_AddShort (sl, spell->last_eat);
2522 elmex 1.1
2523 root 1.16 /* figure out which skill it uses, if it uses one */
2524     if (spell->skill)
2525     {
2526     for (i = 1; i < NUM_SKILLS; i++)
2527     if (!strcmp (spell->skill, skill_names[i]))
2528     {
2529     skill = i + CS_STAT_SKILLINFO;
2530     break;
2531     }
2532 elmex 1.1 }
2533 root 1.16 SockList_AddChar (sl, skill);
2534 elmex 1.1
2535 root 1.16 SockList_AddInt (sl, spell->path_attuned);
2536     SockList_AddInt (sl, (spell->face) ? spell->face->number : 0);
2537 elmex 1.1
2538 root 1.16 len = strlen (spell->name);
2539     SockList_AddChar (sl, (char) len);
2540     memcpy (sl->buf + sl->len, spell->name, len);
2541     sl->len += len;
2542    
2543     if (!spell->msg)
2544     {
2545     SockList_AddShort (sl, 0);
2546     }
2547     else
2548     {
2549     len = strlen (spell->msg);
2550     SockList_AddShort (sl, len);
2551     memcpy (sl->buf + sl->len, spell->msg, len);
2552     sl->len += len;
2553 elmex 1.1 }
2554     }
2555    
2556     /**
2557     * This tells the client to add the spell *ob, if *ob is NULL, then add
2558     * all spells in the player's inventory.
2559     */
2560 root 1.16 void
2561     esrv_add_spells (player *pl, object *spell)
2562     {
2563     SockList sl;
2564    
2565     if (!pl)
2566     {
2567     LOG (llevError, "esrv_add_spells, tried to add a spell to a NULL player");
2568     return;
2569     }
2570     if (!pl->socket.monitor_spells)
2571     return;
2572     sl.buf = (unsigned char *) malloc (MAXSOCKBUF);
2573     strcpy ((char *) sl.buf, "addspell ");
2574     sl.len = strlen ((char *) sl.buf);
2575     if (!spell)
2576     {
2577     for (spell = pl->ob->inv; spell != NULL; spell = spell->below)
2578     {
2579     /* were we to simply keep appending data here, we could exceed
2580     * MAXSOCKBUF if the player has enough spells to add, we know that
2581     * append_spells will always append 19 data bytes, plus 4 length
2582     * bytes and 3 strings (because that is the spec) so we need to
2583     * check that the length of those 3 strings, plus the 23 bytes,
2584     * won't take us over the length limit for the socket, if it does,
2585     * we need to send what we already have, and restart packet formation
2586     */
2587     /* Seeing crashes by overflowed buffers. Quick arithemetic seems
2588     * to show add_spell is 26 bytes + 2 strings. However, the overun
2589     * is hundreds of bytes off, so correcting 22 vs 26 doesn't seem
2590     * like it will fix this
2591     */
2592     if (spell->type != SPELL)
2593     continue;
2594     if (sl.len >= (MAXSOCKBUF - (26 + strlen (spell->name) + (spell->msg ? strlen (spell->msg) : 0))))
2595     {
2596     Send_With_Handling (&pl->socket, &sl);
2597     strcpy ((char *) sl.buf, "addspell ");
2598     sl.len = strlen ((char *) sl.buf);
2599     }
2600     append_spell (pl, &sl, spell);
2601     }
2602     }
2603     else if (spell->type != SPELL)
2604     {
2605     LOG (llevError, "Asked to send a non-spell object as a spell");
2606     return;
2607     }
2608     else
2609     append_spell (pl, &sl, spell);
2610     if (sl.len >= MAXSOCKBUF)
2611     {
2612     LOG (llevError, "Buffer overflow in esrv_add_spells!\n");
2613     fatal (0);
2614     }
2615     /* finally, we can send the packet */
2616     Send_With_Handling (&pl->socket, &sl);
2617     free (sl.buf);
2618 elmex 1.1 }