Crossfire Server  1.75.0
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);
111  SockList_AddShort(sl, coord);
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) {
318  tmp = MIN_NUM_LOOK_OBJECTS;
319  } else if (tmp > MAX_NUM_LOOK_OBJECTS) {
320  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:
632  receive_player_password(pl->ob, buf);
633  break;
634 
635  case ST_GET_PARTY_PASSWORD: /* Get password for party */
636  receive_party_password(pl->ob, buf);
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  return;
725  }
726  buf++;
727  }
728  vals[2] = atoi(buf);
729 
730 /* LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
731  esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
732 }
733 
734 /***************************************************************************
735  *
736  * Start of commands the server sends to the client.
737  *
738  ***************************************************************************
739  */
740 
745 void send_query(socket_struct *ns, uint8_t flags, const char *text) {
746  SockList sl;
747 
748  SockList_Init(&sl);
749  SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
750  Send_With_Handling(ns, &sl);
751  SockList_Term(&sl);
752 }
753 
754 #define AddIfInt64(Old, New, sl, Type) \
755  if (Old != New) { \
756  Old = New; \
757  SockList_AddChar(sl, Type); \
758  SockList_AddInt64(sl, New); \
759  }
760 
761 #define AddIfInt(Old, New, sl, Type) \
762  if (Old != New) { \
763  Old = New; \
764  SockList_AddChar(sl, Type); \
765  SockList_AddInt(sl, New); \
766  }
767 
768 #define AddIfShort(Old, New, sl, Type) \
769  if (Old != New) { \
770  Old = New; \
771  SockList_AddChar(sl, Type); \
772  SockList_AddShort(sl, New); \
773  }
774 
775 #define AddIfFloat(Old, New, sl, Type) \
776  if (Old != New) { \
777  Old = New; \
778  SockList_AddChar(sl, Type); \
779  SockList_AddInt(sl, (long)(New*FLOAT_MULTI));\
780  }
781 
782 #define AddIfString(Old, New, sl, Type) \
783  if (Old == NULL || strcmp(Old, New)) { \
784  free(Old); \
785  Old = strdup_local(New); \
786  SockList_AddChar(sl, Type); \
787  SockList_AddLen8Data(sl, New, strlen(New)); \
788  }
789 
795 static uint8_t is_perfect(const player *pl) {
796  const int16_t until = MIN(11, pl->ob->level);
797  for (int16_t i = 1; i < until; i++) {
798  if (pl->levhp[i] < 9 || pl->levsp[i] < 6 || pl->levgrace[i] < 3) {
799  return 0;
800  }
801  }
802  return 1;
803 }
804 
810 static void send_extra_stats(SockList *sl, player *pl) {
811  uint32_t uflags = 0;
812  const char *god = "none";
813 
814  if (pl->socket->notifications < 3) {
815  return;
816  }
817 
818  if (!pl->peaceful) {
819  uflags |= CF_HOSTILE;
820  }
821  if (!is_perfect(pl)) {
822  uflags |= CF_NOT_PERFECT;
823  }
824 
825 #define FIF(F, C) \
826  if (QUERY_FLAG(pl->ob, F)) { \
827  uflags |= C; \
828  }
830  FIF(FLAG_CONFUSED, CF_CONFUSED); // If confused by an item
834 
835  FOR_INV_PREPARE(pl->ob, item) {
836  if (item->type == DISEASE && !QUERY_FLAG(item, FLAG_STARTEQUIP)) {
837  uflags |= CF_DISEASED;
838  }
839  if (strcmp(item->arch->name, "poisoning") == 0) {
840  uflags |= CF_POISONED;
841  }
842  if (strcmp(item->arch->name, "blindness") == 0) {
843  uflags |= CF_BLIND;
844  }
845  if (item->type == FORCE && strcmp(item->name, "confusion") == 0) {
846  uflags |= CF_CONFUSED;
847  }
848  if (item->type == SKILL && item->subtype == SK_PRAYING && item->title) {
849  god = item->title;
850  }
851  }
852  FOR_INV_FINISH();
853 
856  AddIfString(pl->socket->stats.god, god, sl, CS_STAT_GOD_NAME);
858 }
859 
867  SockList sl;
868  char buf[MAX_BUF];
869  uint16_t flags;
870  uint8_t s;
871 
872  SockList_Init(&sl);
873  SockList_AddString(&sl, "stats ");
874 
875  if (pl->ob != NULL) {
876  AddIfShort(pl->last_stats.hp, pl->ob->stats.hp, &sl, CS_STAT_HP);
878  AddIfShort(pl->last_stats.sp, pl->ob->stats.sp, &sl, CS_STAT_SP);
882  AddIfShort(pl->last_stats.Str, pl->ob->stats.Str, &sl, CS_STAT_STR);
883  AddIfShort(pl->last_stats.Int, pl->ob->stats.Int, &sl, CS_STAT_INT);
884  AddIfShort(pl->last_stats.Pow, pl->ob->stats.Pow, &sl, CS_STAT_POW);
885  AddIfShort(pl->last_stats.Wis, pl->ob->stats.Wis, &sl, CS_STAT_WIS);
886  AddIfShort(pl->last_stats.Dex, pl->ob->stats.Dex, &sl, CS_STAT_DEX);
887  AddIfShort(pl->last_stats.Con, pl->ob->stats.Con, &sl, CS_STAT_CON);
888  AddIfShort(pl->last_stats.Cha, pl->ob->stats.Cha, &sl, CS_STAT_CHA);
889  }
890  if (pl->socket->extended_stats) {
891  int16_t golem_hp, golem_maxhp;
899  if (pl->ob != NULL) {
914  }
915  if (pl->ranges[range_golem]) {
916  object *golem = pl->ranges[range_golem];
917  if (QUERY_FLAG(golem, FLAG_REMOVED) || golem->count != pl->golem_count || QUERY_FLAG(golem, FLAG_FREED)) {
918  golem_hp = 0;
919  golem_maxhp = 0;
920  } else {
921  golem_hp = golem->stats.hp;
922  golem_maxhp = golem->stats.maxhp;
923  }
924  } else {
925  golem_hp = 0;
926  golem_maxhp = 0;
927  }
928  /* send first the maxhp, so the client can set up the display */
929  AddIfShort(pl->last_golem_maxhp, golem_maxhp, &sl, CS_STAT_GOLEM_MAXHP);
930  AddIfShort(pl->last_golem_hp, golem_hp, &sl, CS_STAT_GOLEM_HP);
931  }
932 
933  for (s = 0; s < MAX_SKILLS; s++) {
934  if (pl->last_skill_ob[s]) {
935  // Skill objects can be removed without updating last_skill_ob.
936  // Clean them up here if that's the case.
937  if (QUERY_FLAG(pl->last_skill_ob[s], FLAG_REMOVED)) {
938  LOG(llevDebug, "pruning removed object from last_skill_ob\n");
939  pl->last_skill_ob[s] = NULL;
940  continue;
941  }
942 
943  if (pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
944  /* Always send along the level if exp changes. This
945  * is only 1 extra byte, but keeps processing simpler.
946  */
948  SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
950  pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
951  }
952  }
953  }
954  AddIfInt64(pl->last_stats.exp, pl->ob->stats.exp, &sl, CS_STAT_EXP64);
955  AddIfShort(pl->last_level, (char)pl->ob->level, &sl, CS_STAT_LEVEL);
956  AddIfShort(pl->last_stats.wc, pl->ob->stats.wc, &sl, CS_STAT_WC);
957  AddIfShort(pl->last_stats.ac, pl->ob->stats.ac, &sl, CS_STAT_AC);
958  AddIfShort(pl->last_stats.dam, pl->ob->stats.dam, &sl, CS_STAT_DAM);
959  AddIfFloat(pl->last_speed, pl->ob->speed, &sl, CS_STAT_SPEED);
963  flags = 0;
964  if (pl->fire_on)
965  flags |= SF_FIREON;
966  if (pl->run_on)
967  flags |= SF_RUNON;
968 
969  AddIfShort(pl->last_flags, flags, &sl, CS_STAT_FLAGS);
970  if (pl->socket->sc_version < 1025) {
972  } else {
973  int i;
974 
975  for (i = 0; i < NROFATTACKS; i++) {
976  /* Skip ones we won't send */
977  if (atnr_cs_stat[i] == -1)
978  continue;
979  AddIfShort(pl->last_resist[i], pl->ob->resist[i], &sl, (char)atnr_cs_stat[i]);
980  }
981  }
982  if (pl->socket->monitor_spells) {
986  }
987  /* we want to use the new fire & run system in new client */
988  rangetostring(pl->ob, buf, sizeof(buf));
989  AddIfString(pl->socket->stats.range, buf, &sl, CS_STAT_RANGE);
990  set_title(pl->ob, buf, sizeof(buf));
991  AddIfString(pl->socket->stats.title, buf, &sl, CS_STAT_TITLE);
992 
993  send_extra_stats(&sl, pl);
994 
995  /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
996  if (sl.len > 8) {
997 #ifdef ESRV_DEBUG
998  LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
999 #endif
1000  Send_With_Handling(pl->socket, &sl);
1001  }
1002  SockList_Term(&sl);
1003 }
1004 
1008 void esrv_new_player(player *pl, uint32_t weight) {
1009  SockList sl;
1010 
1011  pl->last_weight = weight;
1012 
1013  if (!(pl->socket->faces_sent[pl->ob->face->number]&NS_FACESENT_FACE))
1014  esrv_send_face(pl->socket, pl->ob->face, 0);
1015 
1016  SockList_Init(&sl);
1017  SockList_AddString(&sl, "player ");
1018  SockList_AddInt(&sl, pl->ob->count);
1019  SockList_AddInt(&sl, weight);
1020  SockList_AddInt(&sl, pl->ob->face->number);
1021  SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
1022 
1023  Send_With_Handling(pl->socket, &sl);
1024  SockList_Term(&sl);
1026 }
1027 
1039  SockList sl;
1040  int i;
1041 
1042  if (anim == NULL) {
1043  LOG(llevError, "esrv_send_anim NULL??\n");
1044  return;
1045  }
1046 
1047  SockList_Init(&sl);
1048  SockList_AddString(&sl, "anim ");
1049  SockList_AddShort(&sl, anim->num);
1050  SockList_AddShort(&sl, 0); /* flags - not used right now */
1051  /* Build up the list of faces. Also, send any information (ie, the
1052  * the face itself) down to the client.
1053  */
1054  for (i = 0; i < anim->num_animations; i++) {
1055  if (!(ns->faces_sent[anim->faces[i]->number]&NS_FACESENT_FACE))
1056  esrv_send_face(ns, anim->faces[i], 0);
1057  /* flags - not used right now */
1058  SockList_AddShort(&sl, anim->faces[i]->number);
1059  }
1060  Send_With_Handling(ns, &sl);
1061  SockList_Term(&sl);
1062  ns->anims_sent[anim->num] = 1;
1063 }
1064 
1065 /****************************************************************************
1066  *
1067  * Start of map related commands.
1068  *
1069  ****************************************************************************/
1070 
1072 static void map_clearcell(struct map_cell_struct *cell, int face, int darkness) {
1073  cell->darkness = darkness;
1074  memset(cell->faces, face, sizeof(cell->faces));
1075 }
1076 
1077 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
1078 
1086 static const object *heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS];
1087 
1088 /****************************************************************************
1089  * This block is for map2 drawing related commands.
1090  * Note that the map2 still uses other functions.
1091  *
1092  ***************************************************************************/
1093 
1113 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) {
1114  uint8_t nlayer, smoothlevel = 0;
1115  const object *head;
1116 
1117  assert(ob != NULL);
1118 
1119  head = HEAD(ob);
1120  const Face *face = ob->face;
1121 
1122  /* This is a multipart object, and we are not at the lower
1123  * right corner. So we need to store away the lower right corner.
1124  */
1125  if (!is_head && (head->arch->tail_x || head->arch->tail_y)
1126  && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
1127  int bx, by, l;
1128 
1129  /* Basically figure out where the offset is from where we
1130  * are right now. the ob->arch->clone.{x,y} values hold
1131  * the offset that this current piece is from the head,
1132  * and the tail is where the tail is from the head.
1133  * Note that bx and by will equal sx and sy if we are
1134  * already working on the bottom right corner. If ob is
1135  * the head, the clone values will be zero, so the right
1136  * thing will still happen.
1137  */
1138  bx = ax+head->arch->tail_x-ob->arch->clone.x;
1139  by = ay+head->arch->tail_y-ob->arch->clone.y;
1140 
1141  /* I don't think this can ever happen, but better to check
1142  * for it just in case.
1143  */
1144  if (bx < ax || by < ay) {
1145  LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
1146  face = NULL;
1147  }
1148  /* the target position must be within +/-1 of our current
1149  * layer as the layers are defined. We are basically checking
1150  * to see if we have already stored this object away.
1151  */
1152  for (l = layer-1; l <= layer+1; l++) {
1153  if (l < 0 || l >= MAP_LAYERS)
1154  continue;
1155  if (heads[by][bx][l] == head)
1156  break;
1157  }
1158  /* Didn't find it. So we need to store it away. Try to store it
1159  * on our original layer, and then move up a layer.
1160  */
1161  if (l == layer+2) {
1162  if (!heads[by][bx][layer])
1163  heads[by][bx][layer] = head;
1164  else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
1165  heads[by][bx][layer+1] = head;
1166  }
1167  return 0;
1168  /* Ok - All done storing away the head for future use */
1169  } else {
1170  uint16_t face_num = face ? face->number : 0;
1171  (*has_obj)++;
1174  face_num = (ob->animation ? ob->animation->num : 0)|(1<<15);
1176  face_num |= ANIM_SYNC;
1177  else if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM))
1178  face_num |= ANIM_RANDOM;
1179  }
1180  /* Since face_num includes the bits for the animation tag,
1181  * and we will store that away in the faces[] array, below
1182  * check works fine _except_ for the case where animation
1183  * speed chances.
1184  */
1185  if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
1186  uint8_t len, anim_speed = 0, i;
1187 
1188  /* This block takes care of sending the actual face
1189  * to the client. */
1190  ns->lastmap.cells[ax][ay].faces[layer] = face_num;
1191 
1192  /* Now form the data packet */
1193  nlayer = MAP2_LAYER_START+layer;
1194 
1195  len = 2;
1196 
1197  if (ob->map && !MAP_NOSMOOTH(ob->map)) {
1198  smoothlevel = ob->smoothlevel;
1199  if (smoothlevel)
1200  len++;
1201  }
1202 
1205  len++;
1206  /* 1/0.004 == 250, so this is a good cap for an
1207  * upper limit */
1208  if (ob->anim_speed)
1209  anim_speed = ob->anim_speed;
1210  else if (FABS(ob->speed) < 0.004)
1211  anim_speed = 255;
1212  else if (FABS(ob->speed) >= 1.0)
1213  anim_speed = 1;
1214  else
1215  anim_speed = (int)(1.0/FABS(ob->speed));
1216 
1217  if (ob->animation && !ns->anims_sent[ob->animation->num])
1218  esrv_send_animation(ns, ob->animation);
1219 
1220  /* If smoothing, need to send smoothing information
1221  * for all faces in the animation sequence. Since
1222  * smoothlevel is an object attribute,
1223  * it applies to all faces.
1224  */
1225  if (smoothlevel) {
1226  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1227  if (!(ns->faces_sent[ob->animation->faces[i]->number]&NS_FACESENT_SMOOTH))
1228  send_smooth(ns, ob->animation->faces[i]);
1229  }
1230  }
1231  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1232  esrv_send_face(ns, face, 0);
1233  }
1234 
1235  if (smoothlevel
1236  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1237  send_smooth(ns, ob->face);
1238 
1239  /* Length of packet */
1240  nlayer |= len<<5;
1241 
1242  SockList_AddChar(sl, nlayer);
1243  SockList_AddShort(sl, face_num);
1244  if (anim_speed)
1245  SockList_AddChar(sl, anim_speed);
1246  if (smoothlevel)
1247  SockList_AddChar(sl, smoothlevel);
1248  return 1;
1249  } /* Face is different */
1250  }
1251  return 0;
1252 }
1253 
1254 /* This function is used see if a layer needs to be cleared.
1255  * It updates the socklist, and returns 1 if the update is
1256  * needed, 0 otherwise.
1257  */
1258 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1259  int nlayer;
1260 
1261  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1262  /* Now form the data packet */
1263  nlayer = 0x10+layer+(2<<5);
1264  SockList_AddChar(sl, nlayer);
1265  SockList_AddShort(sl, 0);
1266  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1267  return 1;
1268  }
1269  return 0;
1270 }
1271 
1283 static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1284  int got_one = 0, poisoned = 0, diseased = 0;
1285  char name[60];
1286  int value, granularity;
1287  const object *probe;
1288 
1289  /* send hp bar if needed */
1290  if ((*alive_layer) != -1 || ob->head || !CAN_PROBE(ob))
1291  return 0;
1292 
1293  if (settings.always_show_hp == 2) {
1294  /* global hp bars are enabled */
1295  granularity = 30;
1296  } else if (settings.always_show_hp == 1 && ob->stats.hp < ob->stats.maxhp) {
1297  granularity = 30;
1298  } else {
1299  /* only give hp bars to monsters that have been probed */
1300  if (!QUERY_FLAG(ob, FLAG_PROBE)) {
1301  return 0;
1302  }
1303  probe = object_find_by_type_and_name(ob, FORCE, "probe_force");
1304  if (probe == NULL || probe->level < 15) {
1305  /* if probe is not null, this is an error, but well */
1306  return 0;
1307  }
1308 
1309  granularity = (probe->level - 14) / 3;
1310  if (granularity <= 0)
1311  granularity = 1;
1312  else if (granularity > 30)
1313  granularity = 30;
1314  }
1315 
1316  if (ob->stats.maxhp > 0) {
1317  value = (ob->stats.hp * granularity) / (ob->stats.maxhp);
1318 
1319  if (value < 0)
1320  value = 0;
1321  else if (value > granularity)
1322  value = granularity;
1323  } else
1324  value = 30;
1325 
1326  value = (value * 30) / granularity;
1327 
1328  if (object_present_in_ob(POISONING, ob) != NULL)
1329  poisoned = 1;
1330  if (object_present_in_ob(DISEASE, ob) != NULL)
1331  diseased = 1;
1332 
1333  if (value > 0) {
1334  archetype *dummy;
1335 
1336  snprintf(name, sizeof(name), "hpbar%s%s%s_%d",
1337  poisoned ? "_poisoned" : "",
1338  diseased ? "_diseased" : "",
1339  (!poisoned && !diseased) ? "_standard" : "",
1340  value);
1341  dummy = try_find_archetype(name);
1342  if (dummy != NULL) {
1343  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1344  (*alive_layer) = MAP_LAYER_FLY2;
1345  }
1346  }
1347 
1348  return got_one;
1349 }
1350 
1354 static bool map2_add_label(int ax, int ay, socket_struct *ns, SockList *sl, enum map2_label subtype, sstring label) {
1355  // label can only be null if subtype is none
1356  assert(subtype != MAP2_LABEL_NONE ? label != NULL : 1);
1357 
1358  // protect old clients from label with additive length, which can cause them to crash
1359  if (ns->sc_version < 1030)
1360  return false;
1361 
1362  // Check if there is any change to last sent data
1363  struct map_cell_struct *cell = &ns->lastmap.cells[ax][ay];
1364  if (cell->label_subtype == subtype &&
1365  (subtype == 0 || cell->label_text == label)) { // none label skips string comparison
1366  return false;
1367  }
1368 
1369  // Store change
1370  if (cell->label_subtype != MAP2_LABEL_NONE)
1371  free_string(cell->label_text);
1372  cell->label_subtype = subtype;
1373  cell->label_text = label;
1374 
1375  int len = 0;
1376  if (label) {
1377  add_refcount(label);
1378  len = strlen(label);
1379  if (len > 256 - 2 - 1) {
1380  LOG(llevError, "The label '%s' is too long to send to the client.", label);
1381  return false;
1382  }
1383  }
1384 
1385  // Send update
1386  SockList_AddChar(sl, MAP2_ADD_LENGTH | MAP2_TYPE_LABEL); // label with additive length
1387  SockList_AddChar(sl, len + 2); // length of payload (subtype + lstring)
1388  SockList_AddChar(sl, subtype);
1389  SockList_AddChar(sl, len); // lstring length prefix
1390  if (label)
1391  SockList_AddString(sl, label);
1392  return true;
1393 }
1394 
1395 static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer) {
1396  socket_struct *ns = plyr->socket;
1397  int got_one = check_probe(ax, ay, ob, sl, ns, has_obj, alive_layer);
1398  // add NPC speech bubble
1399  if (QUERY_FLAG(ob, FLAG_ALIVE) && (QUERY_FLAG(ob, FLAG_UNAGGRESSIVE) || QUERY_FLAG(ob, FLAG_FRIENDLY)) && ob->type != PLAYER) {
1400  if (ob->msg != NULL || object_find_by_arch_name(ob, NPC_DIALOG_ARCH)) {
1401  archetype *dummy = try_find_archetype("speechbubble");
1402  if (dummy != NULL) {
1403  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1404  (*alive_layer) = MAP_LAYER_FLY2;
1405  }
1406  }
1407  }
1408  return got_one;
1409 }
1410 
1414 static bool add_labels(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *got_one) {
1415  socket_struct *ns = plyr->socket;
1416  // add player name label
1417  if (ob->type == PLAYER) {
1418  enum map2_label subtype = MAP2_LABEL_PLAYER;
1419  if (QUERY_FLAG(ob, FLAG_WIZ)) {
1420  subtype = MAP2_LABEL_DM;
1421  } else if (plyr->party) {
1422  if (ob->contr && ob->contr->party == plyr->party) {
1423  subtype = MAP2_LABEL_PLAYER_PARTY;
1424  }
1425  }
1426  *got_one += map2_add_label(ax, ay, ns, sl, subtype, ob->name);
1427  return true;
1428  } else if (object_value_set(ob, "label")) {
1429  const char *label = object_get_value(ob, "label");
1430  *got_one += map2_add_label(ax, ay, ns, sl, MAP2_LABEL_SIGN, label);
1431  return true;
1432  }
1433  return false;
1434 }
1435 
1436 /*
1437  * This function is used to check a space (ax, ay) whose only
1438  * data we may care about are any heads. Basically, this
1439  * space is out of direct view. This is only used with the
1440  * Map2 protocol.
1441  *
1442  * @param ax
1443  * viewport relative x-coordinate
1444  * @param ay
1445  * viewport relative y-coordinate
1446  * @param sl
1447  * the reply to append to
1448  * @param ns
1449  * the client socket
1450  */
1451 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1452  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1453  uint16_t coord;
1454 
1455  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1456  oldlen = sl->len;
1457  SockList_AddShort(sl, coord);
1458 
1459  for (layer = 0; layer < MAP_LAYERS; layer++) {
1460  const object *head;
1461 
1462  head = heads[ay][ax][layer];
1463  if (head) {
1464  /* in this context, got_one should always increase
1465  * because heads should always point to data to really send.
1466  */
1467  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1468  } else {
1469  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1470  }
1471  }
1472  /* Note - if/when lighting information is added, some code is
1473  * needed here - lighting sources that are out of sight may still
1474  * extend into the viewable area.
1475  */
1476 
1477  /* If nothing to do for this space, we
1478  * can erase the coordinate bytes
1479  */
1480  if (!del_one && !got_one) {
1481  sl->len = oldlen;
1482  } else if (del_one && !has_obj) {
1483  /* If we're only deleting faces and not adding, and there
1484  * are not any faces on the space we care about,
1485  * more efficient
1486  * to send 0 as the type/len field.
1487  */
1488  sl->len = oldlen+2; /* 2 bytes for coordinate */
1489  SockList_AddChar(sl, MAP2_TYPE_CLEAR); /* Clear byte */
1490  SockList_AddChar(sl, 255); /* Termination byte */
1491  // Reduce defreferences by passing the inner array offset instead of address of value
1492  map_clearcell(ns->lastmap.cells[ax] + ay, 0, 0);
1493  } else {
1494  SockList_AddChar(sl, 255); /* Termination byte */
1495  }
1496 }
1497 
1498 static void draw_client_map2(object *pl) {
1499  int x, y, ax, ay, darkness, min_x, max_x, min_y, max_y, oldlen, layer;
1500  size_t startlen;
1501  int16_t nx, ny;
1502  SockList sl;
1503  uint16_t coord;
1504  mapstruct *m;
1505  // Dereference once. It should not change in the middle of processing.
1506  player *plyr = pl->contr;
1507 
1508  SockList_Init(&sl);
1509  SockList_AddString(&sl, "map2 ");
1510  startlen = sl.len;
1511 
1512  handle_scroll(plyr->socket, &sl);
1513 
1514  /* Init data to zero */
1515  memset(heads, 0, sizeof(heads));
1516 
1517  /* We could do this logic as conditionals in the if statement,
1518  * but that started to get a bit messy to look at.
1519  */
1520  min_x = pl->x-plyr->socket->mapx/2;
1521  min_y = pl->y-plyr->socket->mapy/2;
1522  max_x = pl->x+(plyr->socket->mapx+1)/2+MAX_HEAD_OFFSET;
1523  max_y = pl->y+(plyr->socket->mapy+1)/2+MAX_HEAD_OFFSET;
1524 
1525  /* x, y are the real map locations. ax, ay are viewport relative
1526  * locations.
1527  */
1528  ay = 0;
1529  for (y = min_y; y < max_y; y++, ay++) {
1530  ax = 0;
1531  for (x = min_x; x < max_x; x++, ax++) {
1532  /* If this space is out of the normal viewable area,
1533  * we only check the heads value. This is used to
1534  * handle big images - if they extend to a viewable
1535  * portion, we need to send just the lower right corner.
1536  */
1537  if (ax >= plyr->socket->mapx || ay >= plyr->socket->mapy) {
1538  check_space_for_heads(ax, ay, &sl, plyr->socket);
1539  } else {
1540  /* This space is within the viewport of the client. Due
1541  * to walls or darkness, it may still not be visible.
1542  */
1543 
1544  /* Meaning of darkness (see defines in LOS_* in los.c):
1545  * LOS_NO_DARKNESS (0) - object is in plain sight, full brightness.
1546  * 1 - MAX_DARKNESS - how dark the space is - higher
1547  * value is darker space. If level is at max darkness,
1548  * you can't see the space (too dark)
1549  * LOS_BLOCKED (100) - space is blocked from sight.
1550  */
1551  darkness = plyr->blocked_los[ax][ay];
1552 
1553  /* If the coordinates are not valid, or it is too
1554  * dark to see, we tell the client as such
1555  */
1556  nx = x;
1557  ny = y;
1558  m = get_map_from_coord(pl->map, &nx, &ny);
1559  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1560 
1561  if (!m) {
1562  /* space is out of map. Update space and clear
1563  * values if this hasn't already been done.
1564  * If the space is out of the map, it shouldn't
1565  * have a head.
1566  */
1567  if (plyr->socket->lastmap.cells[ax][ay].darkness != 0) {
1568  SockList_AddShort(&sl, coord);
1570  SockList_AddChar(&sl, 255); /* Termination byte */
1571  // Reduce dereferences by passing the inner array offset instead of address of value
1572  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1573  }
1574  } else if (darkness >= MAX_LIGHT_RADII) {
1575  /* This block deals with spaces that are not
1576  * visible due to darkness or walls. Still
1577  * need to send the heads for this space.
1578  */
1579  check_space_for_heads(ax, ay, &sl, plyr->socket);
1580  } else {
1581  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1582 
1583  /* In this block, the space is visible. */
1584 
1585  /* Rather than try to figure out what everything
1586  * that we might need to send is, then form the
1587  * packet after that, we presume that we will in
1588  * fact form a packet, and update the bits by what
1589  * we do actually send. If we send nothing, we
1590  * just back out sl.len to the old value, and no
1591  * harm is done.
1592  * I think this is simpler than doing a bunch of
1593  * checks to see what if anything we need to send,
1594  * setting the bits, then doing those checks again
1595  * to add the real data.
1596  */
1597 
1598  oldlen = sl.len;
1599  SockList_AddShort(&sl, coord);
1600 
1601  /* Darkness changed */
1602  if (plyr->socket->lastmap.cells[ax][ay].darkness != darkness
1603  && plyr->socket->darkness) {
1604  plyr->socket->lastmap.cells[ax][ay].darkness = darkness;
1605  /* Darkness tag & length (length=1) */
1606  SockList_AddChar(&sl, MAP2_TYPE_DARKNESS|(1<<5));
1607 
1608  /* Convert darkness level (0-MAX_DARKNESS) to a value
1609  * from 1 (dark) to 255 (bright) for the client.
1610  * Darkness values of 0 (completely dark) are not sent,
1611  * as the space is completely dark.
1612  */
1613  SockList_AddChar(&sl, 255-darkness*(256/MAX_LIGHT_RADII));
1614  have_darkness = 1;
1615  }
1616 
1617  int got_label = 0;
1618  for (layer = 0; layer < MAP_LAYERS; layer++) {
1619  const object *ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1620 
1621  /* Special case: send player itself if invisible */
1622  if (!ob
1623  && x == pl->x
1624  && y == pl->y
1625  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1626  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1627  ob = pl;
1628 
1629  if (ob) {
1630  g1 = has_obj;
1631  old_got = got_one;
1632  got_one += map2_add_ob(ax, ay, layer, ob, &sl, plyr->socket, &has_obj, 0);
1633 
1634  /* if we added the face, or it is a monster's head, check probe spell */
1635  if (got_one != old_got || ob->head == NULL) {
1636  got_one += annotate_ob(ax, ay, ob, &sl, plyr, &has_obj, &alive_layer);
1637  got_label += add_labels(ax, ay, ob, &sl, plyr, &got_one);
1638  }
1639 
1640  /* If we are just storing away the head
1641  * for future use, then effectively this
1642  * space/layer is blank, and we should clear
1643  * it if needed.
1644  */
1645  if (g1 == has_obj) {
1646  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1647  }
1648  } else {
1649  if (layer != alive_layer)
1650  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1651  }
1652  }
1653  if (got_label == 0) {
1654  got_one += map2_add_label(ax, ay, plyr->socket, &sl, MAP2_LABEL_NONE, NULL);
1655  }
1656  /* If nothing to do for this space, we
1657  * can erase the coordinate bytes
1658  */
1659  if (!del_one && !got_one && !have_darkness) {
1660  sl.len = oldlen;
1661  } else if (del_one && !has_obj) {
1662  /* If we're only deleting faces and don't
1663  * have any objs we care about, just clear
1664  * space. Note it is possible we may have
1665  * darkness, but if there is nothing on the
1666  * space, darkness isn't all that interesting
1667  * - we can send it when an object shows up.
1668  */
1669  sl.len = oldlen+2; /* 2 bytes for coordinate */
1671  SockList_AddChar(&sl, 255); /* Termination byte */
1672  // Reduce dereferences by passing the inner array offset instead of address of value
1673  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1674  } else {
1675  SockList_AddChar(&sl, 255); /* Termination byte */
1676  }
1677  }
1678  } /* else this is a viewable space */
1679  } /* for x loop */
1680  } /* for y loop */
1681 
1682  /* Only send this if there are in fact some differences. */
1683  if (sl.len > startlen) {
1684  Send_With_Handling(plyr->socket, &sl);
1685  }
1686  SockList_Term(&sl);
1687 }
1688 
1692 void draw_client_map(object *pl) {
1693  int i, j;
1694  int16_t ax, ay;
1695  int mflags;
1696  mapstruct *m, *pm;
1697  int min_x, min_y, max_x, max_y;
1698 
1699  if (pl->type != PLAYER) {
1700  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1701  return;
1702  }
1703 
1704  if (pl->contr->transport) {
1705  pm = pl->contr->transport->map;
1706  } else
1707  pm = pl->map;
1708 
1709  /* If player is just joining the game, he isn't here yet, so
1710  * the map can get swapped out. If so, don't try to send them
1711  * a map. All will be OK once they really log in.
1712  */
1713  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1714  return;
1715 
1716  /*
1717  * This block just makes sure all the spaces are properly
1718  * updated in terms of what they look like.
1719  */
1720  min_x = pl->x-pl->contr->socket->mapx/2;
1721  min_y = pl->y-pl->contr->socket->mapy/2;
1722  max_x = pl->x+(pl->contr->socket->mapx+1)/2;
1723  max_y = pl->y+(pl->contr->socket->mapy+1)/2;
1724  for (j = min_y; j < max_y; j++) {
1725  for (i = min_x; i < max_x; i++) {
1726  ax = i;
1727  ay = j;
1728  m = pm;
1729  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1730  if (mflags&P_OUT_OF_MAP)
1731  continue;
1732  if (mflags&P_NEED_UPDATE)
1733  update_position(m, ax, ay);
1734  /* If a map is visible to the player, we don't want
1735  * to swap it out just to reload it. This should
1736  * really call something like swap_map, but this is
1737  * much more efficient and 'good enough'
1738  */
1739  if (mflags&P_NEW_MAP)
1740  map_reset_swap(m);
1741  }
1742  }
1743 
1744  /* do LOS after calls to update_position */
1745  if (pl->contr->do_los) {
1746  update_los(pl);
1747  pl->contr->do_los = 0;
1748  }
1749 
1750  draw_client_map2(pl);
1751 }
1752 
1753 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1754  struct Map newmap;
1755  int x, y, mx, my;
1756 
1757  ns->map_scroll_x += dx;
1758  ns->map_scroll_y += dy;
1759 
1760  mx = ns->mapx+MAX_HEAD_OFFSET;
1761  my = ns->mapy+MAX_HEAD_OFFSET;
1762 
1763  /* the x and y here are coordinates for the new map, i.e. if we moved
1764  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1765  * if the destination x or y coordinate is outside the viewable
1766  * area, we clear the values - otherwise, the old values
1767  * are preserved, and the check_head thinks it needs to clear them.
1768  */
1769  for (x = 0; x < mx; x++) {
1770  for (y = 0; y < my; y++) {
1771  if (x >= ns->mapx || y >= ns->mapy) {
1772  /* clear cells outside the viewable area */
1773  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1774  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1775  /* clear newly visible tiles within the viewable area */
1776  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1777  } else {
1778  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1779  }
1780  }
1781  }
1782 
1783  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1784 }
1785 
1791 void send_plugin_custom_message(object *pl, char *buf) {
1792  SockList sl;
1793 
1794  SockList_Init(&sl);
1795  SockList_AddString(&sl, buf);
1796  Send_With_Handling(pl->contr->socket, &sl);
1797  SockList_Term(&sl);
1798 }
1799 
1806  SockList sl;
1807  int flags = 0;
1808  client_spell *spell_info;
1809 
1810  if (!pl->socket || !pl->socket->monitor_spells)
1811  return;
1812 
1813  /* Handles problem at login, where this is called from fix_object
1814  * before we have had a chance to send spells to the player. It does seem
1815  * to me that there should never be a case where update_spells is called
1816  * before add_spells has been called. Add_spells() will update the
1817  * spell_state to non null.
1818  */
1819  if (!pl->spell_state)
1820  return;
1821 
1822  FOR_INV_PREPARE(pl->ob, spell) {
1823  if (spell->type == SPELL) {
1824  spell_info = get_client_spell_state(pl, spell);
1825  /* check if we need to update it*/
1826  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1827  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1828  flags |= UPD_SP_MANA;
1829  }
1830  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1831  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1832  flags |= UPD_SP_GRACE;
1833  }
1834  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1835  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1836  flags |= UPD_SP_DAMAGE;
1837  }
1838  if (flags != 0) {
1839  SockList_Init(&sl);
1840  SockList_AddString(&sl, "updspell ");
1841  SockList_AddChar(&sl, flags);
1842  SockList_AddInt(&sl, spell->count);
1843  if (flags&UPD_SP_MANA)
1844  SockList_AddShort(&sl, spell_info->last_sp);
1845  if (flags&UPD_SP_GRACE)
1846  SockList_AddShort(&sl, spell_info->last_grace);
1847  if (flags&UPD_SP_DAMAGE)
1848  SockList_AddShort(&sl, spell_info->last_dam);
1849  flags = 0;
1850  Send_With_Handling(pl->socket, &sl);
1851  SockList_Term(&sl);
1852  }
1853  }
1854  } FOR_INV_FINISH();
1855 }
1856 
1857 void esrv_remove_spell(player *pl, object *spell) {
1858  SockList sl;
1859 
1860  if (!pl || !spell || spell->env != pl->ob) {
1861  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1862  return;
1863  }
1864  if (!pl->socket->monitor_spells)
1865  return;
1866 
1867  SockList_Init(&sl);
1868  SockList_AddString(&sl, "delspell ");
1869  SockList_AddInt(&sl, spell->count);
1870  Send_With_Handling(pl->socket, &sl);
1871  SockList_Term(&sl);
1872 }
1873 
1881  SockList sl;
1882 
1883  if (!pl->socket->want_pickup)
1884  return;
1885  SockList_Init(&sl);
1886  SockList_AddString(&sl, "pickup ");
1887  SockList_AddInt(&sl, pl->mode);
1888  Send_With_Handling(pl->socket, &sl);
1889  SockList_Term(&sl);
1890 }
1891 
1900 static int spell_client_use(const object *spell) {
1901  switch (spell->subtype)
1902  {
1903  case SP_RAISE_DEAD:
1904  case SP_MAKE_MARK:
1905  return 3;
1906  case SP_RUNE:
1907  if (!spell->other_arch)
1908  return 1;
1909  break;
1910  case SP_CREATE_FOOD:
1911  case SP_CREATE_MISSILE:
1912  return 2;
1913  case SP_SUMMON_MONSTER:
1914  if (spell->randomitems != NULL)
1915  return 2;
1916  /* break; */// If add conditins below, use this break statement
1917  }
1918  // This is not in the switch statement so that it supports fallthrough logic
1919  // on the few spell types that have additional conditions attached.
1920  return 0;
1921 }
1922 
1924 static void append_spell(player *pl, SockList *sl, object *spell) {
1925  client_spell *spell_info;
1926  int len, i, skill = 0;
1927 
1928  if (!spell->name) {
1929  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1930  return;
1931  }
1932 
1933  if (spell->face && !(pl->socket->faces_sent[spell->face->number]&NS_FACESENT_FACE))
1934  esrv_send_face(pl->socket, spell->face, 0);
1935 
1936  spell_info = get_client_spell_state(pl, spell);
1937  SockList_AddInt(sl, spell->count);
1938  SockList_AddShort(sl, spell->level);
1939  SockList_AddShort(sl, spell->casting_time);
1940  /* store costs and damage in the object struct, to compare to later */
1941  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1942  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1943  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1944  /* send the current values */
1945  SockList_AddShort(sl, spell_info->last_sp);
1946  SockList_AddShort(sl, spell_info->last_grace);
1947  SockList_AddShort(sl, spell_info->last_dam);
1948 
1949  /* figure out which skill it uses, if it uses one */
1950  if (spell->skill) {
1951  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++)
1952  if (!strcmp(spell->skill, skill_names[i])) {
1953  skill = i+CS_STAT_SKILLINFO;
1954  break;
1955  }
1956  }
1957  SockList_AddChar(sl, skill);
1958 
1959  SockList_AddInt(sl, spell->path_attuned);
1960  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1961  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1962 
1963  if (!spell->msg) {
1964  SockList_AddShort(sl, 0);
1965  } else {
1966  len = strlen(spell->msg);
1967  SockList_AddShort(sl, len);
1968  SockList_AddData(sl, spell->msg, len);
1969  }
1970 
1971  /* Extended spell information available if the client wants it.
1972  */
1973  if (pl->socket->monitor_spells >= 2) {
1974  /* spellmon 2
1975  */
1976  sstring req = object_get_value(spell, "casting_requirements");
1977 
1978  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1979 
1980  if (req) { /* Requirements */
1981  SockList_AddLen8Data(sl, req, strlen(req));
1982  } else {
1983  SockList_AddChar(sl, 0);
1984  }
1985  /* end spellmon 2
1986  */
1987  }
1988 }
1989 
1994 void esrv_add_spells(player *pl, object *spell) {
1995  SockList sl;
1996  size_t size;
1997  sstring value;
1998 
1999  if (!pl) {
2000  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
2001  return;
2002  }
2003 
2004  if (!pl->socket->monitor_spells)
2005  return;
2006 
2007  SockList_Init(&sl);
2008  SockList_AddString(&sl, "addspell ");
2009  if (!spell) {
2010  FOR_INV_PREPARE(pl->ob, spell) {
2011  if (spell->type != SPELL)
2012  continue;
2013  /* Were we to simply keep appending data here, we could
2014  * exceed the SockList buffer if the player has enough spells
2015  * to add. We know that append_spell will always append
2016  * 23 data bytes, plus 3 length bytes and 2 strings
2017  * (because that is the spec) so we need to check that
2018  * the length of those 2 strings, plus the 26 bytes,
2019  * won't take us over the length limit for the socket.
2020  * If it does, we need to send what we already have,
2021  * and restart packet formation.
2022  */
2023  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
2024  if (pl->socket->monitor_spells >= 2) {
2026  value = object_get_value(spell, "casting_requirements");
2027  size += 2 + (value ? strlen(value) : 0);
2028  }
2029  if (SockList_Avail(&sl) < size) {
2030  Send_With_Handling(pl->socket, &sl);
2031  SockList_Reset(&sl);
2032  SockList_AddString(&sl, "addspell ");
2033  }
2034  append_spell(pl, &sl, spell);
2035  } FOR_INV_FINISH();
2036  } else if (spell->type != SPELL) {
2037  LOG(llevError, "Asked to send a non-spell object as a spell\n");
2038  return;
2039  } else
2040  append_spell(pl, &sl, spell);
2041  /* finally, we can send the packet */
2042  Send_With_Handling(pl->socket, &sl);
2043  SockList_Term(&sl);
2044 }
2045 
2046 /* sends a 'tick' information to the client.
2047  */
2048 void send_tick(player *pl) {
2049  SockList sl;
2050  SockList_Init(&sl);
2051  SockList_AddString(&sl, "tick ");
2052  SockList_AddInt(&sl, pticks);
2053  Send_With_Handling(pl->socket, &sl);
2054  SockList_Term(&sl);
2055 }
2056 
2069 static void add_char_field(SockList *sl, int type, const char *data)
2070 {
2071  int len;
2072 
2073  len = strlen(data);
2074 
2075  if (len) {
2076  /* one extra for length for the type byte */
2077  SockList_AddChar(sl, len+1);
2078  SockList_AddChar(sl, type);
2079  SockList_AddString(sl, data);
2080  }
2081 }
2082 
2104 {
2105  SockList sl;
2106  int num_chars;
2107  linked_char *extra;
2108 
2109  if (ns->account_chars) {
2111  }
2113 
2114  num_chars = 0;
2115  extra = account_get_additional_chars(ns->account_name, ns->account_chars, &num_chars);
2116 
2117  SockList_Init(&sl);
2118  SockList_AddString(&sl, "accountplayers ");
2119 
2120  SockList_AddChar(&sl, static_cast<char>(ns->account_chars->chars.size() + num_chars));
2121 
2122  /* Now add real character data */
2123  for (auto acn : ns->account_chars->chars) {
2124  uint16_t faceno = 0;
2125 
2126  /* Ignore a dead character. They don't need to show up. */
2127  if (acn->isDead) {
2128  continue;
2129  }
2130 
2131  add_char_field(&sl, ACL_NAME, acn->name);
2132  add_char_field(&sl, ACL_CLASS, acn->character_class);
2133  add_char_field(&sl, ACL_RACE, acn->race);
2134  add_char_field(&sl, ACL_FACE, acn->face);
2135  if (acn->face[0] != 0 ) {
2136  const Face *face = try_find_face(acn->face, NULL);
2137 
2138  if (face != NULL) {
2139  if (!(ns->faces_sent[face->number]&NS_FACESENT_FACE)) {
2140  esrv_send_face(ns, face, 0);
2141  }
2142  faceno = face->number;
2143  }
2144  }
2145 
2146  add_char_field(&sl, ACL_PARTY, acn->party);
2147  add_char_field(&sl, ACL_MAP, acn->map);
2148  SockList_AddChar(&sl, 3);
2150  SockList_AddShort(&sl, acn->level);
2151  if (faceno) {
2152  SockList_AddChar(&sl, 3);
2154  SockList_AddShort(&sl, faceno);
2155  }
2156 
2157  SockList_AddChar(&sl, 0);
2158  }
2159  /* Now for any characters where we just have the name */
2160  for (linked_char *e = extra; e != NULL; e = e->next) {
2161  add_char_field(&sl, ACL_NAME, e->name);
2162  SockList_AddChar(&sl, 0);
2163  }
2164 
2165  Send_With_Handling(ns, &sl);
2166  SockList_Term(&sl);
2167 
2168  if (extra) {
2169  free_charlinks(extra);
2170  }
2171 }
2172 
2194 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2195 {
2196  int nlen, plen;
2197 
2198  if (*len < 2) {
2199  return 1;
2200  }
2201 
2202  nlen = (unsigned char)buf[0];
2203  if (nlen >= MAX_BUF || nlen > *len-2) {
2204  return 1;
2205  }
2206  memcpy(name, buf+1, nlen);
2207  name[nlen] = 0;
2208 
2209  plen = (unsigned char)buf[nlen+1];
2210  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2211  return 2;
2212  }
2213  memcpy(password, buf+2+nlen, plen);
2214  password[plen] = 0;
2215 
2216  *len = nlen+plen+2;
2217 
2218  return 0;
2219 }
2230 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2231  char name[MAX_BUF], password[MAX_BUF];
2232  int status;
2233  SockList sl;
2234 
2235  if (len <= 0 || !buf) {
2236  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2237  return;
2238  }
2239 
2240  SockList_Init(&sl);
2241 
2242  status = decode_name_password(buf, &len, name, password);
2243 
2244  if (status == 1) {
2245  SockList_AddString(&sl, "failure accountlogin Name is too long");
2246  Send_With_Handling(ns, &sl);
2247  SockList_Term(&sl);
2248  return;
2249  }
2250  if (status == 2) {
2251  SockList_AddString(&sl, "failure accountlogin Password is too long");
2252  Send_With_Handling(ns, &sl);
2253  SockList_Term(&sl);
2254  return;
2255  }
2256 
2257  if (!account_exists(name)) {
2258  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2259  Send_With_Handling(ns, &sl);
2260  SockList_Term(&sl);
2261  return;
2262  }
2263 
2264  if (account_login(name, password)) {
2265  LOG(llevInfo, "Account login for '%s' from %s\n", name, ns->host);
2266 
2267  if (ns->account_name) free(ns->account_name);
2268  /* We want to store away official name so we do not
2269  * have any case sensitivity issues on the files.
2270  * because we have already checked password, we
2271  * know that account_exists should never return NULL in
2272  * this case.
2273  */
2275 
2277  } else {
2278  LOG(llevInfo, "Failed account login for '%s' from %s\n", name, ns->host);
2279  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2280  Send_With_Handling(ns, &sl);
2281  SockList_Term(&sl);
2282  }
2283 }
2284 
2293 static int account_block_create(const socket_struct *ns) {
2294  /* Check if account creation is blocked. */
2296  /* Account creation is allowed for everyone. */
2297  return 0;
2298  }
2299 
2300  /* Has the trusted host been defined? */
2301  if(settings.account_trusted_host == NULL) {
2302  /* No, allocate it and set it to localhost now. */
2304  }
2305 
2306  /* Return false if the client connected from the trusted host. */
2307  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2308  return 0;
2309  }
2310 
2311  /*
2312  * If we are here, then we are blocking account create and we do
2313  * not trust this client's IP address.
2314  */
2315  return 1;
2316 }
2317 
2329 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2330  char name[MAX_BUF], password[MAX_BUF];
2331  int status;
2332  SockList sl;
2333 
2334  if (len <= 0 || !buf) {
2335  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2336  return;
2337  }
2338 
2339  SockList_Init(&sl);
2340 
2341  status = decode_name_password(buf, &len, name, password);
2342 
2343  if (account_block_create(ns)) {
2344  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2345  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2346  Send_With_Handling(ns, &sl);
2347  SockList_Term(&sl);
2348  return;
2349  }
2350 
2351  if (status == 1) {
2352  SockList_AddString(&sl, "failure accountnew Name is too long");
2353  Send_With_Handling(ns, &sl);
2354  SockList_Term(&sl);
2355  return;
2356  }
2357  if (status == 2) {
2358  SockList_AddString(&sl, "failure accountnew Password is too long");
2359  Send_With_Handling(ns, &sl);
2360  SockList_Term(&sl);
2361  return;
2362  }
2363  /*The minimum length isn't exactly required, but in the current implementation,
2364  * client will send the same password for character for which there is a
2365  * 2 character minimum size. Thus an account with a one character password
2366  * won't be able to create a character. */
2367  if (strlen(name)<settings.min_name) {
2368  SockList_AddString(&sl, "failure accountnew Name is too short");
2369  Send_With_Handling(ns, &sl);
2370  SockList_Term(&sl);
2371  return;
2372  }
2373  if (strlen(password)<2) {
2374  SockList_AddString(&sl, "failure accountnew Password is too short");
2375  Send_With_Handling(ns, &sl);
2376  SockList_Term(&sl);
2377  return;
2378  }
2379 
2380  if (account_exists(name)) {
2381  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2382  Send_With_Handling(ns, &sl);
2383  SockList_Term(&sl);
2384  return;
2385  }
2386 
2387  status = account_check_string(name);
2388  if (status == 1) {
2389  SockList_AddString(&sl,
2390  "failure accountnew Choose a different account name. " VALIDCHAR_MSG);
2391  Send_With_Handling(ns, &sl);
2392  SockList_Term(&sl);
2393  return;
2394  }
2395 
2396  if (status == 2) {
2397  SockList_AddString(&sl,
2398  "failure accountnew That account name is too long");
2399  Send_With_Handling(ns, &sl);
2400  SockList_Term(&sl);
2401  return;
2402  }
2403 
2404  status = account_check_string(password);
2405  if (status == 1) {
2406  SockList_AddString(&sl,
2407  "failure accountnew Choose a different password. " VALIDCHAR_MSG);
2408  Send_With_Handling(ns, &sl);
2409  SockList_Term(&sl);
2410  return;
2411  }
2412 
2413  if (status == 2) {
2414  SockList_AddString(&sl,
2415  "failure accountnew That password is too long");
2416  Send_With_Handling(ns, &sl);
2417  SockList_Term(&sl);
2418  return;
2419  }
2420 
2421  /* If we got here, we passed all checks - so now add it */
2422  if (ns->account_name) free(ns->account_name);
2423  ns->account_name = strdup_local(name);
2424  account_new(name, password);
2425  /* save account information */
2426  accounts_save();
2428 }
2429 
2443 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2444  char name[MAX_BUF], password[MAX_BUF];
2445  int status, force, nlen;
2446  SockList sl;
2447  const char *cp;
2448 
2449  if (len <= 0 || !buf) {
2450  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2451  return;
2452  }
2453 
2454  SockList_Init(&sl);
2455 
2456  if (ns->account_name == NULL) {
2457  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2458  Send_With_Handling(ns, &sl);
2459  SockList_Term(&sl);
2460  return;
2461  }
2462 
2463  force = buf[0];
2464  nlen = len - 1;
2465  status = decode_name_password(buf+1, &nlen, name, password);
2466  if (status == 1) {
2467  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2468  Send_With_Handling(ns, &sl);
2469  SockList_Term(&sl);
2470  return;
2471  }
2472  if (status == 2) {
2473  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2474  Send_With_Handling(ns, &sl);
2475  SockList_Term(&sl);
2476  return;
2477  }
2478 
2479  status = verify_player(name, password);
2480  if (status) {
2481  /* From a security standpoint, telling random folks if it
2482  * it as wrong password makes it easier to hack. However,
2483  * it is fairly easy to determine what characters exist on a server
2484  * (either by trying to create a new one and see if the name is in
2485  * in use, or just looking at the high score file), so this
2486  * really does not make things much less secure
2487  */
2488  if (status == 1)
2489  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2490  else
2491  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2492 
2493  Send_With_Handling(ns, &sl);
2494  SockList_Term(&sl);
2495  return;
2496  }
2497  /* Check to see if this character is associated with an account.
2498  */
2499  cp = account_get_account_for_char(name);
2500  if (cp) {
2501  if (!strcmp(cp, ns->account_name)) {
2502  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2503  Send_With_Handling(ns, &sl);
2504  SockList_Term(&sl);
2505  return;
2506  } else {
2507  if (!force) {
2508  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2509  Send_With_Handling(ns, &sl);
2510  SockList_Term(&sl);
2511  return;
2512  } else if (account_is_logged_in(cp)) {
2513  /* We could be clever and try to handle this case, but it is
2514  * trickier. If the character is logged in, it has to
2515  * be logged out. And the socket holds some data which
2516  * needs to be cleaned up. Since it should be fairly
2517  * uncommon that users need to do this, just disallowing
2518  * it makes things a lot simpler.
2519  */
2520  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2521  Send_With_Handling(ns, &sl);
2522  SockList_Term(&sl);
2523  return;
2524  }
2525  }
2526  }
2527  /* If we have gotten this far, the name/password provided is OK,
2528  * and the character is not associated with a different account (or
2529  * force is true). Now try to add the character to this account.
2530  */
2531  status = account_link(ns->account_name, name);
2532 
2533  /* This should never happen, but check for it just in case -
2534  * if we were able to log in, the account should exist. but
2535  * if this fails, need to give the user some clue.
2536  */
2537  if (status==1) {
2538  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2539  Send_With_Handling(ns, &sl);
2540  SockList_Term(&sl);
2541  return;
2542  } else if (status == 2) {
2543  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2544  Send_With_Handling(ns, &sl);
2545  SockList_Term(&sl);
2546  return;
2547  }
2548 
2549  /* If cp is set, then this character used to belong to a different
2550  * account. Remove it now.
2551  */
2552  if (cp) {
2553  Account_Chars *chars;
2554 
2555  account_remove_player(cp, name);
2556  chars = account_char_load(cp);
2557  account_char_remove(chars, name);
2558  account_char_save(chars);
2559  account_char_free(chars);
2560  }
2561 
2563 
2564  /* store data so nothing is lost in case of crash */
2566 }
2567 
2572 void account_play_cmd(char *buf, int len, socket_struct *ns)
2573 {
2574  char **chars;
2575  int i;
2576  SockList sl;
2577  player *pl;
2578 
2579  if (len <= 0 || !buf) {
2580  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2581  return;
2582  }
2583 
2584  SockList_Init(&sl);
2585 
2586  if (ns->status != Ns_Add) {
2587  SockList_AddString(&sl, "failure accountplay Not allowed right now");
2588  Send_With_Handling(ns, &sl);
2589  SockList_Term(&sl);
2590  return;
2591  }
2592 
2593  if (!buf[0]) {
2594  SockList_AddString(&sl, "failure accountplay Malformed character name");
2595  Send_With_Handling(ns, &sl);
2596  SockList_Term(&sl);
2597  return;
2598  }
2599 
2600  if (ns->account_name == NULL) {
2601  SockList_AddString(&sl, "failure accountplay Not logged in");
2602  Send_With_Handling(ns, &sl);
2603  SockList_Term(&sl);
2604  return;
2605  }
2606 
2607  /* Make sure a client is not trying to spoof us here */
2609 
2610  for (i=0; chars[i]; i++) {
2611  if (strcmp(chars[i], buf) == 0)
2612  break;
2613  }
2614  if (!chars[i]) {
2615  SockList_AddPrintf(&sl,
2616  "failure accountplay Character %s is not associated with account %s",
2617  buf, ns->account_name);
2618  Send_With_Handling(ns, &sl);
2619  SockList_Term(&sl);
2620  return;
2621  }
2622 
2623  for (pl = first_player; pl; pl = pl->next) {
2624  if (pl->ob && pl->socket != ns && strcmp(buf, pl->ob->name) == 0 && pl->state != ST_PLAY_AGAIN && pl->state != ST_GET_NAME) {
2625  SockList_AddPrintf(&sl,
2626  "failure accountplay Character %s is already playing",
2627  buf);
2628  Send_With_Handling(ns, &sl);
2629  SockList_Term(&sl);
2630  return;
2631  }
2632  }
2633 
2634  /* from a protocol standpoint, accountplay can be used
2635  * before there is a player structure (first login) or after
2636  * (character has logged in and is changing characters).
2637  * Checkthe sockets for that second case - if so,
2638  * we don't need to make a new player object, etc.
2639  */
2640  for (pl=first_player; pl; pl=pl->next) {
2641  if (pl->socket == ns) {
2642  /* The player still in the socket must be saved first. */
2643  save_player(pl->ob, 0);
2644  break;
2645  }
2646  }
2647 
2648  /* Some of this logic is from add_player()
2649  * we just don't use add_player() as it does some other work
2650  * we don't really want to do.
2651  */
2652  if (!pl) {
2653  pl = get_player(NULL);
2654  set_player_socket(pl, ns);
2655  ns->status = Ns_Avail;
2656  ns->account_chars = NULL;
2658  } else {
2659  pl->state = ST_PLAYING;
2660  }
2661 
2662  pl->ob->name = add_string(buf);
2663  check_login(pl->ob, NULL);
2664 
2665  SockList_AddString(&sl, "addme_success");
2666  Send_With_Handling(ns, &sl);
2667  SockList_Term(&sl);
2668 }
2669 
2670 #define MAX_CHOICES 100
2671 
2677 void create_player_cmd(char *buf, int len, socket_struct *ns)
2678 {
2679  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2680  int status, nlen, choice_num=0, i;
2681  SockList sl;
2682  player *pl;
2683  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2684  living new_stats;
2685 
2686  if (len <= 0 || !buf) {
2687  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2688  return;
2689  }
2690 
2691  SockList_Init(&sl);
2692 
2693  if (ns->status != Ns_Add) {
2694  SockList_AddString(&sl, "failure createplayer Not allowed right now");
2695  Send_With_Handling(ns, &sl);
2696  SockList_Term(&sl);
2697  return;
2698  }
2699 
2700  nlen = len;
2701  status = decode_name_password(buf, &nlen, name, password);
2702  if (status == 1) {
2703  SockList_AddString(&sl, "failure createplayer Name is too long");
2704  Send_With_Handling(ns, &sl);
2705  SockList_Term(&sl);
2706  return;
2707  }
2708 
2709  /* Minimum character name limit (if set) */
2710  if (strlen(name)<settings.min_name) {
2711  SockList_AddString(&sl, "failure createplayer Name is too short");
2712  Send_With_Handling(ns, &sl);
2713  SockList_Term(&sl);
2714  return;
2715  }
2716 
2717  if (playername_ok(name) == 0) {
2718  SockList_AddString(&sl, "failure createplayer Player name contains invalid characters");
2719  Send_With_Handling(ns, &sl);
2720  SockList_Term(&sl);
2721  return;
2722  }
2723 
2724  /* 2 characters minimum for password */
2725  if (strlen(password)<2) {
2726  SockList_AddString(&sl, "failure createplayer Password is too short");
2727  Send_With_Handling(ns, &sl);
2728  SockList_Term(&sl);
2729  return;
2730  }
2731 
2733  if (status == 2) {
2734  SockList_AddString(&sl, "failure createplayer Password is too long");
2735  Send_With_Handling(ns, &sl);
2736  SockList_Term(&sl);
2737  return;
2738  }
2739 
2740  /* This is a fairly ugly solution - we're truncating the password.
2741  * however, the password information for characters is really
2742  * a legacy issue - when every character is associated with
2743  * an account, legacy login (character name/password) will get
2744  * removed, at which point the only use for password might be
2745  * to move characters from one account to another, but not sure
2746  * if that is something we want to allow.
2747  */
2748  if (strlen(password)>17)
2749  password[16] = 0;
2750 
2751  /* We just can't call check_name(), since that uses draw_info() to
2752  * report status. We are also more permissive on names, so we use
2753  * account_check_string() - if that is safe for account, also safe
2754  * for player names.
2755  */
2756  if (account_check_string(name)) {
2757  SockList_AddString(&sl, "failure createplayer Choose a different character name. " VALIDCHAR_MSG);
2758  Send_With_Handling(ns, &sl);
2759  SockList_Term(&sl);
2760  return;
2761  }
2762 
2763  /* 1 means no such player, 0 is correct name/password (which in this
2764  * case, is an error), and 2 is incorrect password. Only way we
2765  * go onward is if there is no such player.
2766  */
2767  if (verify_player(name, password) != 1) {
2768  SockList_AddString(&sl, "failure createplayer That name is already in use");
2769  Send_With_Handling(ns, &sl);
2770  SockList_Term(&sl);
2771  return;
2772  }
2773 
2774  /* from a protocol standpoint, accountplay can be used
2775  * before there is a player structure (first login) or after
2776  * (character has logged in and is changing characters).
2777  * Check the sockets for that second case - if so,
2778  * we don't need to make a new player object, etc.
2779  */
2780  for (pl=first_player; pl; pl=pl->next)
2781  if (pl->socket == ns) {
2782  if (pl->ob->name) {
2783  if (!strcmp(pl->ob->name, name)) {
2784  /* For some reason not only the socket is the same but also
2785  * the player is already playing. If this happens at this
2786  * point let's assume the character never was able to apply
2787  * a bet of reality to make a correct first-time save.
2788  * So, for safety remove it and start over.
2789  */
2790  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2791  object_remove(pl->ob);
2792  }
2793  else {
2794  /* If this is a different player on the same socket, then we
2795  * need to make sure that the old one is not connected to the player
2796  *
2797  * This prevents bizarre scenarios where the player is on the map
2798  * multiple times (from multiple createplayer commands), and
2799  * only one of them is controlled by the player.
2800  */
2801  if (pl->ob->contr == pl) {
2802  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2803  object_remove(pl->ob);
2804  }
2805  }
2806  }
2807  break;
2808  }
2809 
2810  /* In this mode, we have additional data
2811  * Note that because there are a lot of failure cases in here
2812  * (where we end up not creating the new player), the code
2813  * to create the new player is done within this routine
2814  * after all checks pass. Note that all of the checks
2815  * done are done without using the player structure,
2816  * as pl may be null right now.
2817  */
2818  if (ns->login_method >= 2) {
2819  int i, j, stat_total=0;
2820  char *key, *value, *race=NULL, *class_name=NULL;
2821 
2822  /* By setting this to zero, then we can easily
2823  * check to see if all stats have been set.
2824  */
2825  memset(&new_stats, 0, sizeof(living));
2826 
2827  while (nlen < len) {
2828  i = buf[nlen]; /* Length of this line */
2829  /* Sanity check from client - don't want to loop
2830  * forever if there is a 0 length, and don't
2831  * want to read beyond size of packet.
2832  * Likewise, client should have sent
2833  * the string to us already null terminated,
2834  * but we will just make sure.
2835  */
2836  if ((i == 0) || (nlen + i > len)) break;
2837  buf[nlen + i] = 0;
2838 
2839  /* What we have are a series of lines -
2840  * 'key value' format. Find that space,
2841  * and null it out so we can do strcasecmp.
2842  * If no space, abort processing
2843  */
2844  key = buf + nlen + 1;
2845  value = strchr(key, ' ');
2846  if (!value) break;
2847  *value = 0;
2848  value++;
2849 
2850  if (!strcasecmp(key,"race")) race = value;
2851  else if (!strcasecmp(key,"class")) class_name = value;
2852  else if (!strcasecmp(key,"starting_map")) {
2853  map = try_find_archetype(value);
2854  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2855  SockList_AddString(&sl,
2856  "failure createplayer Invalid starting map");
2857  Send_With_Handling(ns, &sl);
2858  SockList_Term(&sl);
2859  return;
2860  }
2861  }
2862  else if (!strcasecmp(key,"choice")) {
2863  /* In general, MAX_CHOICES should be large enough
2864  * to always handle the choices from the client - of
2865  * course, the client could be broken and send us many
2866  * more choices than we should have, so handle that.
2867  */
2868  if (choice_num == MAX_CHOICES) {
2869  LOG(llevError,
2870  "Number of choices receive exceed max value: %d>%d\n",
2871  choice_num, MAX_CHOICES);
2872  } else {
2873  choices[choice_num] = value;
2874  choice_num++;
2875  }
2876  }
2877  else {
2878  /* Do stat processing here */
2879  for (j=0; j < NUM_STATS; j++) {
2880  if (!strcasecmp(key,short_stat_name[j])) {
2881  int val = atoi(value);
2882 
2883  set_attr_value(&new_stats, j, val);
2884  break;
2885  }
2886  }
2887  if (j >= NUM_STATS) {
2888  /* Bad clients could do this - we should at least report
2889  * it, and useful when trying to add new parameters.
2890  */
2891  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2892  }
2893  }
2894  nlen += i + 1;
2895  }
2896  /* Do some sanity checking now. But checking the stat
2897  * values here, we will catch any 0 values since we do
2898  * a memset above. A properly behaving client should
2899  * never do any of these things, but we do not presume
2900  * clients will behave properly.
2901  */
2902  for (j=0; j<NUM_STATS; j++) {
2903  int val = get_attr_value(&new_stats, j);
2904 
2905  stat_total += val;
2906  if (val > settings.starting_stat_max ||
2907  val < settings.starting_stat_min) {
2908  SockList_AddPrintf(&sl,
2909  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2911  Send_With_Handling(ns, &sl);
2912  SockList_Term(&sl);
2913  return;
2914  }
2915  }
2916  if (stat_total > settings.starting_stat_points) {
2917  SockList_AddPrintf(&sl,
2918  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2919  stat_total, settings.starting_stat_points);
2920  Send_With_Handling(ns, &sl);
2921  SockList_Term(&sl);
2922  return;
2923  }
2924 
2925  if (race)
2926  race_a = try_find_archetype(race);
2927 
2928  if (class_name)
2929  class_a = try_find_archetype(class_name);
2930 
2931  /* This should never happen with a properly behaving client, so the error message
2932  * doesn't have to be that great.
2933  */
2934  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2935  SockList_AddString(&sl,
2936  "failure createplayer Invalid or unknown race or class");
2937  Send_With_Handling(ns, &sl);
2938  SockList_Term(&sl);
2939  return;
2940  }
2941 
2942  /* At current time, only way this can fail is if the adjusted
2943  * stat is less than 1.
2944  */
2945  if (check_race_and_class(&new_stats, race_a, class_a)) {
2946  SockList_AddString(&sl,
2947  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2948  Send_With_Handling(ns, &sl);
2949  SockList_Term(&sl);
2950  return;
2951  }
2952 
2953  if (!pl)
2955  // If we already have a player, we a replaying on the same connection.
2956  // Since add_player normally sets ns->status, we still need that to happen.
2957  else
2958  ns->status = Ns_Avail;
2959 
2960  // We need to copy the name in before apply_race_and_class() because it
2961  // tells the client our character name. If we don't update it, they get the old one.
2962  FREE_AND_COPY(pl->ob->name, name);
2963 
2964  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2965 
2966  } else {
2967  /* In thise case, old login method */
2968  if (!pl)
2969  pl = add_player(ns, ADD_PLAYER_NEW);
2970  // If we already have a player, we a replaying on the same connection.
2971  // Since add_player normally sets ns->status, we still need that to happen.
2972  else
2973  ns->status = Ns_Avail;
2974 
2975  // Make sure to do this on both code branches.
2976  FREE_AND_COPY(pl->ob->name, name);
2977 /* already done by add_player
2978  roll_again(pl->ob);
2979  pl->state = ST_ROLL_STAT;
2980  set_first_map(pl->ob);*/
2981  }
2982 
2983  /* add_player does a lot of the work, but there are a few
2984  * things we need to update, like starting name and
2985  * password.
2986  * This is done before processing in login_method>2.
2987  * The character creation process it does when
2988  * applying the race/class will use this
2989  * name information.
2990  */
2991  FREE_AND_COPY(pl->ob->name_pl, name);
2992  pl->name_changed = 1;
2993  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
2994 
2995  SockList_AddString(&sl, "addme_success");
2996  Send_With_Handling(ns, &sl);
2997  SockList_Term(&sl);
2998 
2999  if (ns->login_method >= 2) {
3000  /* The client could have provided us a map - if so, map will be set
3001  * and we don't want to overwrite it
3002  */
3003  if (!map)
3005  assert(map); // Existence checked in init_dynamic()
3006 
3007  enter_exit(pl->ob, &map->clone);
3008 
3009  if (pl->ob->map == NULL) {
3010  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
3011  abort();
3012  }
3013 
3014  /* copy information to bed of reality information, in case the player dies */
3015  safe_strncpy(pl->savebed_map, pl->ob->map->path, sizeof(pl->savebed_map));
3016  pl->bed_x = pl->ob->x;
3017  pl->bed_y = pl->ob->y;
3018 
3020  }
3021 
3022  /* We insert any objects after we have put the player on the map -
3023  * this makes things safer, as certain objects may expect a normal
3024  * environment. Note that choice_num will only be set in the
3025  * loginmethod > 2, which also checks (and errors out) if the
3026  * race/class is not set, which is why explicit checking for
3027  * those is not need.
3028  */
3029  for (i=0; i < choice_num; i++) {
3030  char *choiceval;
3031  const char *value, *cp;
3032  archetype *arch;
3033  object *op;
3034 
3035  choiceval = strchr(choices[i], ' ');
3036  if (!choiceval) {
3037  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
3038  continue;
3039  }
3040  *choiceval=0;
3041  choiceval++;
3042  value = object_get_value(&race_a->clone, choices[i]);
3043  if (!value)
3044  value = object_get_value(&class_a->clone, choices[i]);
3045 
3046  if (!value) {
3047  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
3048  continue;
3049  }
3050  cp = strstr(value, choiceval);
3051  if (!cp) {
3052  LOG(llevError, "Choice value not found in archetype: %s %s\n",
3053  choices[i], choiceval);
3054  continue;
3055  }
3056 
3057  /* Check to make sure that the matched string is an entire word,
3058  * and not a substring (eg, valid choice being great_sword but
3059  * we just get sword) - the space after the match should either be a
3060  * space or null, and space before match should also be a space
3061  * or the start of the string.
3062  */
3063  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
3064  (cp != value) && (*(cp-1) != ' ')) {
3065 
3066  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
3067  choiceval, value);
3068  continue;
3069  }
3070  arch = try_find_archetype(choiceval);
3071  if (!arch) {
3072  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
3073  continue;
3074  }
3075  op = arch_to_object(arch);
3076  op = object_insert_in_ob(op, pl->ob);
3077  if (QUERY_FLAG(op, FLAG_AUTO_APPLY))
3078  ob_apply(op, pl->ob, 0);
3079  }
3080 
3081  LOG(llevInfo, "new character %s from %s\n", pl->ob->name, pl->ob->contr->socket->host);
3084  "%s has entered the game.", pl->ob->name);
3085 }
3086 
3097 void account_password(char *buf, int len, socket_struct *ns) {
3098  char old[MAX_BUF], change[MAX_BUF];
3099  int status;
3100  SockList sl;
3101 
3102  if (len <= 0 || !buf) {
3103  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
3104  return;
3105  }
3106 
3107  SockList_Init(&sl);
3108 
3109  if (ns->account_name == NULL) {
3110  SockList_AddString(&sl, "failure accountpw Not logged in");
3111  Send_With_Handling(ns, &sl);
3112  SockList_Term(&sl);
3113  return;
3114  }
3115 
3116  status = decode_name_password(buf, &len, old, change);
3117  if (status == 1) {
3118  SockList_AddString(&sl, "failure accountpw Old password is too long");
3119  Send_With_Handling(ns, &sl);
3120  SockList_Term(&sl);
3121  return;
3122  }
3123  if (status == 2) {
3124  SockList_AddString(&sl, "failure accountpw New password is too long");
3125  Send_With_Handling(ns, &sl);
3126  SockList_Term(&sl);
3127  return;
3128  }
3129  /*The minimum length isn't exactly required, but in the current implementation,
3130  * client will send the same password for character for which there is a
3131  * 2 character minimum size. Thus an account with a one character password
3132  * won't be able to create a character. */
3133  if (strlen(change)<2) {
3134  SockList_AddString(&sl, "failure accountpw New password is too short");
3135  Send_With_Handling(ns, &sl);
3136  SockList_Term(&sl);
3137  return;
3138  }
3139 
3140  status = account_check_string(change);
3141  if (status == 1) {
3142  SockList_AddString(&sl,
3143  "failure accountpw Choose a different password. " VALIDCHAR_MSG);
3144  Send_With_Handling(ns, &sl);
3145  SockList_Term(&sl);
3146  return;
3147  }
3148 
3149  if (status == 2) {
3150  SockList_AddString(&sl,
3151  "failure accountpw That password is too long");
3152  Send_With_Handling(ns, &sl);
3153  SockList_Term(&sl);
3154  return;
3155  }
3156 
3157  status = account_change_password(ns->account_name, old, change);
3158  if (status != 0) {
3159  const char *error;
3160 
3161  if (status == 1) {
3162  error = "failure accountpw Illegal characters present";
3163  } else if (status == 2) {
3164  error = "failure accountpw Invalid account";
3165  } else {
3166  error = "failure accountpw Incorrect current password";
3167  }
3168 
3169  SockList_AddString(&sl, error);
3170  Send_With_Handling(ns, &sl);
3171  SockList_Term(&sl);
3172  return;
3173  }
3174 
3175  /* If we got here, we passed all checks, and password was changed */
3177 }
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)
object &#39;ob&#39; at &#39;ax,ay&#39; on &#39;layer&#39; is visible to the client.
Definition: request.cpp:1113
static int account_block_create(const socket_struct *ns)
Checks if account creation is blocked for this connection.
Definition: request.cpp:2293
void account_char_remove(Account_Chars *chars, const char *pl_name)
This removes a character on this account.
void esrv_add_spells(player *pl, object *spell)
This tells the client to add the spell *spell, if spell is NULL, then add all spells in the player&#39;s ...
Definition: request.cpp:1994
Error, serious thing.
Definition: logger.h:11
uint8_t login_method
Login method this client is using.
Definition: newserver.h:132
#define CS_STAT_AC
Definition: newclient.h:104
#define ACL_CLASS
Definition: newclient.h:222
#define CF_BLIND
Blind.
Definition: newclient.h:204
void map_newmap_cmd(socket_struct *ns)
Sound related function.
Definition: request.cpp:687
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
#define CS_STAT_RES_GHOSTHIT
Definition: newclient.h:160
Sound-related defines.
object * ranges[range_size]
Object for each range.
Definition: player.h:118
#define CS_STAT_APPLIED_CON
CON changes from gear or skills.
Definition: newclient.h:139
living orig_stats
Permanent real stats of player.
Definition: player.h:169
#define AddIfInt64(Old, New, sl, Type)
Definition: request.cpp:754
uint8_t faceset
Set the client is using, default 0.
Definition: newserver.h:121
int16_t last_sp
Last spell cost.
Definition: player.h:89
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Need to send an animation sequence to the client.
Definition: request.cpp:1038
#define CS_STAT_BASE_WIS
Definition: newclient.h:130
size_t len
Definition: newclient.h:726
void update_position(mapstruct *m, int x, int y)
This function updates various attributes about a specific space on the map (what it looks like...
Definition: map.cpp:2147
static uint16_t MAP2_COORD_ENCODE(int x, int y, int flags)
Encodes a (x, y) pair suitable for map2 parameters.
Definition: request.cpp:89
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:570
const char * skill_names[MAX_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.cpp:57
#define SP_MAKE_MARK
Definition: spells.h:77
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:110
Information.
Definition: logger.h:12
void add_me_cmd(char *buf, int len, socket_struct *ns)
The client has requested to be added to the game.
Definition: request.cpp:415
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.cpp:74
void enter_exit(object *op, object *exit_ob)
Tries to move &#39;op&#39; to exit_ob.
Definition: server.cpp:727
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.cpp:194
This represents one animation.
Definition: face.h:25
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
static int clamp(int x, int min, int max)
Definition: request.cpp:96
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:141
Definition: object.h:130
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h:158
int account_login(const char *account_name, const char *account_password)
Check if the given account exists, and whether the password is correct.
Definition: account.cpp:318
uint32_t want_pickup
Client wants pickup information when logging in.
Definition: newserver.h:112
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:242
int16_t last_dam
Last damage.
Definition: player.h:91
int account_remove_player(const char *account_name, const char *player_name)
Removes a player name from an account.
Definition: account.cpp:474
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:130
char * god
Definition: newserver.h:61
#define CS_STAT_RES_POISON
Definition: newclient.h:161
#define MAX_LIGHT_RADII
Max radii for &#39;light&#39; object, really large values allow objects that can slow down the game...
Definition: define.h:450
#define ANIM_RANDOM
Definition: newclient.h:363
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
#define CS_STAT_RACE_INT
Definition: newclient.h:122
uint8_t starting_stat_min
Minimum value of a starting stat.
Definition: global.h:321
#define CF_PARALYZED
Player is paralyzed.
Definition: newclient.h:210
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
#define CS_STAT_INT
Definition: newclient.h:96
#define CS_STAT_RES_DRAIN
Definition: newclient.h:159
#define CS_STAT_BASE_POW
Definition: newclient.h:134
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:271
uint32_t last_path_attuned
Last spell attunment sent to client.
Definition: player.h:162
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.cpp:83
int GetInt_String(const unsigned char *data)
Basically does the reverse of SockList_AddInt, but on strings instead.
Definition: lowlevel.cpp:254
#define strdup_local
Definition: compat.h:29
Defines various flags that both the new client and new server use.
#define ACL_FACE_NUM
Definition: newclient.h:228
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
#define AddIfInt(Old, New, sl, Type)
Definition: request.cpp:761
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.cpp:468
int16_t grace
Grace.
Definition: living.h:44
#define AddIfString(Old, New, sl, Type)
Definition: request.cpp:782
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
uint32_t peaceful
If set, won&#39;t attack friendly creatures.
Definition: player.h:148
#define UPD_SP_GRACE
updspell command flag value.
Definition: newclient.h:341
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1880
int account_change_password(const char *account_name, const char *current_password, const char *new_password)
Change an account password.
Definition: account.cpp:627
enum map2_label label_subtype
Definition: newserver.h:34
#define SND_EFFECTS
Those flags are for the &#39;socket.sound&#39; field.
Definition: sounds.h:12
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.cpp:1818
#define CF_CONFUSED
Confused by a spell or an item.
Definition: newclient.h:202
#define CS_STAT_RES_CONF
Definition: newclient.h:157
const char * account_get_account_for_char(const char *charname)
This looks at all the accounts and sees if charname is associated with any of them.
Definition: account.cpp:579
int account_new(const char *account_name, const char *account_password)
Adds an account.
Definition: account.cpp:399
player * first_player
First player.
Definition: init.cpp:106
#define ACL_LEVEL
Definition: newclient.h:224
int16_t maxgrace
Maximum grace.
Definition: living.h:45
#define CS_STAT_GOD_NAME
Name of the god the character worships.
Definition: newclient.h:145
static bool map2_coord_valid(int x)
Definition: request.cpp:76
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
#define SPELL_GRACE
Definition: spells.h:59
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
Number of statistics.
Definition: living.h:18
void send_plugin_custom_message(object *pl, char *buf)
GROS: The following one is used to allow a plugin to send a generic cmd to a player.
Definition: request.cpp:1791
static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer)
Check if a hp bar should be added to the map square.
Definition: request.cpp:1283
#define MAP_TYPE_DEFAULT
If no map is specified, where character starts.
Definition: map.h:60
uint32_t count
Any numbers typed before a command.
Definition: player.h:124
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Draws an extended message on the client.
Definition: info.cpp:62
#define CS_STAT_SPEED
Definition: newclient.h:107
struct Map lastmap
Definition: newserver.h:97
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.cpp:1218
partylist * party
Party this player is part of.
Definition: player.h:205
void receive_player_password(object *op, const char *password)
A player just entered her password, including for changing it.
Definition: c_misc.cpp:1953
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.cpp:1451
#define SND_MUTE
Don&#39;t sent anything for now.
Definition: sounds.h:14
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.cpp:116
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:573
Socket structure, represents a client-server connection.
Definition: newserver.h:93
#define MAP2_TYPE_CLEAR
Definition: newclient.h:42
#define NS_FACESENT_SMOOTH
Definition: newserver.h:142
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:569
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it&#39;s increased effectiveness.
Definition: spell_util.cpp:236
#define CF_HOSTILE
&#39;hostile&#39; flag is set.
Definition: newclient.h:208
living last_orig_stats
Last permanent stats sent to client.
Definition: player.h:171
#define CS_STAT_DEX
Definition: newclient.h:98
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:180
Object for applying character class modifications to someone.
Definition: object.h:143
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:299
#define FLAG_STEALTH
Will wake monsters with less range.
Definition: define.h:300
bool heartbeat
Client will send hearbeats.
Definition: newserver.h:116
#define CS_STAT_BASE_STR
Definition: newclient.h:128
int16_t y
Position in the map for this object.
Definition: object.h:335
static int decode_name_password(const char *buf, int *len, char *name, char *password)
This is a basic routine which extracts the name/password from the buffer.
Definition: request.cpp:2194
#define SF_RUNON
Definition: newclient.h:194
#define AddIfShort(Old, New, sl, Type)
Definition: request.cpp:768
int SP_level_dam_adjust(const object *caster, const object *spob)
Returns adjusted damage based on the caster.
Definition: spell_util.cpp:287
uint32_t mode
Mode of player for pickup.
Definition: player.h:125
const char * account_exists(const char *account_name)
Checks the existing accounts, and see if this account exists.
Definition: account.cpp:296
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
#define MAP2_ADD_LENGTH
Definition: newclient.h:68
uint8_t starting_stat_max
Maximum value of a starting stat.
Definition: global.h:322
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
#define ST_CHANGE_PASSWORD_NEW
Player is entering new password.
Definition: define.h:572
#define CS_STAT_RES_DEATH
Definition: newclient.h:167
enum Sock_Status status
Definition: newserver.h:94
This stores, for a spell a player knows, the last sp/gr/dam information sent to client.
Definition: player.h:87
void version_cmd(char *buf, int len, socket_struct *ns)
Client tells its version.
Definition: request.cpp:651
int verify_player(const char *name, char *password)
This verify that a character of name exits, and that it matches password.
Definition: login.cpp:111
#define ACL_FACE
Definition: newclient.h:225
living applied_stats
Stat changes due to gear or skills.
Definition: player.h:173
#define CS_STAT_MAXSP
Definition: newclient.h:94
sstring label_text
Definition: newserver.h:35
#define CS_STAT_WIS
Definition: newclient.h:97
#define MAX(x, y)
Definition: compat.h:24
void account_new_cmd(char *buf, int len, socket_struct *ns)
Handles the account creation This function shares a fair amount of the same logic as account_login_cm...
Definition: request.cpp:2329
int16_t x
Definition: object.h:335
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:354
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
This is somewhat like key_change_class() above, except we know the race to change to...
Definition: player.cpp:1485
#define SP_CREATE_MISSILE
Definition: spells.h:113
Global type definitions and header inclusions.
#define CF_STEALTHY
Player is stealthy.
Definition: newclient.h:209
#define CS_STAT_FLAGS
Definition: newclient.h:115
char * title
Definition: newserver.h:61
#define safe_strncpy
Definition: compat.h:27
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
#define ACL_MAP
Definition: newclient.h:227
int8_t Con
Use
Definition: living.h:36
#define CS_STAT_RACE_CON
Definition: newclient.h:125
client_spell * spell_state
Spell information sent to client.
Definition: player.h:217
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:564
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.cpp:4237
One map cell, as sent to the client.
Definition: newserver.h:31
int8_t levgrace[11]
What grace bonus the player gained on that level.
Definition: player.h:190
#define ST_PLAYING
Usual state.
Definition: define.h:562
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:252
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:429
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
static void send_smooth(socket_struct *ns, const Face *face)
A lot like the old AskSmooth (in fact, now called by AskSmooth).
Definition: request.cpp:459
void set_attr_value(living *stats, int attr, int8_t value)
Sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on what attr is (STR to POW)...
Definition: living.cpp:218
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:274
#define MIN(x, y)
Definition: compat.h:21
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:116
float weapon_speed
The overall speed of this object.
Definition: object.h:339
object * transport
Transport the player is in.
Definition: player.h:216
Account_Chars * account_chars
Detailed information on characters on this account.
Definition: newserver.h:131
#define VERSION_SC
Definition: newserver.h:154
int16_t bed_x
Definition: player.h:113
#define MAP_LAYER_LIVING2
Definition: map.h:47
#define CS_STAT_EXP64
Definition: newclient.h:117
#define MAP_TYPE_CHOICE
Choice of maps presented to player.
Definition: map.h:61
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:133
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.cpp:2677
#define NROFATTACKS
Definition: attack.h:15
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:161
#define MAX_CHOICES
Definition: request.cpp:2670
#define CS_STAT_BASE_CON
Definition: newclient.h:132
#define CS_STAT_RACE_DEX
Definition: newclient.h:124
#define CS_STAT_WC
Definition: newclient.h:103
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Try to get information about a living thing.
void account_password(char *buf, int len, socket_struct *ns)
Handles the account password change.
Definition: request.cpp:3097
void move_cmd(char *buf, int len, player *pl)
Moves an object (typically, container to inventory).
Definition: request.cpp:708
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:290
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
#define MAP_CLIENT_Y_MINIMUM
Definition: config.h:246
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:129
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:108
uint32_t facecache
If true, client is caching images.
Definition: newserver.h:106
int16_t level
Level of creature or object.
Definition: object.h:361
#define MAX_NUM_LOOK_OBJECTS
The upper bound for the number of objects to send for the &#39;look&#39; window (container or ground view)...
Definition: newserver.h:28
static const int MAP2_COORD_MAX
Definition: request.cpp:74
int16_t sp
Spell points.
Definition: living.h:42
#define NDI_RED
Definition: newclient.h:249
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:108
void new_player_cmd(uint8_t *buf, int len, player *pl)
This handles the commands issued by the player (ie, north, fire, cast, etc.).
Definition: request.cpp:527
void esrv_update_stats(player *pl)
Sends a statistics update.
Definition: request.cpp:866
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
int16_t casting_time
Time left before spell goes off.
Definition: object.h:414
int get_skill_client_code(const char *skill_name)
Return the code of the skill for a client, the index in the skill_names array.
Definition: skill_util.cpp:114
int ssop_t
Parameter type for setsockopt, different between WIN32 and Linux.
Definition: request.cpp:58
#define FLAG_CLIENT_ANIM_SYNC
Let client animate this, synchronized.
Definition: define.h:227
uint32_t sound
Client sound mode.
Definition: newserver.h:115
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
int8_t tail_y
Where the lower right most portion of the object is in comparison to the head.
Definition: object.h:488
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
#define ADD_PLAYER_NO_STATS_ROLL
Stats provided from client.
Definition: player.h:254
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:143
uint32_t cs_version
Definition: newserver.h:117
uint16_t last_item_power
Last value for item_power.
Definition: player.h:166
float character_load
Value between 0 and 1 indicating how much the character is overloaded.
Definition: player.h:137
void SockList_AddData(SockList *sl, const void *data, size_t len)
Adds a data block.
Definition: lowlevel.cpp:167
int account_is_logged_in(const char *name)
This checkes if an account is logged in.
Definition: account.cpp:604
void accounts_save(void)
Save all the account information.
Definition: account.cpp:255
void receive_party_password(object *op, const char *password)
Player entered a party password.
Definition: c_party.cpp:53
int16_t last_resist[NROFATTACKS]
last resist values sent to client.
Definition: player.h:176
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
uint8_t num_animations
How many different faces to animate, size of the faces array.
Definition: face.h:27
#define CS_STAT_RES_FIRE
Definition: newclient.h:154
uint8_t num_look_objects
The maximum number of objects to show on the ground view; this number includes the prev/next group fa...
Definition: newserver.h:126
map2_label
Map label subtypes.
Definition: newclient.h:56
#define CS_STAT_RES_HOLYWORD
Definition: newclient.h:168
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
void set_player_socket(player *p, socket_struct *ns)
This copies the data from the socket into the player structure.
Definition: player.cpp:421
void key_change_class(object *op, char key)
This function takes the key that is passed, and does the appropriate action with it (change race...
Definition: player.cpp:1294
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:550
int8_t Dex
Use
Definition: living.h:36
#define FLAG_CLIENT_SENT
We use it to detect cases were the server is trying to send an upditem when we have not actually sent...
Definition: define.h:336
float speed
Frequency of object &#39;moves&#39; relative to server tick rate.
Definition: object.h:337
void esrv_remove_spell(player *pl, object *spell)
Definition: request.cpp:1857
uint8_t min_name
Minimum characters for an account or player name.
Definition: global.h:331
const char * NPC_DIALOG_ARCH
Definition: dialog.cpp:28
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns)
Definition: request.cpp:1258
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h:252
object * env
Pointer to the object which is the environment.
Definition: object.h:301
#define SET_FLAG(xyz, p)
Definition: define.h:384
#define CS_STAT_LEVEL
Definition: newclient.h:102
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:259
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
#define ST_CONFIRM_QUIT
Player used the &#39;quit&#39; command, make sure that&#39;s ok.
Definition: define.h:566
void key_confirm_quit(object *op, char key)
We receive the reply to the &#39;quit confirmation&#39; message.
Definition: player.cpp:1599
#define UPD_SP_DAMAGE
updspell command flag value.
Definition: newclient.h:342
#define BEAT_INTERVAL
Interval between heartbeat requests.
Definition: config.h:636
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:515
short GetShort_String(const unsigned char *data)
Definition: lowlevel.cpp:258
int8_t Wis
Use
Definition: living.h:36
int16_t last_golem_hp
Last golem hp value sent to the client.
Definition: player.h:177
uint8_t always_show_hp
&#39;probe&#39; spell HP bars for all living things (0, 1, or 2)
Definition: global.h:274
static uint8_t is_perfect(const player *pl)
Check whether the player is perfect relatively to improvement potions.
Definition: request.cpp:795
#define MAP2_TYPE_LABEL
Definition: newclient.h:44
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
One map for a player.
Definition: newserver.h:52
#define CS_STAT_WEAP_SP
Definition: newclient.h:109
#define CS_STAT_BASE_DEX
Definition: newclient.h:131
void player_set_state(player *pl, uint8_t state)
Set the player&#39;s state to the specified one.
Definition: player.cpp:4493
void account_char_save(Account_Chars *chars)
Saves the character information for the given account.
#define CS_STAT_APPLIED_INT
INT changes from gear or skills.
Definition: newclient.h:136
#define MAX_HEAD_OFFSET
This basically defines the largest size an archetype may be - it is used for allocation of some struc...
Definition: newserver.h:46
int strcasecmp(const char *s1, const char *s2)
static void append_spell(player *pl, SockList *sl, object *spell)
appends the spell *spell to the Socklist we will send the data to.
Definition: request.cpp:1924
struct linked_char * next
Definition: global.h:100
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
Control golem.
Definition: player.h:34
uint32_t last_character_flags
Last character flags (CS_STAT_CHARACTER_FLAGS) sent to client.
Definition: player.h:165
socket_struct * socket
Socket information for this player.
Definition: player.h:109
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
uint32_t golem_count
To track the golem.
Definition: player.h:121
uint8_t smoothlevel
how to smooth this square around
Definition: object.h:433
object * head
Points to the main object of a large body.
Definition: object.h:304
#define CS_STAT_BASE_CHA
Definition: newclient.h:133
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:195
#define MAP_LAYERS
This correspondes to the map layers in the map2 protocol.
Definition: map.h:32
client_spell * get_client_spell_state(player *pl, object *spell)
Gets the (client-side) spell state for specified spell.
Definition: player.cpp:145
int8_t map_scroll_y
Definition: newserver.h:98
This is a game-map.
Definition: map.h:320
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:244
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:428
uint32_t sc_version
Versions of the client.
Definition: newserver.h:117
static void draw_client_map2(object *pl)
Definition: request.cpp:1498
void account_login_cmd(char *buf, int len, socket_struct *ns)
Handles the account login.
Definition: request.cpp:2230
#define MAX_TIME
If you feel the game is too fast or too slow, change MAX_TIME.
Definition: config.h:254
#define CF_POISONED
Poisoned.
Definition: newclient.h:203
#define CS_STAT_RACE_POW
Definition: newclient.h:127
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:164
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:563
static const short atnr_cs_stat[NROFATTACKS]
This table translates the attack numbers as used within the program to the value we use when sending ...
Definition: request.cpp:123
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:133
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:367
object * ob
The object representing the player.
Definition: player.h:179
int16_t last_grace
Last grace cost.
Definition: player.h:90
uint32_t fire_on
Player should fire object, not move.
Definition: player.h:144
const Face * face
Face with colors.
Definition: object.h:341
int find_smooth(const Face *face, const Face **smoothed)
Find the smooth face for a given face.
Definition: image.cpp:102
Defines various structures and values that are used for the new client server communication method...
#define MAX_HEAD_POS
Definition: request.cpp:1077
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
#define CS_STAT_CHA
Definition: newclient.h:100
player * get_player(player *p)
Create a player&#39;s object, initialize a player&#39;s structure.
Definition: player.cpp:285
Defines and structures related to commands the player can send.
struct Settings settings
Global settings.
Definition: init.cpp:139
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Asks the client to query the user.
Definition: request.cpp:745
static void map_clearcell(struct map_cell_struct *cell, int face, int darkness)
Clears a map cell.
Definition: request.cpp:1072
float last_speed
Last speed as sent to client.
Definition: player.h:175
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:160
void send_tick(player *pl)
Definition: request.cpp:2048
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:288
int8_t last_level
Last level we sent to client.
Definition: player.h:136
object * object_present_in_ob(uint8_t type, const object *op)
Searches for any objects with a matching type variable in the inventory of the given object...
Definition: object.cpp:3153
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.cpp:246
float last_character_load
Last value sent to the client.
Definition: player.h:138
#define UPD_SP_MANA
updspell command flag value.
Definition: newclient.h:340
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:113
static void add_char_field(SockList *sl, int type, const char *data)
Basic helper function which adds a piece of data for the accountplayers protocol command.
Definition: request.cpp:2069
uint16_t number
This is the image unique identifier.
Definition: face.h:15
#define VERSION_CS
Version >= 1023 understand setup cmd.
Definition: newserver.h:153
Praying.
Definition: skills.h:49
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
Server settings.
Definition: global.h:241
char * range
Definition: newserver.h:61
#define CS_STAT_APPLIED_POW
POW changes from gear or skills.
Definition: newclient.h:141
uint32_t pticks
Number of ticks since time reset.
Definition: time.cpp:47
See Spell.
Definition: object.h:219
uint32_t last_path_denied
Last spell denied sent to client.
Definition: player.h:164
static const object * heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS]
Using a global really isn&#39;t a good approach, but saves the over head of allocating and deallocating s...
Definition: request.cpp:1086
#define SP_RUNE
Definition: spells.h:76
#define CS_STAT_SPELL_REPEL
Definition: newclient.h:119
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:112
#define CS_STAT_STR
Definition: newclient.h:95
#define MSG_TYPE_ADMIN_VERSION
version info
Definition: newclient.h:520
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:609
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:53
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
Tells client the picture it has to use to smooth a picture number given as argument.
Definition: request.cpp:503
uint32_t is_bot
Client shouldn&#39;t be reported to metaserver.
Definition: newserver.h:111
#define CS_STAT_FOOD
Definition: newclient.h:108
#define CS_STAT_APPLIED_DEX
DEX changes from gear or skills.
Definition: newclient.h:138
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
void update_los(object *op)
Recalculates the array which specifies what is visible for the given player-object.
Definition: los.cpp:509
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define CS_STAT_CHARACTER_FLAGS
Character flags, like &#39;confused&#39; and such.
Definition: newclient.h:144
living last_stats
Last stats as sent to client.
Definition: player.h:170
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define MIN_NUM_LOOK_OBJECTS
The lower bound for the number of objects to send for the &#39;look&#39; window (container or ground view)...
Definition: newserver.h:16
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
#define CS_STAT_RES_SLOW
Definition: newclient.h:162
#define MSG_TYPE_ADMIN
Definition: newclient.h:418
int64_t last_skill_exp[MAX_SKILLS]
Last exp sent to client.
Definition: player.h:156
int16_t last_golem_maxhp
Last golem max hp value sent to the client.
Definition: player.h:178
uint32_t extended_stats
Client wants base and maximum statistics information.
Definition: newserver.h:113
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.cpp:2351
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
Structure handling character information for an account.
Definition: account_char.h:27
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
uint8_t mapx
Definition: newserver.h:120
uint32_t last_path_repelled
Last spell repelled sent to client.
Definition: player.h:163
#define MAP_CLIENT_X
This determines the maximum map size the client can request (and thus what the server will send to th...
Definition: config.h:237
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:189
archetype * get_archetype_by_type_subtype(int type, int subtype)
Retrieves an archetype by type and subtype.
Definition: arch.cpp:97
void reply_cmd(char *buf, int len, player *pl)
This is a reply to a previous query.
Definition: request.cpp:589
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:340
#define ANIM_SYNC
Definition: newclient.h:364
Various statistics of objects.
Definition: living.h:35
uint8_t account_block_create
Definition: global.h:328
static const flag_definition flags[]
Flag mapping.
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
#define CS_STAT_APPLIED_CHA
CHA changes from gear or skills.
Definition: newclient.h:140
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.cpp:4093
#define CS_STAT_RES_PARA
Definition: newclient.h:163
#define CS_STAT_RES_COLD
Definition: newclient.h:156
void command_execute(object *pl, char *command)
Handle a player-issued command.
Definition: commands.cpp:456
See Player.
Definition: object.h:112
struct archetype * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:425
uint32_t darkness
True if client wants darkness information.
Definition: newserver.h:107
int is_valid_faceset(int fsn)
Checks specified faceset is valid.
Definition: image.cpp:117
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Gets the layer face of specified square.
Definition: map.h:185
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:395
void esrv_draw_look(object *pl)
Send the look window.
Definition: item.cpp:193
int account_check_string(const char *str)
Checks a string to make sure it does not have any invalid characters.
Definition: account.cpp:360
int account_link(const char *account_name, const char *player_name)
Adds a player name to an account.
Definition: account.cpp:444
void account_add_player_cmd(char *buf, int len, socket_struct *ns)
Handle accountaddplayer from server (add a character to this account).
Definition: request.cpp:2443
uint16_t num
Where we are in the array.
Definition: face.h:29
sstring name_pl
The plural name of the object.
Definition: object.h:323
#define FLAG_AUTO_APPLY
Will be applied when created.
Definition: define.h:237
#define MAP2_TYPE_DARKNESS
Definition: newclient.h:43
Account_Chars * account_char_load(const char *account_name)
For a given account name, load the character information and return it.
static bool add_labels(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *got_one)
Return true if there is a label present on this square.
Definition: request.cpp:1414
#define P_NEW_MAP
Coordinates passed result in a new tiled map.
Definition: map.h:255
#define MAP_CLIENT_Y
Definition: config.h:238
#define MAP_LAYER_LIVING1
Living creatures.
Definition: map.h:46
#define FIF(F, C)
static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer)
Definition: request.cpp:1395
static event_registration m
Definition: citylife.cpp:424
static void send_extra_stats(SockList *sl, player *pl)
Send extra stats for the player, if &#39;notification&#39; is 3.
Definition: request.cpp:810
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.cpp:72
#define CS_STAT_RES_ELEC
Definition: newclient.h:155
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
#define CS_STAT_APPLIED_STR
STR changes from gear or skills.
Definition: newclient.h:135
#define NUM_ANIMATIONS(ob)
Definition: global.h:173
void map_reset_swap(mapstruct *m)
Call this when an in-memory map is used or referenced.
Definition: map.cpp:1759
uint32_t name_changed
If true, the player has set a name.
Definition: player.h:147
Also see SKILL_TOOL (74) below.
Definition: object.h:148
#define CS_STAT_SP
Definition: newclient.h:93
player * find_player_socket(const socket_struct *ns)
Return a player for a socket structure.
Definition: player.cpp:123
#define CS_STAT_RES_MAG
Definition: newclient.h:153
#define CS_STAT_GOLEM_HP
Golem&#39;s current hp, 0 if no golem.
Definition: newclient.h:142
object * last_skill_ob[MAX_SKILLS]
Exp objects sent to client.
Definition: player.h:155
int8_t tail_x
Definition: object.h:488
uint8_t starting_stat_points
How many stat points character starts with.
Definition: global.h:323
int darkness
Cell&#39;s darkness.
Definition: newserver.h:33
sstring name
The name of the object, obviously...
Definition: object.h:319
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.cpp:313
void check_login(object *op, const char *password)
Actually login a player, load from disk and such.
Definition: login.cpp:522
static int spell_client_use(const object *spell)
Give the client-side use information for a spell, to know how to use a spell.
Definition: request.cpp:1900
Only for debugging purposes.
Definition: logger.h:13
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.cpp:300
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:101
void receive_player_name(object *op, const char *name)
A player just entered her name.
Definition: c_misc.cpp:1933
#define CS_STAT_RES_DEPLETE
Definition: newclient.h:166
int8_t Cha
Use
Definition: living.h:36
#define MAP_CLIENT_X_MINIMUM
Definition: config.h:245
uint16_t last_flags
Fire/run on flags for last tick.
Definition: player.h:159
void account_play_cmd(char *buf, int len, socket_struct *ns)
We have received an accountplay command.
Definition: request.cpp:2572
struct statsinfo stats
Definition: newserver.h:102
void send_account_players(socket_struct *ns)
Upon successful login/account creation, we send a list of characters associated with the account to t...
Definition: request.cpp:2103
uint32_t monitor_spells
Client wishes to be informed when their spell list changes.
Definition: newserver.h:114
#define MAP2_COORD_OFFSET
How much the x,y coordinates in the map2 are off from actual upper left corner.
Definition: newclient.h:32
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:145
void set_up_cmd(char *buf, int len, socket_struct *ns)
This is the Setup cmd - easy first implementation.
Definition: request.cpp:143
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 8 bit length field.
Definition: lowlevel.cpp:179
#define CS_STAT_RES_FEAR
Definition: newclient.h:165
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
void account_char_free(Account_Chars *chars)
This frees all data associated with the character information.
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:253
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1753
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
#define ACL_PARTY
Definition: newclient.h:226
#define CS_STAT_APPLIED_WIS
WIS changes from gear or skills.
Definition: newclient.h:137
int8_t Pow
Use
Definition: living.h:36
#define AddIfFloat(Old, New, sl, Type)
Definition: request.cpp:775
#define CS_STAT_ARMOUR
Definition: newclient.h:106
#define ST_CHANGE_PASSWORD_OLD
Player is entering old password to change password.
Definition: define.h:571
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.cpp:1008
void esrv_update_spells(player *pl)
This looks for any spells the player may have that have changed their stats.
Definition: request.cpp:1805
const Face ** faces
The actual faces for the animation.
Definition: face.h:30
#define CS_STAT_DAM
Definition: newclient.h:105
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:565
living last_applied_stats
Last applied stats sent to the client.
Definition: player.h:174
#define SP_SUMMON_MONSTER
Definition: spells.h:101
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:188
#define CF_DISEASED
Has at least one disease.
Definition: newclient.h:206
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.cpp:961
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
#define CS_STAT_TITLE
Definition: newclient.h:111
method_ret ob_apply(object *op, object *applier, int aflags)
Apply an object by running an event hook or an object method.
Definition: ob_methods.cpp:44
static const int MAP2_COORD_MIN
Definition: request.cpp:73
const Face * smooth_face
Definition: image.cpp:36
#define CS_STAT_RACE_STR
Definition: newclient.h:121
int playername_ok(const char *cp)
Is the player name valid.
Definition: player.cpp:257
int64_t exp
Experience.
Definition: living.h:47
#define ACL_RACE
Definition: newclient.h:223
#define CS_STAT_SPELL_DENY
Definition: newclient.h:120
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
#define CS_STAT_HP
Definition: newclient.h:91
int16_t maxsp
Max spell points.
Definition: living.h:43
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
#define VALIDCHAR_MSG
Definition: request.cpp:71
#define CS_STAT_RES_PHYS
Definition: newclient.h:152
#define CS_STAT_RES_BLIND
Definition: newclient.h:169
One player.
Definition: player.h:107
#define SF_FIREON
Definition: newclient.h:193
#define CS_STAT_POW
Definition: newclient.h:112
int8_t map_scroll_x
Definition: newserver.h:98
#define CS_STAT_ITEM_POWER
Equipped item power.
Definition: newclient.h:147
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:228
#define CS_STAT_GOLEM_MAXHP
Golem&#39;s max hp, 0 if no golem.
Definition: newclient.h:143
void set_title(const object *pl, char *buf, size_t len)
Sets player title.
Definition: info.cpp:335
void free_charlinks(linked_char *lc)
Frees a link structure and its next items.
Definition: utils.cpp:616
#define SND_MUSIC
Client wants background music info.
Definition: sounds.h:13
int32_t food
How much food in stomach.
Definition: living.h:48
StringBuffer * buf
Definition: readable.cpp:1563
char ** account_get_players_for_account(const char *account_name)
Returns an array of strings for the characters on this account - the array is null terminated...
Definition: account.cpp:519
Structure containing object statistics.
#define CS_STAT_RANGE
Definition: newclient.h:110
#define SPELL_MANA
Definition: spells.h:58
int16_t maxhp
Max hit points.
Definition: living.h:41
uint8_t subtype
Subtype of object.
Definition: object.h:349
#define CF_NOT_PERFECT
Can drink some improvement potions.
Definition: newclient.h:207
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
#define CS_STAT_RACE_WIS
Definition: newclient.h:123
#define CS_STAT_RACE_CHA
Definition: newclient.h:126
void rangetostring(const object *pl, char *obuf, size_t len)
Get player&#39;s current range attack in obuf.
Definition: info.cpp:265
#define CS_STAT_MAXHP
Definition: newclient.h:92
#define MAP_LAYER_FLY2
Arrows, etc.
Definition: map.h:49
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
int16_t item_power
Total item power of objects equipped.
Definition: player.h:132
void SockList_AddInt64(SockList *sl, uint64_t data)
Adds a 64 bit value.
Definition: lowlevel.cpp:140
const char * sstring
Definition: sstring.h:2
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
int8_t Int
Use
Definition: living.h:36
#define ST_GET_NAME
Player just connected.
Definition: define.h:567
#define CS_STAT_CON
Definition: newclient.h:99
#define CS_STAT_SPELL_ATTUNE
Definition: newclient.h:118
tag_t count
Unique object number for this object.
Definition: object.h:307
static void handle_scroll(socket_struct *socket, SockList *sl)
As part of sending the map2 command, send one or more scroll commands to update the client map to mat...
Definition: request.cpp:104
#define CF_XRAY
Has X-ray.
Definition: newclient.h:205
static bool map2_add_label(int ax, int ay, socket_struct *ns, SockList *sl, enum map2_label subtype, sstring label)
Return true if an update was sent to the client.
Definition: request.cpp:1354
void draw_client_map(object *pl)
Draws client map.
Definition: request.cpp:1692
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:120
#define ACL_NAME
Definition: newclient.h:221
#define CS_STAT_MAXGRACE
Definition: newclient.h:114
char const * newhash(char const *password)
Definition: server.cpp:101
linked_char * account_get_additional_chars(const char *account_name, const Account_Chars *chars, int *count)
Get a list of character names linked to the specified account which are not listed in chars...
Definition: account.cpp:550
living last_race_stats
Last race stats sent to the client.
Definition: player.h:172
#define CS_STAT_RES_ACID
Definition: newclient.h:158
#define SP_CREATE_FOOD
Definition: spells.h:96
#define CS_STAT_OVERLOAD
How much (0 to 1) the character is overloaded.
Definition: newclient.h:146
See Disease.
Definition: object.h:249
#define MAP2_LAYER_START
Definition: newclient.h:67
#define CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
Definition: newclient.h:176
sstring name
Face name, as used by archetypes and such.
Definition: face.h:19
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
#define CS_STAT_BASE_INT
Definition: newclient.h:129
#define MAP_NOSMOOTH(m)
Definition: map.h:87
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
This checks to see if the race and class are legal.
Definition: player.cpp:1435
#define CF_WIZARD
Player is DM.
Definition: newclient.h:211
object clone
An object from which to do object_copy()
Definition: object.h:487
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
uint16_t faces[MAP_LAYERS]
Face numbers.
Definition: newserver.h:32
int8_t Str
Use
Definition: living.h:36
#define CS_STAT_GRACE
Definition: newclient.h:113
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:103
#define ATNR_PHYSICAL
Definition: attack.h:47
int16_t hp
Hit Points.
Definition: living.h:40
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
const Face * get_face_by_id(uint16_t id)
Get a face from its unique identifier.
Definition: assets.cpp:319
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:568
static bool CAN_PROBE(const object *ob)
Determine whether the given object can have an HP bar.
Definition: object.h:618
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
Definition: object.h:229
#define SP_RAISE_DEAD
Definition: spells.h:75
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Move an object to a new location.
Definition: item.cpp:899
std::vector< Account_Char * > chars
Characters of the account.
Definition: account_char.h:30
char * account_trusted_host
Block account creation for untrusted hosts.
Definition: global.h:329