Crossfire Server, Trunk  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:
633  break;
634 
635  case ST_GET_PARTY_PASSWORD: /* Get password for party */
637  break;
638 
639  default:
640  LOG(llevError, "Unknown input state: %d\n", pl->state);
641  }
642 }
643 
651 void version_cmd(char *buf, int len, socket_struct *ns) {
652  char *rest = NULL;
653  char *cs_str = strtok_r(buf, " ", &rest);
654  char *sc_str = strtok_r(NULL, " ", &rest);
655  (void)len;
656 
657  if (cs_str == NULL || sc_str == NULL) {
658  LOG(llevError, "%s: sent invalid version string\n", ns->host);
659  return;
660  } else {
661  ns->cs_version = atoi(cs_str);
662  ns->sc_version = atoi(sc_str);
663  }
664 
665 #ifdef ESRV_DEBUG
666  if (VERSION_CS != ns->cs_version) {
667  LOG(llevDebug, "CS: csversion mismatch (%d,%d)\n", VERSION_CS, ns->cs_version);
668  }
669 
670  if (VERSION_SC != ns->sc_version) {
671  LOG(llevDebug, "CS: scversion mismatch (%d,%d)\n", VERSION_SC, ns->sc_version);
672  }
673 #endif
674 
675  if (rest != NULL) {
676  ns->client = add_string(rest);
677  } else {
678  ns->client = add_string("unknown");
679  }
680 
681  LOG(llevInfo, "Connection from %s (%s), CS %d, SC %d\n",
682  ns->host, ns->client, ns->cs_version, ns->sc_version);
683 }
684 
692  SockList sl;
693 
694  /* If getting a newmap command, this scroll information
695  * is no longer relevant.
696  */
697  ns->map_scroll_x = 0;
698  ns->map_scroll_y = 0;
699 
700 
701  memset(&ns->lastmap, 0, sizeof(ns->lastmap));
702  SockList_Init(&sl);
703  SockList_AddString(&sl, "newmap");
704  Send_With_Handling(ns, &sl);
705  SockList_Term(&sl);
706 }
707 
712 void move_cmd(char *buf, int len, player *pl) {
713  int vals[3], i;
714 
715  if (len <= 0 || !buf) {
716  LOG(llevDebug, "Player '%s' sent bogus move_cmd information\n", pl->ob->name);
717  return;
718  }
719 
720  /* A little funky here. We only cycle for 2 records, because
721  * we obviously am not going to find a space after the third
722  * record. Perhaps we should just replace this with a
723  * sscanf?
724  */
725  for (i = 0; i < 2; i++) {
726  vals[i] = atoi(buf);
727  if (!(buf = strchr(buf, ' '))) {
728  return;
729  }
730  buf++;
731  }
732  vals[2] = atoi(buf);
733 
734 /* LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
735  esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
736 }
737 
738 /***************************************************************************
739  *
740  * Start of commands the server sends to the client.
741  *
742  ***************************************************************************
743  */
744 
749 void send_query(socket_struct *ns, uint8_t flags, const char *text) {
750  SockList sl;
751 
752  SockList_Init(&sl);
753  SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
754  Send_With_Handling(ns, &sl);
755  SockList_Term(&sl);
756 }
757 
758 #define AddIfInt64(Old, New, sl, Type) \
759  if (Old != New) { \
760  Old = New; \
761  SockList_AddChar(sl, Type); \
762  SockList_AddInt64(sl, New); \
763  }
764 
765 #define AddIfInt(Old, New, sl, Type) \
766  if (Old != New) { \
767  Old = New; \
768  SockList_AddChar(sl, Type); \
769  SockList_AddInt(sl, New); \
770  }
771 
772 #define AddIfShort(Old, New, sl, Type) \
773  if (Old != New) { \
774  Old = New; \
775  SockList_AddChar(sl, Type); \
776  SockList_AddShort(sl, New); \
777  }
778 
779 #define AddIfFloat(Old, New, sl, Type) \
780  if (Old != New) { \
781  Old = New; \
782  SockList_AddChar(sl, Type); \
783  SockList_AddInt(sl, (long)(New*FLOAT_MULTI));\
784  }
785 
786 #define AddIfString(Old, New, sl, Type) \
787  if (Old == NULL || strcmp(Old, New)) { \
788  free(Old); \
789  Old = strdup_local(New); \
790  SockList_AddChar(sl, Type); \
791  SockList_AddLen8Data(sl, New, strlen(New)); \
792  }
793 
799 static uint8_t is_perfect(const player *pl) {
800  const int16_t until = MIN(11, pl->ob->level);
801  for (int16_t i = 1; i < until; i++) {
802  if (pl->levhp[i] < 9 || pl->levsp[i] < 6 || pl->levgrace[i] < 3) {
803  return 0;
804  }
805  }
806  return 1;
807 }
808 
814 static void send_extra_stats(SockList *sl, player *pl) {
815  uint32_t uflags = 0;
816  const char *god = "none";
817 
818  if (pl->socket->notifications < 3) {
819  return;
820  }
821 
822  if (!pl->peaceful) {
823  uflags |= CF_HOSTILE;
824  }
825  if (!is_perfect(pl)) {
826  uflags |= CF_NOT_PERFECT;
827  }
828 
829 #define FIF(F, C) \
830  if (QUERY_FLAG(pl->ob, F)) { \
831  uflags |= C; \
832  }
834  FIF(FLAG_CONFUSED, CF_CONFUSED); // If confused by an item
838 
839  FOR_INV_PREPARE(pl->ob, item) {
840  if (item->type == DISEASE && !QUERY_FLAG(item, FLAG_STARTEQUIP)) {
841  uflags |= CF_DISEASED;
842  }
843  if (strcmp(item->arch->name, "poisoning") == 0) {
844  uflags |= CF_POISONED;
845  }
846  if (strcmp(item->arch->name, "blindness") == 0) {
847  uflags |= CF_BLIND;
848  }
849  if (item->type == FORCE && strcmp(item->name, "confusion") == 0) {
850  uflags |= CF_CONFUSED;
851  }
852  if (item->type == SKILL && item->subtype == SK_PRAYING && item->title) {
853  god = item->title;
854  }
855  }
856  FOR_INV_FINISH();
857 
860  AddIfString(pl->socket->stats.god, god, sl, CS_STAT_GOD_NAME);
862 }
863 
871  SockList sl;
872  char buf[MAX_BUF];
873  uint16_t flags;
874  uint8_t s;
875 
876  SockList_Init(&sl);
877  SockList_AddString(&sl, "stats ");
878 
879  if (pl->ob != NULL) {
880  AddIfShort(pl->last_stats.hp, pl->ob->stats.hp, &sl, CS_STAT_HP);
882  AddIfShort(pl->last_stats.sp, pl->ob->stats.sp, &sl, CS_STAT_SP);
886  AddIfShort(pl->last_stats.Str, pl->ob->stats.Str, &sl, CS_STAT_STR);
887  AddIfShort(pl->last_stats.Int, pl->ob->stats.Int, &sl, CS_STAT_INT);
888  AddIfShort(pl->last_stats.Pow, pl->ob->stats.Pow, &sl, CS_STAT_POW);
889  AddIfShort(pl->last_stats.Wis, pl->ob->stats.Wis, &sl, CS_STAT_WIS);
890  AddIfShort(pl->last_stats.Dex, pl->ob->stats.Dex, &sl, CS_STAT_DEX);
891  AddIfShort(pl->last_stats.Con, pl->ob->stats.Con, &sl, CS_STAT_CON);
892  AddIfShort(pl->last_stats.Cha, pl->ob->stats.Cha, &sl, CS_STAT_CHA);
893  }
894  if (pl->socket->extended_stats) {
895  int16_t golem_hp, golem_maxhp;
903  if (pl->ob != NULL) {
918  }
919  if (pl->ranges[range_golem]) {
920  object *golem = pl->ranges[range_golem];
921  if (QUERY_FLAG(golem, FLAG_REMOVED) || golem->count != pl->golem_count || QUERY_FLAG(golem, FLAG_FREED)) {
922  golem_hp = 0;
923  golem_maxhp = 0;
924  } else {
925  golem_hp = golem->stats.hp;
926  golem_maxhp = golem->stats.maxhp;
927  }
928  } else {
929  golem_hp = 0;
930  golem_maxhp = 0;
931  }
932  /* send first the maxhp, so the client can set up the display */
933  AddIfShort(pl->last_golem_maxhp, golem_maxhp, &sl, CS_STAT_GOLEM_MAXHP);
934  AddIfShort(pl->last_golem_hp, golem_hp, &sl, CS_STAT_GOLEM_HP);
935  }
936 
937  for (s = 0; s < MAX_SKILLS; s++) {
938  if (pl->last_skill_ob[s]) {
939  // Skill objects can be removed without updating last_skill_ob.
940  // Clean them up here if that's the case.
941  if (QUERY_FLAG(pl->last_skill_ob[s], FLAG_REMOVED)) {
942  LOG(llevDebug, "pruning removed object from last_skill_ob\n");
943  pl->last_skill_ob[s] = NULL;
944  continue;
945  }
946 
947  if (pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
948  /* Always send along the level if exp changes. This
949  * is only 1 extra byte, but keeps processing simpler.
950  */
952  SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
954  pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
955  }
956  }
957  }
958  AddIfInt64(pl->last_stats.exp, pl->ob->stats.exp, &sl, CS_STAT_EXP64);
959  AddIfShort(pl->last_level, (char)pl->ob->level, &sl, CS_STAT_LEVEL);
960  AddIfShort(pl->last_stats.wc, pl->ob->stats.wc, &sl, CS_STAT_WC);
961  AddIfShort(pl->last_stats.ac, pl->ob->stats.ac, &sl, CS_STAT_AC);
962  AddIfShort(pl->last_stats.dam, pl->ob->stats.dam, &sl, CS_STAT_DAM);
963  AddIfFloat(pl->last_speed, pl->ob->speed, &sl, CS_STAT_SPEED);
967  flags = 0;
968  if (pl->fire_on)
969  flags |= SF_FIREON;
970  if (pl->run_on)
971  flags |= SF_RUNON;
972 
974  if (pl->socket->sc_version < 1025) {
976  } else {
977  int i;
978 
979  for (i = 0; i < NROFATTACKS; i++) {
980  /* Skip ones we won't send */
981  if (atnr_cs_stat[i] == -1)
982  continue;
983  AddIfShort(pl->last_resist[i], pl->ob->resist[i], &sl, (char)atnr_cs_stat[i]);
984  }
985  }
986  if (pl->socket->monitor_spells) {
990  }
991  /* we want to use the new fire & run system in new client */
992  rangetostring(pl->ob, buf, sizeof(buf));
994  set_title(pl->ob, buf, sizeof(buf));
996 
997  send_extra_stats(&sl, pl);
998 
999  /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
1000  if (sl.len > 8) {
1001 #ifdef ESRV_DEBUG
1002  LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
1003 #endif
1004  Send_With_Handling(pl->socket, &sl);
1005  }
1006  SockList_Term(&sl);
1007 }
1008 
1012 void esrv_new_player(player *pl, uint32_t weight) {
1013  SockList sl;
1014 
1015  pl->last_weight = weight;
1016 
1017  if (!(pl->socket->faces_sent[pl->ob->face->number]&NS_FACESENT_FACE))
1018  esrv_send_face(pl->socket, pl->ob->face, 0);
1019 
1020  SockList_Init(&sl);
1021  SockList_AddString(&sl, "player ");
1022  SockList_AddInt(&sl, pl->ob->count);
1023  SockList_AddInt(&sl, weight);
1024  SockList_AddInt(&sl, pl->ob->face->number);
1025  SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
1026 
1027  Send_With_Handling(pl->socket, &sl);
1028  SockList_Term(&sl);
1030 }
1031 
1043  SockList sl;
1044  int i;
1045 
1046  if (anim == NULL) {
1047  LOG(llevError, "esrv_send_anim NULL??\n");
1048  return;
1049  }
1050 
1051  SockList_Init(&sl);
1052  SockList_AddString(&sl, "anim ");
1053  SockList_AddShort(&sl, anim->num);
1054  SockList_AddShort(&sl, 0); /* flags - not used right now */
1055  /* Build up the list of faces. Also, send any information (ie, the
1056  * the face itself) down to the client.
1057  */
1058  for (i = 0; i < anim->num_animations; i++) {
1059  if (!(ns->faces_sent[anim->faces[i]->number]&NS_FACESENT_FACE))
1060  esrv_send_face(ns, anim->faces[i], 0);
1061  /* flags - not used right now */
1062  SockList_AddShort(&sl, anim->faces[i]->number);
1063  }
1064  Send_With_Handling(ns, &sl);
1065  SockList_Term(&sl);
1066  ns->anims_sent[anim->num] = 1;
1067 }
1068 
1069 /****************************************************************************
1070  *
1071  * Start of map related commands.
1072  *
1073  ****************************************************************************/
1074 
1076 static void map_clearcell(struct map_cell_struct *cell, int face, int darkness) {
1077  cell->darkness = darkness;
1078  memset(cell->faces, face, sizeof(cell->faces));
1079 }
1080 
1081 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
1082 
1090 static const object *heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS];
1091 
1092 /****************************************************************************
1093  * This block is for map2 drawing related commands.
1094  * Note that the map2 still uses other functions.
1095  *
1096  ***************************************************************************/
1097 
1117 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) {
1118  uint8_t nlayer, smoothlevel = 0;
1119  const object *head;
1120 
1121  assert(ob != NULL);
1122 
1123  head = HEAD(ob);
1124  const Face *face = ob->face;
1125 
1126  /* This is a multipart object, and we are not at the lower
1127  * right corner. So we need to store away the lower right corner.
1128  */
1129  if (!is_head && (head->arch->tail_x || head->arch->tail_y)
1130  && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
1131  int bx, by, l;
1132 
1133  /* Basically figure out where the offset is from where we
1134  * are right now. the ob->arch->clone.{x,y} values hold
1135  * the offset that this current piece is from the head,
1136  * and the tail is where the tail is from the head.
1137  * Note that bx and by will equal sx and sy if we are
1138  * already working on the bottom right corner. If ob is
1139  * the head, the clone values will be zero, so the right
1140  * thing will still happen.
1141  */
1142  bx = ax+head->arch->tail_x-ob->arch->clone.x;
1143  by = ay+head->arch->tail_y-ob->arch->clone.y;
1144 
1145  /* I don't think this can ever happen, but better to check
1146  * for it just in case.
1147  */
1148  if (bx < ax || by < ay) {
1149  LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
1150  face = NULL;
1151  }
1152  /* the target position must be within +/-1 of our current
1153  * layer as the layers are defined. We are basically checking
1154  * to see if we have already stored this object away.
1155  */
1156  for (l = layer-1; l <= layer+1; l++) {
1157  if (l < 0 || l >= MAP_LAYERS)
1158  continue;
1159  if (heads[by][bx][l] == head)
1160  break;
1161  }
1162  /* Didn't find it. So we need to store it away. Try to store it
1163  * on our original layer, and then move up a layer.
1164  */
1165  if (l == layer+2) {
1166  if (!heads[by][bx][layer])
1167  heads[by][bx][layer] = head;
1168  else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
1169  heads[by][bx][layer+1] = head;
1170  }
1171  return 0;
1172  /* Ok - All done storing away the head for future use */
1173  } else {
1174  uint16_t face_num = face ? face->number : 0;
1175  (*has_obj)++;
1178  face_num = (ob->animation ? ob->animation->num : 0)|(1<<15);
1180  face_num |= ANIM_SYNC;
1181  else if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM))
1182  face_num |= ANIM_RANDOM;
1183  }
1184  /* Since face_num includes the bits for the animation tag,
1185  * and we will store that away in the faces[] array, below
1186  * check works fine _except_ for the case where animation
1187  * speed chances.
1188  */
1189  if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
1190  uint8_t len, anim_speed = 0, i;
1191 
1192  /* This block takes care of sending the actual face
1193  * to the client. */
1194  ns->lastmap.cells[ax][ay].faces[layer] = face_num;
1195 
1196  /* Now form the data packet */
1197  nlayer = MAP2_LAYER_START+layer;
1198 
1199  len = 2;
1200 
1201  if (ob->map && !MAP_NOSMOOTH(ob->map)) {
1202  smoothlevel = ob->smoothlevel;
1203  if (smoothlevel)
1204  len++;
1205  }
1206 
1209  len++;
1210  /* 1/0.004 == 250, so this is a good cap for an
1211  * upper limit */
1212  if (ob->anim_speed)
1213  anim_speed = ob->anim_speed;
1214  else if (FABS(ob->speed) < 0.004)
1215  anim_speed = 255;
1216  else if (FABS(ob->speed) >= 1.0)
1217  anim_speed = 1;
1218  else
1219  anim_speed = (int)(1.0/FABS(ob->speed));
1220 
1221  if (ob->animation && !ns->anims_sent[ob->animation->num])
1222  esrv_send_animation(ns, ob->animation);
1223 
1224  /* If smoothing, need to send smoothing information
1225  * for all faces in the animation sequence. Since
1226  * smoothlevel is an object attribute,
1227  * it applies to all faces.
1228  */
1229  if (smoothlevel) {
1230  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1231  if (!(ns->faces_sent[ob->animation->faces[i]->number]&NS_FACESENT_SMOOTH))
1232  send_smooth(ns, ob->animation->faces[i]);
1233  }
1234  }
1235  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1236  esrv_send_face(ns, face, 0);
1237  }
1238 
1239  if (smoothlevel
1240  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1241  send_smooth(ns, ob->face);
1242 
1243  /* Length of packet */
1244  nlayer |= len<<5;
1245 
1246  SockList_AddChar(sl, nlayer);
1247  SockList_AddShort(sl, face_num);
1248  if (anim_speed)
1249  SockList_AddChar(sl, anim_speed);
1250  if (smoothlevel)
1251  SockList_AddChar(sl, smoothlevel);
1252  return 1;
1253  } /* Face is different */
1254  }
1255  return 0;
1256 }
1257 
1258 /* This function is used see if a layer needs to be cleared.
1259  * It updates the socklist, and returns 1 if the update is
1260  * needed, 0 otherwise.
1261  */
1262 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1263  int nlayer;
1264 
1265  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1266  /* Now form the data packet */
1267  nlayer = 0x10+layer+(2<<5);
1268  SockList_AddChar(sl, nlayer);
1269  SockList_AddShort(sl, 0);
1270  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1271  return 1;
1272  }
1273  return 0;
1274 }
1275 
1287 static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1288  int got_one = 0, poisoned = 0, diseased = 0;
1289  char name[60];
1290  int value, granularity;
1291  const object *probe;
1292 
1293  /* send hp bar if needed */
1294  if ((*alive_layer) != -1 || ob->head || !CAN_PROBE(ob))
1295  return 0;
1296 
1297  if (settings.always_show_hp == 2) {
1298  /* global hp bars are enabled */
1299  granularity = 30;
1300  } else if (settings.always_show_hp == 1 && ob->stats.hp < ob->stats.maxhp) {
1301  granularity = 30;
1302  } else {
1303  /* only give hp bars to monsters that have been probed */
1304  if (!QUERY_FLAG(ob, FLAG_PROBE)) {
1305  return 0;
1306  }
1307  probe = object_find_by_type_and_name(ob, FORCE, "probe_force");
1308  if (probe == NULL || probe->level < 15) {
1309  /* if probe is not null, this is an error, but well */
1310  return 0;
1311  }
1312 
1313  granularity = (probe->level - 14) / 3;
1314  if (granularity <= 0)
1315  granularity = 1;
1316  else if (granularity > 30)
1317  granularity = 30;
1318  }
1319 
1320  if (ob->stats.maxhp > 0) {
1321  value = (ob->stats.hp * granularity) / (ob->stats.maxhp);
1322 
1323  if (value < 0)
1324  value = 0;
1325  else if (value > granularity)
1326  value = granularity;
1327  } else
1328  value = 30;
1329 
1330  value = (value * 30) / granularity;
1331 
1332  if (object_present_in_ob(POISONING, ob) != NULL)
1333  poisoned = 1;
1334  if (object_present_in_ob(DISEASE, ob) != NULL)
1335  diseased = 1;
1336 
1337  if (value > 0) {
1338  archetype *dummy;
1339 
1340  snprintf(name, sizeof(name), "hpbar%s%s%s_%d",
1341  poisoned ? "_poisoned" : "",
1342  diseased ? "_diseased" : "",
1343  (!poisoned && !diseased) ? "_standard" : "",
1344  value);
1345  dummy = try_find_archetype(name);
1346  if (dummy != NULL) {
1347  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1348  (*alive_layer) = MAP_LAYER_FLY2;
1349  }
1350  }
1351 
1352  return got_one;
1353 }
1354 
1358 static bool map2_add_label(int ax, int ay, socket_struct *ns, SockList *sl, enum map2_label subtype, sstring label) {
1359  // label can only be null if subtype is none
1360  assert(subtype != MAP2_LABEL_NONE ? label != NULL : 1);
1361 
1362  // protect old clients from label with additive length, which can cause them to crash
1363  if (ns->sc_version < 1030)
1364  return false;
1365 
1366  // Check if there is any change to last sent data
1367  struct map_cell_struct *cell = &ns->lastmap.cells[ax][ay];
1368  if (cell->label_subtype == subtype &&
1369  (subtype == 0 || cell->label_text == label)) { // none label skips string comparison
1370  return false;
1371  }
1372 
1373  // Store change
1374  if (cell->label_subtype != MAP2_LABEL_NONE)
1375  free_string(cell->label_text);
1376  cell->label_subtype = subtype;
1377  cell->label_text = label;
1378 
1379  int len = 0;
1380  if (label) {
1381  add_refcount(label);
1382  len = strlen(label);
1383  if (len > 256 - 2 - 1) {
1384  LOG(llevError, "The label '%s' is too long to send to the client.", label);
1385  return false;
1386  }
1387  }
1388 
1389  // Send update
1390  SockList_AddChar(sl, MAP2_ADD_LENGTH | MAP2_TYPE_LABEL); // label with additive length
1391  SockList_AddChar(sl, len + 2); // length of payload (subtype + lstring)
1392  SockList_AddChar(sl, subtype);
1393  SockList_AddChar(sl, len); // lstring length prefix
1394  if (label)
1395  SockList_AddString(sl, label);
1396  return true;
1397 }
1398 
1399 static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer) {
1400  socket_struct *ns = plyr->socket;
1401  int got_one = check_probe(ax, ay, ob, sl, ns, has_obj, alive_layer);
1402  // add NPC speech bubble
1403  if (QUERY_FLAG(ob, FLAG_ALIVE) && (QUERY_FLAG(ob, FLAG_UNAGGRESSIVE) || QUERY_FLAG(ob, FLAG_FRIENDLY)) && ob->type != PLAYER) {
1404  if (ob->msg != NULL || object_find_by_arch_name(ob, NPC_DIALOG_ARCH)) {
1405  archetype *dummy = try_find_archetype("speechbubble");
1406  if (dummy != NULL) {
1407  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1408  (*alive_layer) = MAP_LAYER_FLY2;
1409  }
1410  }
1411  }
1412  return got_one;
1413 }
1414 
1418 static bool add_labels(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *got_one) {
1419  socket_struct *ns = plyr->socket;
1420  // add player name label
1421  if (ob->type == PLAYER) {
1422  enum map2_label subtype = MAP2_LABEL_PLAYER;
1423  if (QUERY_FLAG(ob, FLAG_WIZ)) {
1424  subtype = MAP2_LABEL_DM;
1425  } else if (plyr->party) {
1426  if (ob->contr && ob->contr->party == plyr->party) {
1427  subtype = MAP2_LABEL_PLAYER_PARTY;
1428  }
1429  }
1430  *got_one += map2_add_label(ax, ay, ns, sl, subtype, ob->name);
1431  return true;
1432  } else if (object_value_set(ob, "label")) {
1433  const char *label = object_get_value(ob, "label");
1434  *got_one += map2_add_label(ax, ay, ns, sl, MAP2_LABEL_SIGN, label);
1435  return true;
1436  }
1437  return false;
1438 }
1439 
1440 /*
1441  * This function is used to check a space (ax, ay) whose only
1442  * data we may care about are any heads. Basically, this
1443  * space is out of direct view. This is only used with the
1444  * Map2 protocol.
1445  *
1446  * @param ax
1447  * viewport relative x-coordinate
1448  * @param ay
1449  * viewport relative y-coordinate
1450  * @param sl
1451  * the reply to append to
1452  * @param ns
1453  * the client socket
1454  */
1455 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1456  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1457  uint16_t coord;
1458 
1459  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1460  oldlen = sl->len;
1461  SockList_AddShort(sl, coord);
1462 
1463  for (layer = 0; layer < MAP_LAYERS; layer++) {
1464  const object *head;
1465 
1466  head = heads[ay][ax][layer];
1467  if (head) {
1468  /* in this context, got_one should always increase
1469  * because heads should always point to data to really send.
1470  */
1471  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1472  } else {
1473  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1474  }
1475  }
1476  /* Note - if/when lighting information is added, some code is
1477  * needed here - lighting sources that are out of sight may still
1478  * extend into the viewable area.
1479  */
1480 
1481  /* If nothing to do for this space, we
1482  * can erase the coordinate bytes
1483  */
1484  if (!del_one && !got_one) {
1485  sl->len = oldlen;
1486  } else if (del_one && !has_obj) {
1487  /* If we're only deleting faces and not adding, and there
1488  * are not any faces on the space we care about,
1489  * more efficient
1490  * to send 0 as the type/len field.
1491  */
1492  sl->len = oldlen+2; /* 2 bytes for coordinate */
1493  SockList_AddChar(sl, MAP2_TYPE_CLEAR); /* Clear byte */
1494  SockList_AddChar(sl, 255); /* Termination byte */
1495  // Reduce defreferences by passing the inner array offset instead of address of value
1496  map_clearcell(ns->lastmap.cells[ax] + ay, 0, 0);
1497  } else {
1498  SockList_AddChar(sl, 255); /* Termination byte */
1499  }
1500 }
1501 
1502 static void draw_client_map2(object *pl) {
1503  int x, y, ax, ay, darkness, min_x, max_x, min_y, max_y, oldlen, layer;
1504  size_t startlen;
1505  int16_t nx, ny;
1506  SockList sl;
1507  uint16_t coord;
1508  mapstruct *m;
1509  // Dereference once. It should not change in the middle of processing.
1510  player *plyr = pl->contr;
1511 
1512  SockList_Init(&sl);
1513  SockList_AddString(&sl, "map2 ");
1514  startlen = sl.len;
1515 
1516  handle_scroll(plyr->socket, &sl);
1517 
1518  /* Init data to zero */
1519  memset(heads, 0, sizeof(heads));
1520 
1521  /* We could do this logic as conditionals in the if statement,
1522  * but that started to get a bit messy to look at.
1523  */
1524  min_x = pl->x-plyr->socket->mapx/2;
1525  min_y = pl->y-plyr->socket->mapy/2;
1526  max_x = pl->x+(plyr->socket->mapx+1)/2+MAX_HEAD_OFFSET;
1527  max_y = pl->y+(plyr->socket->mapy+1)/2+MAX_HEAD_OFFSET;
1528 
1529  /* x, y are the real map locations. ax, ay are viewport relative
1530  * locations.
1531  */
1532  ay = 0;
1533  for (y = min_y; y < max_y; y++, ay++) {
1534  ax = 0;
1535  for (x = min_x; x < max_x; x++, ax++) {
1536  /* If this space is out of the normal viewable area,
1537  * we only check the heads value. This is used to
1538  * handle big images - if they extend to a viewable
1539  * portion, we need to send just the lower right corner.
1540  */
1541  if (ax >= plyr->socket->mapx || ay >= plyr->socket->mapy) {
1542  check_space_for_heads(ax, ay, &sl, plyr->socket);
1543  } else {
1544  /* This space is within the viewport of the client. Due
1545  * to walls or darkness, it may still not be visible.
1546  */
1547 
1548  /* Meaning of darkness (see defines in LOS_* in los.c):
1549  * LOS_NO_DARKNESS (0) - object is in plain sight, full brightness.
1550  * 1 - MAX_DARKNESS - how dark the space is - higher
1551  * value is darker space. If level is at max darkness,
1552  * you can't see the space (too dark)
1553  * LOS_BLOCKED (100) - space is blocked from sight.
1554  */
1555  darkness = plyr->blocked_los[ax][ay];
1556 
1557  /* If the coordinates are not valid, or it is too
1558  * dark to see, we tell the client as such
1559  */
1560  nx = x;
1561  ny = y;
1562  m = get_map_from_coord(pl->map, &nx, &ny);
1563  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1564 
1565  if (!m) {
1566  /* space is out of map. Update space and clear
1567  * values if this hasn't already been done.
1568  * If the space is out of the map, it shouldn't
1569  * have a head.
1570  */
1571  if (plyr->socket->lastmap.cells[ax][ay].darkness != 0) {
1572  SockList_AddShort(&sl, coord);
1574  SockList_AddChar(&sl, 255); /* Termination byte */
1575  // Reduce dereferences by passing the inner array offset instead of address of value
1576  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1577  }
1578  } else if (darkness >= MAX_LIGHT_RADII) {
1579  /* This block deals with spaces that are not
1580  * visible due to darkness or walls. Still
1581  * need to send the heads for this space.
1582  */
1583  check_space_for_heads(ax, ay, &sl, plyr->socket);
1584  } else {
1585  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1586 
1587  /* In this block, the space is visible. */
1588 
1589  /* Rather than try to figure out what everything
1590  * that we might need to send is, then form the
1591  * packet after that, we presume that we will in
1592  * fact form a packet, and update the bits by what
1593  * we do actually send. If we send nothing, we
1594  * just back out sl.len to the old value, and no
1595  * harm is done.
1596  * I think this is simpler than doing a bunch of
1597  * checks to see what if anything we need to send,
1598  * setting the bits, then doing those checks again
1599  * to add the real data.
1600  */
1601 
1602  oldlen = sl.len;
1603  SockList_AddShort(&sl, coord);
1604 
1605  /* Darkness changed */
1606  if (plyr->socket->lastmap.cells[ax][ay].darkness != darkness
1607  && plyr->socket->darkness) {
1608  plyr->socket->lastmap.cells[ax][ay].darkness = darkness;
1609  /* Darkness tag & length (length=1) */
1610  SockList_AddChar(&sl, MAP2_TYPE_DARKNESS|(1<<5));
1611 
1612  /* Convert darkness level (0-MAX_DARKNESS) to a value
1613  * from 1 (dark) to 255 (bright) for the client.
1614  * Darkness values of 0 (completely dark) are not sent,
1615  * as the space is completely dark.
1616  */
1617  SockList_AddChar(&sl, 255-darkness*(256/MAX_LIGHT_RADII));
1618  have_darkness = 1;
1619  }
1620 
1621  int got_label = 0;
1622  for (layer = 0; layer < MAP_LAYERS; layer++) {
1623  const object *ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1624 
1625  /* Special case: send player itself if invisible */
1626  if (!ob
1627  && x == pl->x
1628  && y == pl->y
1629  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1630  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1631  ob = pl;
1632 
1633  if (ob) {
1634  g1 = has_obj;
1635  old_got = got_one;
1636  got_one += map2_add_ob(ax, ay, layer, ob, &sl, plyr->socket, &has_obj, 0);
1637 
1638  /* if we added the face, or it is a monster's head, check probe spell */
1639  if (got_one != old_got || ob->head == NULL) {
1640  got_one += annotate_ob(ax, ay, ob, &sl, plyr, &has_obj, &alive_layer);
1641  got_label += add_labels(ax, ay, ob, &sl, plyr, &got_one);
1642  }
1643 
1644  /* If we are just storing away the head
1645  * for future use, then effectively this
1646  * space/layer is blank, and we should clear
1647  * it if needed.
1648  */
1649  if (g1 == has_obj) {
1650  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1651  }
1652  } else {
1653  if (layer != alive_layer)
1654  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1655  }
1656  }
1657  if (got_label == 0) {
1658  got_one += map2_add_label(ax, ay, plyr->socket, &sl, MAP2_LABEL_NONE, NULL);
1659  }
1660  /* If nothing to do for this space, we
1661  * can erase the coordinate bytes
1662  */
1663  if (!del_one && !got_one && !have_darkness) {
1664  sl.len = oldlen;
1665  } else if (del_one && !has_obj) {
1666  /* If we're only deleting faces and don't
1667  * have any objs we care about, just clear
1668  * space. Note it is possible we may have
1669  * darkness, but if there is nothing on the
1670  * space, darkness isn't all that interesting
1671  * - we can send it when an object shows up.
1672  */
1673  sl.len = oldlen+2; /* 2 bytes for coordinate */
1675  SockList_AddChar(&sl, 255); /* Termination byte */
1676  // Reduce dereferences by passing the inner array offset instead of address of value
1677  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1678  } else {
1679  SockList_AddChar(&sl, 255); /* Termination byte */
1680  }
1681  }
1682  } /* else this is a viewable space */
1683  } /* for x loop */
1684  } /* for y loop */
1685 
1686  /* Only send this if there are in fact some differences. */
1687  if (sl.len > startlen) {
1688  Send_With_Handling(plyr->socket, &sl);
1689  }
1690  SockList_Term(&sl);
1691 }
1692 
1696 void draw_client_map(object *pl) {
1697  int i, j;
1698  int16_t ax, ay;
1699  int mflags;
1700  mapstruct *m, *pm;
1701  int min_x, min_y, max_x, max_y;
1702 
1703  if (pl->type != PLAYER) {
1704  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1705  return;
1706  }
1707 
1708  if (pl->contr->transport) {
1709  pm = pl->contr->transport->map;
1710  } else
1711  pm = pl->map;
1712 
1713  /* If player is just joining the game, he isn't here yet, so
1714  * the map can get swapped out. If so, don't try to send them
1715  * a map. All will be OK once they really log in.
1716  */
1717  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1718  return;
1719 
1720  /*
1721  * This block just makes sure all the spaces are properly
1722  * updated in terms of what they look like.
1723  */
1724  min_x = pl->x-pl->contr->socket->mapx/2;
1725  min_y = pl->y-pl->contr->socket->mapy/2;
1726  max_x = pl->x+(pl->contr->socket->mapx+1)/2;
1727  max_y = pl->y+(pl->contr->socket->mapy+1)/2;
1728  for (j = min_y; j < max_y; j++) {
1729  for (i = min_x; i < max_x; i++) {
1730  ax = i;
1731  ay = j;
1732  m = pm;
1733  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1734  if (mflags&P_OUT_OF_MAP)
1735  continue;
1736  if (mflags&P_NEED_UPDATE)
1737  update_position(m, ax, ay);
1738  /* If a map is visible to the player, we don't want
1739  * to swap it out just to reload it. This should
1740  * really call something like swap_map, but this is
1741  * much more efficient and 'good enough'
1742  */
1743  if (mflags&P_NEW_MAP)
1744  map_reset_swap(m);
1745  }
1746  }
1747 
1748  /* do LOS after calls to update_position */
1749  if (pl->contr->do_los) {
1750  update_los(pl);
1751  pl->contr->do_los = 0;
1752  }
1753 
1754  draw_client_map2(pl);
1755 }
1756 
1757 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1758  struct Map newmap;
1759  int x, y, mx, my;
1760 
1761  ns->map_scroll_x += dx;
1762  ns->map_scroll_y += dy;
1763 
1764  mx = ns->mapx+MAX_HEAD_OFFSET;
1765  my = ns->mapy+MAX_HEAD_OFFSET;
1766 
1767  /* the x and y here are coordinates for the new map, i.e. if we moved
1768  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1769  * if the destination x or y coordinate is outside the viewable
1770  * area, we clear the values - otherwise, the old values
1771  * are preserved, and the check_head thinks it needs to clear them.
1772  */
1773  for (x = 0; x < mx; x++) {
1774  for (y = 0; y < my; y++) {
1775  if (x >= ns->mapx || y >= ns->mapy) {
1776  /* clear cells outside the viewable area */
1777  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1778  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1779  /* clear newly visible tiles within the viewable area */
1780  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1781  } else {
1782  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1783  }
1784  }
1785  }
1786 
1787  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1788 }
1789 
1795 void send_plugin_custom_message(object *pl, char *buf) {
1796  SockList sl;
1797 
1798  SockList_Init(&sl);
1799  SockList_AddString(&sl, buf);
1800  Send_With_Handling(pl->contr->socket, &sl);
1801  SockList_Term(&sl);
1802 }
1803 
1810  SockList sl;
1811  int flags = 0;
1812  client_spell *spell_info;
1813 
1814  if (!pl->socket || !pl->socket->monitor_spells)
1815  return;
1816 
1817  /* Handles problem at login, where this is called from fix_object
1818  * before we have had a chance to send spells to the player. It does seem
1819  * to me that there should never be a case where update_spells is called
1820  * before add_spells has been called. Add_spells() will update the
1821  * spell_state to non null.
1822  */
1823  if (!pl->spell_state)
1824  return;
1825 
1826  FOR_INV_PREPARE(pl->ob, spell) {
1827  if (spell->type == SPELL) {
1828  spell_info = get_client_spell_state(pl, spell);
1829  /* check if we need to update it*/
1830  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1831  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1832  flags |= UPD_SP_MANA;
1833  }
1834  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1836  flags |= UPD_SP_GRACE;
1837  }
1838  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1839  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1840  flags |= UPD_SP_DAMAGE;
1841  }
1842  if (flags != 0) {
1843  SockList_Init(&sl);
1844  SockList_AddString(&sl, "updspell ");
1845  SockList_AddChar(&sl, flags);
1846  SockList_AddInt(&sl, spell->count);
1847  if (flags&UPD_SP_MANA)
1848  SockList_AddShort(&sl, spell_info->last_sp);
1849  if (flags&UPD_SP_GRACE)
1850  SockList_AddShort(&sl, spell_info->last_grace);
1851  if (flags&UPD_SP_DAMAGE)
1852  SockList_AddShort(&sl, spell_info->last_dam);
1853  flags = 0;
1854  Send_With_Handling(pl->socket, &sl);
1855  SockList_Term(&sl);
1856  }
1857  }
1858  } FOR_INV_FINISH();
1859 }
1860 
1861 void esrv_remove_spell(player *pl, object *spell) {
1862  SockList sl;
1863 
1864  if (!pl || !spell || spell->env != pl->ob) {
1865  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1866  return;
1867  }
1868  if (!pl->socket->monitor_spells)
1869  return;
1870 
1871  SockList_Init(&sl);
1872  SockList_AddString(&sl, "delspell ");
1873  SockList_AddInt(&sl, spell->count);
1874  Send_With_Handling(pl->socket, &sl);
1875  SockList_Term(&sl);
1876 }
1877 
1885  SockList sl;
1886 
1887  if (!pl->socket->want_pickup)
1888  return;
1889  SockList_Init(&sl);
1890  SockList_AddString(&sl, "pickup ");
1891  SockList_AddInt(&sl, pl->mode);
1892  Send_With_Handling(pl->socket, &sl);
1893  SockList_Term(&sl);
1894 }
1895 
1904 static int spell_client_use(const object *spell) {
1905  switch (spell->subtype)
1906  {
1907  case SP_RAISE_DEAD:
1908  case SP_MAKE_MARK:
1909  return 3;
1910  case SP_RUNE:
1911  if (!spell->other_arch)
1912  return 1;
1913  break;
1914  case SP_CREATE_FOOD:
1915  case SP_CREATE_MISSILE:
1916  return 2;
1917  case SP_SUMMON_MONSTER:
1918  if (spell->randomitems != NULL)
1919  return 2;
1920  /* break; */// If add conditins below, use this break statement
1921  }
1922  // This is not in the switch statement so that it supports fallthrough logic
1923  // on the few spell types that have additional conditions attached.
1924  return 0;
1925 }
1926 
1928 static void append_spell(player *pl, SockList *sl, object *spell) {
1929  client_spell *spell_info;
1930  int len, i, skill = 0;
1931 
1932  if (!spell->name) {
1933  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1934  return;
1935  }
1936 
1937  if (spell->face && !(pl->socket->faces_sent[spell->face->number]&NS_FACESENT_FACE))
1938  esrv_send_face(pl->socket, spell->face, 0);
1939 
1940  spell_info = get_client_spell_state(pl, spell);
1941  SockList_AddInt(sl, spell->count);
1942  SockList_AddShort(sl, spell->level);
1943  SockList_AddShort(sl, spell->casting_time);
1944  /* store costs and damage in the object struct, to compare to later */
1945  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1947  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1948  /* send the current values */
1949  SockList_AddShort(sl, spell_info->last_sp);
1950  SockList_AddShort(sl, spell_info->last_grace);
1951  SockList_AddShort(sl, spell_info->last_dam);
1952 
1953  /* figure out which skill it uses, if it uses one */
1954  if (spell->skill) {
1955  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++)
1956  if (!strcmp(spell->skill, skill_names[i])) {
1958  break;
1959  }
1960  }
1961  SockList_AddChar(sl, skill);
1962 
1963  SockList_AddInt(sl, spell->path_attuned);
1964  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1965  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1966 
1967  if (!spell->msg) {
1968  SockList_AddShort(sl, 0);
1969  } else {
1970  len = strlen(spell->msg);
1971  SockList_AddShort(sl, len);
1972  SockList_AddData(sl, spell->msg, len);
1973  }
1974 
1975  /* Extended spell information available if the client wants it.
1976  */
1977  if (pl->socket->monitor_spells >= 2) {
1978  /* spellmon 2
1979  */
1980  sstring req = object_get_value(spell, "casting_requirements");
1981 
1982  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1983 
1984  if (req) { /* Requirements */
1985  SockList_AddLen8Data(sl, req, strlen(req));
1986  } else {
1987  SockList_AddChar(sl, 0);
1988  }
1989  /* end spellmon 2
1990  */
1991  }
1992 }
1993 
1998 void esrv_add_spells(player *pl, object *spell) {
1999  SockList sl;
2000  size_t size;
2001  sstring value;
2002 
2003  if (!pl) {
2004  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
2005  return;
2006  }
2007 
2008  if (!pl->socket->monitor_spells)
2009  return;
2010 
2011  SockList_Init(&sl);
2012  SockList_AddString(&sl, "addspell ");
2013  if (!spell) {
2014  FOR_INV_PREPARE(pl->ob, spell) {
2015  if (spell->type != SPELL)
2016  continue;
2017  /* Were we to simply keep appending data here, we could
2018  * exceed the SockList buffer if the player has enough spells
2019  * to add. We know that append_spell will always append
2020  * 23 data bytes, plus 3 length bytes and 2 strings
2021  * (because that is the spec) so we need to check that
2022  * the length of those 2 strings, plus the 26 bytes,
2023  * won't take us over the length limit for the socket.
2024  * If it does, we need to send what we already have,
2025  * and restart packet formation.
2026  */
2027  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
2028  if (pl->socket->monitor_spells >= 2) {
2030  value = object_get_value(spell, "casting_requirements");
2031  size += 2 + (value ? strlen(value) : 0);
2032  }
2033  if (SockList_Avail(&sl) < size) {
2034  Send_With_Handling(pl->socket, &sl);
2035  SockList_Reset(&sl);
2036  SockList_AddString(&sl, "addspell ");
2037  }
2038  append_spell(pl, &sl, spell);
2039  } FOR_INV_FINISH();
2040  } else if (spell->type != SPELL) {
2041  LOG(llevError, "Asked to send a non-spell object as a spell\n");
2042  return;
2043  } else
2044  append_spell(pl, &sl, spell);
2045  /* finally, we can send the packet */
2046  Send_With_Handling(pl->socket, &sl);
2047  SockList_Term(&sl);
2048 }
2049 
2050 /* sends a 'tick' information to the client.
2051  */
2052 void send_tick(player *pl) {
2053  SockList sl;
2054  SockList_Init(&sl);
2055  SockList_AddString(&sl, "tick ");
2056  SockList_AddInt(&sl, pticks);
2057  Send_With_Handling(pl->socket, &sl);
2058  SockList_Term(&sl);
2059 }
2060 
2073 static void add_char_field(SockList *sl, int type, const char *data)
2074 {
2075  int len;
2076 
2077  len = strlen(data);
2078 
2079  if (len) {
2080  /* one extra for length for the type byte */
2081  SockList_AddChar(sl, len+1);
2082  SockList_AddChar(sl, type);
2083  SockList_AddString(sl, data);
2084  }
2085 }
2086 
2108 {
2109  SockList sl;
2110  int num_chars;
2111  linked_char *extra;
2112 
2113  if (ns->account_chars) {
2115  }
2117 
2118  num_chars = 0;
2119  extra = account_get_additional_chars(ns->account_name, ns->account_chars, &num_chars);
2120 
2121  SockList_Init(&sl);
2122  SockList_AddString(&sl, "accountplayers ");
2123 
2124  SockList_AddChar(&sl, static_cast<char>(ns->account_chars->chars.size() + num_chars));
2125 
2126  /* Now add real character data */
2127  for (auto acn : ns->account_chars->chars) {
2128  uint16_t faceno = 0;
2129 
2130  /* Ignore a dead character. They don't need to show up. */
2131  if (acn->isDead) {
2132  continue;
2133  }
2134 
2135  add_char_field(&sl, ACL_NAME, acn->name);
2136  add_char_field(&sl, ACL_CLASS, acn->character_class);
2137  add_char_field(&sl, ACL_RACE, acn->race);
2138  add_char_field(&sl, ACL_FACE, acn->face);
2139  if (acn->face[0] != 0 ) {
2140  const Face *face = try_find_face(acn->face, NULL);
2141 
2142  if (face != NULL) {
2143  if (!(ns->faces_sent[face->number]&NS_FACESENT_FACE)) {
2144  esrv_send_face(ns, face, 0);
2145  }
2146  faceno = face->number;
2147  }
2148  }
2149 
2150  add_char_field(&sl, ACL_PARTY, acn->party);
2151  add_char_field(&sl, ACL_MAP, acn->map);
2152  SockList_AddChar(&sl, 3);
2154  SockList_AddShort(&sl, acn->level);
2155  if (faceno) {
2156  SockList_AddChar(&sl, 3);
2158  SockList_AddShort(&sl, faceno);
2159  }
2160 
2161  SockList_AddChar(&sl, 0);
2162  }
2163  /* Now for any characters where we just have the name */
2164  for (linked_char *e = extra; e != NULL; e = e->next) {
2165  add_char_field(&sl, ACL_NAME, e->name);
2166  SockList_AddChar(&sl, 0);
2167  }
2168 
2169  Send_With_Handling(ns, &sl);
2170  SockList_Term(&sl);
2171 
2172  if (extra) {
2173  free_charlinks(extra);
2174  }
2175 }
2176 
2198 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2199 {
2200  int nlen, plen;
2201 
2202  if (*len < 2) {
2203  return 1;
2204  }
2205 
2206  nlen = (unsigned char)buf[0];
2207  if (nlen >= MAX_BUF || nlen > *len-2) {
2208  return 1;
2209  }
2210  memcpy(name, buf+1, nlen);
2211  name[nlen] = 0;
2212 
2213  plen = (unsigned char)buf[nlen+1];
2214  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2215  return 2;
2216  }
2217  memcpy(password, buf+2+nlen, plen);
2218  password[plen] = 0;
2219 
2220  *len = nlen+plen+2;
2221 
2222  return 0;
2223 }
2234 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2235  char name[MAX_BUF], password[MAX_BUF];
2236  int status;
2237  SockList sl;
2238 
2239  if (len <= 0 || !buf) {
2240  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2241  return;
2242  }
2243 
2244  SockList_Init(&sl);
2245 
2246  status = decode_name_password(buf, &len, name, password);
2247 
2248  if (status == 1) {
2249  SockList_AddString(&sl, "failure accountlogin Name is too long");
2250  Send_With_Handling(ns, &sl);
2251  SockList_Term(&sl);
2252  return;
2253  }
2254  if (status == 2) {
2255  SockList_AddString(&sl, "failure accountlogin Password is too long");
2256  Send_With_Handling(ns, &sl);
2257  SockList_Term(&sl);
2258  return;
2259  }
2260 
2261  if (!account_exists(name)) {
2262  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2263  Send_With_Handling(ns, &sl);
2264  SockList_Term(&sl);
2265  return;
2266  }
2267 
2268  if (account_login(name, password)) {
2269  LOG(llevInfo, "Account login for '%s' from %s\n", name, ns->host);
2270 
2271  if (ns->account_name) free(ns->account_name);
2272  /* We want to store away official name so we do not
2273  * have any case sensitivity issues on the files.
2274  * because we have already checked password, we
2275  * know that account_exists should never return NULL in
2276  * this case.
2277  */
2279 
2281  } else {
2282  LOG(llevInfo, "Failed account login for '%s' from %s\n", name, ns->host);
2283  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2284  Send_With_Handling(ns, &sl);
2285  SockList_Term(&sl);
2286  }
2287 }
2288 
2297 static int account_block_create(const socket_struct *ns) {
2298  /* Check if account creation is blocked. */
2300  /* Account creation is allowed for everyone. */
2301  return 0;
2302  }
2303 
2304  /* Has the trusted host been defined? */
2305  if(settings.account_trusted_host == NULL) {
2306  /* No, allocate it and set it to localhost now. */
2308  }
2309 
2310  /* Return false if the client connected from the trusted host. */
2311  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2312  return 0;
2313  }
2314 
2315  /*
2316  * If we are here, then we are blocking account create and we do
2317  * not trust this client's IP address.
2318  */
2319  return 1;
2320 }
2321 
2333 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2334  char name[MAX_BUF], password[MAX_BUF];
2335  int status;
2336  SockList sl;
2337 
2338  if (len <= 0 || !buf) {
2339  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2340  return;
2341  }
2342 
2343  SockList_Init(&sl);
2344 
2345  status = decode_name_password(buf, &len, name, password);
2346 
2347  if (account_block_create(ns)) {
2348  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2349  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2350  Send_With_Handling(ns, &sl);
2351  SockList_Term(&sl);
2352  return;
2353  }
2354 
2355  if (status == 1) {
2356  SockList_AddString(&sl, "failure accountnew Name is too long");
2357  Send_With_Handling(ns, &sl);
2358  SockList_Term(&sl);
2359  return;
2360  }
2361  if (status == 2) {
2362  SockList_AddString(&sl, "failure accountnew Password is too long");
2363  Send_With_Handling(ns, &sl);
2364  SockList_Term(&sl);
2365  return;
2366  }
2367  /*The minimum length isn't exactly required, but in the current implementation,
2368  * client will send the same password for character for which there is a
2369  * 2 character minimum size. Thus an account with a one character password
2370  * won't be able to create a character. */
2371  if (strlen(name)<settings.min_name) {
2372  SockList_AddString(&sl, "failure accountnew Name is too short");
2373  Send_With_Handling(ns, &sl);
2374  SockList_Term(&sl);
2375  return;
2376  }
2377  if (strlen(password)<2) {
2378  SockList_AddString(&sl, "failure accountnew Password is too short");
2379  Send_With_Handling(ns, &sl);
2380  SockList_Term(&sl);
2381  return;
2382  }
2383 
2384  if (account_exists(name)) {
2385  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2386  Send_With_Handling(ns, &sl);
2387  SockList_Term(&sl);
2388  return;
2389  }
2390 
2391  status = account_check_string(name);
2392  if (status == 1) {
2393  SockList_AddString(&sl,
2394  "failure accountnew Choose a different account name. " VALIDCHAR_MSG);
2395  Send_With_Handling(ns, &sl);
2396  SockList_Term(&sl);
2397  return;
2398  }
2399 
2400  if (status == 2) {
2401  SockList_AddString(&sl,
2402  "failure accountnew That account name is too long");
2403  Send_With_Handling(ns, &sl);
2404  SockList_Term(&sl);
2405  return;
2406  }
2407 
2408  status = account_check_string(password);
2409  if (status == 1) {
2410  SockList_AddString(&sl,
2411  "failure accountnew Choose a different password. " VALIDCHAR_MSG);
2412  Send_With_Handling(ns, &sl);
2413  SockList_Term(&sl);
2414  return;
2415  }
2416 
2417  if (status == 2) {
2418  SockList_AddString(&sl,
2419  "failure accountnew That password is too long");
2420  Send_With_Handling(ns, &sl);
2421  SockList_Term(&sl);
2422  return;
2423  }
2424 
2425  /* If we got here, we passed all checks - so now add it */
2426  if (ns->account_name) free(ns->account_name);
2428  account_new(name, password);
2429  /* save account information */
2430  accounts_save();
2432 }
2433 
2447 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2448  char name[MAX_BUF], password[MAX_BUF];
2449  int status, force, nlen;
2450  SockList sl;
2451  const char *cp;
2452 
2453  if (len <= 0 || !buf) {
2454  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2455  return;
2456  }
2457 
2458  SockList_Init(&sl);
2459 
2460  if (ns->account_name == NULL) {
2461  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2462  Send_With_Handling(ns, &sl);
2463  SockList_Term(&sl);
2464  return;
2465  }
2466 
2467  force = buf[0];
2468  nlen = len - 1;
2469  status = decode_name_password(buf+1, &nlen, name, password);
2470  if (status == 1) {
2471  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2472  Send_With_Handling(ns, &sl);
2473  SockList_Term(&sl);
2474  return;
2475  }
2476  if (status == 2) {
2477  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2478  Send_With_Handling(ns, &sl);
2479  SockList_Term(&sl);
2480  return;
2481  }
2482 
2483  status = verify_player(name, password);
2484  if (status) {
2485  /* From a security standpoint, telling random folks if it
2486  * it as wrong password makes it easier to hack. However,
2487  * it is fairly easy to determine what characters exist on a server
2488  * (either by trying to create a new one and see if the name is in
2489  * in use, or just looking at the high score file), so this
2490  * really does not make things much less secure
2491  */
2492  if (status == 1)
2493  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2494  else
2495  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2496 
2497  Send_With_Handling(ns, &sl);
2498  SockList_Term(&sl);
2499  return;
2500  }
2501  /* Check to see if this character is associated with an account.
2502  */
2504  if (cp) {
2505  if (!strcmp(cp, ns->account_name)) {
2506  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2507  Send_With_Handling(ns, &sl);
2508  SockList_Term(&sl);
2509  return;
2510  } else {
2511  if (!force) {
2512  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2513  Send_With_Handling(ns, &sl);
2514  SockList_Term(&sl);
2515  return;
2516  } else if (account_is_logged_in(cp)) {
2517  /* We could be clever and try to handle this case, but it is
2518  * trickier. If the character is logged in, it has to
2519  * be logged out. And the socket holds some data which
2520  * needs to be cleaned up. Since it should be fairly
2521  * uncommon that users need to do this, just disallowing
2522  * it makes things a lot simpler.
2523  */
2524  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2525  Send_With_Handling(ns, &sl);
2526  SockList_Term(&sl);
2527  return;
2528  }
2529  }
2530  }
2531  /* If we have gotten this far, the name/password provided is OK,
2532  * and the character is not associated with a different account (or
2533  * force is true). Now try to add the character to this account.
2534  */
2535  status = account_link(ns->account_name, name);
2536 
2537  /* This should never happen, but check for it just in case -
2538  * if we were able to log in, the account should exist. but
2539  * if this fails, need to give the user some clue.
2540  */
2541  if (status==1) {
2542  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2543  Send_With_Handling(ns, &sl);
2544  SockList_Term(&sl);
2545  return;
2546  } else if (status == 2) {
2547  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2548  Send_With_Handling(ns, &sl);
2549  SockList_Term(&sl);
2550  return;
2551  }
2552 
2553  /* If cp is set, then this character used to belong to a different
2554  * account. Remove it now.
2555  */
2556  if (cp) {
2557  Account_Chars *chars;
2558 
2560  chars = account_char_load(cp);
2561  account_char_remove(chars, name);
2562  account_char_save(chars);
2563  account_char_free(chars);
2564  }
2565 
2567 
2568  /* store data so nothing is lost in case of crash */
2570 }
2571 
2576 void account_play_cmd(char *buf, int len, socket_struct *ns)
2577 {
2578  char **chars;
2579  int i;
2580  SockList sl;
2581  player *pl;
2582 
2583  if (len <= 0 || !buf) {
2584  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2585  return;
2586  }
2587 
2588  SockList_Init(&sl);
2589 
2590  if (ns->status != Ns_Add) {
2591  SockList_AddString(&sl, "failure accountplay Not allowed right now");
2592  Send_With_Handling(ns, &sl);
2593  SockList_Term(&sl);
2594  return;
2595  }
2596 
2597  if (!buf[0]) {
2598  SockList_AddString(&sl, "failure accountplay Malformed character name");
2599  Send_With_Handling(ns, &sl);
2600  SockList_Term(&sl);
2601  return;
2602  }
2603 
2604  if (ns->account_name == NULL) {
2605  SockList_AddString(&sl, "failure accountplay Not logged in");
2606  Send_With_Handling(ns, &sl);
2607  SockList_Term(&sl);
2608  return;
2609  }
2610 
2611  /* Make sure a client is not trying to spoof us here */
2613 
2614  for (i=0; chars[i]; i++) {
2615  if (strcmp(chars[i], buf) == 0)
2616  break;
2617  }
2618  if (!chars[i]) {
2619  SockList_AddPrintf(&sl,
2620  "failure accountplay Character %s is not associated with account %s",
2621  buf, ns->account_name);
2622  Send_With_Handling(ns, &sl);
2623  SockList_Term(&sl);
2624  return;
2625  }
2626 
2627  for (pl = first_player; pl; pl = pl->next) {
2628  if (pl->ob && pl->socket != ns && strcmp(buf, pl->ob->name) == 0 && pl->state != ST_PLAY_AGAIN && pl->state != ST_GET_NAME) {
2629  SockList_AddPrintf(&sl,
2630  "failure accountplay Character %s is already playing",
2631  buf);
2632  Send_With_Handling(ns, &sl);
2633  SockList_Term(&sl);
2634  return;
2635  }
2636  }
2637 
2638  /* from a protocol standpoint, accountplay can be used
2639  * before there is a player structure (first login) or after
2640  * (character has logged in and is changing characters).
2641  * Checkthe sockets for that second case - if so,
2642  * we don't need to make a new player object, etc.
2643  */
2644  for (pl=first_player; pl; pl=pl->next) {
2645  if (pl->socket == ns) {
2646  /* The player still in the socket must be saved first. */
2647  save_player(pl->ob, 0);
2648  break;
2649  }
2650  }
2651 
2652  /* Some of this logic is from add_player()
2653  * we just don't use add_player() as it does some other work
2654  * we don't really want to do.
2655  */
2656  if (!pl) {
2657  pl = get_player(NULL);
2658  set_player_socket(pl, ns);
2659  ns->status = Ns_Avail;
2660  ns->account_chars = NULL;
2662  } else {
2663  pl->state = ST_PLAYING;
2664  }
2665 
2666  pl->ob->name = add_string(buf);
2667  check_login(pl->ob, NULL);
2668 
2669  SockList_AddString(&sl, "addme_success");
2670  Send_With_Handling(ns, &sl);
2671  SockList_Term(&sl);
2672 }
2673 
2674 #define MAX_CHOICES 100
2675 
2681 void create_player_cmd(char *buf, int len, socket_struct *ns)
2682 {
2683  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2684  int status, nlen, choice_num=0, i;
2685  SockList sl;
2686  player *pl;
2687  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2688  living new_stats;
2689 
2690  if (len <= 0 || !buf) {
2691  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2692  return;
2693  }
2694 
2695  SockList_Init(&sl);
2696 
2697  if (ns->status != Ns_Add) {
2698  SockList_AddString(&sl, "failure createplayer Not allowed right now");
2699  Send_With_Handling(ns, &sl);
2700  SockList_Term(&sl);
2701  return;
2702  }
2703 
2704  nlen = len;
2705  status = decode_name_password(buf, &nlen, name, password);
2706  if (status == 1) {
2707  SockList_AddString(&sl, "failure createplayer Name is too long");
2708  Send_With_Handling(ns, &sl);
2709  SockList_Term(&sl);
2710  return;
2711  }
2712 
2713  /* Minimum character name limit (if set) */
2714  if (strlen(name)<settings.min_name) {
2715  SockList_AddString(&sl, "failure createplayer Name is too short");
2716  Send_With_Handling(ns, &sl);
2717  SockList_Term(&sl);
2718  return;
2719  }
2720 
2721  if (playername_ok(name) == 0) {
2722  SockList_AddString(&sl, "failure createplayer Player name contains invalid characters");
2723  Send_With_Handling(ns, &sl);
2724  SockList_Term(&sl);
2725  return;
2726  }
2727 
2728  /* 2 characters minimum for password */
2729  if (strlen(password)<2) {
2730  SockList_AddString(&sl, "failure createplayer Password is too short");
2731  Send_With_Handling(ns, &sl);
2732  SockList_Term(&sl);
2733  return;
2734  }
2735 
2737  if (status == 2) {
2738  SockList_AddString(&sl, "failure createplayer Password is too long");
2739  Send_With_Handling(ns, &sl);
2740  SockList_Term(&sl);
2741  return;
2742  }
2743 
2744  /* This is a fairly ugly solution - we're truncating the password.
2745  * however, the password information for characters is really
2746  * a legacy issue - when every character is associated with
2747  * an account, legacy login (character name/password) will get
2748  * removed, at which point the only use for password might be
2749  * to move characters from one account to another, but not sure
2750  * if that is something we want to allow.
2751  */
2752  if (strlen(password)>17)
2753  password[16] = 0;
2754 
2755  /* We just can't call check_name(), since that uses draw_info() to
2756  * report status. We are also more permissive on names, so we use
2757  * account_check_string() - if that is safe for account, also safe
2758  * for player names.
2759  */
2760  if (account_check_string(name)) {
2761  SockList_AddString(&sl, "failure createplayer Choose a different character name. " VALIDCHAR_MSG);
2762  Send_With_Handling(ns, &sl);
2763  SockList_Term(&sl);
2764  return;
2765  }
2766 
2767  /* 1 means no such player, 0 is correct name/password (which in this
2768  * case, is an error), and 2 is incorrect password. Only way we
2769  * go onward is if there is no such player.
2770  */
2771  if (verify_player(name, password) != 1) {
2772  SockList_AddString(&sl, "failure createplayer That name is already in use");
2773  Send_With_Handling(ns, &sl);
2774  SockList_Term(&sl);
2775  return;
2776  }
2777 
2778  /* from a protocol standpoint, accountplay can be used
2779  * before there is a player structure (first login) or after
2780  * (character has logged in and is changing characters).
2781  * Check the sockets for that second case - if so,
2782  * we don't need to make a new player object, etc.
2783  */
2784  for (pl=first_player; pl; pl=pl->next)
2785  if (pl->socket == ns) {
2786  if (pl->ob->name) {
2787  if (!strcmp(pl->ob->name, name)) {
2788  /* For some reason not only the socket is the same but also
2789  * the player is already playing. If this happens at this
2790  * point let's assume the character never was able to apply
2791  * a bet of reality to make a correct first-time save.
2792  * So, for safety remove it and start over.
2793  */
2794  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2795  object_remove(pl->ob);
2796  }
2797  else {
2798  /* If this is a different player on the same socket, then we
2799  * need to make sure that the old one is not connected to the player
2800  *
2801  * This prevents bizarre scenarios where the player is on the map
2802  * multiple times (from multiple createplayer commands), and
2803  * only one of them is controlled by the player.
2804  */
2805  if (pl->ob->contr == pl) {
2806  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2807  object_remove(pl->ob);
2808  }
2809  }
2810  }
2811  break;
2812  }
2813 
2814  /* In this mode, we have additional data
2815  * Note that because there are a lot of failure cases in here
2816  * (where we end up not creating the new player), the code
2817  * to create the new player is done within this routine
2818  * after all checks pass. Note that all of the checks
2819  * done are done without using the player structure,
2820  * as pl may be null right now.
2821  */
2822  if (ns->login_method >= 2) {
2823  int i, j, stat_total=0;
2824  char *key, *value, *race=NULL, *class_name=NULL;
2825 
2826  /* By setting this to zero, then we can easily
2827  * check to see if all stats have been set.
2828  */
2829  memset(&new_stats, 0, sizeof(living));
2830 
2831  while (nlen < len) {
2832  i = buf[nlen]; /* Length of this line */
2833  /* Sanity check from client - don't want to loop
2834  * forever if there is a 0 length, and don't
2835  * want to read beyond size of packet.
2836  * Likewise, client should have sent
2837  * the string to us already null terminated,
2838  * but we will just make sure.
2839  */
2840  if ((i == 0) || (nlen + i > len)) break;
2841  buf[nlen + i] = 0;
2842 
2843  /* What we have are a series of lines -
2844  * 'key value' format. Find that space,
2845  * and null it out so we can do strcasecmp.
2846  * If no space, abort processing
2847  */
2848  key = buf + nlen + 1;
2849  value = strchr(key, ' ');
2850  if (!value) break;
2851  *value = 0;
2852  value++;
2853 
2854  if (!strcasecmp(key,"race")) race = value;
2855  else if (!strcasecmp(key,"class")) class_name = value;
2856  else if (!strcasecmp(key,"starting_map")) {
2857  map = try_find_archetype(value);
2858  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2859  SockList_AddString(&sl,
2860  "failure createplayer Invalid starting map");
2861  Send_With_Handling(ns, &sl);
2862  SockList_Term(&sl);
2863  return;
2864  }
2865  }
2866  else if (!strcasecmp(key,"choice")) {
2867  /* In general, MAX_CHOICES should be large enough
2868  * to always handle the choices from the client - of
2869  * course, the client could be broken and send us many
2870  * more choices than we should have, so handle that.
2871  */
2872  if (choice_num == MAX_CHOICES) {
2873  LOG(llevError,
2874  "Number of choices receive exceed max value: %d>%d\n",
2875  choice_num, MAX_CHOICES);
2876  } else {
2877  choices[choice_num] = value;
2878  choice_num++;
2879  }
2880  }
2881  else {
2882  /* Do stat processing here */
2883  for (j=0; j < NUM_STATS; j++) {
2884  if (!strcasecmp(key,short_stat_name[j])) {
2885  int val = atoi(value);
2886 
2887  set_attr_value(&new_stats, j, val);
2888  break;
2889  }
2890  }
2891  if (j >= NUM_STATS) {
2892  /* Bad clients could do this - we should at least report
2893  * it, and useful when trying to add new parameters.
2894  */
2895  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2896  }
2897  }
2898  nlen += i + 1;
2899  }
2900  /* Do some sanity checking now. But checking the stat
2901  * values here, we will catch any 0 values since we do
2902  * a memset above. A properly behaving client should
2903  * never do any of these things, but we do not presume
2904  * clients will behave properly.
2905  */
2906  for (j=0; j<NUM_STATS; j++) {
2907  int val = get_attr_value(&new_stats, j);
2908 
2909  stat_total += val;
2910  if (val > settings.starting_stat_max ||
2911  val < settings.starting_stat_min) {
2912  SockList_AddPrintf(&sl,
2913  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2915  Send_With_Handling(ns, &sl);
2916  SockList_Term(&sl);
2917  return;
2918  }
2919  }
2920  if (stat_total > settings.starting_stat_points) {
2921  SockList_AddPrintf(&sl,
2922  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2923  stat_total, settings.starting_stat_points);
2924  Send_With_Handling(ns, &sl);
2925  SockList_Term(&sl);
2926  return;
2927  }
2928 
2929  if (race)
2930  race_a = try_find_archetype(race);
2931 
2932  if (class_name)
2933  class_a = try_find_archetype(class_name);
2934 
2935  /* This should never happen with a properly behaving client, so the error message
2936  * doesn't have to be that great.
2937  */
2938  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2939  SockList_AddString(&sl,
2940  "failure createplayer Invalid or unknown race or class");
2941  Send_With_Handling(ns, &sl);
2942  SockList_Term(&sl);
2943  return;
2944  }
2945 
2946  /* At current time, only way this can fail is if the adjusted
2947  * stat is less than 1.
2948  */
2949  if (check_race_and_class(&new_stats, race_a, class_a)) {
2950  SockList_AddString(&sl,
2951  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2952  Send_With_Handling(ns, &sl);
2953  SockList_Term(&sl);
2954  return;
2955  }
2956 
2957  if (!pl)
2959  // If we already have a player, we a replaying on the same connection.
2960  // Since add_player normally sets ns->status, we still need that to happen.
2961  else
2962  ns->status = Ns_Avail;
2963 
2964  // We need to copy the name in before apply_race_and_class() because it
2965  // tells the client our character name. If we don't update it, they get the old one.
2966  FREE_AND_COPY(pl->ob->name, name);
2967 
2968  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2969 
2970  } else {
2971  /* In thise case, old login method */
2972  if (!pl)
2973  pl = add_player(ns, ADD_PLAYER_NEW);
2974  // If we already have a player, we a replaying on the same connection.
2975  // Since add_player normally sets ns->status, we still need that to happen.
2976  else
2977  ns->status = Ns_Avail;
2978 
2979  // Make sure to do this on both code branches.
2980  FREE_AND_COPY(pl->ob->name, name);
2981 /* already done by add_player
2982  roll_again(pl->ob);
2983  pl->state = ST_ROLL_STAT;
2984  set_first_map(pl->ob);*/
2985  }
2986 
2987  /* add_player does a lot of the work, but there are a few
2988  * things we need to update, like starting name and
2989  * password.
2990  * This is done before processing in login_method>2.
2991  * The character creation process it does when
2992  * applying the race/class will use this
2993  * name information.
2994  */
2995  FREE_AND_COPY(pl->ob->name_pl, name);
2996  pl->name_changed = 1;
2997  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
2998 
2999  SockList_AddString(&sl, "addme_success");
3000  Send_With_Handling(ns, &sl);
3001  SockList_Term(&sl);
3002 
3003  if (ns->login_method >= 2) {
3004  /* The client could have provided us a map - if so, map will be set
3005  * and we don't want to overwrite it
3006  */
3007  if (!map)
3009  assert(map); // Existence checked in init_dynamic()
3010 
3011  enter_exit(pl->ob, &map->clone);
3012 
3013  if (pl->ob->map == NULL) {
3014  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
3015  abort();
3016  }
3017 
3018  /* copy information to bed of reality information, in case the player dies */
3019  safe_strncpy(pl->savebed_map, pl->ob->map->path, sizeof(pl->savebed_map));
3020  pl->bed_x = pl->ob->x;
3021  pl->bed_y = pl->ob->y;
3022 
3024  }
3025 
3026  /* We insert any objects after we have put the player on the map -
3027  * this makes things safer, as certain objects may expect a normal
3028  * environment. Note that choice_num will only be set in the
3029  * loginmethod > 2, which also checks (and errors out) if the
3030  * race/class is not set, which is why explicit checking for
3031  * those is not need.
3032  */
3033  for (i=0; i < choice_num; i++) {
3034  char *choiceval;
3035  const char *value, *cp;
3036  archetype *arch;
3037  object *op;
3038 
3039  choiceval = strchr(choices[i], ' ');
3040  if (!choiceval) {
3041  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
3042  continue;
3043  }
3044  *choiceval=0;
3045  choiceval++;
3046  value = object_get_value(&race_a->clone, choices[i]);
3047  if (!value)
3048  value = object_get_value(&class_a->clone, choices[i]);
3049 
3050  if (!value) {
3051  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
3052  continue;
3053  }
3054  cp = strstr(value, choiceval);
3055  if (!cp) {
3056  LOG(llevError, "Choice value not found in archetype: %s %s\n",
3057  choices[i], choiceval);
3058  continue;
3059  }
3060 
3061  /* Check to make sure that the matched string is an entire word,
3062  * and not a substring (eg, valid choice being great_sword but
3063  * we just get sword) - the space after the match should either be a
3064  * space or null, and space before match should also be a space
3065  * or the start of the string.
3066  */
3067  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
3068  (cp != value) && (*(cp-1) != ' ')) {
3069 
3070  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
3071  choiceval, value);
3072  continue;
3073  }
3074  arch = try_find_archetype(choiceval);
3075  if (!arch) {
3076  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
3077  continue;
3078  }
3079  op = arch_to_object(arch);
3080  op = object_insert_in_ob(op, pl->ob);
3081  if (QUERY_FLAG(op, FLAG_AUTO_APPLY))
3082  ob_apply(op, pl->ob, 0);
3083  }
3084 
3085  LOG(llevInfo, "new character %s from %s\n", pl->ob->name, pl->ob->contr->socket->host);
3088  "%s has entered the game.", pl->ob->name);
3089 }
3090 
3101 void account_password(char *buf, int len, socket_struct *ns) {
3102  char old[MAX_BUF], change[MAX_BUF];
3103  int status;
3104  SockList sl;
3105 
3106  if (len <= 0 || !buf) {
3107  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
3108  return;
3109  }
3110 
3111  SockList_Init(&sl);
3112 
3113  if (ns->account_name == NULL) {
3114  SockList_AddString(&sl, "failure accountpw Not logged in");
3115  Send_With_Handling(ns, &sl);
3116  SockList_Term(&sl);
3117  return;
3118  }
3119 
3120  status = decode_name_password(buf, &len, old, change);
3121  if (status == 1) {
3122  SockList_AddString(&sl, "failure accountpw Old password is too long");
3123  Send_With_Handling(ns, &sl);
3124  SockList_Term(&sl);
3125  return;
3126  }
3127  if (status == 2) {
3128  SockList_AddString(&sl, "failure accountpw New password is too long");
3129  Send_With_Handling(ns, &sl);
3130  SockList_Term(&sl);
3131  return;
3132  }
3133  /*The minimum length isn't exactly required, but in the current implementation,
3134  * client will send the same password for character for which there is a
3135  * 2 character minimum size. Thus an account with a one character password
3136  * won't be able to create a character. */
3137  if (strlen(change)<2) {
3138  SockList_AddString(&sl, "failure accountpw New password is too short");
3139  Send_With_Handling(ns, &sl);
3140  SockList_Term(&sl);
3141  return;
3142  }
3143 
3144  status = account_check_string(change);
3145  if (status == 1) {
3146  SockList_AddString(&sl,
3147  "failure accountpw Choose a different password. " VALIDCHAR_MSG);
3148  Send_With_Handling(ns, &sl);
3149  SockList_Term(&sl);
3150  return;
3151  }
3152 
3153  if (status == 2) {
3154  SockList_AddString(&sl,
3155  "failure accountpw That password is too long");
3156  Send_With_Handling(ns, &sl);
3157  SockList_Term(&sl);
3158  return;
3159  }
3160 
3161  status = account_change_password(ns->account_name, old, change);
3162  if (status != 0) {
3163  const char *error;
3164 
3165  if (status == 1) {
3166  error = "failure accountpw Illegal characters present";
3167  } else if (status == 2) {
3168  error = "failure accountpw Invalid account";
3169  } else {
3170  error = "failure accountpw Incorrect current password";
3171  }
3172 
3173  SockList_AddString(&sl, error);
3174  Send_With_Handling(ns, &sl);
3175  SockList_Term(&sl);
3176  return;
3177  }
3178 
3179  /* If we got here, we passed all checks, and password was changed */
3181 }
find_player_socket
player * find_player_socket(const socket_struct *ns)
Return a player for a socket structure.
Definition: player.cpp:123
ADD_PLAYER_NO_STATS_ROLL
#define ADD_PLAYER_NO_STATS_ROLL
Stats provided from client.
Definition: player.h:254
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
SF_FIREON
#define SF_FIREON
Definition: newclient.h:193
CF_BLIND
#define CF_BLIND
Blind.
Definition: newclient.h:204
account_add_player_cmd
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:2447
CLASS
@ CLASS
Object for applying character class modifications to someone.
Definition: object.h:143
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
CS_STAT_RES_DEPLETE
#define CS_STAT_RES_DEPLETE
Definition: newclient.h:166
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
player::do_los
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:143
player::bed_y
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:113
living::exp
int64_t exp
Experience.
Definition: living.h:47
MAP_CLIENT_X
#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
CF_STEALTHY
#define CF_STEALTHY
Player is stealthy.
Definition: newclient.h:209
socket_struct::tick
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:111
atnr_cs_stat
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
PLAYER
@ PLAYER
Definition: object.h:112
MAP_CLIENT_X_MINIMUM
#define MAP_CLIENT_X_MINIMUM
Definition: config.h:245
player::next
player * next
Pointer to next player, NULL if this is last.
Definition: player.h:108
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
global.h
ANIM_SYNC
#define ANIM_SYNC
Definition: newclient.h:352
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:142
socket_struct::sc_version
uint32_t sc_version
Versions of the client.
Definition: newserver.h:118
first_player
player * first_player
First player.
Definition: init.cpp:106
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
CS_STAT_RACE_CON
#define CS_STAT_RACE_CON
Definition: newclient.h:125
print_ext_msg
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
CS_STAT_GRACE
#define CS_STAT_GRACE
Definition: newclient.h:113
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
find_smooth
int find_smooth(const Face *face, const Face **smoothed)
Find the smooth face for a given face.
Definition: image.cpp:102
MAP
@ MAP
Definition: object.h:130
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
socket_struct::heartbeat
bool heartbeat
Client will send hearbeats.
Definition: newserver.h:117
SockList_AddInt64
void SockList_AddInt64(SockList *sl, uint64_t data)
Adds a 64 bit value.
Definition: lowlevel.cpp:140
ACL_FACE_NUM
#define ACL_FACE_NUM
Definition: newclient.h:228
CAN_PROBE
static bool CAN_PROBE(const object *ob)
Determine whether the given object can have an HP bar.
Definition: object.h:616
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:531
send_account_players
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:2107
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
CS_STAT_APPLIED_WIS
#define CS_STAT_APPLIED_WIS
WIS changes from gear or skills.
Definition: newclient.h:137
MAP2_COORD_MAX
static const int MAP2_COORD_MAX
Definition: request.cpp:74
ssop_t
int ssop_t
Parameter type for setsockopt, different between WIN32 and Linux.
Definition: request.cpp:58
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:500
player::mode
uint32_t mode
Mode of player for pickup.
Definition: player.h:125
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
send_query
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Asks the client to query the user.
Definition: request.cpp:749
Map
One map for a player.
Definition: newserver.h:52
account_play_cmd
void account_play_cmd(char *buf, int len, socket_struct *ns)
We have received an accountplay command.
Definition: request.cpp:2576
player::last_golem_hp
int16_t last_golem_hp
Last golem hp value sent to the client.
Definition: player.h:177
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
new_player_cmd
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
client_spell
This stores, for a spell a player knows, the last sp/gr/dam information sent to client.
Definition: player.h:87
CS_STAT_RES_FEAR
#define CS_STAT_RES_FEAR
Definition: newclient.h:165
MAP2_COORD_OFFSET
#define MAP2_COORD_OFFSET
How much the x,y coordinates in the map2 are off from actual upper left corner.
Definition: newclient.h:32
ST_GET_NAME
#define ST_GET_NAME
Player just connected.
Definition: define.h:530
player
One player.
Definition: player.h:107
CS_STAT_DAM
#define CS_STAT_DAM
Definition: newclient.h:105
strdup_local
#define strdup_local
Definition: compat.h:29
ACL_RACE
#define ACL_RACE
Definition: newclient.h:223
player::golem_count
uint32_t golem_count
To track the golem.
Definition: player.h:121
CS_STAT_RES_FIRE
#define CS_STAT_RES_FIRE
Definition: newclient.h:154
ask_smooth_cmd
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
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
newhash
char const * newhash(char const *password)
Definition: server.cpp:101
socket_struct::sound
uint32_t sound
Client sound mode.
Definition: newserver.h:116
command
same as sound ncom command like but with extra the client want tick commands so it knows animation timing the client wants to be informed of pickup mode changes Mode will be sent when the player successfully logs and afterward any time the value is but over many options have become defaults This documents those now obsolete client can handle the bit exp values that are now used values are sent as bit Setting this flag also means that skill exp will be and it will be sent in revised method as described in the stats command Value is an integer in string format else Deprecated client should presume all servers support this server will return FALSE Deprecated replaced with sound2 setup command
Definition: protocol.txt:461
account_get_additional_chars
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
CS_STAT_APPLIED_POW
#define CS_STAT_APPLIED_POW
POW changes from gear or skills.
Definition: newclient.h:141
CS_STAT_HP
#define CS_STAT_HP
Definition: newclient.h:91
socket_struct
Socket structure, represents a client-server connection.
Definition: newserver.h:93
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:121
player::spell_state
client_spell * spell_state
Spell information sent to client.
Definition: player.h:217
get_skill_client_code
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
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:532
FLAG_PARALYZED
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:358
MAP_LAYER_LIVING1
#define MAP_LAYER_LIVING1
Living creatures.
Definition: map.h:46
map2_delete_layer
static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns)
Definition: request.cpp:1262
update_position
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
MAX_NUM_LOOK_OBJECTS
#define MAX_NUM_LOOK_OBJECTS
The upper bound for the number of objects to send for the 'look' window (container or ground view).
Definition: newserver.h:28
MAP2_COORD_MIN
static const int MAP2_COORD_MIN
Definition: request.cpp:73
socket_struct::num_look_objects
uint8_t num_look_objects
The maximum number of objects to show on the ground view; this number includes the prev/next group fa...
Definition: newserver.h:127
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
player::bed_x
int16_t bed_x
Definition: player.h:113
command_execute
void command_execute(object *pl, char *command)
Handle a player-issued command.
Definition: commands.cpp:456
AddIfInt64
#define AddIfInt64(Old, New, sl, Type)
Definition: request.cpp:758
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
MAX_TIME
#define MAX_TIME
If you feel the game is too fast or too slow, change MAX_TIME.
Definition: config.h:254
CS_STAT_SPELL_DENY
#define CS_STAT_SPELL_DENY
Definition: newclient.h:120
account_get_players_for_account
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
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
accounts_save
void accounts_save(void)
Save all the account information.
Definition: account.cpp:255
living::Dex
int8_t Dex
Definition: living.h:36
object::x
int16_t x
Definition: object.h:335
CS_STAT_WIS
#define CS_STAT_WIS
Definition: newclient.h:97
player::peaceful
uint32_t peaceful
If set, won't attack friendly creatures.
Definition: player.h:148
player::ob
object * ob
The object representing the player.
Definition: player.h:179
player::transport
object * transport
Transport the player is in.
Definition: player.h:216
map_cell_struct::label_text
sstring label_text
Definition: newserver.h:35
reply_cmd
void reply_cmd(char *buf, int len, player *pl)
This is a reply to a previous query.
Definition: request.cpp:589
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:129
CS_STAT_SPEED
#define CS_STAT_SPEED
Definition: newclient.h:107
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
socket_struct::extended_stats
uint32_t extended_stats
Client wants base and maximum statistics information.
Definition: newserver.h:114
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:96
append_spell
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:1928
player::last_applied_stats
living last_applied_stats
Last applied stats sent to the client.
Definition: player.h:174
Settings::min_name
uint8_t min_name
Minimum characters for an account or player name.
Definition: global.h:331
SK_PRAYING
@ SK_PRAYING
Praying.
Definition: skills.h:49
CS_STAT_MAXSP
#define CS_STAT_MAXSP
Definition: newclient.h:94
player::levhp
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:188
ST_CHANGE_PASSWORD_NEW
#define ST_CHANGE_PASSWORD_NEW
Player is entering new password.
Definition: define.h:535
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
MIN
#define MIN(x, y)
Definition: compat.h:21
MAP2_LABEL_SIGN
@ MAP2_LABEL_SIGN
Definition: newclient.h:62
CS_STAT_BASE_DEX
#define CS_STAT_BASE_DEX
Definition: newclient.h:131
CS_STAT_RES_MAG
#define CS_STAT_RES_MAG
Definition: newclient.h:153
FIF
#define FIF(F, C)
MAP_LAYERS
#define MAP_LAYERS
This correspondes to the map layers in the map2 protocol.
Definition: map.h:32
player::last_path_denied
uint32_t last_path_denied
Last spell denied sent to client.
Definition: player.h:164
Settings::starting_stat_min
uint8_t starting_stat_min
Minimum value of a starting stat.
Definition: global.h:321
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
client_spell::last_sp
int16_t last_sp
Last spell cost.
Definition: player.h:89
socket_struct::is_bot
uint32_t is_bot
Client shouldn't be reported to metaserver.
Definition: newserver.h:112
get_player
player * get_player(player *p)
Create a player's object, initialize a player's structure.
Definition: player.cpp:285
send_extra_stats
static void send_extra_stats(SockList *sl, player *pl)
Send extra stats for the player, if 'notification' is 3.
Definition: request.cpp:814
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
flags
static const flag_definition flags[]
Flag mapping.
Definition: gridarta-types-convert.cpp:101
FLAG_XRAYS
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:287
CS_STAT_SP
#define CS_STAT_SP
Definition: newclient.h:93
SP_CREATE_FOOD
#define SP_CREATE_FOOD
Definition: spells.h:96
ACL_NAME
#define ACL_NAME
Definition: newclient.h:221
player::last_level
int8_t last_level
Last level we sent to client.
Definition: player.h:136
object::smoothlevel
uint8_t smoothlevel
how to smooth this square around
Definition: object.h:433
player::levsp
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:189
CS_STAT_RES_HOLYWORD
#define CS_STAT_RES_HOLYWORD
Definition: newclient.h:168
annotate_ob
static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer)
Definition: request.cpp:1399
player::savebed_map
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:112
ST_PLAYING
#define ST_PLAYING
Usual state.
Definition: define.h:525
MAP_TYPE_DEFAULT
#define MAP_TYPE_DEFAULT
If no map is specified, where character starts.
Definition: map.h:60
CS_STAT_GOLEM_HP
#define CS_STAT_GOLEM_HP
Golem's current hp, 0 if no golem.
Definition: newclient.h:142
CS_STAT_RES_CONF
#define CS_STAT_RES_CONF
Definition: newclient.h:157
NDI_RED
#define NDI_RED
Definition: newclient.h:249
MAX_HEAD_OFFSET
#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
player::last_stats
living last_stats
Last stats as sent to client.
Definition: player.h:170
account_link
int account_link(const char *account_name, const char *player_name)
Adds a player name to an account.
Definition: account.cpp:444
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:47
socket_struct::inbuf
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:103
CS_STAT_TURN_UNDEAD
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:164
ACL_CLASS
#define ACL_CLASS
Definition: newclient.h:222
SP_CREATE_MISSILE
#define SP_CREATE_MISSILE
Definition: spells.h:113
CF_NOT_PERFECT
#define CF_NOT_PERFECT
Can drink some improvement potions.
Definition: newclient.h:207
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:15
FLAG_STEALTH
#define FLAG_STEALTH
Will wake monsters with less range.
Definition: define.h:299
receive_play_again
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.cpp:962
set_player_socket
void set_player_socket(player *p, socket_struct *ns)
This copies the data from the socket into the player structure.
Definition: player.cpp:421
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can't use command.
Definition: newclient.h:533
map_clearcell
static void map_clearcell(struct map_cell_struct *cell, int face, int darkness)
Clears a map cell.
Definition: request.cpp:1076
CS_STAT_EXP64
#define CS_STAT_EXP64
Definition: newclient.h:117
map2_coord_valid
static bool map2_coord_valid(int x)
Definition: request.cpp:76
range_golem
@ range_golem
Control golem.
Definition: player.h:34
send_plugin_custom_message
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:1795
SockList_Reset
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.cpp:74
CS_STAT_CHARACTER_FLAGS
#define CS_STAT_CHARACTER_FLAGS
Character flags, like 'confused' and such.
Definition: newclient.h:144
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:358
socket_struct::map_scroll_x
int8_t map_scroll_x
Definition: newserver.h:98
set_up_cmd
void set_up_cmd(char *buf, int len, socket_struct *ns)
This is the Setup cmd - easy first implementation.
Definition: request.cpp:143
UPD_SP_MANA
#define UPD_SP_MANA
updspell command flag value.
Definition: newclient.h:328
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
map2_label
map2_label
Map label subtypes.
Definition: newclient.h:56
player::applied_stats
living applied_stats
Stat changes due to gear or skills.
Definition: player.h:173
heads
static const object * heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS]
Using a global really isn't a good approach, but saves the over head of allocating and deallocating s...
Definition: request.cpp:1090
pticks
uint32_t pticks
Number of ticks since time reset.
Definition: time.cpp:47
buf
StringBuffer * buf
Definition: readable.cpp:1565
key_confirm_quit
void key_confirm_quit(object *op, char key)
We receive the reply to the 'quit confirmation' message.
Definition: player.cpp:1600
CS_STAT_APPLIED_DEX
#define CS_STAT_APPLIED_DEX
DEX changes from gear or skills.
Definition: newclient.h:138
add_player
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.cpp:469
object_insert_in_ob
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
POISONING
@ POISONING
Definition: object.h:223
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:408
MAX
#define MAX(x, y)
Definition: compat.h:24
CS_STAT_RACE_STR
#define CS_STAT_RACE_STR
Definition: newclient.h:121
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
CS_STAT_GOLEM_MAXHP
#define CS_STAT_GOLEM_MAXHP
Golem's max hp, 0 if no golem.
Definition: newclient.h:143
SND_EFFECTS
#define SND_EFFECTS
Those flags are for the 'socket.sound' field.
Definition: sounds.h:12
MAP2_LABEL_PLAYER_PARTY
@ MAP2_LABEL_PLAYER_PARTY
Definition: newclient.h:59
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
ACL_MAP
#define ACL_MAP
Definition: newclient.h:227
linked_char
Definition: global.h:98
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
Account_Chars::chars
std::vector< Account_Char * > chars
Characters of the account.
Definition: account_char.h:30
object::path_denied
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
socket_struct::update_look
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:109
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.cpp:246
GetShort_String
short GetShort_String(const unsigned char *data)
Definition: lowlevel.cpp:258
short_stat_name
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.cpp:194
SP_SUMMON_MONSTER
#define SP_SUMMON_MONSTER
Definition: spells.h:101
UPD_SP_DAMAGE
#define UPD_SP_DAMAGE
updspell command flag value.
Definition: newclient.h:330
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
object::path_repelled
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:354
m
static event_registration m
Definition: citylife.cpp:424
AddIfShort
#define AddIfShort(Old, New, sl, Type)
Definition: request.cpp:772
socket_struct::account_chars
Account_Chars * account_chars
Detailed information on characters on this account.
Definition: newserver.h:132
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:536
esrv_send_animation
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Need to send an animation sequence to the client.
Definition: request.cpp:1042
VALIDCHAR_MSG
#define VALIDCHAR_MSG
Definition: request.cpp:71
socket_struct::mapy
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:121
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
socket_struct::stats
struct statsinfo stats
Definition: newserver.h:102
Ns_Avail
@ Ns_Avail
Definition: newserver.h:69
CS_STAT_RACE_DEX
#define CS_STAT_RACE_DEX
Definition: newclient.h:124
CS_STAT_ARMOUR
#define CS_STAT_ARMOUR
Definition: newclient.h:106
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
set_title
void set_title(const object *pl, char *buf, size_t len)
Sets player title.
Definition: info.cpp:335
clamp
static int clamp(int x, int min, int max)
Definition: request.cpp:96
map_cell_struct
One map cell, as sent to the client.
Definition: newserver.h:31
MAP_CLIENT_Y
#define MAP_CLIENT_Y
Definition: config.h:238
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:526
CS_STAT_SPELL_REPEL
#define CS_STAT_SPELL_REPEL
Definition: newclient.h:119
CS_STAT_RACE_CHA
#define CS_STAT_RACE_CHA
Definition: newclient.h:126
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Arrows, etc.
Definition: map.h:49
MAP2_ADD_LENGTH
#define MAP2_ADD_LENGTH
Definition: newclient.h:68
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
player::last_speed
float last_speed
Last speed as sent to client.
Definition: player.h:175
add_refcount
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
CS_STAT_LEVEL
#define CS_STAT_LEVEL
Definition: newclient.h:102
player::run_on
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:145
CS_STAT_CON
#define CS_STAT_CON
Definition: newclient.h:99
account_new_cmd
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:2333
object::anim_speed
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:429
account_login_cmd
void account_login_cmd(char *buf, int len, socket_struct *ns)
Handles the account login.
Definition: request.cpp:2234
playername_ok
int playername_ok(const char *cp)
Is the player name valid.
Definition: player.cpp:257
esrv_send_face
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
client_spell::last_dam
int16_t last_dam
Last damage.
Definition: player.h:91
ACL_PARTY
#define ACL_PARTY
Definition: newclient.h:226
CS_STAT_CHA
#define CS_STAT_CHA
Definition: newclient.h:100
CS_STAT_APPLIED_CHA
#define CS_STAT_APPLIED_CHA
CHA changes from gear or skills.
Definition: newclient.h:140
CS_STAT_RES_SLOW
#define CS_STAT_RES_SLOW
Definition: newclient.h:162
add_labels
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:1418
socket_struct::facecache
uint32_t facecache
If true, client is caching images.
Definition: newserver.h:107
check_race_and_class
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:1436
player::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:180
check_login
void check_login(object *op, const char *password)
Actually login a player, load from disk and such.
Definition: login.cpp:522
object::weapon_speed
float weapon_speed
The overall speed of this object.
Definition: object.h:339
CS_STAT_BASE_POW
#define CS_STAT_BASE_POW
Definition: newclient.h:134
player::last_flags
uint16_t last_flags
Fire/run on flags for last tick.
Definition: player.h:159
account_get_account_for_char
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
CS_STAT_RES_PHYS
#define CS_STAT_RES_PHYS
Definition: newclient.h:152
Settings::account_block_create
uint8_t account_block_create
Definition: global.h:328
CS_STAT_GOD_NAME
#define CS_STAT_GOD_NAME
Name of the god the character worships.
Definition: newclient.h:145
Face::number
uint16_t number
This is the image unique identifier.
Definition: face.h:15
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:118
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:253
map_cell_struct::darkness
int darkness
Cell's darkness.
Definition: newserver.h:33
socket_struct::client
sstring client
Client string sent by client.
Definition: newserver.h:105
account_char_free
void account_char_free(Account_Chars *chars)
This frees all data associated with the character information.
Definition: account_char.cpp:345
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
MAP2_LABEL_NONE
@ MAP2_LABEL_NONE
Definition: newclient.h:57
send_smooth
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
handle_scroll
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
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
draw_client_map
void draw_client_map(object *pl)
Draws client map.
Definition: request.cpp:1696
account_remove_player
int account_remove_player(const char *account_name, const char *player_name)
Removes a player name from an account.
Definition: account.cpp:474
treasurelist::name
sstring name
Usually monster-name/combination.
Definition: treasure.h:86
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
MAX_HEAD_POS
#define MAX_HEAD_POS
Definition: request.cpp:1081
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.cpp:116
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:259
ANIM_RANDOM
#define ANIM_RANDOM
Definition: newclient.h:351
CS_STAT_BASE_CHA
#define CS_STAT_BASE_CHA
Definition: newclient.h:133
object_find_by_type_and_name
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
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
set_attr_value
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
player::last_path_attuned
uint32_t last_path_attuned
Last spell attunment sent to client.
Definition: player.h:162
socket_struct::lastmap
struct Map lastmap
Definition: newserver.h:97
CF_POISONED
#define CF_POISONED
Poisoned.
Definition: newclient.h:203
MAP2_LAYER_START
#define MAP2_LAYER_START
Definition: newclient.h:67
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:228
object::face
const Face * face
Face with colors.
Definition: object.h:341
player::last_character_flags
uint32_t last_character_flags
Last character flags (CS_STAT_CHARACTER_FLAGS) sent to client.
Definition: player.h:165
CS_STAT_APPLIED_STR
#define CS_STAT_APPLIED_STR
STR changes from gear or skills.
Definition: newclient.h:135
socket_struct::host
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
player::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Last exp sent to client.
Definition: player.h:156
ST_ROLL_STAT
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:527
CS_STAT_RACE_POW
#define CS_STAT_RACE_POW
Definition: newclient.h:127
account_password
void account_password(char *buf, int len, socket_struct *ns)
Handles the account password change.
Definition: request.cpp:3101
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1757
GET_MAP_FACE_OBJ
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Gets the layer face of specified square.
Definition: map.h:185
socket_struct::account_name
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:131
MAP2_TYPE_LABEL
#define MAP2_TYPE_LABEL
Definition: newclient.h:44
player::levgrace
int8_t levgrace[11]
What grace bonus the player gained on that level.
Definition: player.h:190
CS_STAT_AC
#define CS_STAT_AC
Definition: newclient.h:104
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
client_spell::last_grace
int16_t last_grace
Last grace cost.
Definition: player.h:90
check_space_for_heads
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.cpp:1455
CS_STAT_OVERLOAD
#define CS_STAT_OVERLOAD
How much (0 to 1) the character is overloaded.
Definition: newclient.h:146
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
MAP_TYPE_CHOICE
#define MAP_TYPE_CHOICE
Choice of maps presented to player.
Definition: map.h:61
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
CS_STAT_WEAP_SP
#define CS_STAT_WEAP_SP
Definition: newclient.h:109
socket_struct::monitor_spells
uint32_t monitor_spells
Client wishes to be informed when their spell list changes.
Definition: newserver.h:115
CS_STAT_APPLIED_CON
#define CS_STAT_APPLIED_CON
CON changes from gear or skills.
Definition: newclient.h:139
esrv_update_spells
void esrv_update_spells(player *pl)
This looks for any spells the player may have that have changed their stats.
Definition: request.cpp:1809
skill_names
const char * skill_names[MAX_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.cpp:57
map_cell_struct::faces
uint16_t faces[MAP_LAYERS]
Face numbers.
Definition: newserver.h:32
socket_struct::faceset
uint8_t faceset
Set the client is using, default 0.
Definition: newserver.h:122
spell
with a maximum of six This is not so if you are wearing plate you receive no benefit Armour is additive with all the supplementry forms of which means that it lasts until the next semi permanent spell effect is cast upon the character spell
Definition: tome-of-magic.txt:44
CS_STAT_RES_GHOSTHIT
#define CS_STAT_RES_GHOSTHIT
Definition: newclient.h:160
linked_char::next
struct linked_char * next
Definition: global.h:100
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
Definition: newclient.h:176
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:661
account_new
int account_new(const char *account_name, const char *account_password)
Adds an account.
Definition: account.cpp:399
player::item_power
int16_t item_power
Total item power of objects equipped.
Definition: player.h:132
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
P_NEED_UPDATE
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:242
CS_STAT_RES_BLIND
#define CS_STAT_RES_BLIND
Definition: newclient.h:169
ST_CONFIRM_QUIT
#define ST_CONFIRM_QUIT
Player used the 'quit' command, make sure that's ok.
Definition: define.h:529
CF_DISEASED
#define CF_DISEASED
Has at least one disease.
Definition: newclient.h:206
MAP2_TYPE_DARKNESS
#define MAP2_TYPE_DARKNESS
Definition: newclient.h:43
socket_struct::map_scroll_y
int8_t map_scroll_y
Definition: newserver.h:98
MAP2_COORD_ENCODE
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
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:252
statsinfo::title
char * title
Definition: newserver.h:61
sproto.h
player::last_weight_limit
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:161
CS_STAT_RACE_INT
#define CS_STAT_RACE_INT
Definition: newclient.h:122
living::sp
int16_t sp
Spell points.
Definition: living.h:42
SND_MUTE
#define SND_MUTE
Don't sent anything for now.
Definition: sounds.h:14
MAX_SKILLS
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
get_map_from_coord
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
VERSION_SC
#define VERSION_SC
Definition: newserver.h:155
get_face_by_id
const Face * get_face_by_id(uint16_t id)
Get a face from its unique identifier.
Definition: assets.cpp:319
player::last_race_stats
living last_race_stats
Last race stats sent to the client.
Definition: player.h:172
living::Int
int8_t Int
Definition: living.h:36
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it's increased effectiveness.
Definition: spell_util.cpp:236
account_is_logged_in
int account_is_logged_in(const char *name)
This checkes if an account is logged in.
Definition: account.cpp:604
object::animation
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:428
player::fire_on
uint32_t fire_on
Player should fire object, not move.
Definition: player.h:144
SockList_Init
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
SockList::len
size_t len
Definition: newclient.h:690
CS_STAT_BASE_WIS
#define CS_STAT_BASE_WIS
Definition: newclient.h:130
is_perfect
static uint8_t is_perfect(const player *pl)
Check whether the player is perfect relatively to improvement potions.
Definition: request.cpp:799
weight
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be and may attack the nearest of your enemies Others can be in that they follow you around and help you in your quest to kill enemies and find treasure SPECIAL ITEMS There are many special items which can be found in of these the most important may be the signs all a player must do is apply the handle In the case of the player must move items over the button to hold it down Some of the larger buttons may need very large items to be moved onto before they can be activated Gates and locked but be for you could fall down into a pit full of ghosts or dragons and not be able to get back out Break away sometimes it may be worth a player s time to test the walls of a map for secret doors Fire such as missile weapons and spells you will notice them going up in smoke ! So be careful not to destroy valuable items Spellbooks sometimes a player can learn the other times they cannot There are many different types of books and scrolls out there Improve item have lower weight
Definition: survival-guide.txt:100
CS_STAT_FOOD
#define CS_STAT_FOOD
Definition: newclient.h:108
socket_struct::cs_version
uint32_t cs_version
Definition: newserver.h:118
player::last_item_power
uint16_t last_item_power
Last value for item_power.
Definition: player.h:166
Animations::num_animations
uint8_t num_animations
How many different faces to animate, size of the faces array.
Definition: face.h:27
living
Various statistics of objects.
Definition: living.h:35
player::last_skill_ob
object * last_skill_ob[MAX_SKILLS]
Exp objects sent to client.
Definition: player.h:155
CS_STAT_WEIGHT_LIM
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:116
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
player::last_weight
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:160
Ns_Add
@ Ns_Add
Definition: newserver.h:70
CS_STAT_ITEM_POWER
#define CS_STAT_ITEM_POWER
Equipped item power.
Definition: newclient.h:147
CS_STAT_RES_POISON
#define CS_STAT_RES_POISON
Definition: newclient.h:161
receive_player_name
void receive_player_name(object *op, const char *name)
A player just entered her name.
Definition: c_misc.cpp:1935
is_valid_faceset
int is_valid_faceset(int fsn)
Checks specified faceset is valid.
Definition: image.cpp:117
CS_STAT_WC
#define CS_STAT_WC
Definition: newclient.h:103
object::head
object * head
Points to the main object of a large body.
Definition: object.h:304
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h:252
player::orig_stats
living orig_stats
Permanent real stats of player.
Definition: player.h:169
object_present_in_ob
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
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
map2_add_label
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:1358
SockList_Term
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
player::last_golem_maxhp
int16_t last_golem_maxhp
Last golem max hp value sent to the client.
Definition: player.h:178
AddIfInt
#define AddIfInt(Old, New, sl, Type)
Definition: request.cpp:765
probe
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Try to get information about a living thing.
Definition: spell_effect.cpp:699
CS_STAT_MAXGRACE
#define CS_STAT_MAXGRACE
Definition: newclient.h:114
key_roll_stat
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.cpp:1219
MAP2_TYPE_CLEAR
#define MAP2_TYPE_CLEAR
Definition: newclient.h:42
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
ST_CHANGE_PASSWORD_OLD
#define ST_CHANGE_PASSWORD_OLD
Player is entering old password to change password.
Definition: define.h:534
Settings::starting_stat_points
uint8_t starting_stat_points
How many stat points character starts with.
Definition: global.h:323
living::Wis
int8_t Wis
Definition: living.h:36
Settings
Server settings.
Definition: global.h:241
create_player_cmd
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.cpp:2681
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:95
apply_race_and_class
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:1486
CS_STAT_BASE_INT
#define CS_STAT_BASE_INT
Definition: newclient.h:129
sounds.h
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:528
CS_STAT_SPELL_ATTUNE
#define CS_STAT_SPELL_ATTUNE
Definition: newclient.h:118
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
SockList_AddData
void SockList_AddData(SockList *sl, const void *data, size_t len)
Adds a data block.
Definition: lowlevel.cpp:167
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
esrv_move_object
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
Animations::faces
const Face ** faces
The actual faces for the animation.
Definition: face.h:30
get_client_spell_state
client_spell * get_client_spell_state(player *pl, object *spell)
Gets the (client-side) spell state for specified spell.
Definition: player.cpp:145
archetype::tail_x
int8_t tail_x
Definition: object.h:488
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
SP_level_dam_adjust
int SP_level_dam_adjust(const object *caster, const object *spob)
Returns adjusted damage based on the caster.
Definition: spell_util.cpp:287
socket_struct::want_pickup
uint32_t want_pickup
Client wants pickup information when logging in.
Definition: newserver.h:113
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.cpp:4237
AddIfFloat
#define AddIfFloat(Old, New, sl, Type)
Definition: request.cpp:779
MAP2_LABEL_DM
@ MAP2_LABEL_DM
Definition: newclient.h:60
send_tick
void send_tick(player *pl)
Definition: request.cpp:2052
map2_add_ob
static int map2_add_ob(int ax, int ay, int layer, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int is_head)
object 'ob' at 'ax,ay' on 'layer' is visible to the client.
Definition: request.cpp:1117
get_map_flags
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
account_block_create
static int account_block_create(const socket_struct *ns)
Checks if account creation is blocked for this connection.
Definition: request.cpp:2297
living::maxsp
int16_t maxsp
Max spell points.
Definition: living.h:43
DISEASE
@ DISEASE
Definition: object.h:249
newserver.h
mapstruct
This is a game-map.
Definition: map.h:318
enter_exit
void enter_exit(object *op, object *exit_ob)
Tries to move 'op' to exit_ob.
Definition: server.cpp:727
SP_RUNE
#define SP_RUNE
Definition: spells.h:76
BEAT_INTERVAL
#define BEAT_INTERVAL
Interval between heartbeat requests.
Definition: config.h:636
map_newmap_cmd
void map_newmap_cmd(socket_struct *ns)
Sound related function.
Definition: request.cpp:691
esrv_add_spells
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's ...
Definition: request.cpp:1998
FLAG_AUTO_APPLY
#define FLAG_AUTO_APPLY
Will be applied when created.
Definition: define.h:237
SND_MUSIC
#define SND_MUSIC
Client wants background music info.
Definition: sounds.h:13
sstring
const typedef char * sstring
Definition: sstring.h:2
living::Cha
int8_t Cha
Definition: living.h:36
NDI_ALL
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:267
socket_struct::status
enum Sock_Status status
Definition: newserver.h:94
Animations
This represents one animation.
Definition: face.h:25
MAP_CLIENT_Y_MINIMUM
#define MAP_CLIENT_Y_MINIMUM
Definition: config.h:246
CS_STAT_RES_COLD
#define CS_STAT_RES_COLD
Definition: newclient.h:156
player::state
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:133
statsinfo::god
char * god
Definition: newserver.h:61
esrv_remove_spell
void esrv_remove_spell(player *pl, object *spell)
Definition: request.cpp:1861
SockList_AddLen8Data
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
receive_player_password
void receive_player_password(object *op, const char *password)
A player just entered her password, including for changing it.
Definition: c_misc.cpp:1955
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:338
add_me_cmd
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
esrv_draw_look
void esrv_draw_look(object *pl)
Send the look window.
Definition: item.cpp:193
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
version_cmd
void version_cmd(char *buf, int len, socket_struct *ns)
Client tells its version.
Definition: request.cpp:651
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
MAP2_LABEL_PLAYER
@ MAP2_LABEL_PLAYER
Definition: newclient.h:58
Map::cells
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:53
CF_CONFUSED
#define CF_CONFUSED
Confused by a spell or an item.
Definition: newclient.h:202
ob_apply
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
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
text
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended text
Definition: media-tags.txt:35
Animations::num
uint16_t num
Where we are in the array.
Definition: face.h:29
living::ac
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:173
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.cpp:83
NDI_DK_ORANGE
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:252
socket_struct::anims_sent
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:101
player::last_orig_stats
living last_orig_stats
Last permanent stats sent to client.
Definition: player.h:171
account_change_password
int account_change_password(const char *account_name, const char *current_password, const char *new_password)
Change an account password.
Definition: account.cpp:627
socket_struct::faces_sent
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
player::last_resist
int16_t last_resist[NROFATTACKS]
last resist values sent to client.
Definition: player.h:176
CS_STAT_RES_DEATH
#define CS_STAT_RES_DEATH
Definition: newclient.h:167
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
player::party
partylist * party
Party this player is part of.
Definition: player.h:205
data
====Textual A command containing textual data has data fields separated by one ASCII space character. word::A sequence of ASCII characters that does not contain the space or nul character. This is to distinguish it from the _string_, which may contain space characters. Not to be confused with a machine word. int::A _word_ containing the textual representation of an integer. Not to be confused with any of the binary integers in the following section. Otherwise known as the "string value of integer data". Must be parsed, e.g. using `atoi()` to get the actual integer value. string::A sequence of ASCII characters. This must only appear at the end of a command, since spaces are used to separate fields of a textual message.=====Binary All multi-byte integers are transmitted in network byte order(MSB first). int8::1-byte(8-bit) integer int16::2-byte(16-bit) integer int32::4-byte(32-bit) integer lstring::A length-prefixed string, which consists of an `int8` followed by that many bytes of the actual string. This is used to transmit a string(that may contain spaces) in the middle of binary data. l2string::Like _lstring_, but is prefixed with an `int16` to support longer strings Implementation Notes ~~~~~~~~~~~~~~~~~~~~ - Typical implementations read two bytes to determine the length of the subsequent read for the actual message, then read and parse the data from each message according to the commands described below. To send a message, the sender builds the message in a buffer, counts the length of the message, sends the length, and finally sends the actual message. TIP:Incorrectly transmitting or receiving the `length` field can lead to apparent "no response" issues as the client or server blocks to read the entire length of the message. - Since the protocol is highly interactive, it may be useful to set `TCP_NODELAY` on both the client and server. - If you are using a language with a buffered output stream, remember to flush the stream after a complete message. - If the connection is lost(which will also happen if the output buffer overflowing), the player is saved and the server cleans up. This does open up some abuses, but there is no perfect solution here. - The server only reads data from the socket if the player has an action. This isn 't really good, since many of the commands below might not be actual commands for the player. The alternative is to look at the data, and if it is a player command and there isn 't time, store it away to be processed later. But this increases complexity, in that the server must start buffering the commands. Fortunately, for now, there are few such client commands. Commands -------- In the documentation below, `S->C` represents a message to the client from the server, and `C->S` represents a message to the server from the client. Commands are documented in a brief format like:C->S:version< csval >[scval[vinfo]] Fields are enclosed like `< this >`. Optional fields are denoted like `[this]`. Spaces that appear in the command are literal, i.e. the<< _version > > command above uses spaces to separate its fields, but the command below does not:C->S:accountlogin< name >< password > As described in<< _messages > >, if a command contains data, then the command is separated from the data by a literal space. Many of the commands below refer to 'object tags'. Whenever the server creates an object, it creates a unique tag for that object(starting at 1 when the server is first run, and ever increasing.) Tags are unique, but are not consistent between runs. Thus, the client can not store tags when it exits and hope to re-use them when it joins the server at a later time - tags are only valid for the current connection. The protocol commands are broken into various sections which based somewhat on what the commands are for(ie, item related commands, map commands, image commands, etc.) In this way, all the commands related to similar functionality is in the same place. Initialization ~~~~~~~~~~~~~~ version ^^^^^^^ C->S:version< csval >[scval[vinfo]] S->C:version< csval >[scval[vinfo]] Used by the client and server to exchange which version of the Crossfire protocol they understand. Neither send this in response to the other - they should both send this shortly after a connection is established. csval::int, version level of C->S communications scval::int, version level of S->C communications vinfo::string, that is purely for informative that general client/server info(ie, javaclient, x11client, winclient, sinix server, etc). It is purely of interest of server admins who can see what type of clients people are using.=====Version ID If a new command is added to the protocol in the C->S direction, then the version number in csval will get increased. Likewise, the same is true for the scval. The version are currently integers, in the form ABCD. A=1, and will likely for quite a while. This will only really change if needed from rollover of B. B represents major protocol changes - if B mismatches, the clients will be totally unusable. Such an example would be change of map or item sending commands(either new commands or new format.) C represents more minor but still significant changes - clients might still work together, but some features that used to work may now fail due to the mismatch. An example may be a change in the meaning of some field in some command - providing the field is the same size, it still should be decoded properly, but the meaning won 't be processed properly. D represents very minor changes or new commands. Things should work no worse if D does not match, however if they do match, some new features might be included. An example of the would be the C->S mark command to mark items. Server not understanding this just means that the server can not process it, and will ignore it.=====Handling As far as the client is concerned, its _scval_ must be at least equal to the server, and its _csval_ should not be newer than the server. The server does not care about the version command it receives right now - all it currently does is log mismatches. In theory, the server should keep track of what the client has, and adjust the commands it sends respectively in the S->C direction. The server is resilant enough that it won 't crash with a version mismatch(however, client may end up sending commands that the server just ignores). It is really up to the client to enforce versioning and quit if the versions don 't match. NOTE:Since all packets have the length as the first 2 bytes, all that either the client or server needs to be able to do is look at the first string and see if it understands it. If not, it knows how many bytes it can skip. As such, exact version matches should not be necessary for proper operation - however, both the client and server needs to be coded to handle such cases.=====History _scval_ and _vinfo_ were added in version 1020. Before then, there was only one version sent in the version command. NOTE:For the most part, this has been obsoleted by the setup command which always return status and whether it understood the command or not. However there are still some cases where using this versioning is useful - an example it the addition of the requestinfo/replyinfo commands - the client wants to wait for acknowledge of all the replyinfo commands it has issued before sending the addme command. However, if the server doesn 't understand these options, the client will never get a response. With the versioning, the client can look at the version and know if it should wait for a response or if the server will never send back. setup ^^^^^ C->S, S->C:setup< option1 >< value1 >< option2 >< value2 > ... Sent by the client to request protocol option changes. This can be at any point during the life of a connection, but usually sent at least once right after the<< _version > > command. The server responds with a message in the same format confirming what configuration options were set. The server only sends a setup command in response to one from the client. The sc_version should be updated in the server if commands have been obsoleted such that old clients may not be able to play. option::word, name of configuration option value::word, value of configuration option. May need further parsing according to the setup options below=====Setup Options There are really 2 set of setup commands here:. Those that control preferences of the client(how big is the map, what faceset to use, etc). . Those that describe capabilities of the client(client supports this protocol command or that) .Setup Options[options="autowidth,header"]|===========================|Command|Description|beat|Ask the server to enable heartbeat support. When heartbeat is enabled, the client must send the server a command every three seconds. If no commands need to be sent, use the `beat` no-op command. Clients that do not contact the server within the interval are assumed to have a temporary connection failure.|bot(0/1 value)|If set to 1, the client will not be considered a player when updating information to the metaserver. This is to avoid having a server with many bots appear more crowded than others.|darkness(0/1 value)|If set to 1(default), the server will send darkness information in the map protocol commands. If 0, the server will not include darkness, thus saving a minor amount of bandwidth. Since the client is free to ignore the darkness information, this does not allow the client to cheat. In the case of the old 'map' protocol command, turning darkness off will result in the masking faces not getting sent to the client.|extended_stats(0/1 value)|If set to 1, the server will send the CS_STAT_RACE_xxx and CS_STAT_BASE_xxx values too, so the client can display various status related to statistics. Default is 0.|facecache(0/1)|Determines if the client is caching images(1) or wants the images sent to it without caching them(0). Default is 0. This replaces the setfacemode command.|faceset(8 bit)|Faceset the client wishes to use. If the faceset is not valid, the server returns the faceset the client will be using(default 0).|loginmethod(8 bit)|Client sends this to server to note login support. This is basically used as a subset of the csversion/scversion to find out what level of login support the server and client support. Current defined values:0:no advanced support - only legacy login method 1:account based login(described more below) 2:new character creation support This list may grow - for example, advanced character creation could become a feature.|map2cmd:(1)|This indicates client support for the map2 protocol command. See the map2 protocol details above for the main differences. Obsolete:This is the only supported mode now, but many clients use it as a sanity check for protocol versions, so the server still replies. It doesn 't do anything with the data|mapsize(int x) X(int y)|Sets the map size to x X y. Note the spaces here are only for clarity - there should be no spaces when actually sent(it should be 11x11 or 25x25). The default map size unless changed is 11x11. The minimum map size the server will allow is 9x9(no technical reason this could be smaller, but I don 't think the game would be smaller). The maximum map size supported in the current protocol is 63x63. However, each server can have its maximum map size sent to most any value. If the client sends an invalid mapsize command or a mapsize of 0x0, the server will respond with a mapsize that is the maximum size the server supports. Thus, if the client wants to know the maximum map size, it can just do a 'mapsize 0x0' or 'mapsize' and it will get the maximum size back. The server will constrain the provided mapsize x &y to the configured minumum and maximums. For example, if the maximum map size is 25x25, the minimum map size is 9x9, and the client sends a 31x7 mapsize request, the mapsize will be set to 25x9 and the server will send back a mapsize 25x9 setup command. When the values are valid, the server will send back a mapsize XxY setup command. Note that this is from its parsed values, so it may not match stringwise with what the client sent, but will match 0 wise. For example, the client may send a 'mapsize 025X025' command, in which case the server will respond with a 'mapsize 25x25' command - the data is functionally the same. The server will send an updated map view when this command is sent.|notifications(int value)|Value indicating what notifications the client accepts. It is incremental, a value means "all notifications till this level". The following levels are supported:1:quest-related notifications("addquest" and "updquest") 2:knowledge-related notifications("addknowledge") 3:character status flags(overloaded, blind,...)|num_look_objects(int value)|The maximum number of objects shown in the ground view. If more objects are present, fake objects are created for selecting the previous/next group of items. Defaults to 50 if not set. The server may adjust the given value to a suitable one data
Definition: protocol.txt:379
GetInt_String
int GetInt_String(const unsigned char *data)
Basically does the reverse of SockList_AddInt, but on strings instead.
Definition: lowlevel.cpp:254
draw_client_map2
static void draw_client_map2(object *pl)
Definition: request.cpp:1502
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Let client animate this, synchronized.
Definition: define.h:227
player::count
uint32_t count
Any numbers typed before a command.
Definition: player.h:124
strcasecmp
int strcasecmp(const char *s1, const char *s2)
FLAG_CONFUSED
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:298
ACL_LEVEL
#define ACL_LEVEL
Definition: newclient.h:224
CS_STAT_TITLE
#define CS_STAT_TITLE
Definition: newclient.h:111
newclient.h
save_player
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
VERSION_CS
#define VERSION_CS
Version >= 1023 understand setup cmd.
Definition: newserver.h:154
Account_Chars
Structure handling character information for an account.
Definition: account_char.h:27
UPD_SP_GRACE
#define UPD_SP_GRACE
updspell command flag value.
Definition: newclient.h:329
get_archetype_by_type_subtype
archetype * get_archetype_by_type_subtype(int type, int subtype)
Retrieves an archetype by type and subtype.
Definition: arch.cpp:97
CS_STAT_POW
#define CS_STAT_POW
Definition: newclient.h:112
skill
skill
Definition: arch-handbook.txt:585
CF_WIZARD
#define CF_WIZARD
Player is DM.
Definition: newclient.h:211
player::character_load
float character_load
Value between 0 and 1 indicating how much the character is overloaded.
Definition: player.h:137
esrv_send_pickup
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1884
object_remove
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
player_set_state
void player_set_state(player *pl, uint8_t state)
Set the player's state to the specified one.
Definition: player.cpp:4494
free_charlinks
void free_charlinks(linked_char *lc)
Frees a link structure and its next items.
Definition: utils.cpp:616
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:274
map_cell_struct::label_subtype
enum map2_label label_subtype
Definition: newserver.h:34
CS_STAT_RACE_WIS
#define CS_STAT_RACE_WIS
Definition: newclient.h:123
AddIfString
#define AddIfString(Old, New, sl, Type)
Definition: request.cpp:786
MAX_CHOICES
#define MAX_CHOICES
Definition: request.cpp:2674
FLAG_CLIENT_SENT
#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:333
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:290
want_pickup
same as sound ncom command like but with extra the client want tick commands so it knows animation timing want_pickup(0/1)|If set
SP_RAISE_DEAD
#define SP_RAISE_DEAD
Definition: spells.h:75
player::last_path_repelled
uint32_t last_path_repelled
Last spell repelled sent to client.
Definition: player.h:163
MIN_NUM_LOOK_OBJECTS
#define MIN_NUM_LOOK_OBJECTS
The lower bound for the number of objects to send for the 'look' window (container or ground view).
Definition: newserver.h:16
SP_MAKE_MARK
#define SP_MAKE_MARK
Definition: spells.h:77
socket_struct::login_method
uint8_t login_method
Login method this client is using.
Definition: newserver.h:133
archetype::tail_y
int8_t tail_y
Where the lower right most portion of the object is in comparison to the head.
Definition: object.h:488
check_probe
static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer)
Check if a hp bar should be added to the map square.
Definition: request.cpp:1287
FLAG_PROBE
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:244
statsinfo::range
char * range
Definition: newserver.h:61
commands.h
player::password
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:195
CS_STAT_MAXHP
#define CS_STAT_MAXHP
Definition: newclient.h:92
move_cmd
void move_cmd(char *buf, int len, player *pl)
Moves an object (typically, container to inventory).
Definition: request.cpp:712
account_char_load
Account_Chars * account_char_load(const char *account_name)
For a given account name, load the character information and return it.
Definition: account_char.cpp:135
key_change_class
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:1295
receive_party_password
void receive_party_password(object *op, const char *password)
Player entered a party password.
Definition: c_party.cpp:53
spell_client_use
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:1904
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
account_check_string
int account_check_string(const char *str)
Checks a string to make sure it does not have any invalid characters.
Definition: account.cpp:360
esrv_update_stats
void esrv_update_stats(player *pl)
Sends a statistics update.
Definition: request.cpp:870
socket_struct::darkness
uint32_t darkness
True if client wants darkness information.
Definition: newserver.h:108
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:109
socket_struct::notifications
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:134
SF_RUNON
#define SF_RUNON
Definition: newclient.h:194
CS_STAT_RANGE
#define CS_STAT_RANGE
Definition: newclient.h:110
Settings::account_trusted_host
char * account_trusted_host
Block account creation for untrusted hosts.
Definition: global.h:329
living::grace
int16_t grace
Grace.
Definition: living.h:44
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
MSG_TYPE_ADMIN_VERSION
#define MSG_TYPE_ADMIN_VERSION
version info
Definition: newclient.h:505
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.cpp:313
P_NEW_MAP
#define P_NEW_MAP
Coordinates passed result in a new tiled map.
Definition: map.h:253
update_los
void update_los(object *op)
Recalculates the array which specifies what is visible for the given player-object.
Definition: los.cpp:509
CS_STAT_BASE_CON
#define CS_STAT_BASE_CON
Definition: newclient.h:132
add_char_field
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:2073
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:98
account_login
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
Settings::always_show_hp
uint8_t always_show_hp
'probe' spell HP bars for all living things (0, 1, or 2)
Definition: global.h:274
player::last_weapon_sp
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h:158
verify_player
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
SPELL
@ SPELL
Definition: object.h:219
CS_STAT_BASE_STR
#define CS_STAT_BASE_STR
Definition: newclient.h:128
smooth_face
const Face * smooth_face
Definition: image.cpp:36
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.cpp:1012
decode_name_password
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:2198
living::Pow
int8_t Pow
Definition: living.h:36
account_char_save
void account_char_save(Account_Chars *chars)
Saves the character information for the given account.
Definition: account_char.cpp:158
player::name_changed
uint32_t name_changed
If true, the player has set a name.
Definition: player.h:147
CS_STAT_RES_DRAIN
#define CS_STAT_RES_DRAIN
Definition: newclient.h:159
MAP_NOSMOOTH
#define MAP_NOSMOOTH(m)
Definition: map.h:87
living.h
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:406
CF_HOSTILE
#define CF_HOSTILE
'hostile' flag is set.
Definition: newclient.h:208
SockList
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:685
map_reset_swap
void map_reset_swap(mapstruct *m)
Call this when an in-memory map is used or referenced.
Definition: map.cpp:1759
CF_PARALYZED
#define CF_PARALYZED
Player is paralyzed.
Definition: newclient.h:210
NUM_STATS
@ NUM_STATS
Number of statistics.
Definition: living.h:18
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:654
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
FORCE
@ FORCE
Definition: object.h:229
player::last_character_load
float last_character_load
Last value sent to the client.
Definition: player.h:138
account_char_remove
void account_char_remove(Account_Chars *chars, const char *pl_name)
This removes a character on this account.
Definition: account_char.cpp:313
NPC_DIALOG_ARCH
const char * NPC_DIALOG_ARCH
Definition: dialog.cpp:28
CS_STAT_APPLIED_INT
#define CS_STAT_APPLIED_INT
INT changes from gear or skills.
Definition: newclient.h:136
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Max radii for 'light' object, really large values allow objects that can slow down the game.
Definition: define.h:435
ACL_FACE
#define ACL_FACE
Definition: newclient.h:225
CF_XRAY
#define CF_XRAY
Has X-ray.
Definition: newclient.h:205
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Get player's current range attack in obuf.
Definition: info.cpp:265
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
MAP_LAYER_LIVING2
#define MAP_LAYER_LIVING2
Definition: map.h:47
NS_FACESENT_SMOOTH
#define NS_FACESENT_SMOOTH
Definition: newserver.h:143
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:533
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
account_exists
const char * account_exists(const char *account_name)
Checks the existing accounts, and see if this account exists.
Definition: account.cpp:296
living::Con
int8_t Con
Definition: living.h:36
face
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the and treasurelist definitions into a single or trs file and the graphics into a face(metadata) and .tar(bitmaps) file
CS_STAT_RES_PARA
#define CS_STAT_RES_PARA
Definition: newclient.h:163
Settings::starting_stat_max
uint8_t starting_stat_max
Maximum value of a starting stat.
Definition: global.h:322
CS_STAT_RES_ACID
#define CS_STAT_RES_ACID
Definition: newclient.h:158
living::Str
int8_t Str
Definition: living.h:36
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
CS_STAT_RES_ELEC
#define CS_STAT_RES_ELEC
Definition: newclient.h:155
CS_STAT_FLAGS
#define CS_STAT_FLAGS
Definition: newclient.h:115