Crossfire Server, Trunk
request.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
42 #include "global.h"
43 
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/time.h>
48 #include <unistd.h>
49 
50 /* This block is basically taken from socket.c - I assume if it works there,
51  * it should work here.
52  */
53 #ifndef WIN32 /* ---win32 exclude unix headers */
54 #include <sys/types.h>
55 #include <netinet/in.h>
56 #include <netinet/tcp.h>
57 #include <netdb.h>
58 typedef int ssop_t;
59 #else
60 #include <winsock2.h>
61 typedef char ssop_t;
62 #endif /* win32 */
63 
64 #include "commands.h"
65 #include "living.h"
66 #include "newserver.h"
67 #include "shared/newclient.h"
68 #include "sounds.h"
69 #include "sproto.h"
70 
71 #define VALIDCHAR_MSG "The first character must be alphanumeric and the last cannot be a space. None of these characters are allowed: :;/\\["
72 
73 static const int MAP2_COORD_MIN = -MAP2_COORD_OFFSET;
74 static const int MAP2_COORD_MAX = 63 - MAP2_COORD_OFFSET;
75 
76 static bool map2_coord_valid(int x) {
77  return x >= MAP2_COORD_MIN && x<= MAP2_COORD_MAX;
78 }
79 
89 static uint16_t MAP2_COORD_ENCODE(int x, int y, int flags) {
90  assert(map2_coord_valid(x));
91  assert(map2_coord_valid(y));
92  assert(flags >= 0 && flags <= 15);
93  return ((x+MAP2_COORD_OFFSET)&0x3f)<<10 | ((y+MAP2_COORD_OFFSET)&0x3f)<<4 | (flags&0x0f);
94 }
95 
96 static int clamp(int x, int min, int max) {
97  return MAX(min, MIN(x, max));
98 }
99 
104 static void handle_scroll(socket_struct *socket, SockList *sl) {
105  // It is possible for map_scroll_x/y to exceed the maximum value that can be encoded
106  // in one scroll command. If that is the case, encode multiple.
107  while (socket->map_scroll_x || socket->map_scroll_y) { // either are non-zero
108  int8_t tx = clamp(socket->map_scroll_x, MAP2_COORD_MIN, MAP2_COORD_MAX);
109  int8_t ty = clamp(socket->map_scroll_y, MAP2_COORD_MIN, MAP2_COORD_MAX);
110  uint16_t coord = MAP2_COORD_ENCODE(tx, ty, 1);
112  socket->map_scroll_x -= tx;
113  socket->map_scroll_y -= ty;
114  }
115 }
116 
123 static const short atnr_cs_stat[NROFATTACKS] = {
128  CS_STAT_RES_DRAIN, -1 /* weaponmagic */,
132  CS_STAT_RES_FEAR, -1 /* Cancellation */,
134  -1 /* Chaos */, -1 /* Counterspell */,
135  -1 /* Godpower */, CS_STAT_RES_HOLYWORD,
137  -1, /* Internal */
138  -1, /* life stealing */
139  -1 /* Disease - not fully done yet */
140 };
141 
143 void set_up_cmd(char *buf, int len, socket_struct *ns) {
144  int s = 0;
145  char *cmd, *param;
146  SockList sl;
147 
148  if (len <= 0 || !buf) {
149  LOG(llevDebug, "IP '%s' sent bogus set_up_cmd information\n", ns->host);
150  return;
151  }
152 
153  /* run through the cmds of setup
154  * syntax is setup <cmdname1> <parameter> <cmdname2> <parameter> ...
155  *
156  * we send the status of the cmd back, or a FALSE is the cmd
157  * is the server unknown
158  * The client then must sort this out
159  */
160 
161  LOG(llevDebug, "setup: %s\n", buf);
162  SockList_Init(&sl);
163  SockList_AddString(&sl, "setup");
164  while (s < len) {
165  cmd = &buf[s];
166 
167  /* find the next space, and put a null there */
168  for (; buf[s] && buf[s] != ' '; s++)
169  ;
170  if (s >= len)
171  break;
172  buf[s++] = 0;
173 
174  while (buf[s] == ' ')
175  s++;
176  if (s >= len)
177  break;
178  param = &buf[s];
179 
180  for (; buf[s] && buf[s] != ' '; s++)
181  ;
182  buf[s++] = 0;
183 
184  while (s < len && buf[s] == ' ')
185  s++;
186 
187  SockList_AddPrintf(&sl, " %s ", cmd);
188 
189  if (!strcmp(cmd, "sound2")) {
190  ns->sound = atoi(param)&(SND_EFFECTS|SND_MUSIC|SND_MUTE);
191  SockList_AddString(&sl, param);
192  } else if (!strcmp(cmd, "spellmon")) {
193  int monitor_spells;
194 
195  monitor_spells = atoi(param);
196  if (monitor_spells < 0 || monitor_spells > 2) {
197  SockList_AddString(&sl, "FALSE");
198  } else {
199  ns->monitor_spells = monitor_spells;
200  SockList_AddPrintf(&sl, "%d", monitor_spells);
201  }
202  } else if (!strcmp(cmd, "darkness")) {
203  int darkness;
204 
205  darkness = atoi(param);
206  if (darkness != 0 && darkness != 1) {
207  SockList_AddString(&sl, "FALSE");
208  } else {
209  ns->darkness = darkness;
210  SockList_AddPrintf(&sl, "%d", darkness);
211  }
212  } else if (!strcmp(cmd, "map2cmd")) {
213  int map2cmd;
214 
215  map2cmd = atoi(param);
216  if (map2cmd != 1) {
217  SockList_AddString(&sl, "FALSE");
218  } else {
219  SockList_AddString(&sl, "1");
220  }
221  } else if (!strcmp(cmd, "facecache")) {
222  int facecache;
223 
224  facecache = atoi(param);
225  if (facecache != 0 && facecache != 1) {
226  SockList_AddString(&sl, "FALSE");
227  } else {
228  ns->facecache = facecache;
229  SockList_AddPrintf(&sl, "%d", facecache);
230  }
231  } else if (!strcmp(cmd, "faceset")) {
232  int q = atoi(param);
233 
234  if (is_valid_faceset(q))
235  ns->faceset = q;
236  SockList_AddPrintf(&sl, "%d", ns->faceset);
237  } else if (!strcmp(cmd, "mapsize")) {
238  int x, y, n;
239 
240  if (sscanf(param, "%dx%d%n", &x, &y, &n) != 2 || n != (int)strlen(param)) {
241  /* mapsize command is invalid, return maximum map size */
242  x = 0;
243  y = 0;
244  }
245 
246  /* Return the maximum map size if the requested x/y is 0, as per
247  * protocol.txt. Note this does not actually change the map size.
248  */
249  if ((x <= 0) && (y <= 0)) {
251  } else {
252  player *pl;
253 
254  /* Constrain the provided map size to what is defined in config.h */
255  if (x < MAP_CLIENT_X_MINIMUM)
257  if (y < MAP_CLIENT_Y_MINIMUM)
259  if (x > MAP_CLIENT_X)
260  x = MAP_CLIENT_X;
261  if (y > MAP_CLIENT_Y)
262  y = MAP_CLIENT_Y;
263 
264  ns->mapx = x;
265  ns->mapy = y;
266 
267  /* better to send back what we are really using and not the
268  * param as given to us in case it gets parsed differently.
269  */
270  SockList_AddPrintf(&sl, "%dx%d", x, y);
271 
272  /* need to update the los, else the view jumps */
273  pl = find_player_socket(ns);
274  if (pl)
275  update_los(pl->ob);
276 
277  /* Client and server need to resynchronize on data - treating it as
278  * a new map is best way to go.
279  */
280  map_newmap_cmd(ns);
281  }
282  } else if (!strcmp(cmd, "tick")) {
283  int tick;
284 
285  tick = atoi(param);
286  if (tick != 0 && tick != 1) {
287  SockList_AddString(&sl, "FALSE");
288  } else {
289  ns->tick = tick;
290  SockList_AddPrintf(&sl, "%d", tick);
291  }
292  } else if (!strcmp(cmd, "bot")) {
293  int is_bot;
294 
295  is_bot = atoi(param);
296  if (is_bot != 0 && is_bot != 1) {
297  SockList_AddString(&sl, "FALSE");
298  } else {
299  ns->is_bot = is_bot;
300  SockList_AddPrintf(&sl, "%d", is_bot);
301  }
302  } else if (!strcmp(cmd, "want_pickup")) {
303  int want_pickup;
304 
305  want_pickup = atoi(param);
306  if (want_pickup != 0 && want_pickup != 1) {
307  SockList_AddString(&sl, "FALSE");
308  } else {
309  ns->want_pickup = want_pickup;
310  SockList_AddPrintf(&sl, "%d", want_pickup);
311  }
312  } else if (!strcmp(cmd, "num_look_objects")) {
313  int tmp;
314  player *pl;
315 
316  tmp = atoi(param);
317  if (tmp < MIN_NUM_LOOK_OBJECTS) {
319  } else if (tmp > MAX_NUM_LOOK_OBJECTS) {
321  }
322  ns->num_look_objects = (uint8_t)tmp;
323  SockList_AddPrintf(&sl, "%d", tmp);
324 
325  pl = find_player_socket(ns);
326  if (pl && pl->ob) {
327  ns->update_look = 1;
328  esrv_draw_look(pl->ob);
329  }
330  } else if (!strcmp(cmd, "extended_stats")) {
331  int extended_stats;
332 
333  extended_stats = atoi(param);
334  if (extended_stats != 0 && extended_stats != 1) {
335  SockList_AddString(&sl, "FALSE");
336  } else {
337  ns->extended_stats = extended_stats;
338  SockList_AddPrintf(&sl, "%d", extended_stats);
339  }
340  } else if (!strcmp(cmd, "beat")) {
341  int use_beat = atoi(param);
342 
343  if (use_beat != 0 && use_beat != 1) {
344  SockList_AddString(&sl, "FALSE");
345  } else {
346  ns->heartbeat = use_beat ? true : false;
347 
348  // Send setup command with standard beat interval.
349  SockList_AddPrintf(&sl, "%d", BEAT_INTERVAL);
350  }
351  } else if (!strcmp(cmd, "loginmethod")) {
352  int loginmethod;
353 
354  loginmethod = atoi(param);
355 
356  /* Only support basic login right now */
357  if (loginmethod > 2) loginmethod=2;
358 
359  ns->login_method = loginmethod;
360  SockList_AddPrintf(&sl, "%d", loginmethod);
361 
362  } else if (!strcmp(cmd, "notifications")) {
363  int notifications;
364 
365  notifications = atoi(param);
366 
367  ns->notifications = MIN(notifications, 3);
368  SockList_AddPrintf(&sl, "%d", ns->notifications);
369 
370  } else if (!strcmp(cmd, "newmapcmd")) {
371  /* newmapcmd is deprecated (now standard part), but some
372  * clients still use this setup option, and if the server
373  * doesn't respond, erroneously report that the client is
374  * too old. Since it is always on, regardless of what is
375  * request, send back one.
376  */
377  SockList_AddString(&sl, "1");
378  } else if (!strcmp(cmd, "extendedTextInfos")) {
379  /* like newmapcmd above, extendedTextInfos is
380  * obsolete, but we respond for the same reason as we do
381  * in newmapcmd
382  */
383  SockList_AddString(&sl, "1");
384  } else if (!strcmp(cmd, "itemcmd")) {
385  /* like newmapcmd above, itemcmd is
386  * obsolete, but we respond for the same reason as we do
387  * in newmapcmd
388  */
389  SockList_AddString(&sl, "2");
390  } else if (!strcmp(cmd, "exp64")) {
391  /* like newmapcmd above, exp64 is
392  * obsolete, but we respond for the same reason as we do
393  * in newmapcmd
394  */
395  SockList_AddString(&sl, "1");
396  } else {
397  /* Didn't get a setup command we understood -
398  * report a failure to the client.
399  */
400  SockList_AddString(&sl, "FALSE");
401  }
402  } /* for processing all the setup commands */
403  Send_With_Handling(ns, &sl);
404  SockList_Term(&sl);
405 }
406 
415 void add_me_cmd(char *buf, int len, socket_struct *ns) {
416  Settings oldsettings;
417  SockList sl;
418  (void)buf;
419  (void)len;
420 
421  oldsettings = settings;
422  if (ns->status != Ns_Add) {
423  SockList_Init(&sl);
424  SockList_AddString(&sl, "addme_failed");
425  Send_With_Handling(ns, &sl);
426  SockList_Term(&sl);
427  } else if (find_player_socket(ns) == NULL) {
428  /* if there is already a player for this socket (add_me was already called),
429  * just ignore, else weird issues. */
430 
431  add_player(ns, 0);
432  /* Basically, the add_player copies the socket structure into
433  * the player structure, so this one (which is from init_sockets)
434  * is not needed anymore. The write below should still work,
435  * as the stuff in ns is still relevant.
436  */
437  SockList_Init(&sl);
438  SockList_AddString(&sl, "addme_success");
439  Send_With_Handling(ns, &sl);
440  SockList_Term(&sl);
441  if (ns->sc_version < 1027 || ns->cs_version < 1023) {
443  "Warning: Your client is too old to receive map data. Please update to a new client at: "
444  "https://sourceforge.net/projects/crossfire/");
445  }
446  }
447  settings = oldsettings;
448 }
449 
459 static void send_smooth(socket_struct *ns, const Face *face) {
460  const Face *smoothface;
461  SockList sl;
462 
463  // A malicious client can send bogus asksmooth commands that don't
464  // translate to any face. Catch those here before the message below
465  // in order to avoid a segfault.
466  if (!face) {
467  LOG(llevError, "Tried to smooth null face.\n");
468  return;
469  }
470 
471  // Try to find a smoothing face, or the default smoothing face. If this
472  // fails, set NS_FACESENT_SMOOTH so we don't try to send it again.
473  //
474  // Failures are usually due to map makers changing the face of a ground
475  // tile, but forgetting to unset smoothlevel.
476  if (!find_smooth(face, &smoothface)
477  && !find_smooth(smooth_face, &smoothface)) {
478  LOG(llevInfo,
479  "Could not smooth face %s. "
480  "Check that this face has a smoothing pixmap, or remove its smoothlevel.\n",
481  face->name);
482  ns->faces_sent[face->number] |= NS_FACESENT_SMOOTH;
483  return;
484  }
485 
486  if (!(ns->faces_sent[smoothface->number]&NS_FACESENT_FACE))
487  esrv_send_face(ns, smoothface, 0);
488 
489  ns->faces_sent[face->number] |= NS_FACESENT_SMOOTH;
490 
491  SockList_Init(&sl);
492  SockList_AddString(&sl, "smooth ");
493  SockList_AddShort(&sl, face->number);
494  SockList_AddShort(&sl, smoothface->number);
495  Send_With_Handling(ns, &sl);
496  SockList_Term(&sl);
497 }
498 
503 void ask_smooth_cmd(char *buf, int len, socket_struct *ns) {
504  uint16_t facenid;
505 
506  if (len <= 0 || !buf) {
507  LOG(llevDebug, "IP '%s' sent bogus ask_smooth_cmd information\n", ns->host);
508  return;
509  }
510 
511  facenid = atoi(buf);
512  send_smooth(ns, get_face_by_id(facenid));
513 }
514 
527 void new_player_cmd(uint8_t *buf, int len, player *pl) {
528  int time, repeat;
529  short packet;
530  char command[MAX_BUF];
531  SockList sl;
532 
533  if (len < 7) {
534  LOG(llevDebug, "Corrupt ncom command - not long enough - discarding\n");
535  return;
536  }
537 
538  packet = GetShort_String(buf);
539  repeat = GetInt_String(buf+2);
540  /* -1 is special - no repeat, but don't update */
541  if (repeat != -1) {
542  pl->count = repeat;
543  }
544  if (len-4 >= MAX_BUF)
545  len = MAX_BUF-5;
546 
547  strncpy(command, (char *)buf+6, len-4);
548  command[len-4] = '\0';
549 
550  /* The following should never happen with a proper or honest client.
551  * Therefore, the error message doesn't have to be too clear - if
552  * someone is playing with a hacked/non working client, this gives them
553  * an idea of the problem, but they deserve what they get
554  */
555  if (pl->state != ST_PLAYING) {
557  "You can not issue commands - state is not ST_PLAYING (%s)",
558  buf);
559  return;
560  }
561 
562  /* This should not happen anymore. */
563  if (pl->ob->speed_left < 0) {
564  LOG(llevError, "Player %s (%s) has negative time - shouldn't do command.\n",
565  pl->ob->name ? pl->ob->name : "(unnamed)", pl->socket->account_name ? pl->socket->account_name : "(no account)");
566  }
567  command_execute(pl->ob, command);
568  /* Perhaps something better should be done with a left over count.
569  * Cleaning up the input should probably be done first - all actions
570  * for the command that issued the count should be done before
571  * any other commands.
572  */
573  pl->count = 0;
574 
575  /* Send confirmation of command execution now */
576  SockList_Init(&sl);
577  SockList_AddString(&sl, "comc ");
578  SockList_AddShort(&sl, packet);
579  if (FABS(pl->ob->speed) < 0.001)
580  time = MAX_TIME*100;
581  else
582  time = (int)(MAX_TIME/FABS(pl->ob->speed));
583  SockList_AddInt(&sl, time);
584  Send_With_Handling(pl->socket, &sl);
585  SockList_Term(&sl);
586 }
587 
589 void reply_cmd(char *buf, int len, player *pl) {
590 
591  if (len <= 0 || !buf) {
592  LOG(llevDebug, "Player '%s' sent bogus reply_cmd information\n", pl->ob->name);
593  return;
594  }
595 
596  /* this avoids any hacking here */
597 
598  switch (pl->state) {
599  case ST_PLAYING:
600  LOG(llevError, "Got reply message with ST_PLAYING input state\n");
601  break;
602 
603  case ST_PLAY_AGAIN:
604  /* We can check this for return value (2==quit). Maybe we
605  * should, and do something appropriate?
606  */
607  receive_play_again(pl->ob, buf[0]);
608  break;
609 
610  case ST_ROLL_STAT:
611  key_roll_stat(pl->ob, buf[0]);
612  break;
613 
614  case ST_CHANGE_CLASS:
615 
616  key_change_class(pl->ob, buf[0]);
617  break;
618 
619  case ST_CONFIRM_QUIT:
620  key_confirm_quit(pl->ob, buf[0]);
621  break;
622 
623  case ST_GET_NAME:
624  receive_player_name(pl->ob, buf);
625  break;
626 
627  case ST_GET_PASSWORD:
628  case ST_CONFIRM_PASSWORD:
633  break;
634 
635  case ST_GET_PARTY_PASSWORD: /* Get password for party */
637  break;
638 
639  default:
640  LOG(llevError, "Unknown input state: %d\n", pl->state);
641  }
642 }
643 
651 void version_cmd(char *buf, int len, socket_struct *ns) {
652  char *rest = NULL;
653  char *cs_str = strtok_r(buf, " ", &rest);
654  char *sc_str = strtok_r(NULL, " ", &rest);
655  (void)len;
656 
657  if (cs_str == NULL || sc_str == NULL) {
658  LOG(llevError, "%s: sent invalid version string\n", ns->host);
659  return;
660  } else {
661  ns->cs_version = atoi(cs_str);
662  ns->sc_version = atoi(sc_str);
663  }
664 
665 #ifdef ESRV_DEBUG
666  if (VERSION_CS != ns->cs_version) {
667  LOG(llevDebug, "CS: csversion mismatch (%d,%d)\n", VERSION_CS, ns->cs_version);
668  }
669 
670  if (VERSION_SC != ns->sc_version) {
671  LOG(llevDebug, "CS: scversion mismatch (%d,%d)\n", VERSION_SC, ns->sc_version);
672  }
673 #endif
674 
675  if (rest != NULL) {
676  LOG(llevInfo, "Connection from %s (%s), CS %d, SC %d\n",
677  ns->host, rest, ns->cs_version, ns->sc_version);
678  }
679 }
680 
688  SockList sl;
689 
690  /* If getting a newmap command, this scroll information
691  * is no longer relevant.
692  */
693  ns->map_scroll_x = 0;
694  ns->map_scroll_y = 0;
695 
696 
697  memset(&ns->lastmap, 0, sizeof(ns->lastmap));
698  SockList_Init(&sl);
699  SockList_AddString(&sl, "newmap");
700  Send_With_Handling(ns, &sl);
701  SockList_Term(&sl);
702 }
703 
708 void move_cmd(char *buf, int len, player *pl) {
709  int vals[3], i;
710 
711  if (len <= 0 || !buf) {
712  LOG(llevDebug, "Player '%s' sent bogus move_cmd information\n", pl->ob->name);
713  return;
714  }
715 
716  /* A little funky here. We only cycle for 2 records, because
717  * we obviously am not going to find a space after the third
718  * record. Perhaps we should just replace this with a
719  * sscanf?
720  */
721  for (i = 0; i < 2; i++) {
722  vals[i] = atoi(buf);
723  if (!(buf = strchr(buf, ' '))) {
724  LOG(llevError, "Incomplete move command: %s\n", buf);
725  return;
726  }
727  buf++;
728  }
729  vals[2] = atoi(buf);
730 
731 /* LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
732  esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
733 }
734 
735 /***************************************************************************
736  *
737  * Start of commands the server sends to the client.
738  *
739  ***************************************************************************
740  */
741 
746 void send_query(socket_struct *ns, uint8_t flags, const char *text) {
747  SockList sl;
748 
749  SockList_Init(&sl);
750  SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
751  Send_With_Handling(ns, &sl);
752  SockList_Term(&sl);
753 }
754 
755 #define AddIfInt64(Old, New, sl, Type) \
756  if (Old != New) { \
757  Old = New; \
758  SockList_AddChar(sl, Type); \
759  SockList_AddInt64(sl, New); \
760  }
761 
762 #define AddIfInt(Old, New, sl, Type) \
763  if (Old != New) { \
764  Old = New; \
765  SockList_AddChar(sl, Type); \
766  SockList_AddInt(sl, New); \
767  }
768 
769 #define AddIfShort(Old, New, sl, Type) \
770  if (Old != New) { \
771  Old = New; \
772  SockList_AddChar(sl, Type); \
773  SockList_AddShort(sl, New); \
774  }
775 
776 #define AddIfFloat(Old, New, sl, Type) \
777  if (Old != New) { \
778  Old = New; \
779  SockList_AddChar(sl, Type); \
780  SockList_AddInt(sl, (long)(New*FLOAT_MULTI));\
781  }
782 
783 #define AddIfString(Old, New, sl, Type) \
784  if (Old == NULL || strcmp(Old, New)) { \
785  free(Old); \
786  Old = strdup_local(New); \
787  SockList_AddChar(sl, Type); \
788  SockList_AddLen8Data(sl, New, strlen(New)); \
789  }
790 
796 static uint8_t is_perfect(const player *pl) {
797  const int16_t until = MIN(11, pl->ob->level);
798  for (int16_t i = 1; i < until; i++) {
799  if (pl->levhp[i] < 9 || pl->levsp[i] < 6 || pl->levgrace[i] < 3) {
800  return 0;
801  }
802  }
803  return 1;
804 }
805 
811 static void send_extra_stats(SockList *sl, player *pl) {
812  uint32_t uflags = 0;
813  const char *god = "none";
814 
815  if (pl->socket->notifications < 3) {
816  return;
817  }
818 
819  if (!pl->peaceful) {
820  uflags |= CF_HOSTILE;
821  }
822  if (!is_perfect(pl)) {
823  uflags |= CF_NOT_PERFECT;
824  }
825 
826 #define FIF(F, C) \
827  if (QUERY_FLAG(pl->ob, F)) { \
828  uflags |= C; \
829  }
831  FIF(FLAG_CONFUSED, CF_CONFUSED); // If confused by an item
835 
836  FOR_INV_PREPARE(pl->ob, item) {
837  if (item->type == DISEASE && !QUERY_FLAG(item, FLAG_STARTEQUIP)) {
838  uflags |= CF_DISEASED;
839  }
840  if (strcmp(item->arch->name, "poisoning") == 0) {
841  uflags |= CF_POISONED;
842  }
843  if (strcmp(item->arch->name, "blindness") == 0) {
844  uflags |= CF_BLIND;
845  }
846  if (item->type == FORCE && strcmp(item->name, "confusion") == 0) {
847  uflags |= CF_CONFUSED;
848  }
849  if (item->type == SKILL && item->subtype == SK_PRAYING && item->title) {
850  god = item->title;
851  }
852  }
853  FOR_INV_FINISH();
854 
855  AddIfInt(pl->last_character_flags, uflags, sl, CS_STAT_CHARACTER_FLAGS);
856  AddIfFloat(pl->last_character_load, pl->character_load, sl, CS_STAT_OVERLOAD);
857  AddIfString(pl->socket->stats.god, god, sl, CS_STAT_GOD_NAME);
858  AddIfShort(pl->last_item_power, pl->item_power, sl, CS_STAT_ITEM_POWER);
859 }
860 
868  SockList sl;
869  char buf[MAX_BUF];
870  uint16_t flags;
871  uint8_t s;
872 
873  SockList_Init(&sl);
874  SockList_AddString(&sl, "stats ");
875 
876  if (pl->ob != NULL) {
877  AddIfShort(pl->last_stats.hp, pl->ob->stats.hp, &sl, CS_STAT_HP);
878  AddIfShort(pl->last_stats.maxhp, pl->ob->stats.maxhp, &sl, CS_STAT_MAXHP);
879  AddIfShort(pl->last_stats.sp, pl->ob->stats.sp, &sl, CS_STAT_SP);
880  AddIfShort(pl->last_stats.maxsp, pl->ob->stats.maxsp, &sl, CS_STAT_MAXSP);
881  AddIfShort(pl->last_stats.grace, pl->ob->stats.grace, &sl, CS_STAT_GRACE);
882  AddIfShort(pl->last_stats.maxgrace, pl->ob->stats.maxgrace, &sl, CS_STAT_MAXGRACE);
883  AddIfShort(pl->last_stats.Str, pl->ob->stats.Str, &sl, CS_STAT_STR);
884  AddIfShort(pl->last_stats.Int, pl->ob->stats.Int, &sl, CS_STAT_INT);
885  AddIfShort(pl->last_stats.Pow, pl->ob->stats.Pow, &sl, CS_STAT_POW);
886  AddIfShort(pl->last_stats.Wis, pl->ob->stats.Wis, &sl, CS_STAT_WIS);
887  AddIfShort(pl->last_stats.Dex, pl->ob->stats.Dex, &sl, CS_STAT_DEX);
888  AddIfShort(pl->last_stats.Con, pl->ob->stats.Con, &sl, CS_STAT_CON);
889  AddIfShort(pl->last_stats.Cha, pl->ob->stats.Cha, &sl, CS_STAT_CHA);
890  }
891  if (pl->socket->extended_stats) {
892  int16_t golem_hp, golem_maxhp;
893  AddIfShort(pl->last_orig_stats.Str, pl->orig_stats.Str, &sl, CS_STAT_BASE_STR);
894  AddIfShort(pl->last_orig_stats.Int, pl->orig_stats.Int, &sl, CS_STAT_BASE_INT);
895  AddIfShort(pl->last_orig_stats.Pow, pl->orig_stats.Pow, &sl, CS_STAT_BASE_POW);
896  AddIfShort(pl->last_orig_stats.Wis, pl->orig_stats.Wis, &sl, CS_STAT_BASE_WIS);
897  AddIfShort(pl->last_orig_stats.Dex, pl->orig_stats.Dex, &sl, CS_STAT_BASE_DEX);
898  AddIfShort(pl->last_orig_stats.Con, pl->orig_stats.Con, &sl, CS_STAT_BASE_CON);
899  AddIfShort(pl->last_orig_stats.Cha, pl->orig_stats.Cha, &sl, CS_STAT_BASE_CHA);
900  if (pl->ob != NULL) {
901  AddIfShort(pl->last_race_stats.Str, 20 + pl->ob->arch->clone.stats.Str, &sl, CS_STAT_RACE_STR);
902  AddIfShort(pl->last_race_stats.Int, 20 + pl->ob->arch->clone.stats.Int, &sl, CS_STAT_RACE_INT);
903  AddIfShort(pl->last_race_stats.Pow, 20 + pl->ob->arch->clone.stats.Pow, &sl, CS_STAT_RACE_POW);
904  AddIfShort(pl->last_race_stats.Wis, 20 + pl->ob->arch->clone.stats.Wis, &sl, CS_STAT_RACE_WIS);
905  AddIfShort(pl->last_race_stats.Dex, 20 + pl->ob->arch->clone.stats.Dex, &sl, CS_STAT_RACE_DEX);
906  AddIfShort(pl->last_race_stats.Con, 20 + pl->ob->arch->clone.stats.Con, &sl, CS_STAT_RACE_CON);
907  AddIfShort(pl->last_race_stats.Cha, 20 + pl->ob->arch->clone.stats.Cha, &sl, CS_STAT_RACE_CHA);
908  AddIfShort(pl->last_applied_stats.Str, pl->applied_stats.Str, &sl, CS_STAT_APPLIED_STR);
909  AddIfShort(pl->last_applied_stats.Int, pl->applied_stats.Int, &sl, CS_STAT_APPLIED_INT);
910  AddIfShort(pl->last_applied_stats.Pow, pl->applied_stats.Pow, &sl, CS_STAT_APPLIED_POW);
911  AddIfShort(pl->last_applied_stats.Wis, pl->applied_stats.Wis, &sl, CS_STAT_APPLIED_WIS);
912  AddIfShort(pl->last_applied_stats.Dex, pl->applied_stats.Dex, &sl, CS_STAT_APPLIED_DEX);
913  AddIfShort(pl->last_applied_stats.Con, pl->applied_stats.Con, &sl, CS_STAT_APPLIED_CON);
914  AddIfShort(pl->last_applied_stats.Cha, pl->applied_stats.Cha, &sl, CS_STAT_APPLIED_CHA);
915  }
916  if (pl->ranges[range_golem]) {
917  object *golem = pl->ranges[range_golem];
918  if (QUERY_FLAG(golem, FLAG_REMOVED) || golem->count != pl->golem_count || QUERY_FLAG(golem, FLAG_FREED)) {
919  golem_hp = 0;
920  golem_maxhp = 0;
921  } else {
922  golem_hp = golem->stats.hp;
923  golem_maxhp = golem->stats.maxhp;
924  }
925  } else {
926  golem_hp = 0;
927  golem_maxhp = 0;
928  }
929  /* send first the maxhp, so the client can set up the display */
930  AddIfShort(pl->last_golem_maxhp, golem_maxhp, &sl, CS_STAT_GOLEM_MAXHP);
931  AddIfShort(pl->last_golem_hp, golem_hp, &sl, CS_STAT_GOLEM_HP);
932  }
933 
934  for (s = 0; s < MAX_SKILLS; s++) {
935  if (pl->last_skill_ob[s]) {
936  // Skill objects can be removed without updating last_skill_ob.
937  // Clean them up here if that's the case.
938  if (QUERY_FLAG(pl->last_skill_ob[s], FLAG_REMOVED)) {
939  LOG(llevDebug, "pruning removed object from last_skill_ob\n");
940  pl->last_skill_ob[s] = NULL;
941  continue;
942  }
943 
944  if (pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
945  /* Always send along the level if exp changes. This
946  * is only 1 extra byte, but keeps processing simpler.
947  */
948  SockList_AddChar(&sl, (char)(get_skill_client_code(pl->last_skill_ob[s]->name) + CS_STAT_SKILLINFO));
949  SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
950  SockList_AddInt64(&sl, pl->last_skill_ob[s]->stats.exp);
951  pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
952  }
953  }
954  }
955  AddIfInt64(pl->last_stats.exp, pl->ob->stats.exp, &sl, CS_STAT_EXP64);
956  AddIfShort(pl->last_level, (char)pl->ob->level, &sl, CS_STAT_LEVEL);
957  AddIfShort(pl->last_stats.wc, pl->ob->stats.wc, &sl, CS_STAT_WC);
958  AddIfShort(pl->last_stats.ac, pl->ob->stats.ac, &sl, CS_STAT_AC);
959  AddIfShort(pl->last_stats.dam, pl->ob->stats.dam, &sl, CS_STAT_DAM);
960  AddIfFloat(pl->last_speed, pl->ob->speed, &sl, CS_STAT_SPEED);
961  AddIfShort(pl->last_stats.food, pl->ob->stats.food, &sl, CS_STAT_FOOD);
962  AddIfFloat(pl->last_weapon_sp, pl->ob->weapon_speed, &sl, CS_STAT_WEAP_SP);
963  AddIfInt(pl->last_weight_limit, (int32_t)get_weight_limit(pl->ob->stats.Str), &sl, CS_STAT_WEIGHT_LIM);
964  flags = 0;
965  if (pl->fire_on)
966  flags |= SF_FIREON;
967  if (pl->run_on)
968  flags |= SF_RUNON;
969 
970  AddIfShort(pl->last_flags, flags, &sl, CS_STAT_FLAGS);
971  if (pl->socket->sc_version < 1025) {
972  AddIfShort(pl->last_resist[ATNR_PHYSICAL], pl->ob->resist[ATNR_PHYSICAL], &sl, CS_STAT_ARMOUR);
973  } else {
974  int i;
975 
976  for (i = 0; i < NROFATTACKS; i++) {
977  /* Skip ones we won't send */
978  if (atnr_cs_stat[i] == -1)
979  continue;
980  AddIfShort(pl->last_resist[i], pl->ob->resist[i], &sl, (char)atnr_cs_stat[i]);
981  }
982  }
983  if (pl->socket->monitor_spells) {
984  AddIfInt(pl->last_path_attuned, pl->ob->path_attuned, &sl, CS_STAT_SPELL_ATTUNE);
985  AddIfInt(pl->last_path_repelled, pl->ob->path_repelled, &sl, CS_STAT_SPELL_REPEL);
986  AddIfInt(pl->last_path_denied, pl->ob->path_denied, &sl, CS_STAT_SPELL_DENY);
987  }
988  /* we want to use the new fire & run system in new client */
989  rangetostring(pl->ob, buf, sizeof(buf));
990  AddIfString(pl->socket->stats.range, buf, &sl, CS_STAT_RANGE);
991  set_title(pl->ob, buf, sizeof(buf));
992  AddIfString(pl->socket->stats.title, buf, &sl, CS_STAT_TITLE);
993 
994  send_extra_stats(&sl, pl);
995 
996  /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
997  if (sl.len > 8) {
998 #ifdef ESRV_DEBUG
999  LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
1000 #endif
1001  Send_With_Handling(pl->socket, &sl);
1002  }
1003  SockList_Term(&sl);
1004 }
1005 
1009 void esrv_new_player(player *pl, uint32_t weight) {
1010  SockList sl;
1011 
1012  pl->last_weight = weight;
1013 
1014  if (!(pl->socket->faces_sent[pl->ob->face->number]&NS_FACESENT_FACE))
1015  esrv_send_face(pl->socket, pl->ob->face, 0);
1016 
1017  SockList_Init(&sl);
1018  SockList_AddString(&sl, "player ");
1019  SockList_AddInt(&sl, pl->ob->count);
1020  SockList_AddInt(&sl, weight);
1021  SockList_AddInt(&sl, pl->ob->face->number);
1022  SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
1023 
1024  Send_With_Handling(pl->socket, &sl);
1025  SockList_Term(&sl);
1027 }
1028 
1040  SockList sl;
1041  int i;
1042 
1043  if (anim == NULL) {
1044  LOG(llevError, "esrv_send_anim NULL??\n");
1045  return;
1046  }
1047 
1048  SockList_Init(&sl);
1049  SockList_AddString(&sl, "anim ");
1050  SockList_AddShort(&sl, anim->num);
1051  SockList_AddShort(&sl, 0); /* flags - not used right now */
1052  /* Build up the list of faces. Also, send any information (ie, the
1053  * the face itself) down to the client.
1054  */
1055  for (i = 0; i < anim->num_animations; i++) {
1056  if (!(ns->faces_sent[anim->faces[i]->number]&NS_FACESENT_FACE))
1057  esrv_send_face(ns, anim->faces[i], 0);
1058  /* flags - not used right now */
1059  SockList_AddShort(&sl, anim->faces[i]->number);
1060  }
1061  Send_With_Handling(ns, &sl);
1062  SockList_Term(&sl);
1063  ns->anims_sent[anim->num] = 1;
1064 }
1065 
1066 /****************************************************************************
1067  *
1068  * Start of map related commands.
1069  *
1070  ****************************************************************************/
1071 
1073 static void map_clearcell(struct map_cell_struct *cell, int face, int darkness) {
1074  cell->darkness = darkness;
1075  memset(cell->faces, face, sizeof(cell->faces));
1076 }
1077 
1078 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
1079 
1087 static const object *heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS];
1088 
1089 /****************************************************************************
1090  * This block is for map2 drawing related commands.
1091  * Note that the map2 still uses other functions.
1092  *
1093  ***************************************************************************/
1094 
1114 static int map2_add_ob(int ax, int ay, int layer, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int is_head) {
1115  uint8_t nlayer, smoothlevel = 0;
1116  const object *head;
1117 
1118  assert(ob != NULL);
1119 
1120  head = HEAD(ob);
1121  const Face *face = ob->face;
1122 
1123  /* This is a multipart object, and we are not at the lower
1124  * right corner. So we need to store away the lower right corner.
1125  */
1126  if (!is_head && (head->arch->tail_x || head->arch->tail_y)
1127  && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
1128  int bx, by, l;
1129 
1130  /* Basically figure out where the offset is from where we
1131  * are right now. the ob->arch->clone.{x,y} values hold
1132  * the offset that this current piece is from the head,
1133  * and the tail is where the tail is from the head.
1134  * Note that bx and by will equal sx and sy if we are
1135  * already working on the bottom right corner. If ob is
1136  * the head, the clone values will be zero, so the right
1137  * thing will still happen.
1138  */
1139  bx = ax+head->arch->tail_x-ob->arch->clone.x;
1140  by = ay+head->arch->tail_y-ob->arch->clone.y;
1141 
1142  /* I don't think this can ever happen, but better to check
1143  * for it just in case.
1144  */
1145  if (bx < ax || by < ay) {
1146  LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
1147  face = NULL;
1148  }
1149  /* the target position must be within +/-1 of our current
1150  * layer as the layers are defined. We are basically checking
1151  * to see if we have already stored this object away.
1152  */
1153  for (l = layer-1; l <= layer+1; l++) {
1154  if (l < 0 || l >= MAP_LAYERS)
1155  continue;
1156  if (heads[by][bx][l] == head)
1157  break;
1158  }
1159  /* Didn't find it. So we need to store it away. Try to store it
1160  * on our original layer, and then move up a layer.
1161  */
1162  if (l == layer+2) {
1163  if (!heads[by][bx][layer])
1164  heads[by][bx][layer] = head;
1165  else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
1166  heads[by][bx][layer+1] = head;
1167  }
1168  return 0;
1169  /* Ok - All done storing away the head for future use */
1170  } else {
1171  uint16_t face_num = face ? face->number : 0;
1172  (*has_obj)++;
1175  face_num = (ob->animation ? ob->animation->num : 0)|(1<<15);
1177  face_num |= ANIM_SYNC;
1179  face_num |= ANIM_RANDOM;
1180  }
1181  /* Since face_num includes the bits for the animation tag,
1182  * and we will store that away in the faces[] array, below
1183  * check works fine _except_ for the case where animation
1184  * speed chances.
1185  */
1186  if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
1187  uint8_t len, anim_speed = 0, i;
1188 
1189  /* This block takes care of sending the actual face
1190  * to the client. */
1191  ns->lastmap.cells[ax][ay].faces[layer] = face_num;
1192 
1193  /* Now form the data packet */
1194  nlayer = MAP2_LAYER_START+layer;
1195 
1196  len = 2;
1197 
1198  if (ob->map && !MAP_NOSMOOTH(ob->map)) {
1199  smoothlevel = ob->smoothlevel;
1200  if (smoothlevel)
1201  len++;
1202  }
1203 
1206  len++;
1207  /* 1/0.004 == 250, so this is a good cap for an
1208  * upper limit */
1209  if (ob->anim_speed)
1210  anim_speed = ob->anim_speed;
1211  else if (FABS(ob->speed) < 0.004)
1212  anim_speed = 255;
1213  else if (FABS(ob->speed) >= 1.0)
1214  anim_speed = 1;
1215  else
1216  anim_speed = (int)(1.0/FABS(ob->speed));
1217 
1218  if (ob->animation && !ns->anims_sent[ob->animation->num])
1219  esrv_send_animation(ns, ob->animation);
1220 
1221  /* If smoothing, need to send smoothing information
1222  * for all faces in the animation sequence. Since
1223  * smoothlevel is an object attribute,
1224  * it applies to all faces.
1225  */
1226  if (smoothlevel) {
1227  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1228  if (!(ns->faces_sent[ob->animation->faces[i]->number]&NS_FACESENT_SMOOTH))
1229  send_smooth(ns, ob->animation->faces[i]);
1230  }
1231  }
1232  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1233  esrv_send_face(ns, face, 0);
1234  }
1235 
1236  if (smoothlevel
1237  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1238  send_smooth(ns, ob->face);
1239 
1240  /* Length of packet */
1241  nlayer |= len<<5;
1242 
1243  SockList_AddChar(sl, nlayer);
1244  SockList_AddShort(sl, face_num);
1245  if (anim_speed)
1246  SockList_AddChar(sl, anim_speed);
1247  if (smoothlevel)
1248  SockList_AddChar(sl, smoothlevel);
1249  return 1;
1250  } /* Face is different */
1251  }
1252  return 0;
1253 }
1254 
1255 /* This function is used see if a layer needs to be cleared.
1256  * It updates the socklist, and returns 1 if the update is
1257  * needed, 0 otherwise.
1258  */
1259 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1260  int nlayer;
1261 
1262  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1263  /* Now form the data packet */
1264  nlayer = 0x10+layer+(2<<5);
1265  SockList_AddChar(sl, nlayer);
1266  SockList_AddShort(sl, 0);
1267  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1268  return 1;
1269  }
1270  return 0;
1271 }
1272 
1284 static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1285  int got_one = 0, poisoned = 0, diseased = 0;
1286  char name[60];
1287  int value, granularity;
1288  const object *probe;
1289 
1290  /* send hp bar if needed */
1291  if ((*alive_layer) != -1 || ob->head || !CAN_PROBE(ob))
1292  return 0;
1293 
1294  if (settings.always_show_hp == 2) {
1295  /* global hp bars are enabled */
1296  granularity = 30;
1297  } else if (settings.always_show_hp == 1 && ob->stats.hp < ob->stats.maxhp) {
1298  granularity = 30;
1299  } else {
1300  /* only give hp bars to monsters that have been probed */
1301  if (!QUERY_FLAG(ob, FLAG_PROBE)) {
1302  return 0;
1303  }
1304  probe = object_find_by_type_and_name(ob, FORCE, "probe_force");
1305  if (probe == NULL || probe->level < 15) {
1306  /* if probe is not null, this is an error, but well */
1307  return 0;
1308  }
1309 
1310  granularity = (probe->level - 14) / 3;
1311  if (granularity <= 0)
1312  granularity = 1;
1313  else if (granularity > 30)
1314  granularity = 30;
1315  }
1316 
1317  if (ob->stats.maxhp > 0) {
1318  value = (ob->stats.hp * granularity) / (ob->stats.maxhp);
1319 
1320  if (value < 0)
1321  value = 0;
1322  else if (value > granularity)
1323  value = granularity;
1324  } else
1325  value = 30;
1326 
1327  value = (value * 30) / granularity;
1328 
1329  if (object_present_in_ob(POISONING, ob) != NULL)
1330  poisoned = 1;
1331  if (object_present_in_ob(DISEASE, ob) != NULL)
1332  diseased = 1;
1333 
1334  if (value > 0) {
1335  archetype *dummy;
1336 
1337  snprintf(name, sizeof(name), "hpbar%s%s%s_%d",
1338  poisoned ? "_poisoned" : "",
1339  diseased ? "_diseased" : "",
1340  (!poisoned && !diseased) ? "_standard" : "",
1341  value);
1342  dummy = try_find_archetype(name);
1343  if (dummy != NULL) {
1344  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1345  (*alive_layer) = MAP_LAYER_FLY2;
1346  }
1347  }
1348 
1349  return got_one;
1350 }
1351 
1352 static void map2_add_label(socket_struct *ns, SockList *sl, enum map2_label subtype, const char *label) {
1353  // protect old clients from label with additive length, which can cause them to crash
1354  if (ns->sc_version < 1030)
1355  return;
1356 
1357  int len = strlen(label);
1358  if (len > 256 - 2 - 1) {
1359  LOG(llevError, "The label '%s' is too long to send to the client.", label);
1360  return;
1361  }
1362  SockList_AddChar(sl, MAP2_ADD_LENGTH | MAP2_TYPE_LABEL); // label with additive length
1363  SockList_AddChar(sl, len + 2); // length of payload (subtype + lstring)
1364  SockList_AddChar(sl, subtype);
1365  SockList_AddChar(sl, len); // lstring length prefix
1366  SockList_AddString(sl, label);
1367 }
1368 
1369 static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer) {
1370  socket_struct *ns = plyr->socket;
1371  int got_one = check_probe(ax, ay, ob, sl, ns, has_obj, alive_layer);
1372  // add NPC speech bubble
1374  if (ob->msg != NULL || object_find_by_arch_name(ob, "npc_dialog")) {
1375  archetype *dummy = try_find_archetype("speechbubble");
1376  if (dummy != NULL) {
1377  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1378  (*alive_layer) = MAP_LAYER_FLY2;
1379  }
1380  }
1381  }
1382  // add player name label
1383  if (ob->type == PLAYER) {
1384  enum map2_label subtype = MAP2_LABEL_PLAYER;
1385  if (QUERY_FLAG(ob, FLAG_WIZ)) {
1386  subtype = MAP2_LABEL_DM;
1387  } else if (plyr->party) {
1388  if (ob->contr && ob->contr->party == plyr->party) {
1389  subtype = MAP2_LABEL_PLAYER_PARTY;
1390  }
1391  }
1392  map2_add_label(ns, sl, subtype, ob->name);
1393  got_one += 1;
1394  }
1395  return got_one;
1396 }
1397 
1398 /*
1399  * This function is used to check a space (ax, ay) whose only
1400  * data we may care about are any heads. Basically, this
1401  * space is out of direct view. This is only used with the
1402  * Map2 protocol.
1403  *
1404  * @param ax
1405  * viewport relative x-coordinate
1406  * @param ay
1407  * viewport relative y-coordinate
1408  * @param sl
1409  * the reply to append to
1410  * @param ns
1411  * the client socket
1412  */
1413 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1414  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1415  uint16_t coord;
1416 
1417  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1418  oldlen = sl->len;
1419  SockList_AddShort(sl, coord);
1420 
1421  for (layer = 0; layer < MAP_LAYERS; layer++) {
1422  const object *head;
1423 
1424  head = heads[ay][ax][layer];
1425  if (head) {
1426  /* in this context, got_one should always increase
1427  * because heads should always point to data to really send.
1428  */
1429  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1430  } else {
1431  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1432  }
1433  }
1434  /* Note - if/when lighting information is added, some code is
1435  * needed here - lighting sources that are out of sight may still
1436  * extend into the viewable area.
1437  */
1438 
1439  /* If nothing to do for this space, we
1440  * can erase the coordinate bytes
1441  */
1442  if (!del_one && !got_one) {
1443  sl->len = oldlen;
1444  } else if (del_one && !has_obj) {
1445  /* If we're only deleting faces and not adding, and there
1446  * are not any faces on the space we care about,
1447  * more efficient
1448  * to send 0 as the type/len field.
1449  */
1450  sl->len = oldlen+2; /* 2 bytes for coordinate */
1451  SockList_AddChar(sl, MAP2_TYPE_CLEAR); /* Clear byte */
1452  SockList_AddChar(sl, 255); /* Termination byte */
1453  // Reduce defreferences by passing the inner array offset instead of address of value
1454  map_clearcell(ns->lastmap.cells[ax] + ay, 0, 0);
1455  } else {
1456  SockList_AddChar(sl, 255); /* Termination byte */
1457  }
1458 }
1459 
1460 static void draw_client_map2(object *pl) {
1461  int x, y, ax, ay, darkness, min_x, max_x, min_y, max_y, oldlen, layer;
1462  size_t startlen;
1463  int16_t nx, ny;
1464  SockList sl;
1465  uint16_t coord;
1466  mapstruct *m;
1467  // Dereference once. It should not change in the middle of processing.
1468  player *plyr = pl->contr;
1469 
1470  SockList_Init(&sl);
1471  SockList_AddString(&sl, "map2 ");
1472  startlen = sl.len;
1473 
1474  handle_scroll(plyr->socket, &sl);
1475 
1476  /* Init data to zero */
1477  memset(heads, 0, sizeof(heads));
1478 
1479  /* We could do this logic as conditionals in the if statement,
1480  * but that started to get a bit messy to look at.
1481  */
1482  min_x = pl->x-plyr->socket->mapx/2;
1483  min_y = pl->y-plyr->socket->mapy/2;
1484  max_x = pl->x+(plyr->socket->mapx+1)/2+MAX_HEAD_OFFSET;
1485  max_y = pl->y+(plyr->socket->mapy+1)/2+MAX_HEAD_OFFSET;
1486 
1487  /* x, y are the real map locations. ax, ay are viewport relative
1488  * locations.
1489  */
1490  ay = 0;
1491  for (y = min_y; y < max_y; y++, ay++) {
1492  ax = 0;
1493  for (x = min_x; x < max_x; x++, ax++) {
1494  /* If this space is out of the normal viewable area,
1495  * we only check the heads value. This is used to
1496  * handle big images - if they extend to a viewable
1497  * portion, we need to send just the lower right corner.
1498  */
1499  if (ax >= plyr->socket->mapx || ay >= plyr->socket->mapy) {
1500  check_space_for_heads(ax, ay, &sl, plyr->socket);
1501  } else {
1502  /* This space is within the viewport of the client. Due
1503  * to walls or darkness, it may still not be visible.
1504  */
1505 
1506  /* Meaning of darkness (see defines in LOS_* in los.c):
1507  * LOS_NO_DARKNESS (0) - object is in plain sight, full brightness.
1508  * 1 - MAX_DARKNESS - how dark the space is - higher
1509  * value is darker space. If level is at max darkness,
1510  * you can't see the space (too dark)
1511  * LOS_BLOCKED (100) - space is blocked from sight.
1512  */
1513  darkness = plyr->blocked_los[ax][ay];
1514 
1515  /* If the coordinates are not valid, or it is too
1516  * dark to see, we tell the client as such
1517  */
1518  nx = x;
1519  ny = y;
1520  m = get_map_from_coord(pl->map, &nx, &ny);
1521  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1522 
1523  if (!m) {
1524  /* space is out of map. Update space and clear
1525  * values if this hasn't already been done.
1526  * If the space is out of the map, it shouldn't
1527  * have a head.
1528  */
1529  if (plyr->socket->lastmap.cells[ax][ay].darkness != 0) {
1530  SockList_AddShort(&sl, coord);
1532  SockList_AddChar(&sl, 255); /* Termination byte */
1533  // Reduce dereferences by passing the inner array offset instead of address of value
1534  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1535  }
1536  } else if (darkness >= MAX_LIGHT_RADII) {
1537  /* This block deals with spaces that are not
1538  * visible due to darkness or walls. Still
1539  * need to send the heads for this space.
1540  */
1541  check_space_for_heads(ax, ay, &sl, plyr->socket);
1542  } else {
1543  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1544 
1545  /* In this block, the space is visible. */
1546 
1547  /* Rather than try to figure out what everything
1548  * that we might need to send is, then form the
1549  * packet after that, we presume that we will in
1550  * fact form a packet, and update the bits by what
1551  * we do actually send. If we send nothing, we
1552  * just back out sl.len to the old value, and no
1553  * harm is done.
1554  * I think this is simpler than doing a bunch of
1555  * checks to see what if anything we need to send,
1556  * setting the bits, then doing those checks again
1557  * to add the real data.
1558  */
1559 
1560  oldlen = sl.len;
1561  SockList_AddShort(&sl, coord);
1562 
1563  /* Darkness changed */
1564  if (plyr->socket->lastmap.cells[ax][ay].darkness != darkness
1565  && plyr->socket->darkness) {
1566  plyr->socket->lastmap.cells[ax][ay].darkness = darkness;
1567  /* Darkness tag & length (length=1) */
1568  SockList_AddChar(&sl, MAP2_TYPE_DARKNESS|(1<<5));
1569 
1570  /* Convert darkness level (0-MAX_DARKNESS) to a value
1571  * from 1 (dark) to 255 (bright) for the client.
1572  * Darkness values of 0 (completely dark) are not sent,
1573  * as the space is completely dark.
1574  */
1575  SockList_AddChar(&sl, 255-darkness*(256/MAX_LIGHT_RADII));
1576  have_darkness = 1;
1577  }
1578 
1579  for (layer = 0; layer < MAP_LAYERS; layer++) {
1580  const object *ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1581 
1582  /* Special case: send player itself if invisible */
1583  if (!ob
1584  && x == pl->x
1585  && y == pl->y
1586  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1587  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1588  ob = pl;
1589 
1590  if (ob) {
1591  g1 = has_obj;
1592  old_got = got_one;
1593  got_one += map2_add_ob(ax, ay, layer, ob, &sl, plyr->socket, &has_obj, 0);
1594 
1595  /* if we added the face, or it is a monster's head, check probe spell */
1596  if (got_one != old_got || ob->head == NULL)
1597  got_one += annotate_ob(ax, ay, ob, &sl, plyr, &has_obj, &alive_layer);
1598 
1599  /* If we are just storing away the head
1600  * for future use, then effectively this
1601  * space/layer is blank, and we should clear
1602  * it if needed.
1603  */
1604  if (g1 == has_obj) {
1605  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1606  }
1607  } else {
1608  if (layer != alive_layer)
1609  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1610  }
1611  }
1612  /* If nothing to do for this space, we
1613  * can erase the coordinate bytes
1614  */
1615  if (!del_one && !got_one && !have_darkness) {
1616  sl.len = oldlen;
1617  } else if (del_one && !has_obj) {
1618  /* If we're only deleting faces and don't
1619  * have any objs we care about, just clear
1620  * space. Note it is possible we may have
1621  * darkness, but if there is nothing on the
1622  * space, darkness isn't all that interesting
1623  * - we can send it when an object shows up.
1624  */
1625  sl.len = oldlen+2; /* 2 bytes for coordinate */
1627  SockList_AddChar(&sl, 255); /* Termination byte */
1628  // Reduce dereferences by passing the inner array offset instead of address of value
1629  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1630  } else {
1631  SockList_AddChar(&sl, 255); /* Termination byte */
1632  }
1633  }
1634  } /* else this is a viewable space */
1635  } /* for x loop */
1636  } /* for y loop */
1637 
1638  /* Only send this if there are in fact some differences. */
1639  if (sl.len > startlen) {
1640  Send_With_Handling(plyr->socket, &sl);
1641  }
1642  SockList_Term(&sl);
1643 }
1644 
1648 void draw_client_map(object *pl) {
1649  int i, j;
1650  int16_t ax, ay;
1651  int mflags;
1652  mapstruct *m, *pm;
1653  int min_x, min_y, max_x, max_y;
1654 
1655  if (pl->type != PLAYER) {
1656  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1657  return;
1658  }
1659 
1660  if (pl->contr->transport) {
1661  pm = pl->contr->transport->map;
1662  } else
1663  pm = pl->map;
1664 
1665  /* If player is just joining the game, he isn't here yet, so
1666  * the map can get swapped out. If so, don't try to send them
1667  * a map. All will be OK once they really log in.
1668  */
1669  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1670  return;
1671 
1672  /*
1673  * This block just makes sure all the spaces are properly
1674  * updated in terms of what they look like.
1675  */
1676  min_x = pl->x-pl->contr->socket->mapx/2;
1677  min_y = pl->y-pl->contr->socket->mapy/2;
1678  max_x = pl->x+(pl->contr->socket->mapx+1)/2;
1679  max_y = pl->y+(pl->contr->socket->mapy+1)/2;
1680  for (j = min_y; j < max_y; j++) {
1681  for (i = min_x; i < max_x; i++) {
1682  ax = i;
1683  ay = j;
1684  m = pm;
1685  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1686  if (mflags&P_OUT_OF_MAP)
1687  continue;
1688  if (mflags&P_NEED_UPDATE)
1689  update_position(m, ax, ay);
1690  /* If a map is visible to the player, we don't want
1691  * to swap it out just to reload it. This should
1692  * really call something like swap_map, but this is
1693  * much more efficient and 'good enough'
1694  */
1695  if (mflags&P_NEW_MAP)
1696  map_reset_swap(m);
1697  }
1698  }
1699 
1700  /* do LOS after calls to update_position */
1701  if (pl->contr->do_los) {
1702  update_los(pl);
1703  pl->contr->do_los = 0;
1704  }
1705 
1707 }
1708 
1709 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1710  struct Map newmap;
1711  int x, y, mx, my;
1712 
1713  ns->map_scroll_x += dx;
1714  ns->map_scroll_y += dy;
1715 
1716  mx = ns->mapx+MAX_HEAD_OFFSET;
1717  my = ns->mapy+MAX_HEAD_OFFSET;
1718 
1719  /* the x and y here are coordinates for the new map, i.e. if we moved
1720  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1721  * if the destination x or y coordinate is outside the viewable
1722  * area, we clear the values - otherwise, the old values
1723  * are preserved, and the check_head thinks it needs to clear them.
1724  */
1725  for (x = 0; x < mx; x++) {
1726  for (y = 0; y < my; y++) {
1727  if (x >= ns->mapx || y >= ns->mapy) {
1728  /* clear cells outside the viewable area */
1729  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1730  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1731  /* clear newly visible tiles within the viewable area */
1732  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1733  } else {
1734  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1735  }
1736  }
1737  }
1738 
1739  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1740 }
1741 
1747 void send_plugin_custom_message(object *pl, char *buf) {
1748  SockList sl;
1749 
1750  SockList_Init(&sl);
1751  SockList_AddString(&sl, buf);
1752  Send_With_Handling(pl->contr->socket, &sl);
1753  SockList_Term(&sl);
1754 }
1755 
1762  SockList sl;
1763  int flags = 0;
1764  client_spell *spell_info;
1765 
1766  if (!pl->socket || !pl->socket->monitor_spells)
1767  return;
1768 
1769  /* Handles problem at login, where this is called from fix_object
1770  * before we have had a chance to send spells to the player. It does seem
1771  * to me that there should never be a case where update_spells is called
1772  * before add_spells has been called. Add_spells() will update the
1773  * spell_state to non null.
1774  */
1775  if (!pl->spell_state)
1776  return;
1777 
1778  FOR_INV_PREPARE(pl->ob, spell) {
1779  if (spell->type == SPELL) {
1780  spell_info = get_client_spell_state(pl, spell);
1781  /* check if we need to update it*/
1782  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1783  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1784  flags |= UPD_SP_MANA;
1785  }
1786  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1787  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1788  flags |= UPD_SP_GRACE;
1789  }
1790  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1791  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1792  flags |= UPD_SP_DAMAGE;
1793  }
1794  if (flags != 0) {
1795  SockList_Init(&sl);
1796  SockList_AddString(&sl, "updspell ");
1797  SockList_AddChar(&sl, flags);
1798  SockList_AddInt(&sl, spell->count);
1799  if (flags&UPD_SP_MANA)
1800  SockList_AddShort(&sl, spell_info->last_sp);
1801  if (flags&UPD_SP_GRACE)
1802  SockList_AddShort(&sl, spell_info->last_grace);
1803  if (flags&UPD_SP_DAMAGE)
1804  SockList_AddShort(&sl, spell_info->last_dam);
1805  flags = 0;
1806  Send_With_Handling(pl->socket, &sl);
1807  SockList_Term(&sl);
1808  }
1809  }
1810  } FOR_INV_FINISH();
1811 }
1812 
1813 void esrv_remove_spell(player *pl, object *spell) {
1814  SockList sl;
1815 
1816  if (!pl || !spell || spell->env != pl->ob) {
1817  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1818  return;
1819  }
1820  if (!pl->socket->monitor_spells)
1821  return;
1822 
1823  SockList_Init(&sl);
1824  SockList_AddString(&sl, "delspell ");
1825  SockList_AddInt(&sl, spell->count);
1826  Send_With_Handling(pl->socket, &sl);
1827  SockList_Term(&sl);
1828 }
1829 
1837  SockList sl;
1838 
1839  if (!pl->socket->want_pickup)
1840  return;
1841  SockList_Init(&sl);
1842  SockList_AddString(&sl, "pickup ");
1843  SockList_AddInt(&sl, pl->mode);
1844  Send_With_Handling(pl->socket, &sl);
1845  SockList_Term(&sl);
1846 }
1847 
1856 static int spell_client_use(const object *spell) {
1857  switch (spell->subtype)
1858  {
1859  case SP_RAISE_DEAD:
1860  case SP_MAKE_MARK:
1861  return 3;
1862  case SP_RUNE:
1863  if (!spell->other_arch)
1864  return 1;
1865  break;
1866  case SP_CREATE_FOOD:
1867  case SP_CREATE_MISSILE:
1868  return 2;
1869  case SP_SUMMON_MONSTER:
1870  if (spell->randomitems != NULL)
1871  return 2;
1872  /* break; */// If add conditins below, use this break statement
1873  }
1874  // This is not in the switch statement so that it supports fallthrough logic
1875  // on the few spell types that have additional conditions attached.
1876  return 0;
1877 }
1878 
1880 static void append_spell(player *pl, SockList *sl, object *spell) {
1881  client_spell *spell_info;
1882  int len, i, skill = 0;
1883 
1884  if (!spell->name) {
1885  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1886  return;
1887  }
1888 
1889  if (spell->face && !(pl->socket->faces_sent[spell->face->number]&NS_FACESENT_FACE))
1890  esrv_send_face(pl->socket, spell->face, 0);
1891 
1892  spell_info = get_client_spell_state(pl, spell);
1893  SockList_AddInt(sl, spell->count);
1894  SockList_AddShort(sl, spell->level);
1895  SockList_AddShort(sl, spell->casting_time);
1896  /* store costs and damage in the object struct, to compare to later */
1897  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1898  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1899  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1900  /* send the current values */
1901  SockList_AddShort(sl, spell_info->last_sp);
1902  SockList_AddShort(sl, spell_info->last_grace);
1903  SockList_AddShort(sl, spell_info->last_dam);
1904 
1905  /* figure out which skill it uses, if it uses one */
1906  if (spell->skill) {
1907  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++)
1908  if (!strcmp(spell->skill, skill_names[i])) {
1909  skill = i+CS_STAT_SKILLINFO;
1910  break;
1911  }
1912  }
1913  SockList_AddChar(sl, skill);
1914 
1915  SockList_AddInt(sl, spell->path_attuned);
1916  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1917  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1918 
1919  if (!spell->msg) {
1920  SockList_AddShort(sl, 0);
1921  } else {
1922  len = strlen(spell->msg);
1923  SockList_AddShort(sl, len);
1924  SockList_AddData(sl, spell->msg, len);
1925  }
1926 
1927  /* Extended spell information available if the client wants it.
1928  */
1929  if (pl->socket->monitor_spells >= 2) {
1930  /* spellmon 2
1931  */
1932  sstring req = object_get_value(spell, "casting_requirements");
1933 
1934  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1935 
1936  if (req) { /* Requirements */
1937  SockList_AddLen8Data(sl, req, strlen(req));
1938  } else {
1939  SockList_AddChar(sl, 0);
1940  }
1941  /* end spellmon 2
1942  */
1943  }
1944 }
1945 
1950 void esrv_add_spells(player *pl, object *spell) {
1951  SockList sl;
1952  size_t size;
1953  sstring value;
1954 
1955  if (!pl) {
1956  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
1957  return;
1958  }
1959 
1960  if (!pl->socket->monitor_spells)
1961  return;
1962 
1963  SockList_Init(&sl);
1964  SockList_AddString(&sl, "addspell ");
1965  if (!spell) {
1966  FOR_INV_PREPARE(pl->ob, spell) {
1967  if (spell->type != SPELL)
1968  continue;
1969  /* Were we to simply keep appending data here, we could
1970  * exceed the SockList buffer if the player has enough spells
1971  * to add. We know that append_spell will always append
1972  * 23 data bytes, plus 3 length bytes and 2 strings
1973  * (because that is the spec) so we need to check that
1974  * the length of those 2 strings, plus the 26 bytes,
1975  * won't take us over the length limit for the socket.
1976  * If it does, we need to send what we already have,
1977  * and restart packet formation.
1978  */
1979  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
1980  if (pl->socket->monitor_spells >= 2) {
1982  value = object_get_value(spell, "casting_requirements");
1983  size += 2 + (value ? strlen(value) : 0);
1984  }
1985  if (SockList_Avail(&sl) < size) {
1986  Send_With_Handling(pl->socket, &sl);
1987  SockList_Reset(&sl);
1988  SockList_AddString(&sl, "addspell ");
1989  }
1990  append_spell(pl, &sl, spell);
1991  } FOR_INV_FINISH();
1992  } else if (spell->type != SPELL) {
1993  LOG(llevError, "Asked to send a non-spell object as a spell\n");
1994  return;
1995  } else
1996  append_spell(pl, &sl, spell);
1997  /* finally, we can send the packet */
1998  Send_With_Handling(pl->socket, &sl);
1999  SockList_Term(&sl);
2000 }
2001 
2002 /* sends a 'tick' information to the client.
2003  */
2005  SockList sl;
2006  SockList_Init(&sl);
2007  SockList_AddString(&sl, "tick ");
2008  SockList_AddInt(&sl, pticks);
2009  Send_With_Handling(pl->socket, &sl);
2010  SockList_Term(&sl);
2011 }
2012 
2025 static void add_char_field(SockList *sl, int type, const char *data)
2026 {
2027  int len;
2028 
2029  len = strlen(data);
2030 
2031  if (len) {
2032  /* one extra for length for the type byte */
2033  SockList_AddChar(sl, len+1);
2034  SockList_AddChar(sl, type);
2035  SockList_AddString(sl, data);
2036  }
2037 }
2038 
2060 {
2061  SockList sl;
2062  int num_chars;
2063  linked_char *extra;
2064 
2065  if (ns->account_chars) {
2067  }
2069 
2070  num_chars = 0;
2071  extra = account_get_additional_chars(ns->account_name, ns->account_chars, &num_chars);
2072 
2073  SockList_Init(&sl);
2074  SockList_AddString(&sl, "accountplayers ");
2075 
2076  SockList_AddChar(&sl, static_cast<char>(ns->account_chars->chars.size() + num_chars));
2077 
2078  /* Now add real character data */
2079  for (auto acn : ns->account_chars->chars) {
2080  uint16_t faceno = 0;
2081 
2082  /* Ignore a dead character. They don't need to show up. */
2083  if (acn->isDead) {
2084  continue;
2085  }
2086 
2087  add_char_field(&sl, ACL_NAME, acn->name);
2088  add_char_field(&sl, ACL_CLASS, acn->character_class);
2089  add_char_field(&sl, ACL_RACE, acn->race);
2090  add_char_field(&sl, ACL_FACE, acn->face);
2091  if (acn->face[0] != 0 ) {
2092  const Face *face = try_find_face(acn->face, NULL);
2093 
2094  if (face != NULL) {
2095  if (!(ns->faces_sent[face->number]&NS_FACESENT_FACE)) {
2096  esrv_send_face(ns, face, 0);
2097  }
2098  faceno = face->number;
2099  }
2100  }
2101 
2102  add_char_field(&sl, ACL_PARTY, acn->party);
2103  add_char_field(&sl, ACL_MAP, acn->map);
2104  SockList_AddChar(&sl, 3);
2106  SockList_AddShort(&sl, acn->level);
2107  if (faceno) {
2108  SockList_AddChar(&sl, 3);
2110  SockList_AddShort(&sl, faceno);
2111  }
2112 
2113  SockList_AddChar(&sl, 0);
2114  }
2115  /* Now for any characters where we just have the name */
2116  for (linked_char *e = extra; e != NULL; e = e->next) {
2117  add_char_field(&sl, ACL_NAME, e->name);
2118  SockList_AddChar(&sl, 0);
2119  }
2120 
2121  Send_With_Handling(ns, &sl);
2122  SockList_Term(&sl);
2123 
2124  if (extra) {
2125  free_charlinks(extra);
2126  }
2127 }
2128 
2150 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2151 {
2152  int nlen, plen;
2153 
2154  if (*len < 2) {
2155  return 1;
2156  }
2157 
2158  nlen = (unsigned char)buf[0];
2159  if (nlen >= MAX_BUF || nlen > *len-2) {
2160  return 1;
2161  }
2162  memcpy(name, buf+1, nlen);
2163  name[nlen] = 0;
2164 
2165  plen = (unsigned char)buf[nlen+1];
2166  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2167  return 2;
2168  }
2169  memcpy(password, buf+2+nlen, plen);
2170  password[plen] = 0;
2171 
2172  *len = nlen+plen+2;
2173 
2174  return 0;
2175 }
2186 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2187  char name[MAX_BUF], password[MAX_BUF];
2188  int status;
2189  SockList sl;
2190 
2191  if (len <= 0 || !buf) {
2192  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2193  return;
2194  }
2195 
2196  SockList_Init(&sl);
2197 
2198  status = decode_name_password(buf, &len, name, password);
2199 
2200  if (status == 1) {
2201  SockList_AddString(&sl, "failure accountlogin Name is too long");
2202  Send_With_Handling(ns, &sl);
2203  SockList_Term(&sl);
2204  return;
2205  }
2206  if (status == 2) {
2207  SockList_AddString(&sl, "failure accountlogin Password is too long");
2208  Send_With_Handling(ns, &sl);
2209  SockList_Term(&sl);
2210  return;
2211  }
2212 
2213  if (!account_exists(name)) {
2214  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2215  Send_With_Handling(ns, &sl);
2216  SockList_Term(&sl);
2217  return;
2218  }
2219 
2220  if (account_login(name, password)) {
2221  LOG(llevInfo, "Account login for '%s' from %s\n", name, ns->host);
2222 
2223  if (ns->account_name) free(ns->account_name);
2224  /* We want to store away official name so we do not
2225  * have any case sensitivity issues on the files.
2226  * because we have already checked password, we
2227  * know that account_exists should never return NULL in
2228  * this case.
2229  */
2231 
2233  } else {
2234  LOG(llevInfo, "Failed account login for '%s' from %s\n", name, ns->host);
2235  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2236  Send_With_Handling(ns, &sl);
2237  SockList_Term(&sl);
2238  }
2239 }
2240 
2249 static int account_block_create(const socket_struct *ns) {
2250  /* Check if account creation is blocked. */
2252  /* Account creation is allowed for everyone. */
2253  return 0;
2254  }
2255 
2256  /* Has the trusted host been defined? */
2257  if(settings.account_trusted_host == NULL) {
2258  /* No, allocate it and set it to localhost now. */
2260  }
2261 
2262  /* Return false if the client connected from the trusted host. */
2263  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2264  return 0;
2265  }
2266 
2267  /*
2268  * If we are here, then we are blocking account create and we do
2269  * not trust this client's IP address.
2270  */
2271  return 1;
2272 }
2273 
2285 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2286  char name[MAX_BUF], password[MAX_BUF];
2287  int status;
2288  SockList sl;
2289 
2290  if (len <= 0 || !buf) {
2291  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2292  return;
2293  }
2294 
2295  SockList_Init(&sl);
2296 
2297  status = decode_name_password(buf, &len, name, password);
2298 
2299  if (account_block_create(ns)) {
2300  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2301  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2302  Send_With_Handling(ns, &sl);
2303  SockList_Term(&sl);
2304  return;
2305  }
2306 
2307  if (status == 1) {
2308  SockList_AddString(&sl, "failure accountnew Name is too long");
2309  Send_With_Handling(ns, &sl);
2310  SockList_Term(&sl);
2311  return;
2312  }
2313  if (status == 2) {
2314  SockList_AddString(&sl, "failure accountnew Password is too long");
2315  Send_With_Handling(ns, &sl);
2316  SockList_Term(&sl);
2317  return;
2318  }
2319  /*The minimum length isn't exactly required, but in the current implementation,
2320  * client will send the same password for character for which there is a
2321  * 2 character minimum size. Thus an account with a one character password
2322  * won't be able to create a character. */
2323  if (strlen(name)<settings.min_name) {
2324  SockList_AddString(&sl, "failure accountnew Name is too short");
2325  Send_With_Handling(ns, &sl);
2326  SockList_Term(&sl);
2327  return;
2328  }
2329  if (strlen(password)<2) {
2330  SockList_AddString(&sl, "failure accountnew Password is too short");
2331  Send_With_Handling(ns, &sl);
2332  SockList_Term(&sl);
2333  return;
2334  }
2335 
2336  if (account_exists(name)) {
2337  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2338  Send_With_Handling(ns, &sl);
2339  SockList_Term(&sl);
2340  return;
2341  }
2342 
2344  if (status == 1) {
2345  SockList_AddString(&sl,
2346  "failure accountnew Choose a different account name. " VALIDCHAR_MSG);
2347  Send_With_Handling(ns, &sl);
2348  SockList_Term(&sl);
2349  return;
2350  }
2351 
2352  if (status == 2) {
2353  SockList_AddString(&sl,
2354  "failure accountnew That account name is too long");
2355  Send_With_Handling(ns, &sl);
2356  SockList_Term(&sl);
2357  return;
2358  }
2359 
2360  status = account_check_string(password);
2361  if (status == 1) {
2362  SockList_AddString(&sl,
2363  "failure accountnew Choose a different password. " VALIDCHAR_MSG);
2364  Send_With_Handling(ns, &sl);
2365  SockList_Term(&sl);
2366  return;
2367  }
2368 
2369  if (status == 2) {
2370  SockList_AddString(&sl,
2371  "failure accountnew That password is too long");
2372  Send_With_Handling(ns, &sl);
2373  SockList_Term(&sl);
2374  return;
2375  }
2376 
2377  /* If we got here, we passed all checks - so now add it */
2378  if (ns->account_name) free(ns->account_name);
2380  account_new(name, password);
2381  /* save account information */
2382  accounts_save();
2384 }
2385 
2399 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2400  char name[MAX_BUF], password[MAX_BUF];
2401  int status, force, nlen;
2402  SockList sl;
2403  const char *cp;
2404 
2405  if (len <= 0 || !buf) {
2406  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2407  return;
2408  }
2409 
2410  SockList_Init(&sl);
2411 
2412  if (ns->account_name == NULL) {
2413  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2414  Send_With_Handling(ns, &sl);
2415  SockList_Term(&sl);
2416  return;
2417  }
2418 
2419  force = buf[0];
2420  nlen = len - 1;
2421  status = decode_name_password(buf+1, &nlen, name, password);
2422  if (status == 1) {
2423  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2424  Send_With_Handling(ns, &sl);
2425  SockList_Term(&sl);
2426  return;
2427  }
2428  if (status == 2) {
2429  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2430  Send_With_Handling(ns, &sl);
2431  SockList_Term(&sl);
2432  return;
2433  }
2434 
2435  status = verify_player(name, password);
2436  if (status) {
2437  /* From a security standpoint, telling random folks if it
2438  * it as wrong password makes it easier to hack. However,
2439  * it is fairly easy to determine what characters exist on a server
2440  * (either by trying to create a new one and see if the name is in
2441  * in use, or just looking at the high score file), so this
2442  * really does not make things much less secure
2443  */
2444  if (status == 1)
2445  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2446  else
2447  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2448 
2449  Send_With_Handling(ns, &sl);
2450  SockList_Term(&sl);
2451  return;
2452  }
2453  /* Check to see if this character is associated with an account.
2454  */
2456  if (cp) {
2457  if (!strcmp(cp, ns->account_name)) {
2458  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2459  Send_With_Handling(ns, &sl);
2460  SockList_Term(&sl);
2461  return;
2462  } else {
2463  if (!force) {
2464  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2465  Send_With_Handling(ns, &sl);
2466  SockList_Term(&sl);
2467  return;
2468  } else if (account_is_logged_in(cp)) {
2469  /* We could be clever and try to handle this case, but it is
2470  * trickier. If the character is logged in, it has to
2471  * be logged out. And the socket holds some data which
2472  * needs to be cleaned up. Since it should be fairly
2473  * uncommon that users need to do this, just disallowing
2474  * it makes things a lot simpler.
2475  */
2476  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2477  Send_With_Handling(ns, &sl);
2478  SockList_Term(&sl);
2479  return;
2480  }
2481  }
2482  }
2483  /* If we have gotten this far, the name/password provided is OK,
2484  * and the character is not associated with a different account (or
2485  * force is true). Now try to add the character to this account.
2486  */
2488 
2489  /* This should never happen, but check for it just in case -
2490  * if we were able to log in, the account should exist. but
2491  * if this fails, need to give the user some clue.
2492  */
2493  if (status==1) {
2494  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2495  Send_With_Handling(ns, &sl);
2496  SockList_Term(&sl);
2497  return;
2498  } else if (status == 2) {
2499  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2500  Send_With_Handling(ns, &sl);
2501  SockList_Term(&sl);
2502  return;
2503  }
2504 
2505  /* If cp is set, then this character used to belong to a different
2506  * account. Remove it now.
2507  */
2508  if (cp) {
2509  Account_Chars *chars;
2510 
2512  chars = account_char_load(cp);
2513  account_char_remove(chars, name);
2514  account_char_save(chars);
2515  account_char_free(chars);
2516  }
2517 
2519 
2520  /* store data so nothing is lost in case of crash */
2522 }
2523 
2528 void account_play_cmd(char *buf, int len, socket_struct *ns)
2529 {
2530  char **chars;
2531  int i;
2532  SockList sl;
2533  player *pl;
2534 
2535  if (len <= 0 || !buf) {
2536  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2537  return;
2538  }
2539 
2540  SockList_Init(&sl);
2541 
2542  if (ns->status != Ns_Add) {
2543  SockList_AddString(&sl, "failure accountplay Not allowed right now");
2544  Send_With_Handling(ns, &sl);
2545  SockList_Term(&sl);
2546  return;
2547  }
2548 
2549  if (!buf[0]) {
2550  SockList_AddString(&sl, "failure accountplay Malformed character name");
2551  Send_With_Handling(ns, &sl);
2552  SockList_Term(&sl);
2553  return;
2554  }
2555 
2556  if (ns->account_name == NULL) {
2557  SockList_AddString(&sl, "failure accountplay Not logged in");
2558  Send_With_Handling(ns, &sl);
2559  SockList_Term(&sl);
2560  return;
2561  }
2562 
2563  /* Make sure a client is not trying to spoof us here */
2565 
2566  for (i=0; chars[i]; i++) {
2567  if (strcmp(chars[i], buf) == 0)
2568  break;
2569  }
2570  if (!chars[i]) {
2571  SockList_AddPrintf(&sl,
2572  "failure accountplay Character %s is not associated with account %s",
2573  buf, ns->account_name);
2574  Send_With_Handling(ns, &sl);
2575  SockList_Term(&sl);
2576  return;
2577  }
2578 
2579  for (pl = first_player; pl; pl = pl->next) {
2580  if (pl->ob && pl->socket != ns && strcmp(buf, pl->ob->name) == 0 && pl->state != ST_PLAY_AGAIN && pl->state != ST_GET_NAME) {
2581  SockList_AddPrintf(&sl,
2582  "failure accountplay Character %s is already playing",
2583  buf);
2584  Send_With_Handling(ns, &sl);
2585  SockList_Term(&sl);
2586  return;
2587  }
2588  }
2589 
2590  /* from a protocol standpoint, accountplay can be used
2591  * before there is a player structure (first login) or after
2592  * (character has logged in and is changing characters).
2593  * Checkthe sockets for that second case - if so,
2594  * we don't need to make a new player object, etc.
2595  */
2596  for (pl=first_player; pl; pl=pl->next) {
2597  if (pl->socket == ns) {
2598  /* The player still in the socket must be saved first. */
2599  save_player(pl->ob, 0);
2600  break;
2601  }
2602  }
2603 
2604  /* Some of this logic is from add_player()
2605  * we just don't use add_player() as it does some other work
2606  * we don't really want to do.
2607  */
2608  if (!pl) {
2609  pl = get_player(NULL);
2610  set_player_socket(pl, ns);
2611  ns->status = Ns_Avail;
2612  ns->account_chars = NULL;
2613  SockList_ResetRead(&pl->socket->inbuf);
2614  } else {
2615  pl->state = ST_PLAYING;
2616  }
2617 
2618  pl->ob->name = add_string(buf);
2619  check_login(pl->ob, NULL);
2620 
2621  SockList_AddString(&sl, "addme_success");
2622  Send_With_Handling(ns, &sl);
2623  SockList_Term(&sl);
2624 }
2625 
2626 #define MAX_CHOICES 100
2627 
2633 void create_player_cmd(char *buf, int len, socket_struct *ns)
2634 {
2635  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2636  int status, nlen, choice_num=0, i;
2637  SockList sl;
2638  player *pl;
2639  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2640  living new_stats;
2641 
2642  if (len <= 0 || !buf) {
2643  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2644  return;
2645  }
2646 
2647  SockList_Init(&sl);
2648 
2649  if (ns->status != Ns_Add) {
2650  SockList_AddString(&sl, "failure createplayer Not allowed right now");
2651  Send_With_Handling(ns, &sl);
2652  SockList_Term(&sl);
2653  return;
2654  }
2655 
2656  nlen = len;
2657  status = decode_name_password(buf, &nlen, name, password);
2658  if (status == 1) {
2659  SockList_AddString(&sl, "failure createplayer Name is too long");
2660  Send_With_Handling(ns, &sl);
2661  SockList_Term(&sl);
2662  return;
2663  }
2664 
2665  /* Minimum character name limit (if set) */
2666  if (strlen(name)<settings.min_name) {
2667  SockList_AddString(&sl, "failure createplayer Name is too short");
2668  Send_With_Handling(ns, &sl);
2669  SockList_Term(&sl);
2670  return;
2671  }
2672 
2673  if (playername_ok(name) == 0) {
2674  SockList_AddString(&sl, "failure createplayer Player name contains invalid characters");
2675  Send_With_Handling(ns, &sl);
2676  SockList_Term(&sl);
2677  return;
2678  }
2679 
2680  /* 2 characters minimum for password */
2681  if (strlen(password)<2) {
2682  SockList_AddString(&sl, "failure createplayer Password is too short");
2683  Send_With_Handling(ns, &sl);
2684  SockList_Term(&sl);
2685  return;
2686  }
2687 
2689  if (status == 2) {
2690  SockList_AddString(&sl, "failure createplayer Password is too long");
2691  Send_With_Handling(ns, &sl);
2692  SockList_Term(&sl);
2693  return;
2694  }
2695 
2696  /* This is a fairly ugly solution - we're truncating the password.
2697  * however, the password information for characters is really
2698  * a legacy issue - when every character is associated with
2699  * an account, legacy login (character name/password) will get
2700  * removed, at which point the only use for password might be
2701  * to move characters from one account to another, but not sure
2702  * if that is something we want to allow.
2703  */
2704  if (strlen(password)>17)
2705  password[16] = 0;
2706 
2707  /* We just can't call check_name(), since that uses draw_info() to
2708  * report status. We are also more permissive on names, so we use
2709  * account_check_string() - if that is safe for account, also safe
2710  * for player names.
2711  */
2712  if (account_check_string(name)) {
2713  SockList_AddString(&sl, "failure createplayer Choose a different character name. " VALIDCHAR_MSG);
2714  Send_With_Handling(ns, &sl);
2715  SockList_Term(&sl);
2716  return;
2717  }
2718 
2719  /* 1 means no such player, 0 is correct name/password (which in this
2720  * case, is an error), and 2 is incorrect password. Only way we
2721  * go onward is if there is no such player.
2722  */
2723  if (verify_player(name, password) != 1) {
2724  SockList_AddString(&sl, "failure createplayer That name is already in use");
2725  Send_With_Handling(ns, &sl);
2726  SockList_Term(&sl);
2727  return;
2728  }
2729 
2730  /* from a protocol standpoint, accountplay can be used
2731  * before there is a player structure (first login) or after
2732  * (character has logged in and is changing characters).
2733  * Check the sockets for that second case - if so,
2734  * we don't need to make a new player object, etc.
2735  */
2736  for (pl=first_player; pl; pl=pl->next)
2737  if (pl->socket == ns) {
2738  if (pl->ob->name) {
2739  if (!strcmp(pl->ob->name, name)) {
2740  /* For some reason not only the socket is the same but also
2741  * the player is already playing. If this happens at this
2742  * point let's assume the character never was able to apply
2743  * a bet of reality to make a correct first-time save.
2744  * So, for safety remove it and start over.
2745  */
2746  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2747  object_remove(pl->ob);
2748  }
2749  else {
2750  /* If this is a different player on the same socket, then we
2751  * need to make sure that the old one is not connected to the player
2752  *
2753  * This prevents bizarre scenarios where the player is on the map
2754  * multiple times (from multiple createplayer commands), and
2755  * only one of them is controlled by the player.
2756  */
2757  if (pl->ob->contr == pl) {
2758  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2759  object_remove(pl->ob);
2760  }
2761  }
2762  }
2763  break;
2764  }
2765 
2766  /* In this mode, we have additional data
2767  * Note that because there are a lot of failure cases in here
2768  * (where we end up not creating the new player), the code
2769  * to create the new player is done within this routine
2770  * after all checks pass. Note that all of the checks
2771  * done are done without using the player structure,
2772  * as pl may be null right now.
2773  */
2774  if (ns->login_method >= 2) {
2775  int i, j, stat_total=0;
2776  char *key, *value, *race=NULL, *class_name=NULL;
2777 
2778  /* By setting this to zero, then we can easily
2779  * check to see if all stats have been set.
2780  */
2781  memset(&new_stats, 0, sizeof(living));
2782 
2783  while (nlen < len) {
2784  i = buf[nlen]; /* Length of this line */
2785  /* Sanity check from client - don't want to loop
2786  * forever if there is a 0 length, and don't
2787  * want to read beyond size of packet.
2788  * Likewise, client should have sent
2789  * the string to us already null terminated,
2790  * but we will just make sure.
2791  */
2792  if ((i == 0) || (nlen + i > len)) break;
2793  buf[nlen + i] = 0;
2794 
2795  /* What we have are a series of lines -
2796  * 'key value' format. Find that space,
2797  * and null it out so we can do strcasecmp.
2798  * If no space, abort processing
2799  */
2800  key = buf + nlen + 1;
2801  value = strchr(key, ' ');
2802  if (!value) break;
2803  *value = 0;
2804  value++;
2805 
2806  if (!strcasecmp(key,"race")) race = value;
2807  else if (!strcasecmp(key,"class")) class_name = value;
2808  else if (!strcasecmp(key,"starting_map")) {
2810  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2811  SockList_AddString(&sl,
2812  "failure createplayer Invalid starting map");
2813  Send_With_Handling(ns, &sl);
2814  SockList_Term(&sl);
2815  return;
2816  }
2817  }
2818  else if (!strcasecmp(key,"choice")) {
2819  /* In general, MAX_CHOICES should be large enough
2820  * to always handle the choices from the client - of
2821  * course, the client could be broken and send us many
2822  * more choices than we should have, so handle that.
2823  */
2824  if (choice_num == MAX_CHOICES) {
2825  LOG(llevError,
2826  "Number of choices receive exceed max value: %d>%d\n",
2827  choice_num, MAX_CHOICES);
2828  } else {
2829  choices[choice_num] = value;
2830  choice_num++;
2831  }
2832  }
2833  else {
2834  /* Do stat processing here */
2835  for (j=0; j < NUM_STATS; j++) {
2836  if (!strcasecmp(key,short_stat_name[j])) {
2837  int val = atoi(value);
2838 
2839  set_attr_value(&new_stats, j, val);
2840  break;
2841  }
2842  }
2843  if (j >= NUM_STATS) {
2844  /* Bad clients could do this - we should at least report
2845  * it, and useful when trying to add new parameters.
2846  */
2847  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2848  }
2849  }
2850  nlen += i + 1;
2851  }
2852  /* Do some sanity checking now. But checking the stat
2853  * values here, we will catch any 0 values since we do
2854  * a memset above. A properly behaving client should
2855  * never do any of these things, but we do not presume
2856  * clients will behave properly.
2857  */
2858  for (j=0; j<NUM_STATS; j++) {
2859  int val = get_attr_value(&new_stats, j);
2860 
2861  stat_total += val;
2862  if (val > settings.starting_stat_max ||
2863  val < settings.starting_stat_min) {
2864  SockList_AddPrintf(&sl,
2865  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2867  Send_With_Handling(ns, &sl);
2868  SockList_Term(&sl);
2869  return;
2870  }
2871  }
2872  if (stat_total > settings.starting_stat_points) {
2873  SockList_AddPrintf(&sl,
2874  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2875  stat_total, settings.starting_stat_points);
2876  Send_With_Handling(ns, &sl);
2877  SockList_Term(&sl);
2878  return;
2879  }
2880 
2881  if (race)
2882  race_a = try_find_archetype(race);
2883 
2884  if (class_name)
2885  class_a = try_find_archetype(class_name);
2886 
2887  /* This should never happen with a properly behaving client, so the error message
2888  * doesn't have to be that great.
2889  */
2890  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2891  SockList_AddString(&sl,
2892  "failure createplayer Invalid or unknown race or class");
2893  Send_With_Handling(ns, &sl);
2894  SockList_Term(&sl);
2895  return;
2896  }
2897 
2898  /* At current time, only way this can fail is if the adjusted
2899  * stat is less than 1.
2900  */
2901  if (check_race_and_class(&new_stats, race_a, class_a)) {
2902  SockList_AddString(&sl,
2903  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2904  Send_With_Handling(ns, &sl);
2905  SockList_Term(&sl);
2906  return;
2907  }
2908 
2909  if (!pl)
2911  // If we already have a player, we a replaying on the same connection.
2912  // Since add_player normally sets ns->status, we still need that to happen.
2913  else
2914  ns->status = Ns_Avail;
2915 
2916  // We need to copy the name in before apply_race_and_class() because it
2917  // tells the client our character name. If we don't update it, they get the old one.
2918  FREE_AND_COPY(pl->ob->name, name);
2919 
2920  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2921 
2922  } else {
2923  /* In thise case, old login method */
2924  if (!pl)
2925  pl = add_player(ns, ADD_PLAYER_NEW);
2926  // If we already have a player, we a replaying on the same connection.
2927  // Since add_player normally sets ns->status, we still need that to happen.
2928  else
2929  ns->status = Ns_Avail;
2930 
2931  // Make sure to do this on both code branches.
2932  FREE_AND_COPY(pl->ob->name, name);
2933 /* already done by add_player
2934  roll_again(pl->ob);
2935  pl->state = ST_ROLL_STAT;
2936  set_first_map(pl->ob);*/
2937  }
2938 
2939  /* add_player does a lot of the work, but there are a few
2940  * things we need to update, like starting name and
2941  * password.
2942  * This is done before processing in login_method>2.
2943  * The character creation process it does when
2944  * applying the race/class will use this
2945  * name information.
2946  */
2947  FREE_AND_COPY(pl->ob->name_pl, name);
2948  pl->name_changed = 1;
2949  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
2950 
2951  SockList_AddString(&sl, "addme_success");
2952  Send_With_Handling(ns, &sl);
2953  SockList_Term(&sl);
2954 
2955  if (ns->login_method >= 2) {
2956  /* The client could have provided us a map - if so, map will be set
2957  * and we don't want to overwrite it
2958  */
2959  if (!map)
2961  assert(map); // Existence checked in init_dynamic()
2962 
2963  enter_exit(pl->ob, &map->clone);
2964 
2965  if (pl->ob->map == NULL) {
2966  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
2967  abort();
2968  }
2969 
2970  /* copy information to bed of reality information, in case the player dies */
2971  safe_strncpy(pl->savebed_map, pl->ob->map->path, sizeof(pl->savebed_map));
2972  pl->bed_x = pl->ob->x;
2973  pl->bed_y = pl->ob->y;
2974 
2976  }
2977 
2978  /* We insert any objects after we have put the player on the map -
2979  * this makes things safer, as certain objects may expect a normal
2980  * environment. Note that choice_num will only be set in the
2981  * loginmethod > 2, which also checks (and errors out) if the
2982  * race/class is not set, which is why explicit checking for
2983  * those is not need.
2984  */
2985  for (i=0; i < choice_num; i++) {
2986  char *choiceval;
2987  const char *value, *cp;
2988  archetype *arch;
2989  object *op;
2990 
2991  choiceval = strchr(choices[i], ' ');
2992  if (!choiceval) {
2993  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
2994  continue;
2995  }
2996  *choiceval=0;
2997  choiceval++;
2998  value = object_get_value(&race_a->clone, choices[i]);
2999  if (!value)
3000  value = object_get_value(&class_a->clone, choices[i]);
3001 
3002  if (!value) {
3003  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
3004  continue;
3005  }
3006  cp = strstr(value, choiceval);
3007  if (!cp) {
3008  LOG(llevError, "Choice value not found in archetype: %s %s\n",
3009  choices[i], choiceval);
3010  continue;
3011  }
3012 
3013  /* Check to make sure that the matched string is an entire word,
3014  * and not a substring (eg, valid choice being great_sword but
3015  * we just get sword) - the space after the match should either be a
3016  * space or null, and space before match should also be a space
3017  * or the start of the string.
3018  */
3019  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
3020  (cp != value) && (*(cp-1) != ' ')) {
3021 
3022  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
3023  choiceval, value);
3024  continue;
3025  }
3026  arch = try_find_archetype(choiceval);
3027  if (!arch) {
3028  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
3029  continue;
3030  }
3031  op = arch_to_object(arch);
3032  op = object_insert_in_ob(op, pl->ob);
3034  ob_apply(op, pl->ob, 0);
3035  }
3036 
3037  LOG(llevInfo, "new character %s from %s\n", pl->ob->name, pl->ob->contr->socket->host);
3040  "%s has entered the game.", pl->ob->name);
3041 }
3042 
3053 void account_password(char *buf, int len, socket_struct *ns) {
3054  char old[MAX_BUF], change[MAX_BUF];
3055  int status;
3056  SockList sl;
3057 
3058  if (len <= 0 || !buf) {
3059  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
3060  return;
3061  }
3062 
3063  SockList_Init(&sl);
3064 
3065  if (ns->account_name == NULL) {
3066  SockList_AddString(&sl, "failure accountpw Not logged in");
3067  Send_With_Handling(ns, &sl);
3068  SockList_Term(&sl);
3069  return;
3070  }
3071 
3072  status = decode_name_password(buf, &len, old, change);
3073  if (status == 1) {
3074  SockList_AddString(&sl, "failure accountpw Old password is too long");
3075  Send_With_Handling(ns, &sl);
3076  SockList_Term(&sl);
3077  return;
3078  }
3079  if (status == 2) {
3080  SockList_AddString(&sl, "failure accountpw New password is too long");
3081  Send_With_Handling(ns, &sl);
3082  SockList_Term(&sl);
3083  return;
3084  }
3085  /*The minimum length isn't exactly required, but in the current implementation,
3086  * client will send the same password for character for which there is a
3087  * 2 character minimum size. Thus an account with a one character password
3088  * won't be able to create a character. */
3089  if (strlen(change)<2) {
3090  SockList_AddString(&sl, "failure accountpw New password is too short");
3091  Send_With_Handling(ns, &sl);
3092  SockList_Term(&sl);
3093  return;
3094  }
3095 
3096  status = account_check_string(change);
3097  if (status == 1) {
3098  SockList_AddString(&sl,
3099  "failure accountpw Choose a different password. " VALIDCHAR_MSG);
3100  Send_With_Handling(ns, &sl);
3101  SockList_Term(&sl);
3102  return;
3103  }
3104 
3105  if (status == 2) {
3106  SockList_AddString(&sl,
3107  "failure accountpw That password is too long");
3108  Send_With_Handling(ns, &sl);
3109  SockList_Term(&sl);
3110  return;
3111  }
3112 
3113  status = account_change_password(ns->account_name, old, change);
3114  if (status != 0) {
3115  const char *error;
3116 
3117  if (status == 1) {
3118  error = "failure accountpw Illegal characters present";
3119  } else if (status == 2) {
3120  error = "failure accountpw Invalid account";
3121  } else {
3122  error = "failure accountpw Incorrect current password";
3123  }
3124 
3125  SockList_AddString(&sl, error);
3126  Send_With_Handling(ns, &sl);
3127  SockList_Term(&sl);
3128  return;
3129  }
3130 
3131  /* If we got here, we passed all checks, and password was changed */
3133 }
find_player_socket
player * find_player_socket(const socket_struct *ns)
Definition: player.cpp:123
ADD_PLAYER_NO_STATS_ROLL
#define ADD_PLAYER_NO_STATS_ROLL
Definition: player.h:247
SF_FIREON
#define SF_FIREON
Definition: newclient.h:192
CF_BLIND
#define CF_BLIND
Definition: newclient.h:203
Face::name
sstring name
Definition: face.h:19
account_add_player_cmd
void account_add_player_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:2399
CLASS
@ CLASS
Definition: object.h:143
CS_STAT_RES_DEPLETE
#define CS_STAT_RES_DEPLETE
Definition: newclient.h:165
Face
Definition: face.h:14
MAP_CLIENT_X
#define MAP_CLIENT_X
Definition: config.h:237
CF_STEALTHY
#define CF_STEALTHY
Definition: newclient.h:208
socket_struct::tick
uint32_t tick
Definition: newserver.h:106
atnr_cs_stat
static const short atnr_cs_stat[NROFATTACKS]
Definition: request.cpp:123
PLAYER
@ PLAYER
Definition: object.h:112
MAP_CLIENT_X_MINIMUM
#define MAP_CLIENT_X_MINIMUM
Definition: config.h:245
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.cpp:127
global.h
ANIM_SYNC
#define ANIM_SYNC
Definition: newclient.h:351
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
socket_struct::sc_version
uint32_t sc_version
Definition: newserver.h:113
first_player
player * first_player
Definition: init.cpp:106
ST_CHANGE_PASSWORD_OLD
#define ST_CHANGE_PASSWORD_OLD
Definition: define.h:550
settings
struct Settings settings
Definition: init.cpp:139
CS_STAT_RACE_CON
#define CS_STAT_RACE_CON
Definition: newclient.h:124
print_ext_msg
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Definition: info.cpp:62
banquet.l
l
Definition: banquet.py:164
CS_STAT_GRACE
#define CS_STAT_GRACE
Definition: newclient.h:112
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
find_smooth
int find_smooth(const Face *face, const Face **smoothed)
Definition: image.cpp:102
MAP
@ MAP
Definition: object.h:130
living::maxhp
int16_t maxhp
Definition: living.h:41
socket_struct::heartbeat
bool heartbeat
Definition: newserver.h:112
SockList_AddInt64
void SockList_AddInt64(SockList *sl, uint64_t data)
Definition: lowlevel.cpp:140
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Definition: define.h:547
ACL_FACE_NUM
#define ACL_FACE_NUM
Definition: newclient.h:227
FLAG_CONFUSED
#define FLAG_CONFUSED
Definition: define.h:311
CAN_PROBE
static bool CAN_PROBE(const object *ob)
Definition: object.h:616
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:241
send_account_players
void send_account_players(socket_struct *ns)
Definition: request.cpp:2059
object::path_attuned
uint32_t path_attuned
Definition: object.h:353
CS_STAT_APPLIED_WIS
#define CS_STAT_APPLIED_WIS
Definition: newclient.h:136
MAP2_COORD_MAX
static const int MAP2_COORD_MAX
Definition: request.cpp:74
ssop_t
int ssop_t
Definition: request.cpp:58
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:499
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
send_query
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Definition: request.cpp:746
Map
Definition: newserver.h:48
account_play_cmd
void account_play_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:2528
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
new_player_cmd
void new_player_cmd(uint8_t *buf, int len, player *pl)
Definition: request.cpp:527
client_spell
Definition: player.h:87
CS_STAT_RES_FEAR
#define CS_STAT_RES_FEAR
Definition: newclient.h:164
MAP2_COORD_OFFSET
#define MAP2_COORD_OFFSET
Definition: newclient.h:32
player
Definition: player.h:105
CS_STAT_DAM
#define CS_STAT_DAM
Definition: newclient.h:104
strdup_local
#define strdup_local
Definition: compat.h:29
ACL_RACE
#define ACL_RACE
Definition: newclient.h:222
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
CS_STAT_RES_FIRE
#define CS_STAT_RES_FIRE
Definition: newclient.h:153
ask_smooth_cmd
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:503
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
newhash
char const * newhash(char const *password)
Definition: server.cpp:101
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
socket_struct::sound
uint32_t sound
Definition: newserver.h:111
account_get_additional_chars
linked_char * account_get_additional_chars(const char *account_name, const Account_Chars *chars, int *count)
Definition: account.cpp:551
CS_STAT_APPLIED_POW
#define CS_STAT_APPLIED_POW
Definition: newclient.h:140
CS_STAT_HP
#define CS_STAT_HP
Definition: newclient.h:90
socket_struct
Definition: newserver.h:89
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
get_skill_client_code
int get_skill_client_code(const char *skill_name)
Definition: skill_util.cpp:116
ST_GET_NAME
#define ST_GET_NAME
Definition: define.h:546
map2_delete_layer
static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns)
Definition: request.cpp:1259
update_position
void update_position(mapstruct *m, int x, int y)
Definition: map.cpp:2118
MAX_NUM_LOOK_OBJECTS
#define MAX_NUM_LOOK_OBJECTS
Definition: newserver.h:28
MAP2_COORD_MIN
static const int MAP2_COORD_MIN
Definition: request.cpp:73
socket_struct::num_look_objects
uint8_t num_look_objects
Definition: newserver.h:122
object::arch
struct archetype * arch
Definition: object.h:424
command_execute
void command_execute(object *pl, char *command)
Definition: commands.cpp:456
AddIfInt64
#define AddIfInt64(Old, New, sl, Type)
Definition: request.cpp:755
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:157
ring_occidental_mages.rest
rest
Definition: ring_occidental_mages.py:16
MAX_TIME
#define MAX_TIME
Definition: config.h:254
CS_STAT_SPELL_DENY
#define CS_STAT_SPELL_DENY
Definition: newclient.h:119
account_get_players_for_account
char ** account_get_players_for_account(const char *account_name)
Definition: account.cpp:520
accounts_save
void accounts_save(void)
Definition: account.cpp:256
CS_STAT_WIS
#define CS_STAT_WIS
Definition: newclient.h:96
reply_cmd
void reply_cmd(char *buf, int len, player *pl)
Definition: request.cpp:589
CS_STAT_SPEED
#define CS_STAT_SPEED
Definition: newclient.h:106
socket_struct::extended_stats
uint32_t extended_stats
Definition: newserver.h:109
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:95
append_spell
static void append_spell(player *pl, SockList *sl, object *spell)
Definition: request.cpp:1880
guildjoin.ob
ob
Definition: guildjoin.py:42
Settings::min_name
uint8_t min_name
Definition: global.h:331
SK_PRAYING
@ SK_PRAYING
Definition: skills.h:49
CS_STAT_MAXSP
#define CS_STAT_MAXSP
Definition: newclient.h:93
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
MIN
#define MIN(x, y)
Definition: compat.h:21
CS_STAT_BASE_DEX
#define CS_STAT_BASE_DEX
Definition: newclient.h:130
CS_STAT_RES_MAG
#define CS_STAT_RES_MAG
Definition: newclient.h:152
FIF
#define FIF(F, C)
MAP_LAYERS
#define MAP_LAYERS
Definition: map.h:32
Settings::starting_stat_min
uint8_t starting_stat_min
Definition: global.h:320
SKILL
@ SKILL
Definition: object.h:148
client_spell::last_sp
int16_t last_sp
Definition: player.h:89
socket_struct::is_bot
uint32_t is_bot
Definition: newserver.h:107
get_player
player * get_player(player *p)
Definition: player.cpp:285
send_extra_stats
static void send_extra_stats(SockList *sl, player *pl)
Definition: request.cpp:811
object::count
tag_t count
Definition: object.h:307
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.cpp:101
CS_STAT_SP
#define CS_STAT_SP
Definition: newclient.h:92
SP_CREATE_FOOD
#define SP_CREATE_FOOD
Definition: spells.h:96
ACL_NAME
#define ACL_NAME
Definition: newclient.h:220
CS_STAT_RES_HOLYWORD
#define CS_STAT_RES_HOLYWORD
Definition: newclient.h:167
annotate_ob
static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer)
Definition: request.cpp:1369
Ice.tmp
int tmp
Definition: Ice.py:207
CS_STAT_GOLEM_HP
#define CS_STAT_GOLEM_HP
Definition: newclient.h:141
CS_STAT_RES_CONF
#define CS_STAT_RES_CONF
Definition: newclient.h:156
NDI_RED
#define NDI_RED
Definition: newclient.h:248
MAX_HEAD_OFFSET
#define MAX_HEAD_OFFSET
Definition: newserver.h:42
account_link
int account_link(const char *account_name, const char *player_name)
Definition: account.cpp:445
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
CS_STAT_TURN_UNDEAD
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:163
ACL_CLASS
#define ACL_CLASS
Definition: newclient.h:221
SP_CREATE_MISSILE
#define SP_CREATE_MISSILE
Definition: spells.h:113
CF_NOT_PERFECT
#define CF_NOT_PERFECT
Definition: newclient.h:206
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
receive_play_again
void receive_play_again(object *op, char key)
Definition: player.cpp:956
set_player_socket
void set_player_socket(player *p, socket_struct *ns)
Definition: player.cpp:413
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:532
map_clearcell
static void map_clearcell(struct map_cell_struct *cell, int face, int darkness)
Definition: request.cpp:1073
CS_STAT_EXP64
#define CS_STAT_EXP64
Definition: newclient.h:116
map2_coord_valid
static bool map2_coord_valid(int x)
Definition: request.cpp:76
FLAG_PROBE
#define FLAG_PROBE
Definition: define.h:257
range_golem
@ range_golem
Definition: player.h:34
send_plugin_custom_message
void send_plugin_custom_message(object *pl, char *buf)
Definition: request.cpp:1747
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.cpp:74
CS_STAT_CHARACTER_FLAGS
#define CS_STAT_CHARACTER_FLAGS
Definition: newclient.h:143
socket_struct::map_scroll_x
int8_t map_scroll_x
Definition: newserver.h:94
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4346
set_up_cmd
void set_up_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:143
UPD_SP_MANA
#define UPD_SP_MANA
Definition: newclient.h:327
object::level
int16_t level
Definition: object.h:361
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
map2_label
map2_label
Definition: newclient.h:56
heads
static const object * heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS]
Definition: request.cpp:1087
pticks
uint32_t pticks
Definition: time.cpp:47
buf
StringBuffer * buf
Definition: readable.cpp:1565
key_confirm_quit
void key_confirm_quit(object *op, char key)
Definition: player.cpp:1592
CS_STAT_APPLIED_DEX
#define CS_STAT_APPLIED_DEX
Definition: newclient.h:137
add_player
player * add_player(socket_struct *ns, int flags)
Definition: player.cpp:460
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2857
map2_add_label
static void map2_add_label(socket_struct *ns, SockList *sl, enum map2_label subtype, const char *label)
Definition: request.cpp:1352
POISONING
@ POISONING
Definition: object.h:223
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:407
MAX
#define MAX(x, y)
Definition: compat.h:24
CS_STAT_RACE_STR
#define CS_STAT_RACE_STR
Definition: newclient.h:120
CS_STAT_GOLEM_MAXHP
#define CS_STAT_GOLEM_MAXHP
Definition: newclient.h:142
SND_EFFECTS
#define SND_EFFECTS
Definition: sounds.h:12
MAP2_LABEL_PLAYER_PARTY
@ MAP2_LABEL_PLAYER_PARTY
Definition: newclient.h:58
ACL_MAP
#define ACL_MAP
Definition: newclient.h:226
linked_char
Definition: global.h:96
Account_Chars::chars
std::vector< Account_Char * > chars
Definition: account_char.h:30
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.cpp:246
GetShort_String
short GetShort_String(const unsigned char *data)
Definition: lowlevel.cpp:258
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.cpp:194
SP_SUMMON_MONSTER
#define SP_SUMMON_MONSTER
Definition: spells.h:101
UPD_SP_DAMAGE
#define UPD_SP_DAMAGE
Definition: newclient.h:329
m
static event_registration m
Definition: citylife.cpp:425
AddIfShort
#define AddIfShort(Old, New, sl, Type)
Definition: request.cpp:769
socket_struct::account_chars
Account_Chars * account_chars
Definition: newserver.h:127
esrv_send_animation
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Definition: request.cpp:1039
VALIDCHAR_MSG
#define VALIDCHAR_MSG
Definition: request.cpp:71
socket_struct::mapy
uint8_t mapy
Definition: newserver.h:116
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:126
Ns_Avail
@ Ns_Avail
Definition: newserver.h:65
CS_STAT_RACE_DEX
#define CS_STAT_RACE_DEX
Definition: newclient.h:123
CS_STAT_ARMOUR
#define CS_STAT_ARMOUR
Definition: newclient.h:105
positioning_system.coord
coord
Definition: positioning_system.py:26
item.q
q
Definition: item.py:32
set_title
void set_title(const object *pl, char *buf, size_t len)
Definition: info.cpp:334
clamp
static int clamp(int x, int min, int max)
Definition: request.cpp:96
map_cell_struct
Definition: newserver.h:31
MAP_CLIENT_Y
#define MAP_CLIENT_Y
Definition: config.h:238
CS_STAT_SPELL_REPEL
#define CS_STAT_SPELL_REPEL
Definition: newclient.h:118
disinfect.map
map
Definition: disinfect.py:4
CS_STAT_RACE_CHA
#define CS_STAT_RACE_CHA
Definition: newclient.h:125
P_NEW_MAP
#define P_NEW_MAP
Definition: map.h:248
MAP2_ADD_LENGTH
#define MAP2_ADD_LENGTH
Definition: newclient.h:67
object::subtype
uint8_t subtype
Definition: object.h:349
CS_STAT_LEVEL
#define CS_STAT_LEVEL
Definition: newclient.h:101
CS_STAT_CON
#define CS_STAT_CON
Definition: newclient.h:98
account_new_cmd
void account_new_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:2285
account_login_cmd
void account_login_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:2186
playername_ok
int playername_ok(const char *cp)
Definition: player.cpp:257
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.cpp:72
client_spell::last_dam
int16_t last_dam
Definition: player.h:91
ACL_PARTY
#define ACL_PARTY
Definition: newclient.h:225
CS_STAT_CHA
#define CS_STAT_CHA
Definition: newclient.h:99
CS_STAT_APPLIED_CHA
#define CS_STAT_APPLIED_CHA
Definition: newclient.h:139
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Definition: define.h:552
CS_STAT_RES_SLOW
#define CS_STAT_RES_SLOW
Definition: newclient.h:161
socket_struct::facecache
uint32_t facecache
Definition: newserver.h:102
check_race_and_class
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
Definition: player.cpp:1429
player::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:178
check_login
void check_login(object *op, const char *password)
Definition: login.cpp:511
CS_STAT_BASE_POW
#define CS_STAT_BASE_POW
Definition: newclient.h:133
account_get_account_for_char
const char * account_get_account_for_char(const char *charname)
Definition: account.cpp:580
CS_STAT_RES_PHYS
#define CS_STAT_RES_PHYS
Definition: newclient.h:151
Settings::account_block_create
uint8_t account_block_create
Definition: global.h:328
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Definition: define.h:542
CS_STAT_GOD_NAME
#define CS_STAT_GOD_NAME
Definition: newclient.h:144
Face::number
uint16_t number
Definition: face.h:15
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Definition: player.h:246
map_cell_struct::darkness
int darkness
Definition: newserver.h:33
account_char_free
void account_char_free(Account_Chars *chars)
Definition: account_char.cpp:345
archetype::clone
object clone
Definition: object.h:487
send_smooth
static void send_smooth(socket_struct *ns, const Face *face)
Definition: request.cpp:459
handle_scroll
static void handle_scroll(socket_struct *socket, SockList *sl)
Definition: request.cpp:104
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
draw_client_map
void draw_client_map(object *pl)
Definition: request.cpp:1648
account_remove_player
int account_remove_player(const char *account_name, const char *player_name)
Definition: account.cpp:475
HEAD
#define HEAD(op)
Definition: object.h:607
MAX_HEAD_POS
#define MAX_HEAD_POS
Definition: request.cpp:1078
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.cpp:116
object::casting_time
int16_t casting_time
Definition: object.h:414
ANIM_RANDOM
#define ANIM_RANDOM
Definition: newclient.h:350
CS_STAT_BASE_CHA
#define CS_STAT_BASE_CHA
Definition: newclient.h:132
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.cpp:4108
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:106
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.cpp:218
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
socket_struct::lastmap
struct Map lastmap
Definition: newserver.h:93
CF_POISONED
#define CF_POISONED
Definition: newclient.h:202
MAP2_LAYER_START
#define MAP2_LAYER_START
Definition: newclient.h:66
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
object::face
const Face * face
Definition: object.h:341
CS_STAT_APPLIED_STR
#define CS_STAT_APPLIED_STR
Definition: newclient.h:134
socket_struct::host
char * host
Definition: newserver.h:100
CS_STAT_RACE_POW
#define CS_STAT_RACE_POW
Definition: newclient.h:126
account_password
void account_password(char *buf, int len, socket_struct *ns)
Definition: request.cpp:3053
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1709
GET_MAP_FACE_OBJ
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Definition: map.h:182
socket_struct::account_name
char * account_name
Definition: newserver.h:126
MAP2_TYPE_LABEL
#define MAP2_TYPE_LABEL
Definition: newclient.h:44
CS_STAT_AC
#define CS_STAT_AC
Definition: newclient.h:103
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
client_spell::last_grace
int16_t last_grace
Definition: player.h:90
check_space_for_heads
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.cpp:1413
CS_STAT_OVERLOAD
#define CS_STAT_OVERLOAD
Definition: newclient.h:145
object::type
uint8_t type
Definition: object.h:348
living::dam
int16_t dam
Definition: living.h:46
CS_STAT_WEAP_SP
#define CS_STAT_WEAP_SP
Definition: newclient.h:108
socket_struct::monitor_spells
uint32_t monitor_spells
Definition: newserver.h:110
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
CS_STAT_APPLIED_CON
#define CS_STAT_APPLIED_CON
Definition: newclient.h:138
MAP_LAYER_LIVING1
#define MAP_LAYER_LIVING1
Definition: map.h:46
navar-midane_time.data
data
Definition: navar-midane_time.py:11
esrv_update_spells
void esrv_update_spells(player *pl)
Definition: request.cpp:1761
skill_names
const char * skill_names[MAX_SKILLS]
Definition: skill_util.cpp:59
map_cell_struct::faces
uint16_t faces[MAP_LAYERS]
Definition: newserver.h:32
socket_struct::faceset
uint8_t faceset
Definition: newserver.h:117
CS_STAT_RES_GHOSTHIT
#define CS_STAT_RES_GHOSTHIT
Definition: newclient.h:159
linked_char::next
struct linked_char * next
Definition: global.h:98
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
Definition: newclient.h:175
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
account_new
int account_new(const char *account_name, const char *account_password)
Definition: account.cpp:400
ST_CHANGE_PASSWORD_NEW
#define ST_CHANGE_PASSWORD_NEW
Definition: define.h:551
CS_STAT_RES_BLIND
#define CS_STAT_RES_BLIND
Definition: newclient.h:168
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
say.max
dictionary max
Definition: say.py:148
CF_DISEASED
#define CF_DISEASED
Definition: newclient.h:205
MAP2_TYPE_DARKNESS
#define MAP2_TYPE_DARKNESS
Definition: newclient.h:43
socket_struct::map_scroll_y
int8_t map_scroll_y
Definition: newserver.h:94
MAP2_COORD_ENCODE
static uint16_t MAP2_COORD_ENCODE(int x, int y, int flags)
Definition: request.cpp:89
archetype
Definition: object.h:483
sproto.h
CS_STAT_RACE_INT
#define CS_STAT_RACE_INT
Definition: newclient.h:121
SND_MUTE
#define SND_MUTE
Definition: sounds.h:14
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.cpp:2321
VERSION_SC
#define VERSION_SC
Definition: newserver.h:150
animate.anim
string anim
Definition: animate.py:20
get_face_by_id
const Face * get_face_by_id(uint16_t id)
Definition: assets.cpp:315
devourers.command
command
Definition: devourers.py:16
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.cpp:236
account_is_logged_in
int account_is_logged_in(const char *name)
Definition: account.cpp:605
MAP_TYPE_CHOICE
#define MAP_TYPE_CHOICE
Definition: map.h:59
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:55
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
SockList::len
size_t len
Definition: newclient.h:689
CS_STAT_BASE_WIS
#define CS_STAT_BASE_WIS
Definition: newclient.h:129
is_perfect
static uint8_t is_perfect(const player *pl)
Definition: request.cpp:796
CS_STAT_FOOD
#define CS_STAT_FOOD
Definition: newclient.h:107
socket_struct::cs_version
uint32_t cs_version
Definition: newserver.h:113
object::other_arch
struct archetype * other_arch
Definition: object.h:425
living
Definition: living.h:35
guild_entry.text
text
Definition: guild_entry.py:41
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:247
CS_STAT_WEIGHT_LIM
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:115
MAX_BUF
#define MAX_BUF
Definition: define.h:35
Ns_Add
@ Ns_Add
Definition: newserver.h:66
CS_STAT_ITEM_POWER
#define CS_STAT_ITEM_POWER
Definition: newclient.h:146
CS_STAT_RES_POISON
#define CS_STAT_RES_POISON
Definition: newclient.h:160
receive_player_name
void receive_player_name(object *op, const char *name)
Definition: c_misc.cpp:1935
is_valid_faceset
int is_valid_faceset(int fsn)
Definition: image.cpp:117
CS_STAT_WC
#define CS_STAT_WC
Definition: newclient.h:102
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Definition: player.h:245
object_present_in_ob
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.cpp:3168
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2369
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:65
AddIfInt
#define AddIfInt(Old, New, sl, Type)
Definition: request.cpp:762
probe
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Definition: spell_effect.cpp:699
FLAG_CLIENT_SENT
#define FLAG_CLIENT_SENT
Definition: define.h:346
CS_STAT_MAXGRACE
#define CS_STAT_MAXGRACE
Definition: newclient.h:113
key_roll_stat
void key_roll_stat(object *op, char key)
Definition: player.cpp:1213
MAP2_TYPE_CLEAR
#define MAP2_TYPE_CLEAR
Definition: newclient.h:42
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Definition: define.h:240
Settings::starting_stat_points
uint8_t starting_stat_points
Definition: global.h:322
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
Settings
Definition: global.h:240
create_player_cmd
void create_player_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:2633
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:94
apply_race_and_class
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
Definition: player.cpp:1479
CS_STAT_BASE_INT
#define CS_STAT_BASE_INT
Definition: newclient.h:128
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
Definition: define.h:544
CS_STAT_SPELL_ATTUNE
#define CS_STAT_SPELL_ATTUNE
Definition: newclient.h:117
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
llevInfo
@ llevInfo
Definition: logger.h:12
SockList_AddData
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:167
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:265
esrv_move_object
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.cpp:899
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
get_client_spell_state
client_spell * get_client_spell_state(player *pl, object *spell)
Definition: player.cpp:144
archetype::tail_x
int8_t tail_x
Definition: object.h:488
object::name
sstring name
Definition: object.h:319
SP_level_dam_adjust
int SP_level_dam_adjust(const object *caster, const object *spob)
Definition: spell_util.cpp:287
socket_struct::want_pickup
uint32_t want_pickup
Definition: newserver.h:108
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.cpp:4252
AddIfFloat
#define AddIfFloat(Old, New, sl, Type)
Definition: request.cpp:776
MAP2_LABEL_DM
@ MAP2_LABEL_DM
Definition: newclient.h:59
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
Definition: define.h:548
send_tick
void send_tick(player *pl)
Definition: request.cpp:2004
map2_add_ob
static int map2_add_ob(int ax, int ay, int layer, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int is_head)
Definition: request.cpp:1114
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.cpp:300
account_block_create
static int account_block_create(const socket_struct *ns)
Definition: request.cpp:2249
item
Definition: item.py:1
DISEASE
@ DISEASE
Definition: object.h:249
P_NEED_UPDATE
#define P_NEED_UPDATE
Definition: map.h:237
newserver.h
mapstruct
Definition: map.h:313
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.cpp:727
SP_RUNE
#define SP_RUNE
Definition: spells.h:76
BEAT_INTERVAL
#define BEAT_INTERVAL
Definition: config.h:636
object::env
object * env
Definition: object.h:301
map_newmap_cmd
void map_newmap_cmd(socket_struct *ns)
Definition: request.cpp:687
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.cpp:1950
SND_MUSIC
#define SND_MUSIC
Definition: sounds.h:13
sstring
const typedef char * sstring
Definition: sstring.h:2
give.op
op
Definition: give.py:33
NDI_ALL
#define NDI_ALL
Definition: newclient.h:266
socket_struct::status
enum Sock_Status status
Definition: newserver.h:90
Animations
Definition: face.h:25
MAP_CLIENT_Y_MINIMUM
#define MAP_CLIENT_Y_MINIMUM
Definition: config.h:246
autojail.value
value
Definition: autojail.py:6
CS_STAT_RES_COLD
#define CS_STAT_RES_COLD
Definition: newclient.h:155
FLAG_AUTO_APPLY
#define FLAG_AUTO_APPLY
Definition: define.h:250
object::skill
sstring skill
Definition: object.h:329
esrv_remove_spell
void esrv_remove_spell(player *pl, object *spell)
Definition: request.cpp:1813
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:179
receive_player_password
void receive_player_password(object *op, const char *password)
Definition: c_misc.cpp:1955
mapstruct::in_memory
uint32_t in_memory
Definition: map.h:333
add_me_cmd
void add_me_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:415
esrv_draw_look
void esrv_draw_look(object *pl)
Definition: item.cpp:193
object::msg
sstring msg
Definition: object.h:330
version_cmd
void version_cmd(char *buf, int len, socket_struct *ns)
Definition: request.cpp:651
diamondslots.y
y
Definition: diamondslots.py:16
MAP2_LABEL_PLAYER
@ MAP2_LABEL_PLAYER
Definition: newclient.h:57
Map::cells
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:49
CF_CONFUSED
#define CF_CONFUSED
Definition: newclient.h:201
ob_apply
method_ret ob_apply(object *op, object *applier, int aflags)
Definition: ob_methods.cpp:44
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:171
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.cpp:83
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:251
socket_struct::anims_sent
uint8_t anims_sent[MAXANIMNUM]
Definition: newserver.h:97
account_change_password
int account_change_password(const char *account_name, const char *current_password, const char *new_password)
Definition: account.cpp:628
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
CS_STAT_RES_DEATH
#define CS_STAT_RES_DEATH
Definition: newclient.h:166
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
player::party
partylist * party
Definition: player.h:203
GetInt_String
int GetInt_String(const unsigned char *data)
Definition: lowlevel.cpp:254
draw_client_map2
static void draw_client_map2(object *pl)
Definition: request.cpp:1460
strcasecmp
int strcasecmp(const char *s1, const char *s2)
castle_read.key
key
Definition: castle_read.py:64
make_face_from_files.int
int
Definition: make_face_from_files.py:32
ACL_LEVEL
#define ACL_LEVEL
Definition: newclient.h:223
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Definition: map.h:49
CS_STAT_TITLE
#define CS_STAT_TITLE
Definition: newclient.h:110
MAP_TYPE_DEFAULT
#define MAP_TYPE_DEFAULT
Definition: map.h:58
object::randomitems
struct treasurelist * randomitems
Definition: object.h:395
newclient.h
save_player
int save_player(object *op, int flag)
Definition: login.cpp:230
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Definition: define.h:549
VERSION_CS
#define VERSION_CS
Definition: newserver.h:149
Account_Chars
Definition: account_char.h:27
UPD_SP_GRACE
#define UPD_SP_GRACE
Definition: newclient.h:328
get_archetype_by_type_subtype
archetype * get_archetype_by_type_subtype(int type, int subtype)
Definition: arch.cpp:99
CS_STAT_POW
#define CS_STAT_POW
Definition: newclient.h:111
CF_WIZARD
#define CF_WIZARD
Definition: newclient.h:210
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.cpp:1836
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.cpp:4471
free_charlinks
void free_charlinks(linked_char *lc)
Definition: utils.cpp:616
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
CS_STAT_RACE_WIS
#define CS_STAT_RACE_WIS
Definition: newclient.h:122
AddIfString
#define AddIfString(Old, New, sl, Type)
Definition: request.cpp:783
MAX_CHOICES
#define MAX_CHOICES
Definition: request.cpp:2626
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:286
SP_RAISE_DEAD
#define SP_RAISE_DEAD
Definition: spells.h:75
MIN_NUM_LOOK_OBJECTS
#define MIN_NUM_LOOK_OBJECTS
Definition: newserver.h:16
SP_MAKE_MARK
#define SP_MAKE_MARK
Definition: spells.h:77
MAP_LAYER_LIVING2
#define MAP_LAYER_LIVING2
Definition: map.h:47
socket_struct::login_method
uint8_t login_method
Definition: newserver.h:128
archetype::tail_y
int8_t tail_y
Definition: object.h:488
check_probe
static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer)
Definition: request.cpp:1284
commands.h
ST_CONFIRM_QUIT
#define ST_CONFIRM_QUIT
Definition: define.h:545
CS_STAT_MAXHP
#define CS_STAT_MAXHP
Definition: newclient.h:91
move_cmd
void move_cmd(char *buf, int len, player *pl)
Definition: request.cpp:708
account_char_load
Account_Chars * account_char_load(const char *account_name)
Definition: account_char.cpp:135
key_change_class
void key_change_class(object *op, char key)
Definition: player.cpp:1289
receive_party_password
void receive_party_password(object *op, const char *password)
Definition: c_party.cpp:53
spell_client_use
static int spell_client_use(const object *spell)
Definition: request.cpp:1856
account_check_string
int account_check_string(const char *str)
Definition: account.cpp:361
esrv_update_stats
void esrv_update_stats(player *pl)
Definition: request.cpp:867
socket_struct::darkness
uint32_t darkness
Definition: newserver.h:103
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
player::socket
socket_struct * socket
Definition: player.h:107
socket_struct::notifications
uint16_t notifications
Definition: newserver.h:129
SF_RUNON
#define SF_RUNON
Definition: newclient.h:193
CS_STAT_RANGE
#define CS_STAT_RANGE
Definition: newclient.h:109
Settings::account_trusted_host
char * account_trusted_host
Definition: global.h:329
report.error
def error(pl)
Definition: report.py:43
object::stats
living stats
Definition: object.h:378
MSG_TYPE_ADMIN_VERSION
#define MSG_TYPE_ADMIN_VERSION
Definition: newclient.h:504
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.cpp:313
update_los
void update_los(object *op)
Definition: los.cpp:509
CS_STAT_BASE_CON
#define CS_STAT_BASE_CON
Definition: newclient.h:131
add_char_field
static void add_char_field(SockList *sl, int type, const char *data)
Definition: request.cpp:2025
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:97
account_login
int account_login(const char *account_name, const char *account_password)
Definition: account.cpp:319
Settings::always_show_hp
uint8_t always_show_hp
Definition: global.h:273
verify_player
int verify_player(const char *name, char *password)
Definition: login.cpp:111
ST_ROLL_STAT
#define ST_ROLL_STAT
Definition: define.h:543
SPELL
@ SPELL
Definition: object.h:219
CS_STAT_BASE_STR
#define CS_STAT_BASE_STR
Definition: newclient.h:127
smooth_face
const Face * smooth_face
Definition: image.cpp:36
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.cpp:1009
decode_name_password
static int decode_name_password(const char *buf, int *len, char *name, char *password)
Definition: request.cpp:2150
account_char_save
void account_char_save(Account_Chars *chars)
Definition: account_char.cpp:158
CS_STAT_RES_DRAIN
#define CS_STAT_RES_DRAIN
Definition: newclient.h:158
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
MAP_NOSMOOTH
#define MAP_NOSMOOTH(m)
Definition: map.h:84
living.h
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:447
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:405
CF_HOSTILE
#define CF_HOSTILE
Definition: newclient.h:207
SockList
Definition: newclient.h:684
map_reset_swap
void map_reset_swap(mapstruct *m)
Definition: map.cpp:1750
CF_PARALYZED
#define CF_PARALYZED
Definition: newclient.h:209
NUM_STATS
@ NUM_STATS
Definition: living.h:18
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
living::hp
int16_t hp
Definition: living.h:40
takeitem.status
status
Definition: takeitem.py:38
FORCE
@ FORCE
Definition: object.h:229
account_char_remove
void account_char_remove(Account_Chars *chars, const char *pl_name)
Definition: account_char.cpp:313
CS_STAT_APPLIED_INT
#define CS_STAT_APPLIED_INT
Definition: newclient.h:135
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Definition: define.h:450
ACL_FACE
#define ACL_FACE
Definition: newclient.h:224
CF_XRAY
#define CF_XRAY
Definition: newclient.h:204
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Definition: info.cpp:264
llevDebug
@ llevDebug
Definition: logger.h:13
NS_FACESENT_SMOOTH
#define NS_FACESENT_SMOOTH
Definition: newserver.h:138
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.cpp:202
account_exists
const char * account_exists(const char *account_name)
Definition: account.cpp:297
give.name
name
Definition: give.py:27
CS_STAT_RES_PARA
#define CS_STAT_RES_PARA
Definition: newclient.h:162
Settings::starting_stat_max
uint8_t starting_stat_max
Definition: global.h:321
CS_STAT_RES_ACID
#define CS_STAT_RES_ACID
Definition: newclient.h:157
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
dragon_attune.force
force
Definition: dragon_attune.py:45
CS_STAT_RES_ELEC
#define CS_STAT_RES_ELEC
Definition: newclient.h:154
CS_STAT_FLAGS
#define CS_STAT_FLAGS
Definition: newclient.h:114