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) {
1222  if (!ns->anims_sent[ob->animation->num])
1223  esrv_send_animation(ns, ob->animation);
1224 
1225  /* If smoothing, need to send smoothing information
1226  * for all faces in the animation sequence. Since
1227  * smoothlevel is an object attribute,
1228  * it applies to all faces.
1229  */
1230  if (smoothlevel) {
1231  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1232  if (!(ns->faces_sent[ob->animation->faces[i]->number]&NS_FACESENT_SMOOTH))
1233  send_smooth(ns, ob->animation->faces[i]);
1234  }
1235  }
1236  }
1237  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1238  esrv_send_face(ns, face, 0);
1239  }
1240 
1241  if (smoothlevel
1242  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1243  send_smooth(ns, ob->face);
1244 
1245  /* Length of packet */
1246  nlayer |= len<<5;
1247 
1248  SockList_AddChar(sl, nlayer);
1249  SockList_AddShort(sl, face_num);
1250  if (anim_speed)
1251  SockList_AddChar(sl, anim_speed);
1252  if (smoothlevel)
1253  SockList_AddChar(sl, smoothlevel);
1254  return 1;
1255  } /* Face is different */
1256  }
1257  return 0;
1258 }
1259 
1260 /* This function is used see if a layer needs to be cleared.
1261  * It updates the socklist, and returns 1 if the update is
1262  * needed, 0 otherwise.
1263  */
1264 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1265  int nlayer;
1266 
1267  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1268  /* Now form the data packet */
1269  nlayer = 0x10+layer+(2<<5);
1270  SockList_AddChar(sl, nlayer);
1271  SockList_AddShort(sl, 0);
1272  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1273  return 1;
1274  }
1275  return 0;
1276 }
1277 
1289 static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1290  int got_one = 0, poisoned = 0, diseased = 0;
1291  char name[60];
1292  int value, granularity;
1293  const object *probe;
1294 
1295  /* send hp bar if needed */
1296  if ((*alive_layer) != -1 || ob->head || !CAN_PROBE(ob))
1297  return 0;
1298 
1299  if (settings.always_show_hp == 2) {
1300  /* global hp bars are enabled */
1301  granularity = 30;
1302  } else if (settings.always_show_hp == 1 && ob->stats.hp < ob->stats.maxhp) {
1303  granularity = 30;
1304  } else {
1305  /* only give hp bars to monsters that have been probed */
1306  if (!QUERY_FLAG(ob, FLAG_PROBE)) {
1307  return 0;
1308  }
1309  probe = object_find_by_type_and_name(ob, FORCE, "probe_force");
1310  if (probe == NULL || probe->level < 15) {
1311  /* if probe is not null, this is an error, but well */
1312  return 0;
1313  }
1314 
1315  granularity = (probe->level - 14) / 3;
1316  if (granularity <= 0)
1317  granularity = 1;
1318  else if (granularity > 30)
1319  granularity = 30;
1320  }
1321 
1322  if (ob->stats.maxhp > 0) {
1323  value = (ob->stats.hp * granularity) / (ob->stats.maxhp);
1324 
1325  if (value < 0)
1326  value = 0;
1327  else if (value > granularity)
1328  value = granularity;
1329  } else
1330  value = 30;
1331 
1332  value = (value * 30) / granularity;
1333 
1334  if (object_present_in_ob(POISONING, ob) != NULL)
1335  poisoned = 1;
1336  if (object_present_in_ob(DISEASE, ob) != NULL)
1337  diseased = 1;
1338 
1339  if (value > 0) {
1340  archetype *dummy;
1341 
1342  snprintf(name, sizeof(name), "hpbar%s%s%s_%d",
1343  poisoned ? "_poisoned" : "",
1344  diseased ? "_diseased" : "",
1345  (!poisoned && !diseased) ? "_standard" : "",
1346  value);
1347  dummy = try_find_archetype(name);
1348  if (dummy != NULL) {
1349  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1350  (*alive_layer) = MAP_LAYER_FLY2;
1351  }
1352  }
1353 
1354  return got_one;
1355 }
1356 
1360 static bool map2_add_label(int ax, int ay, socket_struct *ns, SockList *sl, enum map2_label subtype, sstring label) {
1361  // label can only be null if subtype is none
1362  assert(subtype != MAP2_LABEL_NONE ? label != NULL : 1);
1363 
1364  // protect old clients from label with additive length, which can cause them to crash
1365  if (ns->sc_version < 1030)
1366  return false;
1367 
1368  // Check if there is any change to last sent data
1369  struct map_cell_struct *cell = &ns->lastmap.cells[ax][ay];
1370  if (cell->label_subtype == subtype &&
1371  (subtype == 0 || cell->label_text == label)) { // none label skips string comparison
1372  return false;
1373  }
1374 
1375  // Store change
1376  if (cell->label_subtype != MAP2_LABEL_NONE)
1377  free_string(cell->label_text);
1378  cell->label_subtype = subtype;
1379  cell->label_text = label;
1380 
1381  int len = 0;
1382  if (label) {
1383  add_refcount(label);
1384  len = strlen(label);
1385  if (len > 256 - 2 - 1) {
1386  LOG(llevError, "The label '%s' is too long to send to the client.", label);
1387  return false;
1388  }
1389  }
1390 
1391  // Send update
1392  SockList_AddChar(sl, MAP2_ADD_LENGTH | MAP2_TYPE_LABEL); // label with additive length
1393  SockList_AddChar(sl, len + 2); // length of payload (subtype + lstring)
1394  SockList_AddChar(sl, subtype);
1395  SockList_AddChar(sl, len); // lstring length prefix
1396  if (label)
1397  SockList_AddString(sl, label);
1398  return true;
1399 }
1400 
1401 static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer) {
1402  socket_struct *ns = plyr->socket;
1403  int got_one = check_probe(ax, ay, ob, sl, ns, has_obj, alive_layer);
1404  // add NPC speech bubble
1405  if (QUERY_FLAG(ob, FLAG_ALIVE) && (QUERY_FLAG(ob, FLAG_UNAGGRESSIVE) || QUERY_FLAG(ob, FLAG_FRIENDLY)) && ob->type != PLAYER) {
1406  if (ob->msg != NULL || object_find_by_arch_name(ob, NPC_DIALOG_ARCH)) {
1407  archetype *dummy = try_find_archetype("speechbubble");
1408  if (dummy != NULL) {
1409  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1410  (*alive_layer) = MAP_LAYER_FLY2;
1411  }
1412  }
1413  }
1414  return got_one;
1415 }
1416 
1420 static bool add_labels(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *got_one) {
1421  socket_struct *ns = plyr->socket;
1422  // add player name label
1423  if (ob->type == PLAYER) {
1424  enum map2_label subtype = MAP2_LABEL_PLAYER;
1425  if (QUERY_FLAG(ob, FLAG_WIZ)) {
1426  subtype = MAP2_LABEL_DM;
1427  } else if (plyr->party) {
1428  if (ob->contr && ob->contr->party == plyr->party) {
1429  subtype = MAP2_LABEL_PLAYER_PARTY;
1430  }
1431  }
1432  *got_one += map2_add_label(ax, ay, ns, sl, subtype, ob->name);
1433  return true;
1434  } else if (object_value_set(ob, "label")) {
1435  const char *label = object_get_value(ob, "label");
1436  *got_one += map2_add_label(ax, ay, ns, sl, MAP2_LABEL_SIGN, label);
1437  return true;
1438  }
1439  return false;
1440 }
1441 
1442 /*
1443  * This function is used to check a space (ax, ay) whose only
1444  * data we may care about are any heads. Basically, this
1445  * space is out of direct view. This is only used with the
1446  * Map2 protocol.
1447  *
1448  * @param ax
1449  * viewport relative x-coordinate
1450  * @param ay
1451  * viewport relative y-coordinate
1452  * @param sl
1453  * the reply to append to
1454  * @param ns
1455  * the client socket
1456  */
1457 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1458  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1459  uint16_t coord;
1460 
1461  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1462  oldlen = sl->len;
1463  SockList_AddShort(sl, coord);
1464 
1465  for (layer = 0; layer < MAP_LAYERS; layer++) {
1466  const object *head;
1467 
1468  head = heads[ay][ax][layer];
1469  if (head) {
1470  /* in this context, got_one should always increase
1471  * because heads should always point to data to really send.
1472  */
1473  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1474  } else {
1475  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1476  }
1477  }
1478  /* Note - if/when lighting information is added, some code is
1479  * needed here - lighting sources that are out of sight may still
1480  * extend into the viewable area.
1481  */
1482 
1483  /* If nothing to do for this space, we
1484  * can erase the coordinate bytes
1485  */
1486  if (!del_one && !got_one) {
1487  sl->len = oldlen;
1488  } else if (del_one && !has_obj) {
1489  /* If we're only deleting faces and not adding, and there
1490  * are not any faces on the space we care about,
1491  * more efficient
1492  * to send 0 as the type/len field.
1493  */
1494  sl->len = oldlen+2; /* 2 bytes for coordinate */
1495  SockList_AddChar(sl, MAP2_TYPE_CLEAR); /* Clear byte */
1496  SockList_AddChar(sl, 255); /* Termination byte */
1497  // Reduce defreferences by passing the inner array offset instead of address of value
1498  map_clearcell(ns->lastmap.cells[ax] + ay, 0, 0);
1499  } else {
1500  SockList_AddChar(sl, 255); /* Termination byte */
1501  }
1502 }
1503 
1504 static void draw_client_map2(object *pl) {
1505  int x, y, ax, ay, darkness, min_x, max_x, min_y, max_y, oldlen, layer;
1506  size_t startlen;
1507  int16_t nx, ny;
1508  SockList sl;
1509  uint16_t coord;
1510  mapstruct *m;
1511  // Dereference once. It should not change in the middle of processing.
1512  player *plyr = pl->contr;
1513 
1514  SockList_Init(&sl);
1515  SockList_AddString(&sl, "map2 ");
1516  startlen = sl.len;
1517 
1518  handle_scroll(plyr->socket, &sl);
1519 
1520  /* Init data to zero */
1521  memset(heads, 0, sizeof(heads));
1522 
1523  /* We could do this logic as conditionals in the if statement,
1524  * but that started to get a bit messy to look at.
1525  */
1526  min_x = pl->x-plyr->socket->mapx/2;
1527  min_y = pl->y-plyr->socket->mapy/2;
1528  max_x = pl->x+(plyr->socket->mapx+1)/2+MAX_HEAD_OFFSET;
1529  max_y = pl->y+(plyr->socket->mapy+1)/2+MAX_HEAD_OFFSET;
1530 
1531  /* x, y are the real map locations. ax, ay are viewport relative
1532  * locations.
1533  */
1534  ay = 0;
1535  for (y = min_y; y < max_y; y++, ay++) {
1536  ax = 0;
1537  for (x = min_x; x < max_x; x++, ax++) {
1538  /* If this space is out of the normal viewable area,
1539  * we only check the heads value. This is used to
1540  * handle big images - if they extend to a viewable
1541  * portion, we need to send just the lower right corner.
1542  */
1543  if (ax >= plyr->socket->mapx || ay >= plyr->socket->mapy) {
1544  check_space_for_heads(ax, ay, &sl, plyr->socket);
1545  } else {
1546  /* This space is within the viewport of the client. Due
1547  * to walls or darkness, it may still not be visible.
1548  */
1549 
1550  /* Meaning of darkness (see defines in LOS_* in los.c):
1551  * LOS_NO_DARKNESS (0) - object is in plain sight, full brightness.
1552  * 1 - MAX_DARKNESS - how dark the space is - higher
1553  * value is darker space. If level is at max darkness,
1554  * you can't see the space (too dark)
1555  * LOS_BLOCKED (100) - space is blocked from sight.
1556  */
1557  darkness = plyr->blocked_los[ax][ay];
1558 
1559  /* If the coordinates are not valid, or it is too
1560  * dark to see, we tell the client as such
1561  */
1562  nx = x;
1563  ny = y;
1564  m = get_map_from_coord(pl->map, &nx, &ny);
1565  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1566 
1567  if (!m) {
1568  /* space is out of map. Update space and clear
1569  * values if this hasn't already been done.
1570  * If the space is out of the map, it shouldn't
1571  * have a head.
1572  */
1573  if (plyr->socket->lastmap.cells[ax][ay].darkness != 0) {
1574  SockList_AddShort(&sl, coord);
1576  SockList_AddChar(&sl, 255); /* Termination byte */
1577  // Reduce dereferences by passing the inner array offset instead of address of value
1578  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1579  }
1580  } else if (darkness >= MAX_LIGHT_RADII) {
1581  /* This block deals with spaces that are not
1582  * visible due to darkness or walls. Still
1583  * need to send the heads for this space.
1584  */
1585  check_space_for_heads(ax, ay, &sl, plyr->socket);
1586  } else {
1587  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1588 
1589  /* In this block, the space is visible. */
1590 
1591  /* Rather than try to figure out what everything
1592  * that we might need to send is, then form the
1593  * packet after that, we presume that we will in
1594  * fact form a packet, and update the bits by what
1595  * we do actually send. If we send nothing, we
1596  * just back out sl.len to the old value, and no
1597  * harm is done.
1598  * I think this is simpler than doing a bunch of
1599  * checks to see what if anything we need to send,
1600  * setting the bits, then doing those checks again
1601  * to add the real data.
1602  */
1603 
1604  oldlen = sl.len;
1605  SockList_AddShort(&sl, coord);
1606 
1607  /* Darkness changed */
1608  if (plyr->socket->lastmap.cells[ax][ay].darkness != darkness
1609  && plyr->socket->darkness) {
1610  plyr->socket->lastmap.cells[ax][ay].darkness = darkness;
1611  /* Darkness tag & length (length=1) */
1612  SockList_AddChar(&sl, MAP2_TYPE_DARKNESS|(1<<5));
1613 
1614  /* Convert darkness level (0-MAX_DARKNESS) to a value
1615  * from 1 (dark) to 255 (bright) for the client.
1616  * Darkness values of 0 (completely dark) are not sent,
1617  * as the space is completely dark.
1618  */
1619  SockList_AddChar(&sl, 255-darkness*(256/MAX_LIGHT_RADII));
1620  have_darkness = 1;
1621  }
1622 
1623  int got_label = 0;
1624  for (layer = 0; layer < MAP_LAYERS; layer++) {
1625  const object *ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1626 
1627  /* Special case: send player itself if invisible */
1628  if (!ob
1629  && x == pl->x
1630  && y == pl->y
1631  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1632  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1633  ob = pl;
1634 
1635  if (ob) {
1636  g1 = has_obj;
1637  old_got = got_one;
1638  got_one += map2_add_ob(ax, ay, layer, ob, &sl, plyr->socket, &has_obj, 0);
1639 
1640  /* if we added the face, or it is a monster's head, check probe spell */
1641  if (got_one != old_got || ob->head == NULL) {
1642  got_one += annotate_ob(ax, ay, ob, &sl, plyr, &has_obj, &alive_layer);
1643  got_label += add_labels(ax, ay, ob, &sl, plyr, &got_one);
1644  }
1645 
1646  /* If we are just storing away the head
1647  * for future use, then effectively this
1648  * space/layer is blank, and we should clear
1649  * it if needed.
1650  */
1651  if (g1 == has_obj) {
1652  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1653  }
1654  } else {
1655  if (layer != alive_layer)
1656  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1657  }
1658  }
1659  if (got_label == 0) {
1660  got_one += map2_add_label(ax, ay, plyr->socket, &sl, MAP2_LABEL_NONE, NULL);
1661  }
1662  /* If nothing to do for this space, we
1663  * can erase the coordinate bytes
1664  */
1665  if (!del_one && !got_one && !have_darkness) {
1666  sl.len = oldlen;
1667  } else if (del_one && !has_obj) {
1668  /* If we're only deleting faces and don't
1669  * have any objs we care about, just clear
1670  * space. Note it is possible we may have
1671  * darkness, but if there is nothing on the
1672  * space, darkness isn't all that interesting
1673  * - we can send it when an object shows up.
1674  */
1675  sl.len = oldlen+2; /* 2 bytes for coordinate */
1677  SockList_AddChar(&sl, 255); /* Termination byte */
1678  // Reduce dereferences by passing the inner array offset instead of address of value
1679  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1680  } else {
1681  SockList_AddChar(&sl, 255); /* Termination byte */
1682  }
1683  }
1684  } /* else this is a viewable space */
1685  } /* for x loop */
1686  } /* for y loop */
1687 
1688  /* Only send this if there are in fact some differences. */
1689  if (sl.len > startlen) {
1690  Send_With_Handling(plyr->socket, &sl);
1691  }
1692  SockList_Term(&sl);
1693 }
1694 
1698 void draw_client_map(object *pl) {
1699  int i, j;
1700  int16_t ax, ay;
1701  int mflags;
1702  mapstruct *m, *pm;
1703  int min_x, min_y, max_x, max_y;
1704 
1705  if (pl->type != PLAYER) {
1706  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1707  return;
1708  }
1709 
1710  if (pl->contr->transport) {
1711  pm = pl->contr->transport->map;
1712  } else
1713  pm = pl->map;
1714 
1715  /* If player is just joining the game, he isn't here yet, so
1716  * the map can get swapped out. If so, don't try to send them
1717  * a map. All will be OK once they really log in.
1718  */
1719  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1720  return;
1721 
1722  /*
1723  * This block just makes sure all the spaces are properly
1724  * updated in terms of what they look like.
1725  */
1726  min_x = pl->x-pl->contr->socket->mapx/2;
1727  min_y = pl->y-pl->contr->socket->mapy/2;
1728  max_x = pl->x+(pl->contr->socket->mapx+1)/2;
1729  max_y = pl->y+(pl->contr->socket->mapy+1)/2;
1730  for (j = min_y; j < max_y; j++) {
1731  for (i = min_x; i < max_x; i++) {
1732  ax = i;
1733  ay = j;
1734  m = pm;
1735  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1736  if (mflags&P_OUT_OF_MAP)
1737  continue;
1738  if (mflags&P_NEED_UPDATE)
1739  update_position(m, ax, ay);
1740  /* If a map is visible to the player, we don't want
1741  * to swap it out just to reload it. This should
1742  * really call something like swap_map, but this is
1743  * much more efficient and 'good enough'
1744  */
1745  if (mflags&P_NEW_MAP)
1746  map_reset_swap(m);
1747  }
1748  }
1749 
1750  /* do LOS after calls to update_position */
1751  if (pl->contr->do_los) {
1752  update_los(pl);
1753  pl->contr->do_los = 0;
1754  }
1755 
1756  draw_client_map2(pl);
1757 }
1758 
1759 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1760  struct Map newmap;
1761  int x, y, mx, my;
1762 
1763  ns->map_scroll_x += dx;
1764  ns->map_scroll_y += dy;
1765 
1766  mx = ns->mapx+MAX_HEAD_OFFSET;
1767  my = ns->mapy+MAX_HEAD_OFFSET;
1768 
1769  /* the x and y here are coordinates for the new map, i.e. if we moved
1770  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1771  * if the destination x or y coordinate is outside the viewable
1772  * area, we clear the values - otherwise, the old values
1773  * are preserved, and the check_head thinks it needs to clear them.
1774  */
1775  for (x = 0; x < mx; x++) {
1776  for (y = 0; y < my; y++) {
1777  if (x >= ns->mapx || y >= ns->mapy) {
1778  /* clear cells outside the viewable area */
1779  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1780  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1781  /* clear newly visible tiles within the viewable area */
1782  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1783  } else {
1784  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1785  }
1786  }
1787  }
1788 
1789  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1790 }
1791 
1797 void send_plugin_custom_message(object *pl, char *buf) {
1798  SockList sl;
1799 
1800  SockList_Init(&sl);
1801  SockList_AddString(&sl, buf);
1802  Send_With_Handling(pl->contr->socket, &sl);
1803  SockList_Term(&sl);
1804 }
1805 
1812  SockList sl;
1813  int flags = 0;
1814  client_spell *spell_info;
1815 
1816  if (!pl->socket || !pl->socket->monitor_spells)
1817  return;
1818 
1819  /* Handles problem at login, where this is called from fix_object
1820  * before we have had a chance to send spells to the player. It does seem
1821  * to me that there should never be a case where update_spells is called
1822  * before add_spells has been called. Add_spells() will update the
1823  * spell_state to non null.
1824  */
1825  if (!pl->spell_state)
1826  return;
1827 
1828  FOR_INV_PREPARE(pl->ob, spell) {
1829  if (spell->type == SPELL) {
1830  spell_info = get_client_spell_state(pl, spell);
1831  /* check if we need to update it*/
1832  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1833  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1834  flags |= UPD_SP_MANA;
1835  }
1836  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1838  flags |= UPD_SP_GRACE;
1839  }
1840  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1841  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1842  flags |= UPD_SP_DAMAGE;
1843  }
1844  if (flags != 0) {
1845  SockList_Init(&sl);
1846  SockList_AddString(&sl, "updspell ");
1847  SockList_AddChar(&sl, flags);
1848  SockList_AddInt(&sl, spell->count);
1849  if (flags&UPD_SP_MANA)
1850  SockList_AddShort(&sl, spell_info->last_sp);
1851  if (flags&UPD_SP_GRACE)
1852  SockList_AddShort(&sl, spell_info->last_grace);
1853  if (flags&UPD_SP_DAMAGE)
1854  SockList_AddShort(&sl, spell_info->last_dam);
1855  flags = 0;
1856  Send_With_Handling(pl->socket, &sl);
1857  SockList_Term(&sl);
1858  }
1859  }
1860  } FOR_INV_FINISH();
1861 }
1862 
1863 void esrv_remove_spell(player *pl, object *spell) {
1864  SockList sl;
1865 
1866  if (!pl || !spell || spell->env != pl->ob) {
1867  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1868  return;
1869  }
1870  if (!pl->socket->monitor_spells)
1871  return;
1872 
1873  SockList_Init(&sl);
1874  SockList_AddString(&sl, "delspell ");
1875  SockList_AddInt(&sl, spell->count);
1876  Send_With_Handling(pl->socket, &sl);
1877  SockList_Term(&sl);
1878 }
1879 
1887  SockList sl;
1888 
1889  if (!pl->socket->want_pickup)
1890  return;
1891  SockList_Init(&sl);
1892  SockList_AddString(&sl, "pickup ");
1893  SockList_AddInt(&sl, pl->mode);
1894  Send_With_Handling(pl->socket, &sl);
1895  SockList_Term(&sl);
1896 }
1897 
1906 static int spell_client_use(const object *spell) {
1907  switch (spell->subtype)
1908  {
1909  case SP_RAISE_DEAD:
1910  case SP_MAKE_MARK:
1911  return 3;
1912  case SP_RUNE:
1913  if (!spell->other_arch)
1914  return 1;
1915  break;
1916  case SP_CREATE_FOOD:
1917  case SP_CREATE_MISSILE:
1918  return 2;
1919  case SP_SUMMON_MONSTER:
1920  if (spell->randomitems != NULL)
1921  return 2;
1922  /* break; */// If add conditins below, use this break statement
1923  }
1924  // This is not in the switch statement so that it supports fallthrough logic
1925  // on the few spell types that have additional conditions attached.
1926  return 0;
1927 }
1928 
1930 static void append_spell(player *pl, SockList *sl, object *spell) {
1931  client_spell *spell_info;
1932  int len, i, skill = 0;
1933 
1934  if (!spell->name) {
1935  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1936  return;
1937  }
1938 
1939  if (spell->face && !(pl->socket->faces_sent[spell->face->number]&NS_FACESENT_FACE))
1940  esrv_send_face(pl->socket, spell->face, 0);
1941 
1942  spell_info = get_client_spell_state(pl, spell);
1943  SockList_AddInt(sl, spell->count);
1944  SockList_AddShort(sl, spell->level);
1945  SockList_AddShort(sl, spell->casting_time);
1946  /* store costs and damage in the object struct, to compare to later */
1947  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1949  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1950  /* send the current values */
1951  SockList_AddShort(sl, spell_info->last_sp);
1952  SockList_AddShort(sl, spell_info->last_grace);
1953  SockList_AddShort(sl, spell_info->last_dam);
1954 
1955  /* figure out which skill it uses, if it uses one */
1956  if (spell->skill) {
1957  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++)
1958  if (!strcmp(spell->skill, skill_names[i])) {
1960  break;
1961  }
1962  }
1963  SockList_AddChar(sl, skill);
1964 
1965  SockList_AddInt(sl, spell->path_attuned);
1966  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1967  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1968 
1969  if (!spell->msg) {
1970  SockList_AddShort(sl, 0);
1971  } else {
1972  len = strlen(spell->msg);
1973  SockList_AddShort(sl, len);
1974  SockList_AddData(sl, spell->msg, len);
1975  }
1976 
1977  /* Extended spell information available if the client wants it.
1978  */
1979  if (pl->socket->monitor_spells >= 2) {
1980  /* spellmon 2
1981  */
1982  sstring req = object_get_value(spell, "casting_requirements");
1983 
1984  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1985 
1986  if (req) { /* Requirements */
1987  SockList_AddLen8Data(sl, req, strlen(req));
1988  } else {
1989  SockList_AddChar(sl, 0);
1990  }
1991  /* end spellmon 2
1992  */
1993  }
1994 }
1995 
2000 void esrv_add_spells(player *pl, object *spell) {
2001  SockList sl;
2002  size_t size;
2003  sstring value;
2004 
2005  if (!pl) {
2006  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
2007  return;
2008  }
2009 
2010  if (!pl->socket->monitor_spells)
2011  return;
2012 
2013  SockList_Init(&sl);
2014  SockList_AddString(&sl, "addspell ");
2015  if (!spell) {
2016  FOR_INV_PREPARE(pl->ob, spell) {
2017  if (spell->type != SPELL)
2018  continue;
2019  /* Were we to simply keep appending data here, we could
2020  * exceed the SockList buffer if the player has enough spells
2021  * to add. We know that append_spell will always append
2022  * 23 data bytes, plus 3 length bytes and 2 strings
2023  * (because that is the spec) so we need to check that
2024  * the length of those 2 strings, plus the 26 bytes,
2025  * won't take us over the length limit for the socket.
2026  * If it does, we need to send what we already have,
2027  * and restart packet formation.
2028  */
2029  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
2030  if (pl->socket->monitor_spells >= 2) {
2032  value = object_get_value(spell, "casting_requirements");
2033  size += 2 + (value ? strlen(value) : 0);
2034  }
2035  if (SockList_Avail(&sl) < size) {
2036  Send_With_Handling(pl->socket, &sl);
2037  SockList_Reset(&sl);
2038  SockList_AddString(&sl, "addspell ");
2039  }
2040  append_spell(pl, &sl, spell);
2041  } FOR_INV_FINISH();
2042  } else if (spell->type != SPELL) {
2043  LOG(llevError, "Asked to send a non-spell object as a spell\n");
2044  return;
2045  } else
2046  append_spell(pl, &sl, spell);
2047  /* finally, we can send the packet */
2048  Send_With_Handling(pl->socket, &sl);
2049  SockList_Term(&sl);
2050 }
2051 
2052 /* sends a 'tick' information to the client.
2053  */
2054 void send_tick(player *pl) {
2055  SockList sl;
2056  SockList_Init(&sl);
2057  SockList_AddString(&sl, "tick ");
2058  SockList_AddInt(&sl, pticks);
2059  Send_With_Handling(pl->socket, &sl);
2060  SockList_Term(&sl);
2061 }
2062 
2075 static void add_char_field(SockList *sl, int type, const char *data)
2076 {
2077  int len;
2078 
2079  len = strlen(data);
2080 
2081  if (len) {
2082  /* one extra for length for the type byte */
2083  SockList_AddChar(sl, len+1);
2084  SockList_AddChar(sl, type);
2085  SockList_AddString(sl, data);
2086  }
2087 }
2088 
2110 {
2111  SockList sl;
2112  int num_chars;
2113  linked_char *extra;
2114 
2115  if (ns->account_chars) {
2117  }
2119 
2120  num_chars = 0;
2121  extra = account_get_additional_chars(ns->account_name, ns->account_chars, &num_chars);
2122 
2123  SockList_Init(&sl);
2124  SockList_AddString(&sl, "accountplayers ");
2125 
2126  SockList_AddChar(&sl, static_cast<char>(ns->account_chars->chars.size() + num_chars));
2127 
2128  /* Now add real character data */
2129  for (auto acn : ns->account_chars->chars) {
2130  uint16_t faceno = 0;
2131 
2132  /* Ignore a dead character. They don't need to show up. */
2133  if (acn->isDead) {
2134  continue;
2135  }
2136 
2137  add_char_field(&sl, ACL_NAME, acn->name);
2138  add_char_field(&sl, ACL_CLASS, acn->character_class);
2139  add_char_field(&sl, ACL_RACE, acn->race);
2140  add_char_field(&sl, ACL_FACE, acn->face);
2141  if (acn->face[0] != 0 ) {
2142  const Face *face = try_find_face(acn->face, NULL);
2143 
2144  if (face != NULL) {
2145  if (!(ns->faces_sent[face->number]&NS_FACESENT_FACE)) {
2146  esrv_send_face(ns, face, 0);
2147  }
2148  faceno = face->number;
2149  }
2150  }
2151 
2152  add_char_field(&sl, ACL_PARTY, acn->party);
2153  add_char_field(&sl, ACL_MAP, acn->map);
2154  SockList_AddChar(&sl, 3);
2156  SockList_AddShort(&sl, acn->level);
2157  if (faceno) {
2158  SockList_AddChar(&sl, 3);
2160  SockList_AddShort(&sl, faceno);
2161  }
2162 
2163  SockList_AddChar(&sl, 0);
2164  }
2165  /* Now for any characters where we just have the name */
2166  for (linked_char *e = extra; e != NULL; e = e->next) {
2167  add_char_field(&sl, ACL_NAME, e->name);
2168  SockList_AddChar(&sl, 0);
2169  }
2170 
2171  Send_With_Handling(ns, &sl);
2172  SockList_Term(&sl);
2173 
2174  if (extra) {
2175  free_charlinks(extra);
2176  }
2177 }
2178 
2200 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2201 {
2202  int nlen, plen;
2203 
2204  if (*len < 2) {
2205  return 1;
2206  }
2207 
2208  nlen = (unsigned char)buf[0];
2209  if (nlen >= MAX_BUF || nlen > *len-2) {
2210  return 1;
2211  }
2212  memcpy(name, buf+1, nlen);
2213  name[nlen] = 0;
2214 
2215  plen = (unsigned char)buf[nlen+1];
2216  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2217  return 2;
2218  }
2219  memcpy(password, buf+2+nlen, plen);
2220  password[plen] = 0;
2221 
2222  *len = nlen+plen+2;
2223 
2224  return 0;
2225 }
2236 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2237  char name[MAX_BUF], password[MAX_BUF];
2238  int status;
2239  SockList sl;
2240 
2241  if (len <= 0 || !buf) {
2242  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2243  return;
2244  }
2245 
2246  SockList_Init(&sl);
2247 
2248  status = decode_name_password(buf, &len, name, password);
2249 
2250  if (status == 1) {
2251  SockList_AddString(&sl, "failure accountlogin Name is too long");
2252  Send_With_Handling(ns, &sl);
2253  SockList_Term(&sl);
2254  return;
2255  }
2256  if (status == 2) {
2257  SockList_AddString(&sl, "failure accountlogin Password is too long");
2258  Send_With_Handling(ns, &sl);
2259  SockList_Term(&sl);
2260  return;
2261  }
2262 
2263  if (!account_exists(name)) {
2264  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2265  Send_With_Handling(ns, &sl);
2266  SockList_Term(&sl);
2267  return;
2268  }
2269 
2270  if (account_login(name, password)) {
2271  LOG(llevInfo, "Account login for '%s' from %s\n", name, ns->host);
2272 
2273  if (ns->account_name) free(ns->account_name);
2274  /* We want to store away official name so we do not
2275  * have any case sensitivity issues on the files.
2276  * because we have already checked password, we
2277  * know that account_exists should never return NULL in
2278  * this case.
2279  */
2281 
2283  } else {
2284  LOG(llevInfo, "Failed account login for '%s' from %s\n", name, ns->host);
2285  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2286  Send_With_Handling(ns, &sl);
2287  SockList_Term(&sl);
2288  }
2289 }
2290 
2299 static int account_block_create(const socket_struct *ns) {
2300  /* Check if account creation is blocked. */
2302  /* Account creation is allowed for everyone. */
2303  return 0;
2304  }
2305 
2306  /* Has the trusted host been defined? */
2307  if(settings.account_trusted_host == NULL) {
2308  /* No, allocate it and set it to localhost now. */
2310  }
2311 
2312  /* Return false if the client connected from the trusted host. */
2313  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2314  return 0;
2315  }
2316 
2317  /*
2318  * If we are here, then we are blocking account create and we do
2319  * not trust this client's IP address.
2320  */
2321  return 1;
2322 }
2323 
2335 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2336  char name[MAX_BUF], password[MAX_BUF];
2337  int status;
2338  SockList sl;
2339 
2340  if (len <= 0 || !buf) {
2341  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2342  return;
2343  }
2344 
2345  SockList_Init(&sl);
2346 
2347  status = decode_name_password(buf, &len, name, password);
2348 
2349  if (account_block_create(ns)) {
2350  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2351  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2352  Send_With_Handling(ns, &sl);
2353  SockList_Term(&sl);
2354  return;
2355  }
2356 
2357  if (status == 1) {
2358  SockList_AddString(&sl, "failure accountnew Name is too long");
2359  Send_With_Handling(ns, &sl);
2360  SockList_Term(&sl);
2361  return;
2362  }
2363  if (status == 2) {
2364  SockList_AddString(&sl, "failure accountnew Password is too long");
2365  Send_With_Handling(ns, &sl);
2366  SockList_Term(&sl);
2367  return;
2368  }
2369  /*The minimum length isn't exactly required, but in the current implementation,
2370  * client will send the same password for character for which there is a
2371  * 2 character minimum size. Thus an account with a one character password
2372  * won't be able to create a character. */
2373  if (strlen(name)<settings.min_name) {
2374  SockList_AddString(&sl, "failure accountnew Name is too short");
2375  Send_With_Handling(ns, &sl);
2376  SockList_Term(&sl);
2377  return;
2378  }
2379  if (strlen(password)<2) {
2380  SockList_AddString(&sl, "failure accountnew Password is too short");
2381  Send_With_Handling(ns, &sl);
2382  SockList_Term(&sl);
2383  return;
2384  }
2385 
2386  if (account_exists(name)) {
2387  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2388  Send_With_Handling(ns, &sl);
2389  SockList_Term(&sl);
2390  return;
2391  }
2392 
2393  status = account_check_string(name);
2394  if (status == 1) {
2395  SockList_AddString(&sl,
2396  "failure accountnew Choose a different account name. " VALIDCHAR_MSG);
2397  Send_With_Handling(ns, &sl);
2398  SockList_Term(&sl);
2399  return;
2400  }
2401 
2402  if (status == 2) {
2403  SockList_AddString(&sl,
2404  "failure accountnew That account name is too long");
2405  Send_With_Handling(ns, &sl);
2406  SockList_Term(&sl);
2407  return;
2408  }
2409 
2410  status = account_check_string(password);
2411  if (status == 1) {
2412  SockList_AddString(&sl,
2413  "failure accountnew Choose a different password. " VALIDCHAR_MSG);
2414  Send_With_Handling(ns, &sl);
2415  SockList_Term(&sl);
2416  return;
2417  }
2418 
2419  if (status == 2) {
2420  SockList_AddString(&sl,
2421  "failure accountnew That password is too long");
2422  Send_With_Handling(ns, &sl);
2423  SockList_Term(&sl);
2424  return;
2425  }
2426 
2427  /* If we got here, we passed all checks - so now add it */
2428  if (ns->account_name) free(ns->account_name);
2430  account_new(name, password);
2431  /* save account information */
2432  accounts_save();
2434 }
2435 
2449 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2450  char name[MAX_BUF], password[MAX_BUF];
2451  int status, force, nlen;
2452  SockList sl;
2453  const char *cp;
2454 
2455  if (len <= 0 || !buf) {
2456  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2457  return;
2458  }
2459 
2460  SockList_Init(&sl);
2461 
2462  if (ns->account_name == NULL) {
2463  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2464  Send_With_Handling(ns, &sl);
2465  SockList_Term(&sl);
2466  return;
2467  }
2468 
2469  force = buf[0];
2470  nlen = len - 1;
2471  status = decode_name_password(buf+1, &nlen, name, password);
2472  if (status == 1) {
2473  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2474  Send_With_Handling(ns, &sl);
2475  SockList_Term(&sl);
2476  return;
2477  }
2478  if (status == 2) {
2479  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2480  Send_With_Handling(ns, &sl);
2481  SockList_Term(&sl);
2482  return;
2483  }
2484 
2485  status = verify_player(name, password);
2486  if (status) {
2487  /* From a security standpoint, telling random folks if it
2488  * it as wrong password makes it easier to hack. However,
2489  * it is fairly easy to determine what characters exist on a server
2490  * (either by trying to create a new one and see if the name is in
2491  * in use, or just looking at the high score file), so this
2492  * really does not make things much less secure
2493  */
2494  if (status == 1)
2495  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2496  else
2497  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2498 
2499  Send_With_Handling(ns, &sl);
2500  SockList_Term(&sl);
2501  return;
2502  }
2503  /* Check to see if this character is associated with an account.
2504  */
2506  if (cp) {
2507  if (!strcmp(cp, ns->account_name)) {
2508  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2509  Send_With_Handling(ns, &sl);
2510  SockList_Term(&sl);
2511  return;
2512  } else {
2513  if (!force) {
2514  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2515  Send_With_Handling(ns, &sl);
2516  SockList_Term(&sl);
2517  return;
2518  } else if (account_is_logged_in(cp)) {
2519  /* We could be clever and try to handle this case, but it is
2520  * trickier. If the character is logged in, it has to
2521  * be logged out. And the socket holds some data which
2522  * needs to be cleaned up. Since it should be fairly
2523  * uncommon that users need to do this, just disallowing
2524  * it makes things a lot simpler.
2525  */
2526  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2527  Send_With_Handling(ns, &sl);
2528  SockList_Term(&sl);
2529  return;
2530  }
2531  }
2532  }
2533  /* If we have gotten this far, the name/password provided is OK,
2534  * and the character is not associated with a different account (or
2535  * force is true). Now try to add the character to this account.
2536  */
2537  status = account_link(ns->account_name, name);
2538 
2539  /* This should never happen, but check for it just in case -
2540  * if we were able to log in, the account should exist. but
2541  * if this fails, need to give the user some clue.
2542  */
2543  if (status==1) {
2544  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2545  Send_With_Handling(ns, &sl);
2546  SockList_Term(&sl);
2547  return;
2548  } else if (status == 2) {
2549  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2550  Send_With_Handling(ns, &sl);
2551  SockList_Term(&sl);
2552  return;
2553  }
2554 
2555  /* If cp is set, then this character used to belong to a different
2556  * account. Remove it now.
2557  */
2558  if (cp) {
2559  Account_Chars *chars;
2560 
2562  chars = account_char_load(cp);
2563  account_char_remove(chars, name);
2564  account_char_save(chars);
2565  account_char_free(chars);
2566  }
2567 
2569 
2570  /* store data so nothing is lost in case of crash */
2572 }
2573 
2578 void account_play_cmd(char *buf, int len, socket_struct *ns)
2579 {
2580  char **chars;
2581  int i;
2582  SockList sl;
2583  player *pl;
2584 
2585  if (len <= 0 || !buf) {
2586  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2587  return;
2588  }
2589 
2590  SockList_Init(&sl);
2591 
2592  if (ns->status != Ns_Add) {
2593  SockList_AddString(&sl, "failure accountplay Not allowed right now");
2594  Send_With_Handling(ns, &sl);
2595  SockList_Term(&sl);
2596  return;
2597  }
2598 
2599  if (!buf[0]) {
2600  SockList_AddString(&sl, "failure accountplay Malformed character name");
2601  Send_With_Handling(ns, &sl);
2602  SockList_Term(&sl);
2603  return;
2604  }
2605 
2606  if (ns->account_name == NULL) {
2607  SockList_AddString(&sl, "failure accountplay Not logged in");
2608  Send_With_Handling(ns, &sl);
2609  SockList_Term(&sl);
2610  return;
2611  }
2612 
2613  /* Make sure a client is not trying to spoof us here */
2615 
2616  for (i=0; chars[i]; i++) {
2617  if (strcmp(chars[i], buf) == 0)
2618  break;
2619  }
2620  if (!chars[i]) {
2621  SockList_AddPrintf(&sl,
2622  "failure accountplay Character %s is not associated with account %s",
2623  buf, ns->account_name);
2624  Send_With_Handling(ns, &sl);
2625  SockList_Term(&sl);
2626  return;
2627  }
2628 
2629  for (pl = first_player; pl; pl = pl->next) {
2630  if (pl->ob && pl->socket != ns && strcmp(buf, pl->ob->name) == 0 && pl->state != ST_PLAY_AGAIN && pl->state != ST_GET_NAME) {
2631  SockList_AddPrintf(&sl,
2632  "failure accountplay Character %s is already playing",
2633  buf);
2634  Send_With_Handling(ns, &sl);
2635  SockList_Term(&sl);
2636  return;
2637  }
2638  }
2639 
2640  /* from a protocol standpoint, accountplay can be used
2641  * before there is a player structure (first login) or after
2642  * (character has logged in and is changing characters).
2643  * Checkthe sockets for that second case - if so,
2644  * we don't need to make a new player object, etc.
2645  */
2646  for (pl=first_player; pl; pl=pl->next) {
2647  if (pl->socket == ns) {
2648  /* The player still in the socket must be saved first. */
2649  save_player(pl->ob, 0);
2650  break;
2651  }
2652  }
2653 
2654  /* Some of this logic is from add_player()
2655  * we just don't use add_player() as it does some other work
2656  * we don't really want to do.
2657  */
2658  if (!pl) {
2659  pl = get_player(NULL);
2660  set_player_socket(pl, ns);
2661  ns->status = Ns_Avail;
2662  ns->account_chars = NULL;
2664  } else {
2665  pl->state = ST_PLAYING;
2666  }
2667 
2668  pl->ob->name = add_string(buf);
2669  check_login(pl->ob, NULL);
2670 
2671  SockList_AddString(&sl, "addme_success");
2672  Send_With_Handling(ns, &sl);
2673  SockList_Term(&sl);
2674 }
2675 
2676 #define MAX_CHOICES 100
2677 
2683 void create_player_cmd(char *buf, int len, socket_struct *ns)
2684 {
2685  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2686  int status, nlen, choice_num=0, i;
2687  SockList sl;
2688  player *pl;
2689  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2690  living new_stats;
2691 
2692  if (len <= 0 || !buf) {
2693  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2694  return;
2695  }
2696 
2697  SockList_Init(&sl);
2698 
2699  if (ns->status != Ns_Add) {
2700  SockList_AddString(&sl, "failure createplayer Not allowed right now");
2701  Send_With_Handling(ns, &sl);
2702  SockList_Term(&sl);
2703  return;
2704  }
2705 
2706  nlen = len;
2707  status = decode_name_password(buf, &nlen, name, password);
2708  if (status == 1) {
2709  SockList_AddString(&sl, "failure createplayer Name is too long");
2710  Send_With_Handling(ns, &sl);
2711  SockList_Term(&sl);
2712  return;
2713  }
2714 
2715  /* Minimum character name limit (if set) */
2716  if (strlen(name)<settings.min_name) {
2717  SockList_AddString(&sl, "failure createplayer Name is too short");
2718  Send_With_Handling(ns, &sl);
2719  SockList_Term(&sl);
2720  return;
2721  }
2722 
2723  if (playername_ok(name) == 0) {
2724  SockList_AddString(&sl, "failure createplayer Player name contains invalid characters");
2725  Send_With_Handling(ns, &sl);
2726  SockList_Term(&sl);
2727  return;
2728  }
2729 
2730  /* 2 characters minimum for password */
2731  if (strlen(password)<2) {
2732  SockList_AddString(&sl, "failure createplayer Password is too short");
2733  Send_With_Handling(ns, &sl);
2734  SockList_Term(&sl);
2735  return;
2736  }
2737 
2739  if (status == 2) {
2740  SockList_AddString(&sl, "failure createplayer Password is too long");
2741  Send_With_Handling(ns, &sl);
2742  SockList_Term(&sl);
2743  return;
2744  }
2745 
2746  /* This is a fairly ugly solution - we're truncating the password.
2747  * however, the password information for characters is really
2748  * a legacy issue - when every character is associated with
2749  * an account, legacy login (character name/password) will get
2750  * removed, at which point the only use for password might be
2751  * to move characters from one account to another, but not sure
2752  * if that is something we want to allow.
2753  */
2754  if (strlen(password)>17)
2755  password[16] = 0;
2756 
2757  /* We just can't call check_name(), since that uses draw_info() to
2758  * report status. We are also more permissive on names, so we use
2759  * account_check_string() - if that is safe for account, also safe
2760  * for player names.
2761  */
2762  if (account_check_string(name)) {
2763  SockList_AddString(&sl, "failure createplayer Choose a different character name. " VALIDCHAR_MSG);
2764  Send_With_Handling(ns, &sl);
2765  SockList_Term(&sl);
2766  return;
2767  }
2768 
2769  /* 1 means no such player, 0 is correct name/password (which in this
2770  * case, is an error), and 2 is incorrect password. Only way we
2771  * go onward is if there is no such player.
2772  */
2773  if (verify_player(name, password) != 1) {
2774  SockList_AddString(&sl, "failure createplayer That name is already in use");
2775  Send_With_Handling(ns, &sl);
2776  SockList_Term(&sl);
2777  return;
2778  }
2779 
2780  /* from a protocol standpoint, accountplay can be used
2781  * before there is a player structure (first login) or after
2782  * (character has logged in and is changing characters).
2783  * Check the sockets for that second case - if so,
2784  * we don't need to make a new player object, etc.
2785  */
2786  for (pl=first_player; pl; pl=pl->next)
2787  if (pl->socket == ns) {
2788  if (pl->ob->name) {
2789  if (!strcmp(pl->ob->name, name)) {
2790  /* For some reason not only the socket is the same but also
2791  * the player is already playing. If this happens at this
2792  * point let's assume the character never was able to apply
2793  * a bet of reality to make a correct first-time save.
2794  * So, for safety remove it and start over.
2795  */
2796  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2797  object_remove(pl->ob);
2798  }
2799  else {
2800  /* If this is a different player on the same socket, then we
2801  * need to make sure that the old one is not connected to the player
2802  *
2803  * This prevents bizarre scenarios where the player is on the map
2804  * multiple times (from multiple createplayer commands), and
2805  * only one of them is controlled by the player.
2806  */
2807  if (pl->ob->contr == pl) {
2808  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2809  object_remove(pl->ob);
2810  }
2811  }
2812  }
2813  break;
2814  }
2815 
2816  /* In this mode, we have additional data
2817  * Note that because there are a lot of failure cases in here
2818  * (where we end up not creating the new player), the code
2819  * to create the new player is done within this routine
2820  * after all checks pass. Note that all of the checks
2821  * done are done without using the player structure,
2822  * as pl may be null right now.
2823  */
2824  if (ns->login_method >= 2) {
2825  int i, j, stat_total=0;
2826  char *key, *value, *race=NULL, *class_name=NULL;
2827 
2828  /* By setting this to zero, then we can easily
2829  * check to see if all stats have been set.
2830  */
2831  memset(&new_stats, 0, sizeof(living));
2832 
2833  while (nlen < len) {
2834  i = buf[nlen]; /* Length of this line */
2835  /* Sanity check from client - don't want to loop
2836  * forever if there is a 0 length, and don't
2837  * want to read beyond size of packet.
2838  * Likewise, client should have sent
2839  * the string to us already null terminated,
2840  * but we will just make sure.
2841  */
2842  if ((i == 0) || (nlen + i > len)) break;
2843  buf[nlen + i] = 0;
2844 
2845  /* What we have are a series of lines -
2846  * 'key value' format. Find that space,
2847  * and null it out so we can do strcasecmp.
2848  * If no space, abort processing
2849  */
2850  key = buf + nlen + 1;
2851  value = strchr(key, ' ');
2852  if (!value) break;
2853  *value = 0;
2854  value++;
2855 
2856  if (!strcasecmp(key,"race")) race = value;
2857  else if (!strcasecmp(key,"class")) class_name = value;
2858  else if (!strcasecmp(key,"starting_map")) {
2859  map = try_find_archetype(value);
2860  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2861  SockList_AddString(&sl,
2862  "failure createplayer Invalid starting map");
2863  Send_With_Handling(ns, &sl);
2864  SockList_Term(&sl);
2865  return;
2866  }
2867  }
2868  else if (!strcasecmp(key,"choice")) {
2869  /* In general, MAX_CHOICES should be large enough
2870  * to always handle the choices from the client - of
2871  * course, the client could be broken and send us many
2872  * more choices than we should have, so handle that.
2873  */
2874  if (choice_num == MAX_CHOICES) {
2875  LOG(llevError,
2876  "Number of choices receive exceed max value: %d>%d\n",
2877  choice_num, MAX_CHOICES);
2878  } else {
2879  choices[choice_num] = value;
2880  choice_num++;
2881  }
2882  }
2883  else {
2884  /* Do stat processing here */
2885  for (j=0; j < NUM_STATS; j++) {
2886  if (!strcasecmp(key,short_stat_name[j])) {
2887  int val = atoi(value);
2888 
2889  set_attr_value(&new_stats, j, val);
2890  break;
2891  }
2892  }
2893  if (j >= NUM_STATS) {
2894  /* Bad clients could do this - we should at least report
2895  * it, and useful when trying to add new parameters.
2896  */
2897  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2898  }
2899  }
2900  nlen += i + 1;
2901  }
2902  /* Do some sanity checking now. But checking the stat
2903  * values here, we will catch any 0 values since we do
2904  * a memset above. A properly behaving client should
2905  * never do any of these things, but we do not presume
2906  * clients will behave properly.
2907  */
2908  for (j=0; j<NUM_STATS; j++) {
2909  int val = get_attr_value(&new_stats, j);
2910 
2911  stat_total += val;
2912  if (val > settings.starting_stat_max ||
2913  val < settings.starting_stat_min) {
2914  SockList_AddPrintf(&sl,
2915  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2917  Send_With_Handling(ns, &sl);
2918  SockList_Term(&sl);
2919  return;
2920  }
2921  }
2922  if (stat_total > settings.starting_stat_points) {
2923  SockList_AddPrintf(&sl,
2924  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2925  stat_total, settings.starting_stat_points);
2926  Send_With_Handling(ns, &sl);
2927  SockList_Term(&sl);
2928  return;
2929  }
2930 
2931  if (race)
2932  race_a = try_find_archetype(race);
2933 
2934  if (class_name)
2935  class_a = try_find_archetype(class_name);
2936 
2937  /* This should never happen with a properly behaving client, so the error message
2938  * doesn't have to be that great.
2939  */
2940  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2941  SockList_AddString(&sl,
2942  "failure createplayer Invalid or unknown race or class");
2943  Send_With_Handling(ns, &sl);
2944  SockList_Term(&sl);
2945  return;
2946  }
2947 
2948  /* At current time, only way this can fail is if the adjusted
2949  * stat is less than 1.
2950  */
2951  if (check_race_and_class(&new_stats, race_a, class_a)) {
2952  SockList_AddString(&sl,
2953  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2954  Send_With_Handling(ns, &sl);
2955  SockList_Term(&sl);
2956  return;
2957  }
2958 
2959  if (!pl)
2961  // If we already have a player, we a replaying on the same connection.
2962  // Since add_player normally sets ns->status, we still need that to happen.
2963  else
2964  ns->status = Ns_Avail;
2965 
2966  // We need to copy the name in before apply_race_and_class() because it
2967  // tells the client our character name. If we don't update it, they get the old one.
2968  FREE_AND_COPY(pl->ob->name, name);
2969 
2970  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2971 
2972  } else {
2973  /* In thise case, old login method */
2974  if (!pl)
2975  pl = add_player(ns, ADD_PLAYER_NEW);
2976  // If we already have a player, we a replaying on the same connection.
2977  // Since add_player normally sets ns->status, we still need that to happen.
2978  else
2979  ns->status = Ns_Avail;
2980 
2981  // Make sure to do this on both code branches.
2982  FREE_AND_COPY(pl->ob->name, name);
2983 /* already done by add_player
2984  roll_again(pl->ob);
2985  pl->state = ST_ROLL_STAT;
2986  set_first_map(pl->ob);*/
2987  }
2988 
2989  /* add_player does a lot of the work, but there are a few
2990  * things we need to update, like starting name and
2991  * password.
2992  * This is done before processing in login_method>2.
2993  * The character creation process it does when
2994  * applying the race/class will use this
2995  * name information.
2996  */
2997  FREE_AND_COPY(pl->ob->name_pl, name);
2998  pl->name_changed = 1;
2999  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
3000 
3001  SockList_AddString(&sl, "addme_success");
3002  Send_With_Handling(ns, &sl);
3003  SockList_Term(&sl);
3004 
3005  if (ns->login_method >= 2) {
3006  /* The client could have provided us a map - if so, map will be set
3007  * and we don't want to overwrite it
3008  */
3009  if (!map)
3011  assert(map); // Existence checked in init_dynamic()
3012 
3013  enter_exit(pl->ob, &map->clone);
3014 
3015  if (pl->ob->map == NULL) {
3016  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
3017  abort();
3018  }
3019 
3020  /* copy information to bed of reality information, in case the player dies */
3021  safe_strncpy(pl->savebed_map, pl->ob->map->path, sizeof(pl->savebed_map));
3022  pl->bed_x = pl->ob->x;
3023  pl->bed_y = pl->ob->y;
3024 
3026  }
3027 
3028  /* We insert any objects after we have put the player on the map -
3029  * this makes things safer, as certain objects may expect a normal
3030  * environment. Note that choice_num will only be set in the
3031  * loginmethod > 2, which also checks (and errors out) if the
3032  * race/class is not set, which is why explicit checking for
3033  * those is not need.
3034  */
3035  for (i=0; i < choice_num; i++) {
3036  char *choiceval;
3037  const char *value, *cp;
3038  archetype *arch;
3039  object *op;
3040 
3041  choiceval = strchr(choices[i], ' ');
3042  if (!choiceval) {
3043  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
3044  continue;
3045  }
3046  *choiceval=0;
3047  choiceval++;
3048  value = object_get_value(&race_a->clone, choices[i]);
3049  if (!value)
3050  value = object_get_value(&class_a->clone, choices[i]);
3051 
3052  if (!value) {
3053  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
3054  continue;
3055  }
3056  cp = strstr(value, choiceval);
3057  if (!cp) {
3058  LOG(llevError, "Choice value not found in archetype: %s %s\n",
3059  choices[i], choiceval);
3060  continue;
3061  }
3062 
3063  /* Check to make sure that the matched string is an entire word,
3064  * and not a substring (eg, valid choice being great_sword but
3065  * we just get sword) - the space after the match should either be a
3066  * space or null, and space before match should also be a space
3067  * or the start of the string.
3068  */
3069  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
3070  (cp != value) && (*(cp-1) != ' ')) {
3071 
3072  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
3073  choiceval, value);
3074  continue;
3075  }
3076  arch = try_find_archetype(choiceval);
3077  if (!arch) {
3078  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
3079  continue;
3080  }
3081  op = arch_to_object(arch);
3082  op = object_insert_in_ob(op, pl->ob);
3083  if (QUERY_FLAG(op, FLAG_AUTO_APPLY))
3084  ob_apply(op, pl->ob, 0);
3085  }
3086 
3087  LOG(llevInfo, "new character %s from %s\n", pl->ob->name, pl->ob->contr->socket->host);
3090  "%s has entered the game.", pl->ob->name);
3091 }
3092 
3103 void account_password(char *buf, int len, socket_struct *ns) {
3104  char old[MAX_BUF], change[MAX_BUF];
3105  int status;
3106  SockList sl;
3107 
3108  if (len <= 0 || !buf) {
3109  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
3110  return;
3111  }
3112 
3113  SockList_Init(&sl);
3114 
3115  if (ns->account_name == NULL) {
3116  SockList_AddString(&sl, "failure accountpw Not logged in");
3117  Send_With_Handling(ns, &sl);
3118  SockList_Term(&sl);
3119  return;
3120  }
3121 
3122  status = decode_name_password(buf, &len, old, change);
3123  if (status == 1) {
3124  SockList_AddString(&sl, "failure accountpw Old password is too long");
3125  Send_With_Handling(ns, &sl);
3126  SockList_Term(&sl);
3127  return;
3128  }
3129  if (status == 2) {
3130  SockList_AddString(&sl, "failure accountpw New password is too long");
3131  Send_With_Handling(ns, &sl);
3132  SockList_Term(&sl);
3133  return;
3134  }
3135  /*The minimum length isn't exactly required, but in the current implementation,
3136  * client will send the same password for character for which there is a
3137  * 2 character minimum size. Thus an account with a one character password
3138  * won't be able to create a character. */
3139  if (strlen(change)<2) {
3140  SockList_AddString(&sl, "failure accountpw New password is too short");
3141  Send_With_Handling(ns, &sl);
3142  SockList_Term(&sl);
3143  return;
3144  }
3145 
3146  status = account_check_string(change);
3147  if (status == 1) {
3148  SockList_AddString(&sl,
3149  "failure accountpw Choose a different password. " VALIDCHAR_MSG);
3150  Send_With_Handling(ns, &sl);
3151  SockList_Term(&sl);
3152  return;
3153  }
3154 
3155  if (status == 2) {
3156  SockList_AddString(&sl,
3157  "failure accountpw That password is too long");
3158  Send_With_Handling(ns, &sl);
3159  SockList_Term(&sl);
3160  return;
3161  }
3162 
3163  status = account_change_password(ns->account_name, old, change);
3164  if (status != 0) {
3165  const char *error;
3166 
3167  if (status == 1) {
3168  error = "failure accountpw Illegal characters present";
3169  } else if (status == 2) {
3170  error = "failure accountpw Invalid account";
3171  } else {
3172  error = "failure accountpw Incorrect current password";
3173  }
3174 
3175  SockList_AddString(&sl, error);
3176  Send_With_Handling(ns, &sl);
3177  SockList_Term(&sl);
3178  return;
3179  }
3180 
3181  /* If we got here, we passed all checks, and password was changed */
3183 }
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:2449
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
Problems requiring server admin to fix.
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:2109
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:82
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:2578
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:1264
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:2156
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:455
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:131
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:1930
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:333
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:323
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:1401
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:1797
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:361
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:1564
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:102
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:2335
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:2236
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:1420
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:330
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:1698
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:3103
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1759
GET_MAP_FACE_OBJ
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Gets the layer face of specified square.
Definition: map.h:187
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:210
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:1457
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:1811
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:104
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:244
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:254
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:2360
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:1360
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:325
living::Wis
int8_t Wis
Definition: living.h:36
Settings
Server settings.
Definition: global.h:245
create_player_cmd
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.cpp:2683
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:14
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:2054
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:2299
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:320
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:2000
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:1863
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:340
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:177
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:1504
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:1886
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:621
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:2676
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:1289
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:1906
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:331
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:255
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:2075
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:278
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:2200
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:89
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:1767
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:15
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:324
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