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 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

# Content
1 /*
2 * static char *rcsid_init_c =
3 * "$Id$";
4 */
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 /** 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 {
126 int flags = 0;
127
128 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
133 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 ob->map->width, ob->map->height, ob->map->path);
136 }
137 else
138 snprintf (buf, MAX_BUF, "mapinfo current");
139
140 Write_String_To_Socket (&pl->socket, buf, strlen (buf));
141 }
142 }
143
144 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 /** This is the Setup cmd - easy first implementation */
221 void SetUp(char *buf, int len, NewSocket *ns)
222 {
223 int s, slen;
224 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 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
258 if (!strcmp(cmd,"sound")) {
259 ns->sound = atoi(param);
260 safe_strcat(cmdback, param, &slen, HUGE_BUF);
261 }
262 else if (!strcmp(cmd,"exp64")) {
263 ns->exp64 = atoi(param);
264 safe_strcat(cmdback, param, &slen, HUGE_BUF);
265 } else if (!strcmp(cmd, "spellmon")) {
266 ns->monitor_spells = atoi(param);
267 safe_strcat(cmdback, param, &slen, HUGE_BUF);
268 } else if (!strcmp(cmd,"darkness")) {
269 ns->darkness = atoi(param);
270 safe_strcat(cmdback, param, &slen, HUGE_BUF);
271 } 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 safe_strcat(cmdback, ns->mapmode == Map1Cmd?"1":"0", &slen, HUGE_BUF);
276 } 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 safe_strcat(cmdback, ns->mapmode == Map1aCmd?"1":"0", &slen, HUGE_BUF);
281 } else if (!strcmp(cmd,"newmapcmd")) {
282 ns->newmapcmd= atoi(param);
283 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 } else if (!strcmp(cmd,"facecache")) {
291 ns->facecache = atoi(param);
292 safe_strcat(cmdback, param, &slen, HUGE_BUF);
293 } 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 safe_strcat(cmdback, tmpbuf, &slen, HUGE_BUF);
301 /* 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 safe_strcat(cmdback, tmpbuf, &slen, HUGE_BUF);
317 } 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 safe_strcat(cmdback, tmpbuf, &slen, HUGE_BUF);
330 } 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 safe_strcat(cmdback, tmpbuf, &slen, HUGE_BUF);
338 /* 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 /* Added by tchize
345 * prepare to use the mapextended command
346 */
347 char tmpbuf[20];
348 ns->ext_mapinfos = (atoi(param));
349 sprintf(tmpbuf,"%d", ns->ext_mapinfos);
350 safe_strcat(cmdback, tmpbuf, &slen, HUGE_BUF);
351 } else if (!strcmp(cmd,"extendedTextInfos")) {
352 /* Added by tchize
353 * prepare to use the extended text commands
354 * Client toggle this to non zero to get exttext
355 */
356 char tmpbuf[20];
357
358 ns->has_readable_type = (atoi(param));
359 sprintf(tmpbuf,"%d", ns->has_readable_type);
360 safe_strcat(cmdback, tmpbuf, &slen, HUGE_BUF);
361 } else {
362 /* Didn't get a setup command we understood -
363 * report a failure to the client.
364 */
365 safe_strcat(cmdback, "FALSE", &slen, HUGE_BUF);
366 }
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 static void SendSmooth(NewSocket *ns, uint16 face) {
486 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 LOG(llevDebug,"Corrupt ncom command <%s> not long enough - discarding\n", buf);
592 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 LOG(llevDebug,"CS: connection from client of type <%s>, ip %s\n", cp, ns->host);
741
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 pl->socket.current_map = 0;
793 }
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
1848 check_map_change (pl->contr);
1849 }
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 mapstruct *m, *pm;
1863
1864 if (pl->type != PLAYER) {
1865 LOG(llevError,"draw_client_map called with non player/non eric-server\n");
1866 return;
1867 }
1868
1869 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 * 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 if (pm==NULL || pm->in_memory!=MAP_IN_MEMORY) return;
1880
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 m = pm;
1888 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 m = get_map_from_coord(pm, &nx, &ny);
1940 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
1972 check_map_change (pl->contr);
1973 }
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 strcpy((char*)sl.buf,"replyinfo skill_info\n");
2052 for (i=1; i< NUM_SKILLS; i++) {
2053 sprintf((char*)sl.buf + strlen((char*)sl.buf), "%d:%s\n", i + CS_STAT_SKILLINFO,
2054 skill_names[i]);
2055 }
2056 sl.len = strlen((char*)sl.buf);
2057 if (sl.len >= MAXSOCKBUF) {
2058 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 strcpy((char*)sl.buf,"replyinfo spell_paths\n");
2075 for(i=0; i<NRSPELLPATHS; i++)
2076 sprintf((char*)sl.buf + strlen((char*)sl.buf), "%d:%s\n", 1<<i, spellpathnames[i]);
2077 sl.len = strlen((char*)sl.buf);
2078 if (sl.len >= MAXSOCKBUF) {
2079 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 strcpy((char*)sl.buf,"updspell ");
2113 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 strcpy((char*)sl.buf,"delspell ");
2137 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 int len, i, skill=0;
2146
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 /* 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 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 strcpy((char*)sl.buf,"addspell ");
2205 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 if (sl.len >= (MAXSOCKBUF - (26 + strlen(spell->name) +
2223 (spell->msg?strlen(spell->msg):0)))) {
2224 Send_With_Handling(&pl->socket, &sl);
2225 strcpy((char*)sl.buf,"addspell ");
2226 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 if (sl.len >= MAXSOCKBUF) {
2237 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