ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/request.C
Revision: 1.91
Committed: Mon Apr 30 04:25:30 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.90: +32 -0 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 pippijn 1.64 * CrossFire, A Multiplayer game for X-windows
3     *
4     * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5     * Copyright (C) 2001 Mark Wedel
6     * Copyright (C) 1992 Frank Tore Johansen
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *
22     * The author can be reached via e-mail to <crossfire@schmorp.de>
23     */
24 elmex 1.1
25     /**
26     * \file
27     * Client handling.
28     *
29     * \date 2003-12-02
30     *
31     * This file implements all of the goo on the server side for handling
32     * clients. It's got a bunch of global variables for keeping track of
33     * each of the clients.
34     *
35     * Note: All functions that are used to process data from the client
36     * have the prototype of (char *data, int datalen, int client_num). This
37     * way, we can use one dispatch table.
38     *
39     * esrv_map_new starts updating the map
40     *
41     */
42    
43     #include <global.h>
44     #include <sproto.h>
45    
46     #include <living.h>
47     #include <commands.h>
48    
49     /* This block is basically taken from socket.c - I assume if it works there,
50     * it should work here.
51     */
52 pippijn 1.26 #include <sys/types.h>
53     #include <sys/time.h>
54     #include <sys/socket.h>
55     #include <netinet/in.h>
56     #include <netdb.h>
57 elmex 1.1
58 root 1.38 #include <unistd.h>
59     #include <sys/time.h>
60 elmex 1.1
61     #include "sounds.h"
62    
63     /**
64     * This table translates the attack numbers as used within the
65     * program to the value we use when sending STATS command to the
66     * client. If a value is -1, then we don't send that to the
67     * client.
68     */
69 root 1.16 short atnr_cs_stat[NROFATTACKS] = { CS_STAT_RES_PHYS,
70     CS_STAT_RES_MAG, CS_STAT_RES_FIRE, CS_STAT_RES_ELEC,
71     CS_STAT_RES_COLD, CS_STAT_RES_CONF, CS_STAT_RES_ACID,
72     CS_STAT_RES_DRAIN, -1 /* weaponmagic */ ,
73     CS_STAT_RES_GHOSTHIT, CS_STAT_RES_POISON,
74     CS_STAT_RES_SLOW, CS_STAT_RES_PARA, CS_STAT_TURN_UNDEAD,
75     CS_STAT_RES_FEAR, -1 /* Cancellation */ ,
76     CS_STAT_RES_DEPLETE, CS_STAT_RES_DEATH,
77     -1 /* Chaos */ , -1 /* Counterspell */ ,
78     -1 /* Godpower */ , CS_STAT_RES_HOLYWORD,
79     CS_STAT_RES_BLIND,
80     -1, /* Internal */
81     -1, /* life stealing */
82     -1 /* Disease - not fully done yet */
83 elmex 1.1 };
84    
85 root 1.2 static void
86 root 1.43 socket_map_scroll (client *ns, int dx, int dy)
87 root 1.2 {
88 root 1.16 struct Map newmap;
89     int x, y, mx, my;
90 root 1.2
91 root 1.42 ns->send_packet_printf ("map_scroll %d %d", dx, dy);
92 root 1.2
93 root 1.16 /* If we are using the Map1aCmd, we may in fact send
94     * head information that is outside the viewable map.
95     * So set the mx,my to the max value we want to
96     * look for. Removed code to do so - it caused extra
97     * complexities for the client, and probably doesn't make
98     * that much difference in bandwidth.
99     */
100     mx = ns->mapx;
101     my = ns->mapy;
102 root 1.2
103 root 1.16 /* the x and y here are coordinates for the new map, i.e. if we moved
104     * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
105     * if the destination x or y coordinate is outside the viewable
106     * area, we clear the values - otherwise, the old values
107     * are preserved, and the check_head thinks it needs to clear them.
108     */
109     for (x = 0; x < mx; x++)
110     {
111     for (y = 0; y < my; y++)
112     {
113     if (x >= ns->mapx || y >= ns->mapy)
114 root 1.25 /* clear cells outside the viewable area */
115     memset (&newmap.cells[x][y], 0, sizeof (struct MapCell));
116 root 1.16 else if ((x + dx) < 0 || (x + dx) >= ns->mapx || (y + dy) < 0 || (y + dy) >= ns->mapy)
117 root 1.25 /* clear newly visible tiles within the viewable area */
118     memset (&(newmap.cells[x][y]), 0, sizeof (struct MapCell));
119 root 1.16 else
120 root 1.25 memcpy (&(newmap.cells[x][y]), &(ns->lastmap.cells[x + dx][y + dy]), sizeof (struct MapCell));
121 root 1.12 }
122 root 1.2 }
123    
124 root 1.16 memcpy (&(ns->lastmap), &newmap, sizeof (struct Map));
125 root 1.2
126 root 1.16 /* Make sure that the next "map1" command will be sent (even if it is
127     * empty).
128     */
129     ns->sent_scroll = 1;
130 root 1.2 }
131    
132 root 1.7 static void
133     clear_map (player *pl)
134     {
135 root 1.50 memset (&pl->ns->lastmap, 0, sizeof (pl->ns->lastmap));
136 root 1.7
137 root 1.79 pl->ns->force_newmap = false;
138    
139 root 1.50 if (pl->ns->newmapcmd == 1)
140     pl->ns->send_packet ("newmap");
141 root 1.7
142 root 1.50 pl->ns->floorbox_reset ();
143 root 1.7 }
144    
145 root 1.66 /** check for map/region change and send new map data */
146 elmex 1.1 static void
147     check_map_change (player *pl)
148     {
149 root 1.50 client &socket = *pl->ns;
150 root 1.2 object *ob = pl->ob;
151 root 1.16 char buf[MAX_BUF]; /* eauugggh */
152 elmex 1.1
153 root 1.85 if (socket.current_map != ob->map || socket.force_newmap)
154 root 1.79 {
155 root 1.7 clear_map (pl);
156 root 1.80 socket.current_map = ob->map;
157 elmex 1.1
158 root 1.2 if (socket.mapinfocmd)
159 elmex 1.1 {
160 root 1.16 if (ob->map && ob->map->path[0])
161 root 1.2 {
162     int flags = 0;
163 elmex 1.1
164 root 1.90 if (ob->map->tile_path[0]) flags |= 1;
165     if (ob->map->tile_path[1]) flags |= 2;
166     if (ob->map->tile_path[2]) flags |= 4;
167     if (ob->map->tile_path[3]) flags |= 8;
168 root 1.2
169     snprintf (buf, MAX_BUF, "mapinfo - spatial %d %d %d %d %d %s",
170 root 1.55 flags, socket.mapx / 2 - ob->x, socket.mapy / 2 - ob->y, ob->map->width, ob->map->height, &ob->map->path);
171 root 1.2 }
172     else
173     snprintf (buf, MAX_BUF, "mapinfo current");
174 elmex 1.1
175 root 1.32 socket.send_packet (buf);
176 root 1.16 }
177 elmex 1.1 }
178 root 1.2 else if (socket.current_x != ob->x || socket.current_y != ob->y)
179     {
180 root 1.7 int dx = ob->x - socket.current_x;
181     int dy = ob->y - socket.current_y;
182    
183     if (socket.buggy_mapscroll && (abs (dx) > 8 || abs (dy) > 8))
184 root 1.16 clear_map (pl); // current (<= 1.9.1) clients have unchecked buffer overflows
185 root 1.7 else
186     {
187     socket_map_scroll (&socket, ob->x - socket.current_x, ob->y - socket.current_y);
188 root 1.46 socket.floorbox_reset ();
189 root 1.7 }
190 root 1.2 }
191    
192     socket.current_x = ob->x;
193     socket.current_y = ob->y;
194 root 1.66
195     region *reg = ob->region ();
196     if (socket.current_region != reg)
197     {
198     socket.current_region = reg;
199     socket.send_packet_printf ("drawinfo 0 You are now %s.\n(use whereami for more details)", &reg->longname);
200     }
201 elmex 1.1 }
202    
203 root 1.40 /**
204     * RequestInfo is sort of a meta command. There is some specific
205     * request of information, but we call other functions to provide
206     * that information.
207     */
208     void
209 root 1.41 RequestInfo (char *buf, int len, client * ns)
210 root 1.40 {
211     char *params = NULL, *cp;
212    
213     /* No match */
214     char bigbuf[MAX_BUF];
215     int slen;
216    
217     /* Set up replyinfo before we modify any of the buffers - this is used
218     * if we don't find a match.
219     */
220     strcpy (bigbuf, "replyinfo ");
221     slen = strlen (bigbuf);
222     safe_strcat (bigbuf, buf, &slen, MAX_BUF);
223    
224     /* find the first space, make it null, and update the
225     * params pointer.
226     */
227     for (cp = buf; *cp != '\0'; cp++)
228     if (*cp == ' ')
229     {
230     *cp = '\0';
231     params = cp + 1;
232     break;
233     }
234    
235     if (!strcmp (buf, "image_info"))
236     send_image_info (ns, params);
237     else if (!strcmp (buf, "image_sums"))
238     send_image_sums (ns, params);
239     else if (!strcmp (buf, "skill_info"))
240     send_skill_info (ns, params);
241     else if (!strcmp (buf, "spell_paths"))
242     send_spell_paths (ns, params);
243     else
244     ns->send_packet (bigbuf, len);
245     }
246    
247 root 1.16 void
248     ExtCmd (char *buf, int len, player *pl)
249 elmex 1.1 {
250 root 1.10 INVOKE_PLAYER (EXTCMD, pl, ARG_DATA (buf, len));
251 elmex 1.1 }
252    
253 root 1.16 void
254 root 1.45 ExtiCmd (char *buf, int len, client *ns)
255     {
256     INVOKE_CLIENT (EXTICMD, ns, ARG_DATA (buf, len));
257     }
258    
259     void
260 root 1.16 MapInfoCmd (char *buf, int len, player *pl)
261 elmex 1.1 {
262     // <mapinfo tag spatial tile-path
263     // >mapinfo tag spatial flags x y w h hash
264 root 1.16
265 pippijn 1.15 char bigbuf[MAX_BUF], *token;
266 elmex 1.1
267     token = buf;
268     // copy token
269     if (!(buf = strchr (buf, ' ')))
270     return;
271    
272     *buf++ = 0;
273    
274     if (!strncmp (buf, "spatial ", 8))
275     {
276     buf += 8;
277    
278     // initial map and its origin
279 root 1.21 maptile *map = pl->ob->map;
280 elmex 1.1 sint16 dx, dy;
281 root 1.50 int mapx = pl->ns->mapx / 2 - pl->ob->x;
282     int mapy = pl->ns->mapy / 2 - pl->ob->y;
283 root 1.16 int max_distance = 8; // limit maximum path length to something generous
284 elmex 1.1
285     while (*buf && map && max_distance)
286     {
287     int dir = *buf++;
288    
289     switch (dir)
290     {
291 root 1.58 case '1':
292     dx = 0;
293     dy = -1;
294     map = map->xy_find (dx, dy);
295     map && (mapy -= map->height);
296     break;
297     case '2':
298     mapx += map->width;
299     dx = map->width;
300     dy = 0;
301     map = map->xy_find (dx, dy);
302     break;
303     case '3':
304     mapy += map->height;
305     dx = 0;
306     dy = map->height;
307     map = map->xy_find (dx, dy);
308     break;
309     case '4':
310     dx = -1;
311     dy = 0;
312     map = map->xy_find (dx, dy);
313     map && (mapx -= map->width);
314     break;
315 elmex 1.1 }
316    
317     --max_distance;
318     }
319    
320     if (!max_distance)
321     snprintf (bigbuf, MAX_BUF, "mapinfo %s error", token);
322 root 1.16 else if (map && map->path[0])
323 elmex 1.1 {
324     int flags = 0;
325    
326 root 1.90 if (map->tile_path[0]) flags |= 1;
327     if (map->tile_path[1]) flags |= 2;
328     if (map->tile_path[2]) flags |= 4;
329     if (map->tile_path[3]) flags |= 8;
330 root 1.16
331 root 1.55 snprintf (bigbuf, MAX_BUF, "mapinfo %s spatial %d %d %d %d %d %s", token, flags, mapx, mapy, map->width, map->height, &map->path);
332 elmex 1.1 }
333     else
334     snprintf (bigbuf, MAX_BUF, "mapinfo %s nomap", token);
335     }
336     else
337     snprintf (bigbuf, MAX_BUF, "mapinfo %s unsupported", token);
338 root 1.16
339 root 1.50 pl->ns->send_packet (bigbuf);
340 elmex 1.1 }
341    
342 root 1.83 /** This is the Setup cmd */
343 root 1.16 void
344 root 1.41 SetUp (char *buf, int len, client * ns)
345 elmex 1.1 {
346 root 1.83 INVOKE_CLIENT (SETUP, ns, ARG_DATA (buf, len));
347 elmex 1.1 }
348    
349     /**
350     * The client has requested to be added to the game.
351     * This is what takes care of it. We tell the client how things worked out.
352     * I am not sure if this file is the best place for this function. however,
353     * it either has to be here or init_sockets needs to be exported.
354     */
355 root 1.16 void
356 root 1.77 AddMeCmd (char *buf, int len, client *ns)
357 elmex 1.1 {
358 root 1.51 INVOKE_CLIENT (ADDME, ns, ARG_DATA (buf, len));
359 elmex 1.1 }
360    
361     /** Reply to ExtendedInfos command */
362 root 1.16 void
363 root 1.41 ToggleExtendedInfos (char *buf, int len, client * ns)
364 root 1.16 {
365     char cmdback[MAX_BUF];
366     char command[50];
367     int info, nextinfo;
368    
369     cmdback[0] = '\0';
370     nextinfo = 0;
371 root 1.17
372 root 1.16 while (1)
373     {
374     /* 1. Extract an info */
375     info = nextinfo;
376 root 1.17
377 root 1.16 while ((info < len) && (buf[info] == ' '))
378     info++;
379 root 1.17
380 root 1.16 if (info >= len)
381     break;
382 root 1.17
383 root 1.16 nextinfo = info + 1;
384 root 1.17
385 root 1.16 while ((nextinfo < len) && (buf[nextinfo] != ' '))
386     nextinfo++;
387 root 1.17
388 root 1.16 if (nextinfo - info >= 49) /*Erroneous info asked */
389     continue;
390 root 1.17
391 root 1.16 strncpy (command, &(buf[info]), nextinfo - info);
392 root 1.17
393 root 1.16 /* 2. Interpret info */
394     if (!strcmp ("smooth", command))
395 root 1.17 /* Toggle smoothing */
396     ns->EMI_smooth = !ns->EMI_smooth;
397 root 1.16 else
398 root 1.17 /*bad value */;
399    
400 root 1.16 /*3. Next info */
401     }
402 root 1.17
403 root 1.16 strcpy (cmdback, "ExtendedInfoSet");
404 root 1.17
405 root 1.16 if (ns->EMI_smooth)
406     {
407     strcat (cmdback, " ");
408     strcat (cmdback, "smoothing");
409     }
410 root 1.17
411 root 1.32 ns->send_packet (cmdback);
412 elmex 1.1 }
413 root 1.16
414 elmex 1.1 /*
415     #define MSG_TYPE_BOOK 1
416     #define MSG_TYPE_CARD 2
417     #define MSG_TYPE_PAPER 3
418     #define MSG_TYPE_SIGN 4
419     #define MSG_TYPE_MONUMENT 5
420     #define MSG_TYPE_SCRIPTED_DIALOG 6*/
421 root 1.16
422 elmex 1.1 /** Reply to ExtendedInfos command */
423 root 1.16 void
424 root 1.41 ToggleExtendedText (char *buf, int len, client * ns)
425 root 1.16 {
426     char cmdback[MAX_BUF];
427     char temp[10];
428     char command[50];
429     int info, nextinfo, i, flag;
430    
431     cmdback[0] = '\0';
432 root 1.17
433 root 1.16 nextinfo = 0;
434     while (1)
435     {
436     /* 1. Extract an info */
437     info = nextinfo;
438 root 1.17
439 root 1.16 while ((info < len) && (buf[info] == ' '))
440     info++;
441 root 1.17
442 root 1.16 if (info >= len)
443     break;
444 root 1.17
445 root 1.16 nextinfo = info + 1;
446 root 1.17
447 root 1.16 while ((nextinfo < len) && (buf[nextinfo] != ' '))
448     nextinfo++;
449 root 1.17
450 root 1.16 if (nextinfo - info >= 49) /*Erroneous info asked */
451     continue;
452 root 1.17
453 root 1.16 strncpy (command, &(buf[info]), nextinfo - info);
454     command[nextinfo - info] = '\0';
455     /* 2. Interpret info */
456     i = sscanf (command, "%d", &flag);
457 root 1.17
458 root 1.16 if ((i == 1) && (flag > 0) && (flag <= MSG_TYPE_LAST))
459     ns->supported_readables |= (1 << flag);
460     /*3. Next info */
461     }
462 root 1.17
463 root 1.16 /* Send resulting state */
464     strcpy (cmdback, "ExtendedTextSet");
465 root 1.17
466 root 1.16 for (i = 0; i <= MSG_TYPE_LAST; i++)
467     if (ns->supported_readables & (1 << i))
468     {
469     strcat (cmdback, " ");
470     snprintf (temp, sizeof (temp), "%d", i);
471     strcat (cmdback, temp);
472     }
473 root 1.17
474 root 1.32 ns->send_packet (cmdback);
475 elmex 1.1 }
476    
477     /**
478 root 1.77 * client requested an image. send it rate-limited
479     * before flushing.
480     */
481     void
482     AskFaceCmd (char *buf, int len, client *ns)
483     {
484     ns->askface.push_back (atoi (buf));
485     }
486    
487     /**
488 root 1.68 * Tells client the picture it has to use
489     * to smooth a picture number given as argument.
490     */
491 root 1.16 void
492 root 1.44 AskSmooth (char *buf, int len, client *ns)
493 root 1.16 {
494 root 1.74 ns->send_face (atoi (buf));
495 root 1.84 ns->flush_fx ();
496 elmex 1.1 }
497    
498     /**
499     * This handles the general commands from the client (ie, north, fire, cast,
500     * etc.)
501     */
502 root 1.16 void
503     PlayerCmd (char *buf, int len, player *pl)
504 elmex 1.1 {
505 root 1.16 /* Check if there is a count. In theory, a zero count could also be
506     * sent, so check for that also.
507     */
508     if (atoi (buf) || buf[0] == '0')
509     {
510     pl->count = atoi ((char *) buf);
511 root 1.44
512 root 1.16 buf = strchr (buf, ' '); /* advance beyond the numbers */
513     if (!buf)
514 root 1.44 return;
515    
516 root 1.16 buf++;
517 elmex 1.1 }
518 root 1.44
519 root 1.16 execute_newserver_command (pl->ob, (char *) buf);
520 root 1.44
521 root 1.16 /* Perhaps something better should be done with a left over count.
522     * Cleaning up the input should probably be done first - all actions
523     * for the command that issued the count should be done before any other
524     * commands.
525     */
526     pl->count = 0;
527 elmex 1.1 }
528    
529    
530     /**
531     * This handles the general commands from the client (ie, north, fire, cast,
532     * etc.). It is a lot like PlayerCmd above, but is called with the
533     * 'ncom' method which gives more information back to the client so it
534     * can throttle.
535     */
536 root 1.16 void
537 root 1.39 NewPlayerCmd (char *buf, int len, player *pl)
538 elmex 1.1 {
539 root 1.44 if (len <= 6)
540 root 1.16 {
541     LOG (llevDebug, "Corrupt ncom command <%s> not long enough - discarding\n", buf);
542     return;
543     }
544    
545 root 1.44 uint16 cmdid = net_uint16 ((uint8 *)buf);
546     sint32 repeat = net_sint32 ((uint8 *)buf + 2);
547 root 1.30
548 root 1.16 /* -1 is special - no repeat, but don't update */
549     if (repeat != -1)
550 root 1.28 pl->count = repeat;
551    
552 root 1.44 buf += 6; //len -= 6;
553 root 1.16
554 root 1.44 execute_newserver_command (pl->ob, buf);
555 root 1.28
556 root 1.16 /* Perhaps something better should be done with a left over count.
557     * Cleaning up the input should probably be done first - all actions
558     * for the command that issued the count should be done before any other
559     * commands.
560     */
561     pl->count = 0;
562    
563 root 1.44 //TODO: schmorp thinks whatever this calculates, it makes no sense at all
564 root 1.65 int time = fabs (pl->ob->speed) < 0.001
565 root 1.44 ? time = MAX_TIME * 100
566 root 1.65 : time = (int) (MAX_TIME / fabs (pl->ob->speed));
567 root 1.27
568 root 1.28 /* Send confirmation of command execution now */
569 root 1.47 packet sl ("comc");
570     sl << uint16 (cmdid) << uint32 (time);
571 root 1.50 pl->ns->send_packet (sl);
572 elmex 1.1 }
573    
574     /** This is a reply to a previous query. */
575 root 1.16 void
576 root 1.49 ReplyCmd (char *buf, int len, client *ns)
577 elmex 1.1 {
578 root 1.50 if (ns->state == ST_CUSTOM)
579     {
580     INVOKE_CLIENT (REPLY, ns, ARG_DATA (buf, len));
581     return;
582     }
583    
584 root 1.49 if (!ns->pl)
585     return; //TODO: depends on the exact reply we are after
586     //TODO: but right now, we always have a ns->pl
587    
588     player *pl = ns->pl;
589    
590 root 1.16 /* This is to synthesize how the data would be stored if it
591 root 1.44 * was normally entered. A bit of a hack, and should be cleaned up
592 root 1.16 * once all the X11 code is removed from the server.
593     *
594     * We pass 13 to many of the functions because this way they
595     * think it was the carriage return that was entered, and the
596     * function then does not try to do additional input.
597     */
598     snprintf (pl->write_buf, sizeof (pl->write_buf), ":%s", buf);
599    
600     /* this avoids any hacking here */
601    
602 root 1.50 switch (ns->state)
603 root 1.16 {
604 root 1.44 case ST_PLAYING:
605     LOG (llevError, "Got reply message with ST_PLAYING input state\n");
606     break;
607    
608     case ST_GET_PARTY_PASSWORD: /* Get password for party */
609     receive_party_password (pl->ob, 13);
610     break;
611 elmex 1.1
612 root 1.44 default:
613 root 1.50 LOG (llevError, "Unknown input state: %d\n", ns->state);
614 elmex 1.1 }
615     }
616    
617     /**
618     * Client tells its version. If there is a mismatch, we close the
619     * socket. In real life, all we should care about is the client having
620     * something older than the server. If we assume the client will be
621     * backwards compatible, having it be a later version should not be a
622     * problem.
623     */
624 root 1.16 void
625 root 1.41 VersionCmd (char *buf, int len, client * ns)
626 elmex 1.1 {
627 root 1.16 if (!buf)
628     {
629     LOG (llevError, "CS: received corrupted version command\n");
630     return;
631 elmex 1.1 }
632    
633 root 1.16 ns->cs_version = atoi (buf);
634     ns->sc_version = ns->cs_version;
635 root 1.44
636     LOG (llevDebug, "connection from client <%s>\n", buf);
637    
638     //TODO: should log here just for statistics
639    
640     //if (VERSION_CS != ns->cs_version)
641     // unchecked;
642    
643     char *cp = strchr (buf + 1, ' ');
644 root 1.16 if (!cp)
645     return;
646 root 1.44
647 root 1.16 ns->sc_version = atoi (cp);
648 root 1.44
649     //if (VERSION_SC != ns->sc_version)
650     // unchecked;
651    
652 root 1.16 cp = strchr (cp + 1, ' ');
653 root 1.44
654 root 1.16 if (cp)
655     {
656 root 1.89 ns->version = cp + 1;
657 root 1.16
658 root 1.29 if (ns->sc_version < 1026)
659 root 1.44 ns->send_packet_printf ("drawinfo %d %s", NDI_RED,
660 root 1.16 "**** VERSION WARNING ****\n**** CLIENT IS TOO OLD!! UPDATE THE CLIENT!! ****");
661 elmex 1.1 }
662     }
663    
664     /** sound related functions. */
665 root 1.16 void
666 root 1.41 SetSound (char *buf, int len, client * ns)
667 elmex 1.1 {
668 root 1.16 ns->sound = atoi (buf);
669 elmex 1.1 }
670    
671     /** client wants the map resent */
672 root 1.16 void
673     MapRedrawCmd (char *buf, int len, player *pl)
674 elmex 1.1 {
675     /* This function is currently disabled; just clearing the map state results in
676     * display errors. It should clear the cache and send a newmap command.
677     * Unfortunately this solution does not work because some client versions send
678     * a mapredraw command after receiving a newmap command.
679     */
680     }
681    
682     /**
683     * Moves an object (typically, container to inventory).
684     * syntax is: move (to) (tag) (nrof)
685     */
686 root 1.16 void
687     MoveCmd (char *buf, int len, player *pl)
688 elmex 1.1 {
689 root 1.16 int vals[3], i;
690 elmex 1.1
691 root 1.16 /* A little funky here. We only cycle for 2 records, because
692 root 1.44 * we obviously are not going to find a space after the third
693     * record. Perhaps we should just replace this with a
694 root 1.16 * sscanf?
695     */
696     for (i = 0; i < 2; i++)
697     {
698     vals[i] = atoi (buf);
699 root 1.44
700 root 1.16 if (!(buf = strchr (buf, ' ')))
701     {
702     LOG (llevError, "Incomplete move command: %s\n", buf);
703     return;
704 root 1.12 }
705 root 1.44
706 root 1.16 buf++;
707 elmex 1.1 }
708 root 1.44
709 root 1.16 vals[2] = atoi (buf);
710 elmex 1.1
711     /* LOG(llevDebug,"Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
712 root 1.16 esrv_move_object (pl->ob, vals[0], vals[1], vals[2]);
713 elmex 1.1 }
714    
715     /******************************************************************************
716     *
717     * Start of commands the server sends to the client.
718     *
719     ******************************************************************************/
720    
721     /**
722     * Asks the client to query the user. This way, the client knows
723     * it needs to send something back (vs just printing out a message)
724     */
725 root 1.16 void
726 root 1.82 send_query (client *ns, uint8 flags, const char *text)
727 elmex 1.1 {
728 root 1.44 ns->send_packet_printf ("query %d %s", flags, text ? text : "");
729 elmex 1.1 }
730    
731 root 1.91 /**
732     * Get player's current range attack in obuf.
733     */
734     static void
735     rangetostring (object *ob, char *obuf)
736     {
737     dynbuf_text buf;
738    
739     player *pl = ob->contr;
740    
741     if (pl->ranged_skill)
742     {
743     buf.printf (" Range: %s", &pl->ranged_skill->name);
744    
745     if (pl->ranged_ob)
746     buf.printf (" (%s)", query_base_name (pl->ranged_ob, 0));
747     }
748    
749     if (pl->combat_skill)
750     {
751     buf.printf (" Combat: %s", &pl->combat_skill->name);
752    
753     if (pl->combat_ob)
754     buf.printf (" (%s)", query_base_name (pl->combat_ob, 0));
755     }
756    
757     if (pl->golem)
758     buf.printf (" Golem: %s", &pl->golem->name);
759    
760     strcpy (obuf, buf.linearise () + 1);
761     }
762    
763 elmex 1.1 #define AddIfInt64(Old,New,Type) if (Old != New) {\
764 root 1.12 Old = New; \
765 root 1.28 sl << uint8 (Type) << uint64 (New); \
766 root 1.12 }
767 elmex 1.1
768     #define AddIfInt(Old,New,Type) if (Old != New) {\
769 root 1.12 Old = New; \
770 root 1.28 sl << uint8 (Type) << uint32 (New); \
771 root 1.12 }
772 elmex 1.1
773     #define AddIfShort(Old,New,Type) if (Old != New) {\
774 root 1.12 Old = New; \
775 root 1.28 sl << uint8 (Type) << uint16 (New); \
776 root 1.12 }
777 elmex 1.1
778     #define AddIfFloat(Old,New,Type) if (Old != New) {\
779 root 1.12 Old = New; \
780 root 1.28 sl << uint8 (Type) << uint32 (New*FLOAT_MULTI); \
781 root 1.12 }
782 elmex 1.1
783     #define AddIfString(Old,New,Type) if (Old == NULL || strcmp(Old,New)) {\
784 root 1.28 free(Old); Old = strdup (New);\
785     sl << uint8 (Type) << data8 (New); \
786 root 1.12 }
787 elmex 1.1
788     /**
789     * Sends a statistics update. We look at the old values,
790     * and only send what has changed. Stat mapping values are in newclient.h
791     * Since this gets sent a lot, this is actually one of the few binary
792     * commands for now.
793     */
794 root 1.16 void
795     esrv_update_stats (player *pl)
796 elmex 1.1 {
797 root 1.16 char buf[MAX_BUF];
798     uint16 flags;
799    
800 root 1.61 client *ns = pl->ns;
801     if (!ns)
802     return;
803    
804     object *ob = pl->ob;
805     if (!ob)
806 root 1.53 return;
807    
808 root 1.47 packet sl ("stats");
809 elmex 1.1
810 root 1.61 AddIfShort (ns->last_stats.hp, ob->stats.hp, CS_STAT_HP);
811     AddIfShort (ns->last_stats.maxhp, ob->stats.maxhp, CS_STAT_MAXHP);
812     AddIfShort (ns->last_stats.sp, ob->stats.sp, CS_STAT_SP);
813     AddIfShort (ns->last_stats.maxsp, ob->stats.maxsp, CS_STAT_MAXSP);
814     AddIfShort (ns->last_stats.grace, ob->stats.grace, CS_STAT_GRACE);
815     AddIfShort (ns->last_stats.maxgrace, ob->stats.maxgrace, CS_STAT_MAXGRACE);
816     AddIfShort (ns->last_stats.Str, ob->stats.Str, CS_STAT_STR);
817     AddIfShort (ns->last_stats.Dex, ob->stats.Dex, CS_STAT_DEX);
818     AddIfShort (ns->last_stats.Con, ob->stats.Con, CS_STAT_CON);
819     AddIfShort (ns->last_stats.Int, ob->stats.Int, CS_STAT_INT);
820     AddIfShort (ns->last_stats.Wis, ob->stats.Wis, CS_STAT_WIS);
821     AddIfShort (ns->last_stats.Pow, ob->stats.Pow, CS_STAT_POW);
822     AddIfShort (ns->last_stats.Cha, ob->stats.Cha, CS_STAT_CHA);
823 root 1.22
824 root 1.52 for (int s = 0; s < NUM_SKILLS; s++)
825 root 1.61 if (object *skill = pl->last_skill_ob[s])
826     if (skill->stats.exp != ns->last_skill_exp [s])
827     {
828     ns->last_skill_exp [s] = skill->stats.exp;
829    
830     /* Always send along the level if exp changes. This is only
831     * 1 extra byte, but keeps processing simpler.
832     */
833     sl << uint8 (s + CS_STAT_SKILLINFO)
834     << uint8 (skill->level)
835     << uint64 (skill->stats.exp);
836     }
837 root 1.28
838 root 1.61 AddIfInt64 (ns->last_stats.exp, ob->stats.exp, CS_STAT_EXP64);
839     AddIfShort (ns->last_level, ob->level, CS_STAT_LEVEL);
840     AddIfShort (ns->last_stats.wc, ob->stats.wc, CS_STAT_WC);
841     AddIfShort (ns->last_stats.ac, ob->stats.ac, CS_STAT_AC);
842     AddIfShort (ns->last_stats.dam, ob->stats.dam, CS_STAT_DAM);
843     AddIfFloat (ns->last_speed, ob->speed, CS_STAT_SPEED);
844     AddIfShort (ns->last_stats.food, ob->stats.food, CS_STAT_FOOD);
845     AddIfFloat (ns->last_weapon_sp, pl->weapon_sp, CS_STAT_WEAP_SP);
846     AddIfInt (ns->last_weight_limit, weight_limit[ob->stats.Str], CS_STAT_WEIGHT_LIM);
847 root 1.22
848 root 1.16 flags = 0;
849 root 1.22
850 root 1.16 if (pl->fire_on)
851     flags |= SF_FIREON;
852 root 1.22
853 root 1.16 if (pl->run_on)
854     flags |= SF_RUNON;
855    
856 root 1.61 AddIfShort (ns->last_flags, flags, CS_STAT_FLAGS);
857 root 1.22
858 root 1.61 if (ns->sc_version < 1025)
859     { AddIfShort (ns->last_resist[ATNR_PHYSICAL], ob->resist[ATNR_PHYSICAL], CS_STAT_ARMOUR) }
860 root 1.16 else
861 root 1.44 for (int i = 0; i < NROFATTACKS; i++)
862     {
863     /* Skip ones we won't send */
864     if (atnr_cs_stat[i] == -1)
865     continue;
866 root 1.16
867 root 1.61 AddIfShort (ns->last_resist[i], ob->resist[i], atnr_cs_stat[i]);
868 root 1.44 }
869 root 1.22
870 root 1.50 if (pl->ns->monitor_spells)
871 root 1.16 {
872 root 1.61 AddIfInt (ns->last_path_attuned, ob->path_attuned, CS_STAT_SPELL_ATTUNE);
873     AddIfInt (ns->last_path_repelled, ob->path_repelled, CS_STAT_SPELL_REPEL);
874     AddIfInt (ns->last_path_denied, ob->path_denied, CS_STAT_SPELL_DENY);
875 root 1.16 }
876 root 1.22
877 root 1.61 rangetostring (ob, buf); /* we want use the new fire & run system in new client */
878     AddIfString (ns->stats.range, buf, CS_STAT_RANGE);
879     set_title (ob, buf);
880     AddIfString (ns->stats.title, buf, CS_STAT_TITLE);
881 root 1.16
882     /* Only send it away if we have some actual data */
883 root 1.34 if (sl.length () > 6)
884 root 1.61 ns->send_packet (sl);
885 elmex 1.1 }
886    
887     /**
888     * Tells the client that here is a player it should start using.
889     */
890 root 1.16 void
891     esrv_new_player (player *pl, uint32 weight)
892 elmex 1.1 {
893 root 1.47 packet sl ("player");
894 elmex 1.1
895 root 1.28 sl << uint32 (pl->ob->count)
896     << uint32 (weight)
897 root 1.69 << uint32 (pl->ob->face)
898 root 1.28 << data8 (pl->ob->name);
899 root 1.16
900 root 1.61 pl->ns->last_weight = weight;
901 root 1.50 pl->ns->send_packet (sl);
902 root 1.16 SET_FLAG (pl->ob, FLAG_CLIENT_SENT);
903 elmex 1.1 }
904    
905     /******************************************************************************
906     *
907     * Start of map related commands.
908     *
909     ******************************************************************************/
910    
911     /** Clears a map cell */
912 root 1.16 static void
913 root 1.70 map_clearcell (struct MapCell *cell, int count)
914 elmex 1.1 {
915 root 1.75 cell->faces[0] = 0;
916     cell->faces[1] = 0;
917     cell->faces[2] = 0;
918     cell->smooth[0] = 0;
919     cell->smooth[1] = 0;
920     cell->smooth[2] = 0;
921     cell->count = count;
922     cell->stat_hp = 0;
923     cell->flags = 0;
924     cell->player = 0;
925 elmex 1.1 }
926    
927     #define MAX_LAYERS 3
928    
929     /**
930     * Removes the need to replicate the same code for each layer.
931     * this returns true if this space is now in fact different than
932     * it was.
933     * sl is the socklist this data is going into.
934     * ns is the socket we are working on - all the info we care
935     * about is in this socket structure, so now need not pass the
936     * entire player object.
937     * layer is the layer to update, with 2 being the floor and 0 the
938     * top layer (this matches what the GET_MAP_FACE and GET_MAP_FACE_OBJ)
939     * take. Interesting to note that before this function, the map1 function
940     * numbers the spaces differently - I think this was a leftover from
941     * the map command, where the faces stack up. Sinces that is no longer
942     * the case, it seems to make more sense to have these layer values
943     * actually match.
944     */
945 root 1.16 static int
946 root 1.75 update_space (packet &sl, client &ns, mapspace &ms, MapCell &lastcell, int layer)
947 elmex 1.1 {
948 root 1.75 object *ob = ms.faces_obj [layer];
949 root 1.16
950     /* If there is no object for this space, or if the face for the object
951     * is the blank face, set the face number to zero.
952     * else if we have the stored head object for this space, that takes
953     * precedence over the other object for this space.
954     * otherwise, we do special head processing
955     */
956 root 1.75 uint16 face_num = ob && ob->face != blank_face ? ob->face : 0;
957 root 1.16
958     /* We've gotten what face we want to use for the object. Now see if
959     * if it has changed since we last sent it to the client.
960     */
961 root 1.75 if (lastcell.faces[layer] != face_num)
962 root 1.16 {
963 root 1.75 lastcell.faces[layer] = face_num;
964 root 1.73
965 root 1.74 if (!ns.faces_sent[face_num])
966 root 1.73 if (ob)
967     ns.send_faces (ob);
968     else
969     ns.send_face (face_num);
970 root 1.28
971     sl << uint16 (face_num);
972 root 1.16 return 1;
973 elmex 1.1 }
974 root 1.28
975 root 1.16 /* Nothing changed */
976     return 0;
977 elmex 1.1 }
978    
979     /**
980     * Returns the size of a data for a map square as returned by
981     * mapextended. There are CLIENTMAPX*CLIENTMAPY*LAYERS entries
982     * available.
983     */
984 root 1.16 int
985 root 1.41 getExtendedMapInfoSize (client * ns)
986 root 1.16 {
987     int result = 0;
988    
989     if (ns->ext_mapinfos)
990     {
991     if (ns->EMI_smooth)
992     result += 1; /*One byte for smoothlevel */
993 elmex 1.1 }
994 root 1.44
995 root 1.16 return result;
996 elmex 1.1 }
997 root 1.16
998 root 1.62 // prefetch (and touch) all maps within a specific distancd
999     static void
1000     prefetch_surrounding_maps (maptile *map, int distance)
1001     {
1002     map->last_access = runtime;
1003    
1004     if (--distance)
1005     for (int dir = 4; --dir; )
1006     if (const shstr &path = map->tile_path [dir])
1007     if (maptile *&neigh = map->tile_map [dir])
1008     prefetch_surrounding_maps (neigh, distance);
1009     else
1010     neigh = maptile::find_async (path, map);
1011     }
1012    
1013     // prefetch a generous area around the player
1014     static void
1015     prefetch_surrounding_maps (object *op)
1016     {
1017     prefetch_surrounding_maps (op->map, 3);
1018     }
1019    
1020 elmex 1.1 /**
1021     * This function uses the new map1 protocol command to send the map
1022     * to the client. It is necessary because the old map command supports
1023     * a maximum map size of 15x15.
1024     * This function is much simpler than the old one. This is because
1025     * the old function optimized to send as few face identifiers as possible,
1026     * at the expense of sending more coordinate location (coordinates were
1027     * only 1 byte, faces 2 bytes, so this was a worthwhile savings). Since
1028     * we need 2 bytes for coordinates and 2 bytes for faces, such a trade off
1029     * maps no sense. Instead, we actually really only use 12 bits for coordinates,
1030     * and use the other 4 bits for other informatiion. For full documentation
1031     * of what we send, see the doc/Protocol file.
1032     * I will describe internally what we do:
1033 root 1.50 * the ns->lastmap shows how the map last looked when sent to the client.
1034 elmex 1.1 * in the lastmap structure, there is a cells array, which is set to the
1035     * maximum viewable size (As set in config.h).
1036     * in the cells, there are faces and a count value.
1037     * we use the count value to hold the darkness value. If -1, then this space
1038     * is not viewable.
1039     * we use faces[0] faces[1] faces[2] to hold what the three layers
1040     * look like.
1041     */
1042 root 1.16 void
1043     draw_client_map1 (object *pl)
1044 elmex 1.1 {
1045 root 1.72 int x, y, ax, ay, startlen, max_x, max_y, oldlen;
1046 root 1.16 sint16 nx, ny;
1047     int estartlen, eoldlen;
1048     uint8 eentrysize;
1049     uint16 ewhatstart, ewhatflag;
1050     uint8 extendedinfos;
1051 root 1.21 maptile *m;
1052 root 1.16
1053 root 1.50 client &socket = *pl->contr->ns;
1054 root 1.16
1055 root 1.60 if (!pl->active)
1056 root 1.58 return;
1057    
1058 root 1.16 check_map_change (pl->contr);
1059 root 1.62 prefetch_surrounding_maps (pl);
1060 root 1.16
1061 root 1.47 packet sl (socket.mapmode == Map1Cmd ? "map1" : "map1a");
1062 root 1.33 packet esl;
1063 root 1.28
1064 root 1.34 startlen = sl.length ();
1065 root 1.25
1066 root 1.16 /*Extendedmapinfo structure initialisation */
1067     if (socket.ext_mapinfos)
1068     {
1069     extendedinfos = EMI_NOREDRAW;
1070 root 1.25
1071 root 1.16 if (socket.EMI_smooth)
1072     extendedinfos |= EMI_SMOOTH;
1073 root 1.25
1074 root 1.34 ewhatstart = esl.length ();
1075 root 1.16 ewhatflag = extendedinfos; /*The EMI_NOREDRAW bit
1076     could need to be taken away */
1077     eentrysize = getExtendedMapInfoSize (&socket);
1078 root 1.28 esl << "mapextended "
1079     << uint8 (extendedinfos)
1080     << uint8 (eentrysize);
1081 root 1.34
1082     estartlen = esl.length ();
1083 root 1.16 }
1084 root 1.25
1085 root 1.16 /* x,y are the real map locations. ax, ay are viewport relative
1086     * locations.
1087     */
1088     ay = 0;
1089    
1090     /* We could do this logic as conditionals in the if statement,
1091     * but that started to get a bit messy to look at.
1092     */
1093     max_x = pl->x + (socket.mapx + 1) / 2;
1094     max_y = pl->y + (socket.mapy + 1) / 2;
1095 root 1.25
1096 root 1.76 maptile *plmap = pl->map;
1097    
1098 root 1.16 for (y = pl->y - socket.mapy / 2; y < max_y; y++, ay++)
1099     {
1100     ax = 0;
1101     for (x = pl->x - socket.mapx / 2; x < max_x; x++, ax++)
1102     {
1103 root 1.72 int emask, mask;
1104 root 1.16 emask = mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4;
1105    
1106 root 1.25 MapCell &lastcell = socket.lastmap.cells[ax][ay];
1107 root 1.16
1108     /* If the coordinates are not valid, or it is too dark to see,
1109     * we tell the client as such
1110     */
1111     nx = x;
1112     ny = y;
1113 root 1.76 m = get_map_from_coord (plmap, &nx, &ny);
1114 root 1.25
1115 root 1.16 if (!m)
1116     {
1117     /* space is out of map. Update space and clear values
1118     * if this hasn't already been done. If the space is out
1119     * of the map, it shouldn't have a head
1120     */
1121     if (lastcell.count != -1)
1122     {
1123 root 1.28 sl << uint16 (mask);
1124 root 1.70 map_clearcell (&lastcell, -1);
1125 root 1.12 }
1126 root 1.72
1127     continue;
1128 root 1.16 }
1129 root 1.72
1130     m->touch ();
1131    
1132     int d = pl->contr->blocked_los[ax][ay];
1133    
1134     if (d > 3)
1135 root 1.16 {
1136 root 1.56
1137 root 1.16 int need_send = 0, count;
1138    
1139     /* This block deals with spaces that are not visible for whatever
1140 root 1.71 * reason. Still may need to send the head for this space.
1141 root 1.16 */
1142 root 1.12
1143 root 1.34 oldlen = sl.length ();
1144 root 1.3
1145 root 1.28 sl << uint16 (mask);
1146 root 1.25
1147 root 1.16 if (lastcell.count != -1)
1148     need_send = 1;
1149 root 1.25
1150 root 1.16 count = -1;
1151 root 1.3
1152 root 1.70 /* properly clear a previously sent big face */
1153 root 1.72 if (lastcell.faces[0] || lastcell.faces[1] || lastcell.faces[2]
1154 root 1.70 || lastcell.stat_hp || lastcell.flags || lastcell.player)
1155     need_send = 1;
1156 root 1.3
1157 root 1.70 map_clearcell (&lastcell, count);
1158 root 1.3
1159 root 1.16 if ((mask & 0xf) || need_send)
1160 root 1.37 sl[oldlen + 1] = mask & 0xff;
1161 root 1.16 else
1162 root 1.34 sl.reset (oldlen);
1163 root 1.16 }
1164     else
1165     {
1166 root 1.71 /* In this block, the space is visible.
1167 root 1.16 */
1168    
1169     /* Rather than try to figure out what everything that we might
1170     * need to send is, then form the packet after that,
1171     * we presume that we will in fact form a packet, and update
1172     * the bits by what we do actually send. If we send nothing,
1173 root 1.34 * we just back out sl.length () to the old value, and no harm
1174 root 1.16 * is done.
1175     * I think this is simpler than doing a bunch of checks to see
1176     * what if anything we need to send, setting the bits, then
1177     * doing those checks again to add the real data.
1178     */
1179 root 1.72 oldlen = sl.length ();
1180 root 1.34 eoldlen = esl.length ();
1181 root 1.72
1182 root 1.28 sl << uint16 (mask);
1183 root 1.16
1184     unsigned char dummy;
1185     unsigned char *last_ext = &dummy;
1186    
1187     /* Darkness changed */
1188     if (lastcell.count != d && socket.darkness)
1189     {
1190     mask |= 0x8;
1191    
1192     if (socket.extmap)
1193     {
1194     *last_ext |= 0x80;
1195 root 1.37 last_ext = &sl[sl.length ()];
1196 root 1.28 sl << uint8 (d);
1197 root 1.16 }
1198     else
1199 root 1.28 sl << uint8 (255 - 64 * d);
1200 root 1.16 }
1201 root 1.3
1202 root 1.16 lastcell.count = d;
1203 root 1.8
1204 root 1.75 mapspace &ms = m->at (nx, ny);
1205    
1206 root 1.16 if (socket.extmap)
1207     {
1208 root 1.86 uint8 stat_hp = 0;
1209 root 1.16 uint8 stat_width = 0;
1210 root 1.86 uint8 flags = 0;
1211     tag_t player = 0;
1212 root 1.16
1213     // send hp information, if applicable
1214 root 1.75 if (object *op = ms.faces_obj [0])
1215 root 1.16 {
1216     if (op->head || op->invisible)
1217     ; // do not show
1218     else if (op->type == PLAYER
1219     || QUERY_FLAG (op, FLAG_MONSTER) || QUERY_FLAG (op, FLAG_ALIVE) || QUERY_FLAG (op, FLAG_GENERATOR))
1220     {
1221     if (op->stats.maxhp > 0 && (unsigned) op->stats.maxhp > (unsigned) op->stats.hp)
1222     {
1223     stat_hp = 255 - (op->stats.hp * 255 + 254) / op->stats.maxhp;
1224     stat_width = op->arch->tail_x;
1225     }
1226     }
1227 elmex 1.1
1228 root 1.24 if (op->msg && op->msg[0] == '@')
1229     flags |= 1;
1230    
1231 root 1.16 if (op->type == PLAYER && op != pl)
1232     player = op->count;
1233     }
1234 root 1.12
1235 root 1.16 if (lastcell.stat_hp != stat_hp)
1236     {
1237     lastcell.stat_hp = stat_hp;
1238    
1239     mask |= 0x8;
1240     *last_ext |= 0x80;
1241 root 1.37 last_ext = &sl[sl.length ()];
1242 root 1.27
1243     sl << uint8 (5) << uint8 (stat_hp);
1244 root 1.16
1245     if (stat_width > 1)
1246     {
1247     *last_ext |= 0x80;
1248 root 1.37 last_ext = &sl[sl.length ()];
1249 root 1.27
1250     sl << uint8 (6) << uint8 (stat_width);
1251 root 1.16 }
1252     }
1253 root 1.12
1254 root 1.20 if (lastcell.player != player)
1255 root 1.16 {
1256     lastcell.player = player;
1257    
1258     mask |= 0x8;
1259     *last_ext |= 0x80;
1260 root 1.37 last_ext = &sl[sl.length ()];
1261 root 1.27
1262 root 1.87 sl << uint8 (0x47) << uint8 (4) << (uint32)player;
1263 root 1.16 }
1264 root 1.24
1265     if (lastcell.flags != flags)
1266     {
1267     lastcell.flags = flags;
1268    
1269     mask |= 0x8;
1270     *last_ext |= 0x80;
1271 root 1.37 last_ext = &sl[sl.length ()];
1272 root 1.27
1273     sl << uint8 (8) << uint8 (flags);
1274 root 1.24 }
1275 root 1.16 }
1276 root 1.12
1277 root 1.16 /* Floor face */
1278 root 1.75 if (update_space (sl, socket, ms, lastcell, 2))
1279 root 1.16 mask |= 0x4;
1280    
1281     /* Middle face */
1282 root 1.75 if (update_space (sl, socket, ms, lastcell, 1))
1283 root 1.16 mask |= 0x2;
1284    
1285 root 1.75 if (ms.player () == pl
1286     && (pl->invisible & (pl->invisible < 50 ? 1 : 7)))
1287 root 1.16 {
1288 root 1.75 // force player to be visible to himself if invisible
1289 root 1.69 if (lastcell.faces[0] != pl->face)
1290 root 1.16 {
1291 root 1.69 lastcell.faces[0] = pl->face;
1292 root 1.75
1293 root 1.16 mask |= 0x1;
1294 root 1.75 sl << uint16 (pl->face);
1295 root 1.25
1296 root 1.73 socket.send_faces (pl);
1297 root 1.12 }
1298     }
1299 root 1.75 /* Top face */
1300     else if (update_space (sl, socket, ms, lastcell, 0))
1301     mask |= 0x1;
1302    
1303 root 1.25
1304 root 1.16 /* Check to see if we are in fact sending anything for this
1305     * space by checking the mask. If so, update the mask.
1306     * if not, reset the len to that from before adding the mask
1307     * value, so we don't send those bits.
1308     */
1309     if (mask & 0xf)
1310 root 1.37 sl[oldlen + 1] = mask & 0xff;
1311 root 1.16 else
1312 root 1.34 sl.reset (oldlen);
1313 root 1.25
1314 root 1.75 if (socket.ext_mapinfos)
1315     esl << uint16 (emask);
1316    
1317     if (socket.EMI_smooth)
1318     {
1319     for (int layer = 2+1; layer--; )
1320     {
1321     object *ob = ms.faces_obj [layer];
1322    
1323     // If there is no object for this space, or if the face for the object
1324     // is the blank face, set the smoothlevel to zero.
1325     int smoothlevel = ob && ob->face != blank_face ? ob->smoothlevel : 0;
1326    
1327     // We've gotten what face we want to use for the object. Now see if
1328     // if it has changed since we last sent it to the client.
1329     if (lastcell.smooth[layer] != smoothlevel)
1330     {
1331     lastcell.smooth[layer] = smoothlevel;
1332     esl << uint8 (smoothlevel);
1333     emask |= 1 << layer;
1334     }
1335     }
1336    
1337     if (emask & 0xf)
1338     esl[eoldlen + 1] = emask & 0xff;
1339     else
1340     esl.reset (eoldlen);
1341     }
1342 root 1.16 } /* else this is a viewable space */
1343     } /* for x loop */
1344     } /* for y loop */
1345    
1346 root 1.84 socket.flush_fx ();
1347    
1348 root 1.16 /* Verify that we in fact do need to send this */
1349     if (socket.ext_mapinfos)
1350     {
1351 root 1.34 if (!(sl.length () > startlen || socket.sent_scroll))
1352 root 1.16 {
1353     /* No map data will follow, so don't say the client
1354     * it doesn't need draw!
1355     */
1356 root 1.72 ewhatflag &= ~EMI_NOREDRAW;
1357 root 1.37 esl[ewhatstart + 1] = ewhatflag & 0xff;
1358 root 1.16 }
1359 root 1.18
1360 root 1.34 if (esl.length () > estartlen)
1361 root 1.37 socket.send_packet (esl);
1362 root 1.16 }
1363 root 1.18
1364 root 1.34 if (sl.length () > startlen || socket.sent_scroll)
1365 root 1.16 {
1366 root 1.37 socket.send_packet (sl);
1367 root 1.16 socket.sent_scroll = 0;
1368 elmex 1.1 }
1369     }
1370    
1371     /**
1372     * Draws client map.
1373     */
1374 root 1.16 void
1375     draw_client_map (object *pl)
1376 elmex 1.1 {
1377 root 1.16 int i, j;
1378 pippijn 1.67 sint16 ax, ay; /* ax and ay goes from 0 to max-size of arrays */
1379     int mflags;
1380 root 1.16 struct Map newmap;
1381 root 1.21 maptile *m, *pm;
1382 root 1.16
1383     if (pl->type != PLAYER)
1384     {
1385     LOG (llevError, "draw_client_map called with non player/non eric-server\n");
1386     return;
1387     }
1388    
1389     pm = pl->map;
1390    
1391     /* If player is just joining the game, he isn't here yet, so the map
1392     * can get swapped out. If so, don't try to send them a map. All will
1393     * be OK once they really log in.
1394     */
1395     if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1396     return;
1397    
1398     memset (&newmap, 0, sizeof (struct Map));
1399    
1400 root 1.50 for (j = (pl->y - pl->contr->ns->mapy / 2); j < (pl->y + (pl->contr->ns->mapy + 1) / 2); j++)
1401     for (i = (pl->x - pl->contr->ns->mapx / 2); i < (pl->x + (pl->contr->ns->mapx + 1) / 2); i++)
1402 root 1.48 {
1403     ax = i;
1404     ay = j;
1405     m = pm;
1406     mflags = get_map_flags (m, &m, ax, ay, &ax, &ay);
1407    
1408     if (mflags & P_OUT_OF_MAP)
1409     continue;
1410    
1411     /* If a map is visible to the player, we don't want to swap it out
1412     * just to reload it. This should really call something like
1413     * swap_map, but this is much more efficient and 'good enough'
1414     */
1415     if (mflags & P_NEW_MAP)
1416     m->timeout = 50;
1417     }
1418 root 1.44
1419 root 1.16 /* do LOS after calls to update_position */
1420     if (pl->contr->do_los)
1421     {
1422     update_los (pl);
1423     pl->contr->do_los = 0;
1424     }
1425    
1426 root 1.34 /* Big maps need a different drawing mechanism to work */
1427     draw_client_map1 (pl);
1428 elmex 1.1 }
1429    
1430    
1431     /*****************************************************************************/
1432 root 1.16
1433 elmex 1.1 /* GROS: The following one is used to allow a plugin to send a generic cmd to*/
1434 root 1.16
1435 elmex 1.1 /* a player. Of course, the client need to know the command to be able to */
1436 root 1.16
1437 elmex 1.1 /* manage it ! */
1438 root 1.16
1439 elmex 1.1 /*****************************************************************************/
1440 root 1.16 void
1441     send_plugin_custom_message (object *pl, char *buf)
1442 elmex 1.1 {
1443 root 1.50 pl->contr->ns->send_packet (buf);
1444 elmex 1.1 }
1445    
1446     /**
1447     * This sends the skill number to name mapping. We ignore
1448     * the params - we always send the same info no matter what.
1449     */
1450 root 1.16 void
1451 root 1.41 send_skill_info (client *ns, char *params)
1452 elmex 1.1 {
1453 root 1.33 packet sl;
1454 root 1.28 sl << "replyinfo skill_info\n";
1455    
1456     for (int i = 1; i < NUM_SKILLS; i++)
1457 root 1.29 sl.printf ("%d:%s\n", i + CS_STAT_SKILLINFO, &skill_names[i]);
1458 elmex 1.1
1459 root 1.34 if (sl.length () >= MAXSOCKBUF)
1460 root 1.16 {
1461     LOG (llevError, "Buffer overflow in send_skill_info!\n");
1462     fatal (0);
1463 elmex 1.1 }
1464 root 1.28
1465 root 1.37 ns->send_packet (sl);
1466 elmex 1.1 }
1467    
1468     /**
1469     * This sends the spell path to name mapping. We ignore
1470     * the params - we always send the same info no matter what.
1471     */
1472 root 1.16 void
1473 root 1.41 send_spell_paths (client * ns, char *params)
1474 root 1.16 {
1475 root 1.33 packet sl;
1476 root 1.28
1477     sl << "replyinfo spell_paths\n";
1478    
1479     for (int i = 0; i < NRSPELLPATHS; i++)
1480 root 1.29 sl.printf ("%d:%s\n", 1 << i, spellpathnames[i]);
1481 root 1.16
1482 root 1.34 if (sl.length () >= MAXSOCKBUF)
1483 root 1.16 {
1484     LOG (llevError, "Buffer overflow in send_spell_paths!\n");
1485     fatal (0);
1486 elmex 1.1 }
1487 root 1.28
1488 root 1.37 ns->send_packet (sl);
1489 elmex 1.1 }
1490    
1491     /**
1492     * This looks for any spells the player may have that have changed their stats.
1493     * it then sends an updspell packet for each spell that has changed in this way
1494     */
1495 root 1.16 void
1496     esrv_update_spells (player *pl)
1497     {
1498 root 1.53 if (!pl->ns)
1499     return;
1500    
1501 root 1.50 if (!pl->ns->monitor_spells)
1502 root 1.16 return;
1503 root 1.28
1504     for (object *spell = pl->ob->inv; spell; spell = spell->below)
1505 root 1.16 {
1506     if (spell->type == SPELL)
1507     {
1508 root 1.28 int flags = 0;
1509    
1510 root 1.16 /* check if we need to update it */
1511     if (spell->last_sp != SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA))
1512     {
1513     spell->last_sp = SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA);
1514     flags |= UPD_SP_MANA;
1515     }
1516 root 1.28
1517 root 1.16 if (spell->last_grace != SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE))
1518     {
1519     spell->last_grace = SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE);
1520     flags |= UPD_SP_GRACE;
1521     }
1522 root 1.28
1523 root 1.16 if (spell->last_eat != spell->stats.dam + SP_level_dam_adjust (pl->ob, spell))
1524     {
1525     spell->last_eat = spell->stats.dam + SP_level_dam_adjust (pl->ob, spell);
1526     flags |= UPD_SP_DAMAGE;
1527     }
1528 root 1.28
1529     if (flags)
1530 root 1.16 {
1531 root 1.33 packet sl;
1532 root 1.27
1533 root 1.28 sl << "updspell "
1534     << uint8 (flags)
1535     << uint32 (spell->count);
1536 root 1.27
1537     if (flags & UPD_SP_MANA ) sl << uint16 (spell->last_sp);
1538     if (flags & UPD_SP_GRACE ) sl << uint16 (spell->last_grace);
1539     if (flags & UPD_SP_DAMAGE) sl << uint16 (spell->last_eat);
1540    
1541 root 1.50 pl->ns->send_packet (sl);
1542 root 1.12 }
1543     }
1544 elmex 1.1 }
1545     }
1546    
1547 root 1.16 void
1548     esrv_remove_spell (player *pl, object *spell)
1549     {
1550 root 1.50 if (!pl->ns->monitor_spells)
1551 root 1.16 return;
1552 root 1.28
1553 root 1.16 if (!pl || !spell || spell->env != pl->ob)
1554     {
1555     LOG (llevError, "Invalid call to esrv_remove_spell");
1556     return;
1557     }
1558 root 1.27
1559 root 1.47 packet sl ("delspell");
1560 root 1.28
1561 root 1.47 sl << uint32 (spell->count);
1562 root 1.27
1563 root 1.50 pl->ns->send_packet (sl);
1564 elmex 1.1 }
1565    
1566     /* appends the spell *spell to the Socklist we will send the data to. */
1567 root 1.16 static void
1568 root 1.33 append_spell (player *pl, packet &sl, object *spell)
1569 root 1.16 {
1570 pippijn 1.67 int i, skill = 0;
1571 root 1.16
1572     if (!(spell->name))
1573     {
1574     LOG (llevError, "item number %d is a spell with no name.\n", spell->count);
1575     return;
1576     }
1577 root 1.27
1578 root 1.16 /* store costs and damage in the object struct, to compare to later */
1579 root 1.27 spell->last_sp = SP_level_spellpoint_cost (pl->ob, spell, SPELL_MANA);
1580 root 1.16 spell->last_grace = SP_level_spellpoint_cost (pl->ob, spell, SPELL_GRACE);
1581 root 1.27 spell->last_eat = spell->stats.dam + SP_level_dam_adjust (pl->ob, spell);
1582 elmex 1.1
1583 root 1.16 /* figure out which skill it uses, if it uses one */
1584     if (spell->skill)
1585     {
1586     for (i = 1; i < NUM_SKILLS; i++)
1587     if (!strcmp (spell->skill, skill_names[i]))
1588     {
1589     skill = i + CS_STAT_SKILLINFO;
1590     break;
1591     }
1592 elmex 1.1 }
1593    
1594 root 1.69 // spells better have a face
1595     if (!spell->face)
1596     {
1597     LOG (llevError, "%s: spell has no face, but face is mandatory.\n", &spell->name);
1598     spell->face = face_find ("burnout.x11", blank_face);
1599     }
1600    
1601 root 1.27 /* send the current values */
1602     sl << uint32 (spell->count)
1603     << uint16 (spell->level)
1604     << uint16 (spell->casting_time)
1605     << uint16 (spell->last_sp)
1606     << uint16 (spell->last_grace)
1607     << uint16 (spell->last_eat)
1608     << uint8 (skill)
1609     << uint32 (spell->path_attuned)
1610 root 1.69 << uint32 (spell->face)
1611 root 1.27 << data8 (spell->name)
1612     << data16 (spell->msg);
1613 elmex 1.1 }
1614    
1615     /**
1616     * This tells the client to add the spell *ob, if *ob is NULL, then add
1617     * all spells in the player's inventory.
1618     */
1619 root 1.16 void
1620     esrv_add_spells (player *pl, object *spell)
1621     {
1622     if (!pl)
1623     {
1624     LOG (llevError, "esrv_add_spells, tried to add a spell to a NULL player");
1625     return;
1626     }
1627 root 1.28
1628 root 1.50 if (!pl->ns->monitor_spells)
1629 root 1.16 return;
1630 root 1.28
1631 root 1.47 packet sl ("addspell");
1632 root 1.28
1633 root 1.16 if (!spell)
1634     {
1635 root 1.69 for (spell = pl->ob->inv; spell; spell = spell->below)
1636 root 1.16 {
1637     /* were we to simply keep appending data here, we could exceed
1638     * MAXSOCKBUF if the player has enough spells to add, we know that
1639     * append_spells will always append 19 data bytes, plus 4 length
1640     * bytes and 3 strings (because that is the spec) so we need to
1641     * check that the length of those 3 strings, plus the 23 bytes,
1642     * won't take us over the length limit for the socket, if it does,
1643     * we need to send what we already have, and restart packet formation
1644     */
1645     /* Seeing crashes by overflowed buffers. Quick arithemetic seems
1646     * to show add_spell is 26 bytes + 2 strings. However, the overun
1647     * is hundreds of bytes off, so correcting 22 vs 26 doesn't seem
1648     * like it will fix this
1649     */
1650     if (spell->type != SPELL)
1651     continue;
1652 root 1.27
1653 root 1.34 if (sl.length () >= (MAXSOCKBUF - (26 + strlen (spell->name) + (spell->msg ? strlen (spell->msg) : 0))))
1654 root 1.16 {
1655 root 1.50 pl->ns->send_packet (sl);
1656 root 1.34
1657     sl.reset ();
1658     sl << "addspell ";
1659 root 1.16 }
1660 root 1.27
1661     append_spell (pl, sl, spell);
1662 root 1.16 }
1663     }
1664     else if (spell->type != SPELL)
1665     {
1666     LOG (llevError, "Asked to send a non-spell object as a spell");
1667     return;
1668     }
1669     else
1670 root 1.27 append_spell (pl, sl, spell);
1671    
1672 root 1.28 if (sl.length () >= MAXSOCKBUF)
1673 root 1.16 {
1674     LOG (llevError, "Buffer overflow in esrv_add_spells!\n");
1675     fatal (0);
1676     }
1677 root 1.27
1678 root 1.16 /* finally, we can send the packet */
1679 root 1.50 pl->ns->send_packet (sl);
1680 elmex 1.1 }
1681 root 1.28