ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/request.c
Revision: 1.8
Committed: Mon May 1 12:22:03 2006 UTC (18 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +4 -4 lines
Log Message:
Fix another crash.

Some clueless idiot decided to name the constant that defines the maximum
buffer size PLUS ONE to MAXSOCKBUF, and some naive people believed that
would actually be the max sock buf size. It's not.

File Contents

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