Crossfire Server, Branches 1.12  R18729
request.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_request_c =
3  * "$Id: request.c 17660 2012-03-23 19:08:26Z akirschbaum $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2001-2006 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 
59 #include <assert.h>
60 #include <global.h>
61 #include <sproto.h>
62 
63 #include <newclient.h>
64 #include <newserver.h>
65 #include <living.h>
66 #include <commands.h>
67 
68 /* This block is basically taken from socket.c - I assume if it works there,
69  * it should work here.
70  */
71 #ifndef WIN32 /* ---win32 exclude unix headers */
72 #include <sys/types.h>
73 #include <sys/time.h>
74 #include <sys/socket.h>
75 #include <netinet/in.h>
76 #include <netinet/tcp.h>
77 #include <netdb.h>
78 #endif /* win32 */
79 
80 #ifdef HAVE_UNISTD_H
81 #include <unistd.h>
82 #endif
83 
84 #ifdef HAVE_SYS_TIME_H
85 #include <sys/time.h>
86 #endif
87 
88 #include "sounds.h"
89 
96 static const short atnr_cs_stat[NROFATTACKS] = {
101  CS_STAT_RES_DRAIN, -1 /* weaponmagic */,
105  CS_STAT_RES_FEAR, -1 /* Cancellation */,
107  -1 /* Chaos */, -1 /* Counterspell */,
108  -1 /* Godpower */, CS_STAT_RES_HOLYWORD,
110  -1, /* Internal */
111  -1, /* life stealing */
112  -1 /* Disease - not fully done yet */
113 };
114 
116 void set_up_cmd(char *buf, int len, socket_struct *ns) {
117  int s;
118  char *cmd, *param;
119  SockList sl;
120 
121  /* run through the cmds of setup
122  * syntax is setup <cmdname1> <parameter> <cmdname2> <parameter> ...
123  *
124  * we send the status of the cmd back, or a FALSE is the cmd
125  * is the server unknown
126  * The client then must sort this out
127  */
128 
129  LOG(llevInfo, "Get SetupCmd:: %s\n", buf);
130  SockList_Init(&sl);
131  SockList_AddString(&sl, "setup");
132  for (s = 0; s < len; ) {
133  cmd = &buf[s];
134 
135  /* find the next space, and put a null there */
136  for (; buf[s] && buf[s] != ' '; s++)
137  ;
138  if (s >= len)
139  break;
140  buf[s++] = 0;
141 
142  while (buf[s] == ' ')
143  s++;
144  if (s >= len)
145  break;
146  param = &buf[s];
147 
148  for (; buf[s] && buf[s] != ' '; s++)
149  ;
150  buf[s++] = 0;
151 
152  while (s < len && buf[s] == ' ')
153  s++;
154 
155  SockList_AddPrintf(&sl, " %s ", cmd);
156 
157  if (!strcmp(cmd, "sound")) {
158  /* this is the old sound command, which means the client doesn't understand our sound => mute. */
159  ns->sound = 0;
160  SockList_AddString(&sl, "FALSE");
161  } else if (!strcmp(cmd, "sound2")) {
162  ns->sound = atoi(param)&(SND_EFFECTS|SND_MUSIC|SND_MUTE);
163  SockList_AddString(&sl, param);
164  } else if (!strcmp(cmd, "exp64")) {
165  /* for compatibility, return 1 since older clients can be confused else. */
166  SockList_AddString(&sl, "1");
167  } else if (!strcmp(cmd, "spellmon")) {
168  int monitor_spells;
169 
170  monitor_spells = atoi(param);
171  if (monitor_spells != 0 && monitor_spells != 1) {
172  SockList_AddString(&sl, "FALSE");
173  } else {
174  ns->monitor_spells = monitor_spells;
175  SockList_AddPrintf(&sl, "%d", monitor_spells);
176  }
177  } else if (!strcmp(cmd, "darkness")) {
178  int darkness;
179 
180  darkness = atoi(param);
181  if (darkness != 0 && darkness != 1) {
182  SockList_AddString(&sl, "FALSE");
183  } else {
184  ns->darkness = darkness;
185  SockList_AddPrintf(&sl, "%d", darkness);
186  }
187  } else if (!strcmp(cmd, "map2cmd")) {
188  int map2cmd;
189 
190  map2cmd = atoi(param);
191  if (map2cmd != 1) {
192  SockList_AddString(&sl, "FALSE");
193  } else {
194  SockList_AddString(&sl, "1");
195  }
196  } else if (!strcmp(cmd, "newmapcmd")) {
197  int newmapcmd;
198 
199  newmapcmd = atoi(param);
200  if (newmapcmd != 0 && newmapcmd != 1) {
201  SockList_AddString(&sl, "FALSE");
202  } else {
203  ns->newmapcmd = newmapcmd;
204  SockList_AddPrintf(&sl, "%d", newmapcmd);
205  }
206  } else if (!strcmp(cmd, "facecache")) {
207  int facecache;
208 
209  facecache = atoi(param);
210  if (facecache != 0 && facecache != 1) {
211  SockList_AddString(&sl, "FALSE");
212  } else {
213  ns->facecache = facecache;
214  SockList_AddPrintf(&sl, "%d", facecache);
215  }
216  } else if (!strcmp(cmd, "faceset")) {
217  int q = atoi(param);
218 
219  if (is_valid_faceset(q))
220  ns->faceset = q;
221  SockList_AddPrintf(&sl, "%d", ns->faceset);
222  } else if (!strcmp(cmd, "itemcmd")) {
223  /* client ignore the value anyway. */
224  SockList_AddString(&sl, "2");
225  } else if (!strcmp(cmd, "mapsize")) {
226  int x, y, n;
227 
228  if (sscanf(param, "%dx%d%n", &x, &y, &n) != 2 || n != (int)strlen(param)) {
229  x = 0;
230  y = 0;
231  }
232  if (x < 9 || y < 9 || x > MAP_CLIENT_X || y > MAP_CLIENT_Y) {
234  } else {
235  ns->mapx = x;
236  ns->mapy = y;
237  /* better to send back what we are really using and not the
238  * param as given to us in case it gets parsed differently.
239  */
240  SockList_AddPrintf(&sl, "%dx%d", x, y);
241  /* Client and server need to resynchronize on data - treating it as
242  * a new map is best way to go.
243  */
244  map_newmap_cmd(ns);
245  }
246  } else if (!strcmp(cmd, "extendedMapInfos")) {
247  SockList_AddString(&sl, "1");
248  } else if (!strcmp(cmd, "extendedTextInfos")) {
249  int has_readable_type;
250 
251  has_readable_type = atoi(param);
252  if (has_readable_type != 0 && has_readable_type != 1) {
253  SockList_AddString(&sl, "FALSE");
254  } else {
255  ns->has_readable_type = has_readable_type;
256  SockList_AddPrintf(&sl, "%d", has_readable_type);
257  }
258  } else if (!strcmp(cmd, "tick")) {
259  int tick;
260 
261  tick = atoi(param);
262  if (tick != 0 && tick != 1) {
263  SockList_AddString(&sl, "FALSE");
264  } else {
265  ns->tick = tick;
266  SockList_AddPrintf(&sl, "%d", tick);
267  }
268  } else if (!strcmp(cmd, "bot")) {
269  int is_bot;
270 
271  is_bot = atoi(param);
272  if (is_bot != 0 && is_bot != 1) {
273  SockList_AddString(&sl, "FALSE");
274  } else {
275  ns->is_bot = is_bot;
276  SockList_AddPrintf(&sl, "%d", is_bot);
277  }
278  } else if (!strcmp(cmd, "want_pickup")) {
279  int want_pickup;
280 
281  want_pickup = atoi(param);
282  if (want_pickup != 0 && want_pickup != 1) {
283  SockList_AddString(&sl, "FALSE");
284  } else {
285  ns->want_pickup = want_pickup;
286  SockList_AddPrintf(&sl, "%d", want_pickup);
287  }
288  } else if (!strcmp(cmd, "inscribe")) {
289  SockList_AddString(&sl, "1");
290  } else if (!strcmp(cmd, "num_look_objects")) {
291  int tmp;
292 
293  tmp = atoi(param);
294  if (tmp < MIN_NUM_LOOK_OBJECTS) {
295  tmp = MIN_NUM_LOOK_OBJECTS;
296  } else if (tmp > MAX_NUM_LOOK_OBJECTS) {
297  tmp = MAX_NUM_LOOK_OBJECTS;
298  }
299  ns->num_look_objects = (uint8)tmp;
300  SockList_AddPrintf(&sl, "%d", tmp);
301  } else {
302  /* Didn't get a setup command we understood -
303  * report a failure to the client.
304  */
305  SockList_AddString(&sl, "FALSE");
306  }
307  } /* for processing all the setup commands */
308  Send_With_Handling(ns, &sl);
309  SockList_Term(&sl);
310 }
311 
320 void add_me_cmd(char *buf, int len, socket_struct *ns) {
321  Settings oldsettings;
322  SockList sl;
323 
324  oldsettings = settings;
325  if (ns->status != Ns_Add) {
326  SockList_Init(&sl);
327  SockList_AddString(&sl, "addme_failed");
328  Send_With_Handling(ns, &sl);
329  SockList_Term(&sl);
330  } else {
331  add_player(ns);
332  /* Basically, the add_player copies the socket structure into
333  * the player structure, so this one (which is from init_sockets)
334  * is not needed anymore. The write below should still work,
335  * as the stuff in ns is still relevant.
336  */
337  SockList_Init(&sl);
338  SockList_AddString(&sl, "addme_success");
339  Send_With_Handling(ns, &sl);
340  SockList_Term(&sl);
341  if (ns->sc_version < 1027 || ns->cs_version < 1023) {
342  /* The space in the link isn't correct, but in my
343  * quick test with client 1.1.0, it didn't print it
344  * out correctly when done as a single line.
345  */
346  SockList_Init(&sl);
347  SockList_AddString(&sl, "drawinfo 3 Warning: Your client is too old to receive map data. Please update to a new client at http://sourceforge.net/project/showfiles.php ?group_id=13833");
348  Send_With_Handling(ns, &sl);
349  SockList_Term(&sl);
350  }
351 
353  ns->status = Ns_Avail;
354  }
355  settings = oldsettings;
356 }
357 
359 void toggle_extended_infos_cmd(char *buf, int len, socket_struct *ns) {
360  SockList sl;
361  char command[50];
362  int info, nextinfo, smooth = 0;
363 
364  nextinfo = 0;
365  while (1) {
366  /* 1. Extract an info*/
367  info = nextinfo;
368  while (info < len && buf[info] == ' ')
369  info++;
370  if (info >= len)
371  break;
372  nextinfo = info+1;
373  while (nextinfo < len && buf[nextinfo] != ' ')
374  nextinfo++;
375  if (nextinfo-info >= 49) /*Erroneous info asked*/
376  continue;
377  strncpy(command, &buf[info], nextinfo-info);
378  command[nextinfo-info] = '\0';
379  /* 2. Interpret info*/
380  if (!strcmp("smooth", command)) {
381  /* Toggle smoothing*/
382  smooth = 1;
383  } else {
384  /*bad value*/
385  }
386  /*3. Next info*/
387  }
388  SockList_Init(&sl);
389  SockList_AddString(&sl, "ExtendedInfoSet");
390  if (smooth) {
391  SockList_AddString(&sl, " smoothing");
392  }
393  Send_With_Handling(ns, &sl);
394  SockList_Term(&sl);
395 }
396 
398 void toggle_extended_text_cmd(char *buf, int len, socket_struct *ns) {
399  SockList sl;
400  char command[50];
401  int info, nextinfo, i, flag;
402 
403  nextinfo = 0;
404  while (1) {
405  /* 1. Extract an info*/
406  info = nextinfo;
407  while (info < len && buf[info] == ' ')
408  info++;
409  if (info >= len)
410  break;
411  nextinfo = info+1;
412  while (nextinfo < len && buf[nextinfo] != ' ')
413  nextinfo++;
414  if (nextinfo-info >= 49) /*Erroneous info asked*/
415  continue;
416  strncpy(command, &buf[info], nextinfo-info);
417  command[nextinfo-info] = '\0';
418  /* 2. Interpret info*/
419  i = sscanf(command, "%d", &flag);
420  if (i == 1 && flag > 0 && flag <= MSG_TYPE_LAST)
421  ns->supported_readables |= (1<<flag);
422  /*3. Next info*/
423  }
424  /* Send resulting state */
425  SockList_Init(&sl);
426  SockList_AddString(&sl, "ExtendedTextSet");
427  for (i = 0; i <= MSG_TYPE_LAST; i++)
428  if (ns->supported_readables&(1<<i)) {
429  SockList_AddPrintf(&sl, " %d", i);
430  }
431  Send_With_Handling(ns, &sl);
432  SockList_Term(&sl);
433 }
434 
442 static void send_smooth(socket_struct *ns, uint16 face) {
443  uint16 smoothface;
444  SockList sl;
445 
446  /* If we can't find a face, return and set it so we won't
447  * try to send this again.
448  */
449  if (!find_smooth(face, &smoothface)
450  && !find_smooth(smooth_face->number, &smoothface)) {
451  LOG(llevError, "could not findsmooth for %d. Neither default (%s)\n", face, smooth_face->name);
452  ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
453  return;
454  }
455 
456  if (!(ns->faces_sent[smoothface]&NS_FACESENT_FACE))
457  esrv_send_face(ns, smoothface, 0);
458 
459  ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
460 
461  SockList_Init(&sl);
462  SockList_AddString(&sl, "smooth ");
463  SockList_AddShort(&sl, face);
464  SockList_AddShort(&sl, smoothface);
465  Send_With_Handling(ns, &sl);
466  SockList_Term(&sl);
467 }
468 
473 void ask_smooth_cmd(char *buf, int len, socket_struct *ns) {
474  uint16 facenbr;
475 
476  facenbr = atoi(buf);
477  send_smooth(ns, facenbr);
478 }
479 
492 void new_player_cmd(uint8 *buf, int len, player *pl) {
493  int time, repeat;
494  short packet;
495  char command[MAX_BUF];
496  SockList sl;
497 
498  if (len < 7) {
499  LOG(llevDebug, "Corrupt ncom command - not long enough - discarding\n");
500  return;
501  }
502 
503  packet = GetShort_String(buf);
504  repeat = GetInt_String(buf+2);
505  /* -1 is special - no repeat, but don't update */
506  if (repeat != -1) {
507  pl->count = repeat;
508  }
509  if (len-4 >= MAX_BUF)
510  len = MAX_BUF-5;
511 
512  strncpy(command, (char *)buf+6, len-4);
513  command[len-4] = '\0';
514 
515  /* The following should never happen with a proper or honest client.
516  * Therefore, the error message doesn't have to be too clear - if
517  * someone is playing with a hacked/non working client, this gives them
518  * an idea of the problem, but they deserve what they get
519  */
520  if (pl->state != ST_PLAYING) {
522  "You can not issue commands - state is not ST_PLAYING (%s)",
523  "You can not issue commands - state is not ST_PLAYING (%s)",
524  buf);
525  return;
526  }
527 
528  /* This should not happen anymore. */
529  if (pl->ob->speed_left < -1.0) {
530  LOG(llevError, "Player has negative time - shouldn't do command.\n");
531  }
532  /* In c_new.c */
533  execute_newserver_command(pl->ob, command);
534  /* Perhaps something better should be done with a left over count.
535  * Cleaning up the input should probably be done first - all actions
536  * for the command that issued the count should be done before
537  * any other commands.
538  */
539  pl->count = 0;
540 
541  /* Send confirmation of command execution now */
542  SockList_Init(&sl);
543  SockList_AddString(&sl, "comc ");
544  SockList_AddShort(&sl, packet);
545  if (FABS(pl->ob->speed) < 0.001)
546  time = MAX_TIME*100;
547  else
548  time = (int)(MAX_TIME/FABS(pl->ob->speed));
549  SockList_AddInt(&sl, time);
550  Send_With_Handling(&pl->socket, &sl);
551  SockList_Term(&sl);
552 }
553 
555 void reply_cmd(char *buf, int len, player *pl) {
556  /* This is to synthesize how the data would be stored if it
557  * was normally entered. A bit of a hack, and should be cleaned up
558  * once all the X11 code is removed from the server.
559  *
560  * We pass 13 to many of the functions because this way they
561  * think it was the carriage return that was entered, and the
562  * function then does not try to do additional input.
563  */
564  snprintf(pl->write_buf, sizeof(pl->write_buf), ":%s", buf);
565 
566  /* this avoids any hacking here */
567 
568  switch (pl->state) {
569  case ST_PLAYING:
570  LOG(llevError, "Got reply message with ST_PLAYING input state\n");
571  break;
572 
573  case ST_PLAY_AGAIN:
574  /* We can check this for return value (2==quit). Maybe we
575  * should, and do something appropriate?
576  */
577  receive_play_again(pl->ob, buf[0]);
578  break;
579 
580  case ST_ROLL_STAT:
581  key_roll_stat(pl->ob, buf[0]);
582  break;
583 
584  case ST_CHANGE_CLASS:
585 
586  key_change_class(pl->ob, buf[0]);
587  break;
588 
589  case ST_CONFIRM_QUIT:
590  key_confirm_quit(pl->ob, buf[0]);
591  break;
592 
593  case ST_GET_NAME:
594  receive_player_name(pl->ob);
595  break;
596 
597  case ST_GET_PASSWORD:
598  case ST_CONFIRM_PASSWORD:
603  break;
604 
605  case ST_GET_PARTY_PASSWORD: /* Get password for party */
607  break;
608 
609  default:
610  LOG(llevError, "Unknown input state: %d\n", pl->state);
611  }
612 }
613 
621 void version_cmd(char *buf, int len, socket_struct *ns) {
622  char *cp;
623 
624  if (!buf) {
625  LOG(llevError, "CS: received corrupted version command\n");
626  return;
627  }
628 
629  ns->cs_version = atoi(buf);
630  ns->sc_version = ns->cs_version;
631  if (VERSION_CS != ns->cs_version) {
632 #ifdef ESRV_DEBUG
633  LOG(llevDebug, "CS: csversion mismatch (%d,%d)\n", VERSION_CS, ns->cs_version);
634 #endif
635  }
636  cp = strchr(buf+1, ' ');
637  if (!cp)
638  return;
639  ns->sc_version = atoi(cp);
640  if (VERSION_SC != ns->sc_version) {
641 #ifdef ESRV_DEBUG
642  LOG(llevDebug, "CS: scversion mismatch (%d,%d)\n", VERSION_SC, ns->sc_version);
643 #endif
644  }
645  cp = strchr(cp+1, ' ');
646  if (cp) {
647  LOG(llevDebug, "CS: connection from client of type <%s>, ip %s\n", cp, ns->host);
648  }
649 }
650 
656 void set_sound_cmd(char *buf, int len, socket_struct *ns) {
657 }
658 
662 void map_redraw_cmd(char *buf, int len, player *pl) {
663  /* This function is currently disabled; just clearing the
664  * map state results in display errors. It should clear the
665  * cache and send a newmap command. Unfortunately this
666  * solution does not work because some client versions send
667  * a mapredraw command after receiving a newmap command.
668  */
669 }
670 
673  /* If getting a newmap command, this scroll information
674  * is no longer relevant.
675  */
676  ns->map_scroll_x = 0;
677  ns->map_scroll_y = 0;
678 
679  if (ns->newmapcmd == 1) {
680  SockList sl;
681 
682  memset(&ns->lastmap, 0, sizeof(ns->lastmap));
683  SockList_Init(&sl);
684  SockList_AddString(&sl, "newmap");
685  Send_With_Handling(ns, &sl);
686  SockList_Term(&sl);
687  }
688 }
689 
694 void move_cmd(char *buf, int len, player *pl) {
695  int vals[3], i;
696 
697  /* A little funky here. We only cycle for 2 records, because
698  * we obviously am not going to find a space after the third
699  * record. Perhaps we should just replace this with a
700  * sscanf?
701  */
702  for (i = 0; i < 2; i++) {
703  vals[i] = atoi(buf);
704  if (!(buf = strchr(buf, ' '))) {
705  LOG(llevError, "Incomplete move command: %s\n", buf);
706  return;
707  }
708  buf++;
709  }
710  vals[2] = atoi(buf);
711 
712 /* LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
713  esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
714 }
715 
716 /***************************************************************************
717  *
718  * Start of commands the server sends to the client.
719  *
720  ***************************************************************************
721  */
722 
727 void send_query(socket_struct *ns, uint8 flags, const char *text) {
728  SockList sl;
729 
730  SockList_Init(&sl);
731  SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
732  Send_With_Handling(ns, &sl);
733  SockList_Term(&sl);
734 }
735 
736 #define AddIfInt64(Old, New, Type) \
737  if (Old != New) { \
738  Old = New; \
739  SockList_AddChar(&sl, Type); \
740  SockList_AddInt64(&sl, New); \
741  }
742 
743 #define AddIfInt(Old, New, Type) \
744  if (Old != New) { \
745  Old = New; \
746  SockList_AddChar(&sl, Type); \
747  SockList_AddInt(&sl, New); \
748  }
749 
750 #define AddIfShort(Old, New, Type) \
751  if (Old != New) { \
752  Old = New; \
753  SockList_AddChar(&sl, Type); \
754  SockList_AddShort(&sl, New); \
755  }
756 
757 #define AddIfFloat(Old, New, Type) \
758  if (Old != New) { \
759  Old = New; \
760  SockList_AddChar(&sl, Type); \
761  SockList_AddInt(&sl, (long)(New*FLOAT_MULTI));\
762  }
763 
764 #define AddIfString(Old, New, Type) \
765  if (Old == NULL || strcmp(Old, New)) { \
766  if (Old) \
767  free(Old); \
768  Old = strdup_local(New); \
769  SockList_AddChar(&sl, Type); \
770  SockList_AddLen8Data(&sl, New, strlen(New));\
771  }
772 
780  SockList sl;
781  char buf[MAX_BUF];
782  uint16 flags;
783  uint8 s;
784 
785  SockList_Init(&sl);
786  SockList_AddString(&sl, "stats ");
787 
788  if (pl->ob != NULL) {
802  }
803 
804  for (s = 0; s < NUM_SKILLS; s++) {
805  if (pl->last_skill_ob[s]
806  && pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
807  /* Always send along the level if exp changes. This
808  * is only 1 extra byte, but keeps processing simpler.
809  */
810  SockList_AddChar(&sl, (char)(s+CS_STAT_SKILLINFO));
811  SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
813  pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
814  }
815  }
817  AddIfShort(pl->last_level, (char)pl->ob->level, CS_STAT_LEVEL);
825  flags = 0;
826  if (pl->fire_on)
827  flags |= SF_FIREON;
828  if (pl->run_on)
829  flags |= SF_RUNON;
830 
831  AddIfShort(pl->last_flags, flags, CS_STAT_FLAGS);
832  if (pl->socket.sc_version < 1025) {
834  } else {
835  int i;
836 
837  for (i = 0; i < NROFATTACKS; i++) {
838  /* Skip ones we won't send */
839  if (atnr_cs_stat[i] == -1)
840  continue;
841  AddIfShort(pl->last_resist[i], pl->ob->resist[i], (char)atnr_cs_stat[i]);
842  }
843  }
844  if (pl->socket.monitor_spells) {
848  }
849  /* we want to use the new fire & run system in new client */
850  rangetostring(pl->ob, buf, sizeof(buf));
852  set_title(pl->ob, buf, sizeof(buf));
854 
855  /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
856  if (sl.len > 8) {
857 #ifdef ESRV_DEBUG
858  LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
859 #endif
860  Send_With_Handling(&pl->socket, &sl);
861  }
862  SockList_Term(&sl);
863 }
864 
868 void esrv_new_player(player *pl, uint32 weight) {
869  SockList sl;
870 
871  pl->last_weight = weight;
872 
873  if (!(pl->socket.faces_sent[pl->ob->face->number]&NS_FACESENT_FACE))
874  esrv_send_face(&pl->socket, pl->ob->face->number, 0);
875 
876  SockList_Init(&sl);
877  SockList_AddString(&sl, "player ");
878  SockList_AddInt(&sl, pl->ob->count);
879  SockList_AddInt(&sl, weight);
880  SockList_AddInt(&sl, pl->ob->face->number);
881  SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
882 
883  Send_With_Handling(&pl->socket, &sl);
884  SockList_Term(&sl);
886 }
887 
895 void esrv_send_animation(socket_struct *ns, short anim_num) {
896  SockList sl;
897  int i;
898 
899  /* Do some checking on the anim_num we got. Note that the animations
900  * are added in contigous order, so if the number is in the valid
901  * range, it must be a valid animation.
902  */
903  if (anim_num < 0 || anim_num > num_animations) {
904  LOG(llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
905  return;
906  }
907 
908  SockList_Init(&sl);
909  SockList_AddString(&sl, "anim ");
910  SockList_AddShort(&sl, anim_num);
911  SockList_AddShort(&sl, 0); /* flags - not used right now */
912  /* Build up the list of faces. Also, send any information (ie, the
913  * the face itself) down to the client.
914  */
915  for (i = 0; i < animations[anim_num].num_animations; i++) {
916  if (!(ns->faces_sent[animations[anim_num].faces[i]]&NS_FACESENT_FACE))
917  esrv_send_face(ns, animations[anim_num].faces[i], 0);
918  /* flags - not used right now */
919  SockList_AddShort(&sl, animations[anim_num].faces[i]);
920  }
921  Send_With_Handling(ns, &sl);
922  SockList_Term(&sl);
923  ns->anims_sent[anim_num] = 1;
924 }
925 
926 /****************************************************************************
927  *
928  * Start of map related commands.
929  *
930  ****************************************************************************/
931 
933 static void map_clearcell(struct map_cell_struct *cell, int face, int count) {
934  cell->darkness = count;
935  memset(cell->faces, face, sizeof(cell->faces));
936 }
937 
938 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
939 
948 
949 /****************************************************************************
950  * This block is for map2 drawing related commands.
951  * Note that the map2 still uses other functions.
952  *
953  ***************************************************************************/
954 
974 static int map2_add_ob(int ax, int ay, int layer, object *ob, SockList *sl, socket_struct *ns, int *has_obj, int is_head) {
975  uint16 face_num;
976  uint8 nlayer, smoothlevel = 0;
977  object *head;
978 
979  assert(ob != NULL);
980 
981  head = ob->head ? ob->head : ob;
982  face_num = ob->face->number;
983 
984  /* This is a multipart object, and we are not at the lower
985  * right corner. So we need to store away the lower right corner.
986  */
987  if (!is_head && (head->arch->tail_x || head->arch->tail_y)
988  && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
989  int bx, by, l;
990 
991  /* Basically figure out where the offset is from where we
992  * are right now. the ob->arch->clone.{x,y} values hold
993  * the offset that this current piece is from the head,
994  * and the tail is where the tail is from the head.
995  * Note that bx and by will equal sx and sy if we are
996  * already working on the bottom right corner. If ob is
997  * the head, the clone values will be zero, so the right
998  * thing will still happen.
999  */
1000  bx = ax+head->arch->tail_x-ob->arch->clone.x;
1001  by = ay+head->arch->tail_y-ob->arch->clone.y;
1002 
1003  /* I don't think this can ever happen, but better to check
1004  * for it just in case.
1005  */
1006  if (bx < ax || by < ay) {
1007  LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
1008  face_num = 0;
1009  }
1010  /* the target position must be within +/-1 of our current
1011  * layer as the layers are defined. We are basically checking
1012  * to see if we have already stored this object away.
1013  */
1014  for (l = layer-1; l <= layer+1; l++) {
1015  if (l < 0 || l >= MAP_LAYERS)
1016  continue;
1017  if (heads[by][bx][l] == head)
1018  break;
1019  }
1020  /* Didn't find it. So we need to store it away. Try to store it
1021  * on our original layer, and then move up a layer.
1022  */
1023  if (l == layer+2) {
1024  if (!heads[by][bx][layer])
1025  heads[by][bx][layer] = head;
1026  else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
1027  heads[by][bx][layer+1] = head;
1028  }
1029  return 0;
1030  /* Ok - All done storing away the head for future use */
1031  } else {
1032  (*has_obj)++;
1035  face_num = ob->animation_id|(1<<15);
1037  face_num |= ANIM_SYNC;
1038  else if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM))
1039  face_num |= ANIM_RANDOM;
1040  }
1041  /* Since face_num includes the bits for the animation tag,
1042  * and we will store that away in the faces[] array, below
1043  * check works fine _except_ for the case where animation
1044  * speed chances.
1045  */
1046  if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
1047  uint8 len, anim_speed = 0, i;
1048 
1049  /* This block takes care of sending the actual face
1050  * to the client. */
1051  ns->lastmap.cells[ax][ay].faces[layer] = face_num;
1052 
1053  /* Now form the data packet */
1054  nlayer = 0x10+layer;
1055 
1056  len = 2;
1057 
1058  if (!MAP_NOSMOOTH(ob->map)) {
1059  smoothlevel = ob->smoothlevel;
1060  if (smoothlevel)
1061  len++;
1062  }
1063 
1066  len++;
1067  /* 1/0.004 == 250, so this is a good cap for an
1068  * upper limit */
1069  if (ob->anim_speed)
1070  anim_speed = ob->anim_speed;
1071  else if (FABS(ob->speed) < 0.004)
1072  anim_speed = 255;
1073  else if (FABS(ob->speed) >= 1.0)
1074  anim_speed = 1;
1075  else
1076  anim_speed = (int)(1.0/FABS(ob->speed));
1077 
1078  if (!ns->anims_sent[ob->animation_id])
1080 
1081  /* If smoothing, need to send smoothing information
1082  * for all faces in the animation sequence. Since
1083  * smoothlevel is an object attribute,
1084  * it applies to all faces.
1085  */
1086  if (smoothlevel) {
1087  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1090  }
1091  }
1092  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1093  esrv_send_face(ns, face_num, 0);
1094  }
1095 
1096  if (smoothlevel
1097  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1098  send_smooth(ns, ob->face->number);
1099 
1100  /* Length of packet */
1101  nlayer |= len<<5;
1102 
1103  SockList_AddChar(sl, nlayer);
1104  SockList_AddShort(sl, face_num);
1105  if (anim_speed)
1106  SockList_AddChar(sl, anim_speed);
1107  if (smoothlevel)
1108  SockList_AddChar(sl, smoothlevel);
1109  return 1;
1110  } /* Face is different */
1111  }
1112  return 0;
1113 }
1114 
1115 /* This function is used see if a layer needs to be cleared.
1116  * It updates the socklist, and returns 1 if the update is
1117  * needed, 0 otherwise.
1118  */
1119 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1120  int nlayer;
1121 
1122  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1123  /* Now form the data packet */
1124  nlayer = 0x10+layer+(2<<5);
1125  SockList_AddChar(sl, nlayer);
1126  SockList_AddShort(sl, 0);
1127  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1128  return 1;
1129  }
1130  return 0;
1131 }
1132 
1133 /*
1134  * This function is used to check a space (ax, ay) whose only
1135  * data we may care about are any heads. Basically, this
1136  * space is out of direct view. This is only used with the
1137  * Map2 protocol.
1138  *
1139  * @param ax
1140  * viewport relative x-coordinate
1141  * @param ay
1142  * viewport relative y-coordinate
1143  * @param sl
1144  * the reply to append to
1145  * @param ns
1146  * the client socket
1147  */
1148 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1149  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1150  uint16 coord;
1151 
1152  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1153  oldlen = sl->len;
1154  SockList_AddShort(sl, coord);
1155 
1156  for (layer = 0; layer < MAP_LAYERS; layer++) {
1157  object *head;
1158 
1159  head = heads[ay][ax][layer];
1160  if (head) {
1161  /* in this context, got_one should always increase
1162  * because heads should always point to data to really send.
1163  */
1164  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1165  } else {
1166  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1167  }
1168  }
1169  /* Note - if/when lighting information is added, some code is
1170  * needed here - lighting sources that are out of sight may still
1171  * extend into the viewable area.
1172  */
1173 
1174  /* If nothing to do for this space, we
1175  * can erase the coordinate bytes
1176  */
1177  if (!del_one && !got_one) {
1178  sl->len = oldlen;
1179  } else if (del_one && !has_obj) {
1180  /* If we're only deleting faces and not adding, and there
1181  * are not any faces on the space we care about,
1182  * more efficient
1183  * to send 0 as the type/len field.
1184  */
1185  sl->len = oldlen+2; /* 2 bytes for coordinate */
1186  SockList_AddChar(sl, 0); /* Clear byte */
1187  SockList_AddChar(sl, 255); /* Termination byte */
1188  map_clearcell(&ns->lastmap.cells[ax][ay], 0, 0);
1189  } else {
1190  SockList_AddChar(sl, 255); /* Termination byte */
1191  }
1192 }
1193 
1194 void draw_client_map2(object *pl) {
1195  int x, y, ax, ay, d, min_x, max_x, min_y, max_y, oldlen, layer;
1196  size_t startlen;
1197  sint16 nx, ny;
1198  SockList sl;
1199  uint16 coord;
1200  mapstruct *m;
1201  object *ob;
1202 
1203  SockList_Init(&sl);
1204  SockList_AddString(&sl, "map2 ");
1205  startlen = sl.len;
1206 
1207  /* Handle map scroll */
1208  if (pl->contr->socket.map_scroll_x || pl->contr->socket.map_scroll_y) {
1210  pl->contr->socket.map_scroll_x = 0;
1211  pl->contr->socket.map_scroll_y = 0;
1212  SockList_AddShort(&sl, coord);
1213  }
1214 
1215  /* Init data to zero */
1216  memset(heads, 0, sizeof(heads));
1217 
1218  /* We could do this logic as conditionals in the if statement,
1219  * but that started to get a bit messy to look at.
1220  */
1221  min_x = pl->x-pl->contr->socket.mapx/2;
1222  min_y = pl->y-pl->contr->socket.mapy/2;
1223  max_x = pl->x+(pl->contr->socket.mapx+1)/2+MAX_HEAD_OFFSET;
1224  max_y = pl->y+(pl->contr->socket.mapy+1)/2+MAX_HEAD_OFFSET;
1225 
1226  /* x, y are the real map locations. ax, ay are viewport relative
1227  * locations.
1228  */
1229  ay = 0;
1230  for (y = min_y; y < max_y; y++, ay++) {
1231  ax = 0;
1232  for (x = min_x; x < max_x; x++, ax++) {
1233  /* If this space is out of the normal viewable area,
1234  * we only check the heads value. This is used to
1235  * handle big images - if they extend to a viewable
1236  * portion, we need to send just the lower right corner.
1237  */
1238  if (ax >= pl->contr->socket.mapx || ay >= pl->contr->socket.mapy) {
1239  check_space_for_heads(ax, ay, &sl, &pl->contr->socket);
1240  } else {
1241  /* This space is within the viewport of the client. Due
1242  * to walls or darkness, it may still not be visible.
1243  */
1244 
1245  /* Meaning of d:
1246  * 0 - object is in plain sight, full brightness.
1247  * 1 - MAX_DARKNESS - how dark the space is - higher
1248  * value is darker space. If level is at max darkness,
1249  * you can't see the space (too dark)
1250  * 100 - space is blocked from sight.
1251  */
1252  d = pl->contr->blocked_los[ax][ay];
1253 
1254  /* If the coordinates are not valid, or it is too
1255  * dark to see, we tell the client as such
1256  */
1257  nx = x;
1258  ny = y;
1259  m = get_map_from_coord(pl->map, &nx, &ny);
1260  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1261 
1262  if (!m) {
1263  /* space is out of map. Update space and clear
1264  * values if this hasn't already been done.
1265  * If the space is out of the map, it shouldn't
1266  * have a head.
1267  */
1268  if (pl->contr->socket.lastmap.cells[ax][ay].darkness != 0) {
1269  SockList_AddShort(&sl, coord);
1270  SockList_AddChar(&sl, 0);
1271  SockList_AddChar(&sl, 255); /* Termination byte */
1272  map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
1273  }
1274  } else if (d >= MAX_LIGHT_RADII) {
1275  /* This block deals with spaces that are not
1276  * visible due to darkness or walls. Still
1277  * need to send the heads for this space.
1278  */
1279  check_space_for_heads(ax, ay, &sl, &pl->contr->socket);
1280  } else {
1281  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1;
1282 
1283  /* In this block, the space is visible. */
1284 
1285  /* Rather than try to figure out what everything
1286  * that we might need to send is, then form the
1287  * packet after that, we presume that we will in
1288  * fact form a packet, and update the bits by what
1289  * we do actually send. If we send nothing, we
1290  * just back out sl.len to the old value, and no
1291  * harm is done.
1292  * I think this is simpler than doing a bunch of
1293  * checks to see what if anything we need to send,
1294  * setting the bits, then doing those checks again
1295  * to add the real data.
1296  */
1297 
1298  oldlen = sl.len;
1299  SockList_AddShort(&sl, coord);
1300 
1301  /* Darkness changed */
1302  if (pl->contr->socket.lastmap.cells[ax][ay].darkness != d
1303  && pl->contr->socket.darkness) {
1304  pl->contr->socket.lastmap.cells[ax][ay].darkness = d;
1305  /* Darkness tag & length*/
1306  SockList_AddChar(&sl, 0x1|1<<5);
1307  SockList_AddChar(&sl, 255-d*(256/MAX_LIGHT_RADII));
1308  have_darkness = 1;
1309  }
1310 
1311  for (layer = 0; layer < MAP_LAYERS; layer++) {
1312  ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1313 
1314  /* Special case: send player itself if invisible */
1315  if (!ob
1316  && x == pl->x
1317  && y == pl->y
1318  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1319  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1320  ob = pl;
1321 
1322  if (ob) {
1323  g1 = has_obj;
1324  got_one += map2_add_ob(ax, ay, layer, ob, &sl, &pl->contr->socket, &has_obj, 0);
1325  /* If we are just storing away the head
1326  * for future use, then effectively this
1327  * space/layer is blank, and we should clear
1328  * it if needed.
1329  */
1330  if (g1 == has_obj)
1331  del_one += map2_delete_layer(ax, ay, layer, &sl, &pl->contr->socket);
1332  } else {
1333  del_one += map2_delete_layer(ax, ay, layer, &sl, &pl->contr->socket);
1334  }
1335  }
1336  /* If nothing to do for this space, we
1337  * can erase the coordinate bytes
1338  */
1339  if (!del_one && !got_one && !have_darkness) {
1340  sl.len = oldlen;
1341  } else if (del_one && !has_obj) {
1342  /* If we're only deleting faces and don't
1343  * have any objs we care about, just clear
1344  * space. Note it is possible we may have
1345  * darkness, but if there is nothing on the
1346  * space, darkness isn't all that interesting
1347  * - we can send it when an object shows up.
1348  */
1349  sl.len = oldlen+2; /* 2 bytes for coordinate */
1350  SockList_AddChar(&sl, 0); /* Clear byte */
1351  SockList_AddChar(&sl, 255); /* Termination byte */
1352  map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
1353  } else {
1354  SockList_AddChar(&sl, 255); /* Termination byte */
1355  }
1356  }
1357  } /* else this is a viewable space */
1358  } /* for x loop */
1359  } /* for y loop */
1360 
1361  /* Only send this if there are in fact some differences. */
1362  if (sl.len > startlen) {
1363  Send_With_Handling(&pl->contr->socket, &sl);
1364  }
1365  SockList_Term(&sl);
1366 }
1367 
1371 void draw_client_map(object *pl) {
1372  int i, j;
1373  sint16 ax, ay;
1374  int mflags;
1375  mapstruct *m, *pm;
1376  int min_x, min_y, max_x, max_y;
1377 
1378  if (pl->type != PLAYER) {
1379  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1380  return;
1381  }
1382 
1383  if (pl->contr->transport) {
1384  pm = pl->contr->transport->map;
1385  } else
1386  pm = pl->map;
1387 
1388  /* If player is just joining the game, he isn't here yet, so
1389  * the map can get swapped out. If so, don't try to send them
1390  * a map. All will be OK once they really log in.
1391  */
1392  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1393  return;
1394 
1395  /*
1396  * This block just makes sure all the spaces are properly
1397  * updated in terms of what they look like.
1398  */
1399  min_x = pl->x-pl->contr->socket.mapx/2;
1400  min_y = pl->y-pl->contr->socket.mapy/2;
1401  max_x = pl->x+(pl->contr->socket.mapx+1)/2;
1402  max_y = pl->y+(pl->contr->socket.mapy+1)/2;
1403  for (j = min_y; j < max_y; j++) {
1404  for (i = min_x; i < max_x; i++) {
1405  ax = i;
1406  ay = j;
1407  m = pm;
1408  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1409  if (mflags&P_OUT_OF_MAP)
1410  continue;
1411  if (mflags&P_NEED_UPDATE)
1412  update_position(m, ax, ay);
1413  /* If a map is visible to the player, we don't want
1414  * to swap it out just to reload it. This should
1415  * really call something like swap_map, but this is
1416  * much more efficient and 'good enough'
1417  */
1418  if (mflags&P_NEW_MAP)
1419  m->timeout = 50;
1420  }
1421  }
1422 
1423  /* do LOS after calls to update_position */
1424  if (pl->contr->do_los) {
1425  update_los(pl);
1426  pl->contr->do_los = 0;
1427  }
1428 
1429  draw_client_map2(pl);
1430 }
1431 
1432 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1433  struct Map newmap;
1434  int x, y, mx, my;
1435 
1436  ns->map_scroll_x += dx;
1437  ns->map_scroll_y += dy;
1438 
1439  mx = ns->mapx+MAX_HEAD_OFFSET;
1440  my = ns->mapy+MAX_HEAD_OFFSET;
1441 
1442  /* the x and y here are coordinates for the new map, i.e. if we moved
1443  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1444  * if the destination x or y coordinate is outside the viewable
1445  * area, we clear the values - otherwise, the old values
1446  * are preserved, and the check_head thinks it needs to clear them.
1447  */
1448  for (x = 0; x < mx; x++) {
1449  for (y = 0; y < my; y++) {
1450  if (x >= ns->mapx || y >= ns->mapy) {
1451  /* clear cells outside the viewable area */
1452  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1453  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1454  /* clear newly visible tiles within the viewable area */
1455  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1456  } else {
1457  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1458  }
1459  }
1460  }
1461 
1462  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1463 }
1464 
1470 void send_plugin_custom_message(object *pl, char *buf) {
1471  SockList sl;
1472 
1473  SockList_Init(&sl);
1474  SockList_AddString(&sl, buf);
1475  Send_With_Handling(&pl->contr->socket, &sl);
1476  SockList_Term(&sl);
1477 }
1478 
1482 void send_exp_table(socket_struct *ns, char *params) {
1483  SockList sl;
1484  int i;
1485  extern sint64 *levels;
1486 
1487  SockList_Init(&sl);
1488  SockList_AddString(&sl, "replyinfo exp_table\n");
1490  for (i = 1; i <= settings.max_level; i++) {
1491  if (SockList_Avail(&sl) < 8) {
1492  LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
1493  break;
1494  }
1495  SockList_AddInt64(&sl, levels[i]);
1496  }
1497  Send_With_Handling(ns, &sl);
1498  SockList_Term(&sl);
1499 }
1500 
1505 void send_skill_info(socket_struct *ns, char *params) {
1506  SockList sl;
1507  int i;
1508 
1509  SockList_Init(&sl);
1510  SockList_AddString(&sl, "replyinfo skill_info\n");
1511  for (i = 1; i < NUM_SKILLS; i++) {
1512  size_t len;
1513 
1514  len = 16+strlen(skill_names[i]); /* upper bound for length */
1515  if (SockList_Avail(&sl) < len) {
1516  LOG(llevError, "Buffer overflow in send_skill_info, not sending all skill information\n");
1517  break;
1518  }
1519 
1520  SockList_AddPrintf(&sl, "%d:%s\n", i+CS_STAT_SKILLINFO, skill_names[i]);
1521  }
1522  Send_With_Handling(ns, &sl);
1523  SockList_Term(&sl);
1524 }
1525 
1530 void send_spell_paths(socket_struct *ns, char *params) {
1531  SockList sl;
1532  int i;
1533 
1534  SockList_Init(&sl);
1535  SockList_AddString(&sl, "replyinfo spell_paths\n");
1536  for (i = 0; i < NRSPELLPATHS; i++) {
1537  size_t len;
1538 
1539  len = 16+strlen(spellpathnames[i]); /* upper bound for length */
1540  if (SockList_Avail(&sl) < len) {
1541  LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
1542  break;
1543  }
1544 
1545  SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
1546  }
1547  Send_With_Handling(ns, &sl);
1548  SockList_Term(&sl);
1549 }
1550 
1558  archetype *race;
1559 
1560  SockList_AddString(sl, "replyinfo race_list ");
1561 
1562  for (race = first_archetype; race; race = race->next) {
1563  if (race->clone.type == PLAYER) {
1564  SockList_AddPrintf(sl, "|%s", race->name);
1565  }
1566  }
1567 }
1568 
1578 void send_race_list(socket_struct *ns, char *params) {
1579  static SockList sl;
1580  static int sl_initialized = 0;
1581 
1582  if (!sl_initialized) {
1583  sl_initialized = 1;
1584  SockList_Init(&sl);
1585  build_race_list_reply(&sl);
1586  }
1587 
1588  Send_With_Handling(ns, &sl);
1589 }
1590 
1600 void send_race_info(socket_struct *ns, char *params) {
1601  archetype *race = try_find_archetype(params);
1602  SockList sl;
1603 
1604  SockList_Init(&sl);
1605  SockList_AddPrintf(&sl, "replyinfo race_info %s", params);
1606 
1607  if (race) {
1608  }
1609 
1610  Send_With_Handling(ns, &sl);
1611  SockList_Term(&sl);
1612 }
1613 
1621  archetype *cl;
1622 
1623  SockList_Reset(sl);
1624  SockList_AddString(sl, "replyinfo class_list ");
1625 
1626  for (cl = first_archetype; cl; cl = cl->next) {
1627  if (cl->clone.type == CLASS) {
1628  SockList_AddPrintf(sl, "|%s", cl->name);
1629  }
1630  }
1631 }
1632 
1642 void send_class_list(socket_struct *ns, char *params) {
1643  static SockList sl;
1644  static int sl_initialized = 0;
1645 
1646  if (!sl_initialized) {
1647  sl_initialized = 1;
1648  SockList_Init(&sl);
1650  }
1651 
1652  Send_With_Handling(ns, &sl);
1653 }
1654 
1664 void send_class_info(socket_struct *ns, char *params) {
1665 }
1666 
1673  SockList sl;
1674  int flags = 0;
1675  object *spell;
1676  client_spell *spell_info;
1677 
1678  if (!pl->socket.monitor_spells)
1679  return;
1680 
1681  /* Handles problem at login, where this is called from fix_object
1682  * before we have had a chance to send spells to the player. It does seem
1683  * to me that there should never be a case where update_spells is called
1684  * before add_spells has been called. Add_spells() will update the
1685  * spell_state to non null.
1686  */
1687  if (!pl->spell_state)
1688  return;
1689 
1690  for (spell = pl->ob->inv; spell != NULL; spell = spell->below) {
1691  if (spell->type == SPELL) {
1692  spell_info = get_client_spell_state(pl, spell);
1693  /* check if we need to update it*/
1694  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1695  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1696  flags |= UPD_SP_MANA;
1697  }
1698  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1699  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1700  flags |= UPD_SP_GRACE;
1701  }
1702  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1703  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1704  flags |= UPD_SP_DAMAGE;
1705  }
1706  if (flags != 0) {
1707  SockList_Init(&sl);
1708  SockList_AddString(&sl, "updspell ");
1709  SockList_AddChar(&sl, flags);
1710  SockList_AddInt(&sl, spell->count);
1711  if (flags&UPD_SP_MANA)
1712  SockList_AddShort(&sl, spell_info->last_sp);
1713  if (flags&UPD_SP_GRACE)
1714  SockList_AddShort(&sl, spell_info->last_grace);
1715  if (flags&UPD_SP_DAMAGE)
1716  SockList_AddShort(&sl, spell_info->last_dam);
1717  flags = 0;
1718  Send_With_Handling(&pl->socket, &sl);
1719  SockList_Term(&sl);
1720  }
1721  }
1722  }
1723 }
1724 
1725 void esrv_remove_spell(player *pl, object *spell) {
1726  SockList sl;
1727 
1728  if (!pl->socket.monitor_spells)
1729  return;
1730  if (!pl || !spell || spell->env != pl->ob) {
1731  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1732  return;
1733  }
1734  SockList_Init(&sl);
1735  SockList_AddString(&sl, "delspell ");
1736  SockList_AddInt(&sl, spell->count);
1737  Send_With_Handling(&pl->socket, &sl);
1738  SockList_Term(&sl);
1739 }
1740 
1748  SockList sl;
1749 
1750  if (!pl->socket.want_pickup)
1751  return;
1752  SockList_Init(&sl);
1753  SockList_AddString(&sl, "pickup ");
1754  SockList_AddInt(&sl, pl->mode);
1755  Send_With_Handling(&pl->socket, &sl);
1756  SockList_Term(&sl);
1757 }
1758 
1760 static void append_spell(player *pl, SockList *sl, object *spell) {
1761  client_spell *spell_info;
1762  int len, i, skill = 0;
1763 
1764  if (!spell->name) {
1765  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1766  return;
1767  }
1768 
1769  if (spell->face && !(pl->socket.faces_sent[spell->face->number]&NS_FACESENT_FACE))
1770  esrv_send_face(&pl->socket, spell->face->number, 0);
1771 
1772  spell_info = get_client_spell_state(pl, spell);
1773  SockList_AddInt(sl, spell->count);
1774  SockList_AddShort(sl, spell->level);
1775  SockList_AddShort(sl, spell->casting_time);
1776  /* store costs and damage in the object struct, to compare to later */
1777  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1778  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1779  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1780  /* send the current values */
1781  SockList_AddShort(sl, spell_info->last_sp);
1782  SockList_AddShort(sl, spell_info->last_grace);
1783  SockList_AddShort(sl, spell_info->last_dam);
1784 
1785  /* figure out which skill it uses, if it uses one */
1786  if (spell->skill) {
1787  for (i = 1; i < NUM_SKILLS; i++)
1788  if (!strcmp(spell->skill, skill_names[i])) {
1789  skill = i+CS_STAT_SKILLINFO;
1790  break;
1791  }
1792  }
1793  SockList_AddChar(sl, skill);
1794 
1795  SockList_AddInt(sl, spell->path_attuned);
1796  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1797  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1798 
1799  if (!spell->msg) {
1800  SockList_AddShort(sl, 0);
1801  } else {
1802  len = strlen(spell->msg);
1803  SockList_AddShort(sl, len);
1804  SockList_AddData(sl, spell->msg, len);
1805  }
1806 }
1807 
1812 void esrv_add_spells(player *pl, object *spell) {
1813  SockList sl;
1814 
1815  if (!pl) {
1816  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
1817  return;
1818  }
1819 
1820  if (!pl->socket.monitor_spells)
1821  return;
1822 
1823  SockList_Init(&sl);
1824  SockList_AddString(&sl, "addspell ");
1825  if (!spell) {
1826  for (spell = pl->ob->inv; spell != NULL; spell = spell->below) {
1827  if (spell->type != SPELL)
1828  continue;
1829  /* Were we to simply keep appending data here, we could
1830  * exceed the SockList buffer if the player has enough spells
1831  * to add. We know that append_spell will always append
1832  * 23 data bytes, plus 3 length bytes and 2 strings
1833  * (because that is the spec) so we need to check that
1834  * the length of those 2 strings, plus the 26 bytes,
1835  * won't take us over the length limit for the socket.
1836  * If it does, we need to send what we already have,
1837  * and restart packet formation.
1838  */
1839  if (SockList_Avail(&sl) < 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0)) {
1840  Send_With_Handling(&pl->socket, &sl);
1841  SockList_Reset(&sl);
1842  SockList_AddString(&sl, "addspell ");
1843  }
1844  append_spell(pl, &sl, spell);
1845  }
1846  } else if (spell->type != SPELL) {
1847  LOG(llevError, "Asked to send a non-spell object as a spell\n");
1848  return;
1849  } else
1850  append_spell(pl, &sl, spell);
1851  /* finally, we can send the packet */
1852  Send_With_Handling(&pl->socket, &sl);
1853  SockList_Term(&sl);
1854 }
1855 
1856 /* sends a 'tick' information to the client.
1857  * We also take the opportunity to toggle TCP_NODELAY -
1858  * this forces the data in the socket to be flushed sooner to the
1859  * client - otherwise, the OS tries to wait for full packets
1860  * and will this hold sending the data for some amount of time,
1861  * which thus adds some additional latency.
1862  */
1864  SockList sl;
1865  int tmp;
1866 
1867  SockList_Init(&sl);
1868  SockList_AddString(&sl, "tick ");
1869  SockList_AddInt(&sl, pticks);
1870  tmp = 1;
1871  if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
1872  LOG(llevError, "send_tick: Unable to turn on TCP_NODELAY\n");
1873 
1874  Send_With_Handling(&pl->socket, &sl);
1875  tmp = 0;
1876  if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
1877  LOG(llevError, "send_tick: Unable to turn off TCP_NODELAY\n");
1878  SockList_Term(&sl);
1879 }
void map_newmap_cmd(socket_struct *ns)
Definition: request.c:672
#define CS_STAT_RANGE
Definition: newclient.h:113
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:187
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
Definition: map.c:330
#define CS_STAT_SPELL_DENY
Definition: newclient.h:123
sint8 Int
Definition: living.h:78
Definition: player.h:146
uint32 last_path_attuned
Definition: player.h:199
sint8 ac
Definition: living.h:79
size_t len
Definition: newclient.h:575
#define MAX_HEAD_POS
Definition: request.c:938
#define ST_GET_PARTY_PASSWORD
Definition: define.h:894
#define CS_STAT_SPEED
Definition: newclient.h:110
#define CS_STAT_ARMOUR
Definition: newclient.h:109
void send_spell_paths(socket_struct *ns, char *params)
Definition: request.c:1530
sint32 last_weight_limit
Definition: player.h:198
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:85
signed short sint16
Definition: global.h:72
uint8 num_look_objects
Definition: newserver.h:149
uint32 pticks
Definition: time.c:56
#define NS_FACESENT_FACE
Definition: newserver.h:164
void esrv_add_spells(player *pl, object *spell)
Definition: request.c:1812
uint32 cs_version
Definition: newserver.h:141
int find_smooth(uint16 face, uint16 *smoothed)
Definition: image.c:401
static void send_smooth(socket_struct *ns, uint16 face)
Definition: request.c:442
#define P_NEED_UPDATE
Definition: map.h:260
#define CS_STAT_RES_MAG
Definition: newclient.h:129
void new_player_cmd(uint8 *buf, int len, player *pl)
Definition: request.c:492
#define MAX_LIGHT_RADII
Definition: define.h:759
static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns)
Definition: request.c:1119
void SockList_Init(SockList *sl)
Definition: lowlevel.c:67
void send_skill_info(socket_struct *ns, char *params)
Definition: request.c:1505
#define SET_FLAG(xyz, p)
Definition: define.h:510
void receive_player_password(object *op)
Definition: c_misc.c:2160
#define FABS(x)
Definition: define.h:61
sint8 last_level
Definition: player.h:175
signed int sint32
Definition: global.h:64
#define CS_STAT_MAXGRACE
Definition: newclient.h:117
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:239
#define CS_STAT_RES_PARA
Definition: newclient.h:139
EXTERN int num_animations
Definition: global.h:242
uint32 last_path_denied
Definition: player.h:201
#define CS_STAT_SPELL_ATTUNE
Definition: newclient.h:121
#define SND_EFFECTS
Definition: sounds.h:46
void send_tick(player *pl)
Definition: request.c:1863
#define SPELL_GRACE
Definition: spells.h:87
sint16 maxgrace
Definition: living.h:86
void send_race_list(socket_struct *ns, char *params)
Definition: request.c:1578
uint32 tick
Definition: newserver.h:136
void SockList_AddShort(SockList *sl, uint16 data)
Definition: lowlevel.c:113
struct Map lastmap
Definition: newserver.h:118
void key_roll_stat(object *op, char key)
Definition: player.c:1079
sint16 max_level
Definition: global.h:391
#define SND_MUTE
Definition: sounds.h:48
#define ST_CHANGE_PASSWORD_CONFIRM
Definition: define.h:897
static object * heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS]
Definition: request.c:947
object clone
Definition: object.h:326
socket_struct socket
Definition: player.h:148
sint16 invisible
Definition: object.h:211
#define NS_FACESENT_SMOOTH
Definition: newserver.h:165
void map_redraw_cmd(char *buf, int len, player *pl)
Definition: request.c:662
#define CS_STAT_RES_BLIND
Definition: newclient.h:145
#define ST_CONFIRM_PASSWORD
Definition: define.h:893
sint64 * levels
Definition: exp.c:39
#define CS_STAT_RES_FEAR
Definition: newclient.h:141
const char * skill_names[NUM_SKILLS]
Definition: skill_util.c:65
uint32 mode
Definition: player.h:164
uint32 run_on
Definition: player.h:182
int is_valid_faceset(int fsn)
Definition: image.c:575
int SP_level_dam_adjust(const object *caster, const object *spob)
Definition: spell_util.c:332
sint64 exp
Definition: living.h:88
uint32 in_memory
Definition: map.h:366
#define CS_STAT_SPELL_REPEL
Definition: newclient.h:122
#define AddIfInt64(Old, New, Type)
Definition: request.c:736
#define CS_STAT_FOOD
Definition: newclient.h:111
#define ST_CHANGE_PASSWORD_NEW
Definition: define.h:896
enum Sock_Status status
Definition: newserver.h:116
sint16 last_sp
Definition: player.h:113
sint16 x
Definition: object.h:179
sint8 map_scroll_y
Definition: newserver.h:119
void set_sound_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:656
uint32 path_attuned
Definition: object.h:194
Fontindex * faces
Definition: face.h:59
void esrv_remove_spell(player *pl, object *spell)
Definition: request.c:1725
sint16 sp
Definition: living.h:83
#define AddIfString(Old, New, Type)
Definition: request.c:764
uint8 smoothlevel
Definition: object.h:274
#define CS_STAT_RES_PHYS
Definition: newclient.h:128
#define CS_STAT_RES_POISON
Definition: newclient.h:137
uint32 path_repelled
Definition: object.h:195
char * title
Definition: newserver.h:86
void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format,...)
Definition: standalone.c:175
sint64 last_skill_exp[NUM_SKILLS]
Definition: player.h:192
#define ST_ROLL_STAT
Definition: define.h:888
void send_class_info(socket_struct *ns, char *params)
Definition: request.c:1664
uint32 sc_version
Definition: newserver.h:141
Definition: object.h:321
#define ST_PLAYING
Definition: define.h:886
char * host
Definition: newserver.h:125
#define PLAYER
Definition: define.h:113
#define CS_STAT_MAXSP
Definition: newclient.h:97
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:126
static void build_race_list_reply(SockList *sl)
Definition: request.c:1557
#define UPD_SP_GRACE
Definition: newclient.h:266
sint16 maxsp
Definition: living.h:84
#define CS_STAT_POW
Definition: newclient.h:115
sint8 Con
Definition: living.h:78
sint16 hp
Definition: living.h:81
sint32 timeout
Definition: map.h:362
#define VERSION_SC
Definition: newserver.h:181
#define CS_STAT_RES_DEPLETE
Definition: newclient.h:142
#define MAP_LAYER_LIVING2
Definition: map.h:75
void version_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:621
client_spell * get_client_spell_state(player *pl, object *spell)
Definition: player.c:147
uint16 number
Definition: face.h:43
#define MAP_IN_MEMORY
Definition: map.h:151
#define CS_STAT_GRACE
Definition: newclient.h:116
const char * name
Definition: face.h:48
#define MAX_NUM_LOOK_OBJECTS
Definition: newserver.h:56
uint32 sound
Definition: newserver.h:139
sint16 maxhp
Definition: living.h:82
uint8 * faces_sent
Definition: newserver.h:121
#define SF_RUNON
Definition: newclient.h:178
#define CS_STAT_SKILLINFO
Definition: newclient.h:170
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:537
uint32 path_denied
Definition: object.h:196
Socket_Info socket_info
Definition: init.c:63
void SockList_AddInt64(SockList *sl, uint64 data)
Definition: lowlevel.c:137
uint32 has_readable_type
Definition: newserver.h:133
void move_cmd(char *buf, int len, player *pl)
Definition: request.c:694
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:164
#define CS_STAT_DAM
Definition: newclient.h:108
#define AddIfInt(Old, New, Type)
Definition: request.c:743
float speed_left
Definition: object.h:182
void key_change_class(object *op, char key)
Definition: player.c:1156
#define FLAG_CLIENT_SENT
Definition: define.h:645
void draw_client_map(object *pl)
Definition: request.c:1371
sint8 Wis
Definition: living.h:78
static const short atnr_cs_stat[NROFATTACKS]
Definition: request.c:96
void receive_party_password(object *op)
Definition: c_party.c:248
#define ST_CONFIRM_QUIT
Definition: define.h:890
void key_confirm_quit(object *op, char key)
Definition: player.c:1278
void add_player(socket_struct *ns)
Definition: player.c:383
short GetShort_String(const unsigned char *data)
Definition: lowlevel.c:243
struct mapdef * map
Definition: object.h:155
void SockList_Term(SockList *sl)
Definition: lowlevel.c:77
#define CS_STAT_RES_DEATH
Definition: newclient.h:143
Definition: newserver.h:77
#define CS_STAT_WIS
Definition: newclient.h:100
#define CS_STAT_WC
Definition: newclient.h:106
#define MAX_HEAD_OFFSET
Definition: newserver.h:71
#define FLAG_CLIENT_ANIM_SYNC
Definition: define.h:536
object * transport
Definition: player.h:249
static void build_class_list_reply(SockList *sl)
Definition: request.c:1620
void send_exp_table(socket_struct *ns, char *params)
Definition: request.c:1482
float weapon_sp
Definition: player.h:194
void update_position(mapstruct *m, int x, int y)
Definition: map.c:2124
sint16 dam
Definition: living.h:87
uint32 monitor_spells
Definition: newserver.h:135
#define MAP_LAYERS
Definition: map.h:60
#define CS_STAT_FLAGS
Definition: newclient.h:118
sint8 map_scroll_x
Definition: newserver.h:119
const char * name
Definition: object.h:167
static void append_spell(player *pl, SockList *sl, object *spell)
Definition: request.c:1760
struct obj * env
Definition: object.h:151
#define SPELL
Definition: define.h:283
#define MAX_TIME
Definition: config.h:221
#define CS_STAT_LEVEL
Definition: newclient.h:105
uint8 state
Definition: player.h:172
uint32 is_bot
Definition: newserver.h:137
#define ST_PLAY_AGAIN
Definition: define.h:887
struct obj * below
Definition: object.h:145
#define MSG_TYPE_LAST
Definition: newclient.h:337
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:154
#define AddIfFloat(Old, New, Type)
Definition: request.c:757
sint32 last_weight
Definition: player.h:197
unsigned char uint8
Definition: global.h:75
sint8 Cha
Definition: living.h:78
#define P_OUT_OF_MAP
Definition: map.h:272
mapstruct * get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y)
Definition: map.c:2366
EXTERN Animations * animations
Definition: global.h:241
uint32 facecache
Definition: newserver.h:128
sint16 y
Definition: object.h:179
New_Face * smooth_face
Definition: image.c:66
struct pl * contr
Definition: object.h:134
#define CS_STAT_DEX
Definition: newclient.h:101
uint8 num_animations
Definition: face.h:56
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:231
sint8 tail_y
Definition: object.h:327
#define ATNR_PHYSICAL
Definition: attack.h:77
#define CS_STAT_EXP64
Definition: newclient.h:120
#define VERSION_CS
Definition: newserver.h:180
archetype * try_find_archetype(const char *name)
Definition: arch.c:671
uint32 count
Definition: player.h:163
#define CS_STAT_RES_COLD
Definition: newclient.h:132
#define UPD_SP_MANA
Definition: newclient.h:265
char * range
Definition: newserver.h:86
float speed
Definition: object.h:181
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:78
int execute_newserver_command(object *pl, char *command)
Definition: c_new.c:98
#define CS_STAT_RES_DRAIN
Definition: newclient.h:135
uint32 last_path_repelled
Definition: player.h:200
#define MAX_BUF
Definition: define.h:81
#define CS_STAT_WEAP_SP
Definition: newclient.h:112
#define NRSPELLPATHS
Definition: spells.h:68
void send_query(socket_struct *ns, uint8 flags, const char *text)
Definition: request.c:727
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:473
#define MIN_NUM_LOOK_OBJECTS
Definition: newserver.h:44
uint16 faces[MAP_LAYERS]
Definition: newserver.h:60
uint32 supported_readables
Definition: newserver.h:140
void draw_client_map2(object *pl)
Definition: request.c:1194
#define UPD_SP_DAMAGE
Definition: newclient.h:267
#define AddIfShort(Old, New, Type)
Definition: request.c:750
unsigned short uint16
Definition: global.h:67
const char * skill
Definition: object.h:174
void add_me_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:320
#define MAP_CLIENT_X
Definition: config.h:212
#define NUM_SKILLS
Definition: skills.h:95
sint8 wc
Definition: living.h:79
void SockList_AddChar(SockList *sl, char c)
Definition: lowlevel.c:103
#define CLASS
Definition: define.h:149
static const flag_definition flags[]
client_spell * spell_state
Definition: player.h:250
#define SF_FIREON
Definition: newclient.h:177
#define CS_STAT_RES_ACID
Definition: newclient.h:134
sint8 Str
Definition: living.h:78
uint32 darkness
Definition: newserver.h:130
void receive_player_name(object *op)
Definition: c_misc.c:2142
sint16 resist[NROFATTACKS]
Definition: object.h:192
#define CS_STAT_TITLE
Definition: newclient.h:114
object * ob
Definition: player.h:207
#define CS_STAT_RES_ELEC
Definition: newclient.h:131
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Definition: map.h:205
#define P_NEW_MAP
Definition: map.h:273
#define ANIM_SYNC
Definition: newclient.h:274
#define MAP_CLIENT_Y
Definition: config.h:213
#define MAP_LAYER_LIVING1
Definition: map.h:74
sint16 last_resist[NROFATTACKS]
Definition: player.h:206
void set_up_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:116
sint16 last_grace
Definition: player.h:114
float last_speed
Definition: player.h:205
#define CS_STAT_RES_SLOW
Definition: newclient.h:138
living last_stats
Definition: player.h:204
sint16 grace
Definition: living.h:85
sint16 last_dam
Definition: player.h:115
#define NUM_ANIMATIONS(ob)
Definition: global.h:255
void esrv_send_face(socket_struct *ns, short face_num, int nocache)
Definition: image.c:96
#define CS_STAT_RES_CONF
Definition: newclient.h:133
void esrv_update_spells(player *pl)
Definition: request.c:1672
tag_t count
Definition: object.h:157
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.c:1148
living stats
Definition: object.h:219
sint8 Dex
Definition: living.h:78
struct archt * arch
Definition: object.h:263
float last_weapon_sp
Definition: player.h:195
void send_plugin_custom_message(object *pl, char *buf)
Definition: request.c:1470
#define ANIM_RANDOM
Definition: newclient.h:273
void esrv_send_pickup(player *pl)
Definition: request.c:1747
uint32 do_los
Definition: player.h:180
struct statsinfo stats
Definition: newserver.h:123
struct Settings settings
Definition: init.c:48
#define CS_STAT_RES_FIRE
Definition: newclient.h:130
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:176
void send_class_list(socket_struct *ns, char *params)
Definition: request.c:1642
struct archt * next
Definition: object.h:323
#define NROFATTACKS
Definition: attack.h:45
static void map_clearcell(struct map_cell_struct *cell, int face, int count)
Definition: request.c:933
#define CS_STAT_HP
Definition: newclient.h:94
#define ST_CHANGE_PASSWORD_OLD
Definition: define.h:895
#define MSG_TYPE_COMMAND
Definition: newclient.h:326
sint16 SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.c:281
const uint32 weight_limit[MAX_STAT+1]
Definition: living.c:143
#define ST_CHANGE_CLASS
Definition: define.h:889
const char * msg
Definition: object.h:175
uint32 fire_on
Definition: player.h:181
uint32 newmapcmd
Definition: newserver.h:129
sint16 casting_time
Definition: object.h:253
void update_los(object *op)
Definition: los.c:467
uint16 animation_id
Definition: object.h:267
void receive_play_again(object *op, char key)
Definition: player.c:839
void esrv_send_animation(socket_struct *ns, short anim_num)
Definition: request.c:895
void toggle_extended_infos_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:359
void esrv_update_stats(player *pl)
Definition: request.c:779
uint8 anim_speed
Definition: object.h:268
sint8 Pow
Definition: living.h:78
struct obj * inv
Definition: object.h:148
#define NDI_UNIQUE
Definition: newclient.h:219
struct obj * head
Definition: object.h:154
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
#define CS_STAT_INT
Definition: newclient.h:99
uint8 anims_sent[MAXANIMNUM]
Definition: newserver.h:122
unsigned int uint32
Definition: global.h:58
void set_title(const object *pl, char *buf, size_t len)
Definition: info.c:415
#define SND_MUSIC
Definition: sounds.h:47
#define CS_STAT_CON
Definition: newclient.h:102
object * last_skill_ob[NUM_SKILLS]
Definition: player.h:191
#define CS_STAT_SP
Definition: newclient.h:96
#define SPELL_MANA
Definition: spells.h:86
#define CS_STAT_CHA
Definition: newclient.h:103
void rangetostring(const object *pl, char *obuf, size_t len)
Definition: info.c:343
uint16 last_flags
Definition: player.h:196
sint8 tail_x
Definition: object.h:327
Definition: map.h:346
#define CS_STAT_RES_HOLYWORD
Definition: newclient.h:144
#define ST_GET_NAME
Definition: define.h:891
New_Face * face
Definition: object.h:183
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:119
char write_buf[MAX_BUF]
Definition: player.h:225
static int map2_add_ob(int ax, int ay, int layer, object *ob, SockList *sl, socket_struct *ns, int *has_obj, int is_head)
Definition: request.c:974
void reply_cmd(char *buf, int len, player *pl)
Definition: request.c:555
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:140
void SockList_AddInt(SockList *sl, uint32 data)
Definition: lowlevel.c:124
sint16 level
Definition: object.h:202
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:447
EXTERN archetype * first_archetype
Definition: global.h:195
void esrv_new_player(player *pl, uint32 weight)
Definition: request.c:868
void toggle_extended_text_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:398
#define MAP_NOSMOOTH(m)
Definition: map.h:108
const char * name
Definition: object.h:322
#define MAP2_COORD_ENCODE(x, y, flags)
Definition: newclient.h:74
#define CS_STAT_STR
Definition: newclient.h:98
#define CS_STAT_AC
Definition: newclient.h:107
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1432
void send_race_info(socket_struct *ns, char *params)
Definition: request.c:1600
uint8 type
Definition: object.h:189
uint32 want_pickup
Definition: newserver.h:138
sint8 blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:210
#define ST_GET_PASSWORD
Definition: define.h:892
sint32 food
Definition: living.h:89
uint8 faceset
Definition: newserver.h:144
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:541
#define CS_STAT_MAXHP
Definition: newclient.h:95
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.c:773
#define CS_STAT_RES_GHOSTHIT
Definition: newclient.h:136