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  LOG(llevInfo, "Connection from %s (%s), CS %d, SC %d\n",
677  ns->host, rest, ns->cs_version, ns->sc_version);
678  }
679 }
680 
688  SockList sl;
689 
690  /* If getting a newmap command, this scroll information
691  * is no longer relevant.
692  */
693  ns->map_scroll_x = 0;
694  ns->map_scroll_y = 0;
695 
696 
697  memset(&ns->lastmap, 0, sizeof(ns->lastmap));
698  SockList_Init(&sl);
699  SockList_AddString(&sl, "newmap");
700  Send_With_Handling(ns, &sl);
701  SockList_Term(&sl);
702 }
703 
708 void move_cmd(char *buf, int len, player *pl) {
709  int vals[3], i;
710 
711  if (len <= 0 || !buf) {
712  LOG(llevDebug, "Player '%s' sent bogus move_cmd information\n", pl->ob->name);
713  return;
714  }
715 
716  /* A little funky here. We only cycle for 2 records, because
717  * we obviously am not going to find a space after the third
718  * record. Perhaps we should just replace this with a
719  * sscanf?
720  */
721  for (i = 0; i < 2; i++) {
722  vals[i] = atoi(buf);
723  if (!(buf = strchr(buf, ' '))) {
724  return;
725  }
726  buf++;
727  }
728  vals[2] = atoi(buf);
729 
730 /* LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
731  esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
732 }
733 
734 /***************************************************************************
735  *
736  * Start of commands the server sends to the client.
737  *
738  ***************************************************************************
739  */
740 
745 void send_query(socket_struct *ns, uint8_t flags, const char *text) {
746  SockList sl;
747 
748  SockList_Init(&sl);
749  SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
750  Send_With_Handling(ns, &sl);
751  SockList_Term(&sl);
752 }
753 
754 #define AddIfInt64(Old, New, sl, Type) \
755  if (Old != New) { \
756  Old = New; \
757  SockList_AddChar(sl, Type); \
758  SockList_AddInt64(sl, New); \
759  }
760 
761 #define AddIfInt(Old, New, sl, Type) \
762  if (Old != New) { \
763  Old = New; \
764  SockList_AddChar(sl, Type); \
765  SockList_AddInt(sl, New); \
766  }
767 
768 #define AddIfShort(Old, New, sl, Type) \
769  if (Old != New) { \
770  Old = New; \
771  SockList_AddChar(sl, Type); \
772  SockList_AddShort(sl, New); \
773  }
774 
775 #define AddIfFloat(Old, New, sl, Type) \
776  if (Old != New) { \
777  Old = New; \
778  SockList_AddChar(sl, Type); \
779  SockList_AddInt(sl, (long)(New*FLOAT_MULTI));\
780  }
781 
782 #define AddIfString(Old, New, sl, Type) \
783  if (Old == NULL || strcmp(Old, New)) { \
784  free(Old); \
785  Old = strdup_local(New); \
786  SockList_AddChar(sl, Type); \
787  SockList_AddLen8Data(sl, New, strlen(New)); \
788  }
789 
795 static uint8_t is_perfect(const player *pl) {
796  const int16_t until = MIN(11, pl->ob->level);
797  for (int16_t i = 1; i < until; i++) {
798  if (pl->levhp[i] < 9 || pl->levsp[i] < 6 || pl->levgrace[i] < 3) {
799  return 0;
800  }
801  }
802  return 1;
803 }
804 
810 static void send_extra_stats(SockList *sl, player *pl) {
811  uint32_t uflags = 0;
812  const char *god = "none";
813 
814  if (pl->socket->notifications < 3) {
815  return;
816  }
817 
818  if (!pl->peaceful) {
819  uflags |= CF_HOSTILE;
820  }
821  if (!is_perfect(pl)) {
822  uflags |= CF_NOT_PERFECT;
823  }
824 
825 #define FIF(F, C) \
826  if (QUERY_FLAG(pl->ob, F)) { \
827  uflags |= C; \
828  }
830  FIF(FLAG_CONFUSED, CF_CONFUSED); // If confused by an item
834 
835  FOR_INV_PREPARE(pl->ob, item) {
836  if (item->type == DISEASE && !QUERY_FLAG(item, FLAG_STARTEQUIP)) {
837  uflags |= CF_DISEASED;
838  }
839  if (strcmp(item->arch->name, "poisoning") == 0) {
840  uflags |= CF_POISONED;
841  }
842  if (strcmp(item->arch->name, "blindness") == 0) {
843  uflags |= CF_BLIND;
844  }
845  if (item->type == FORCE && strcmp(item->name, "confusion") == 0) {
846  uflags |= CF_CONFUSED;
847  }
848  if (item->type == SKILL && item->subtype == SK_PRAYING && item->title) {
849  god = item->title;
850  }
851  }
852  FOR_INV_FINISH();
853 
856  AddIfString(pl->socket->stats.god, god, sl, CS_STAT_GOD_NAME);
858 }
859 
867  SockList sl;
868  char buf[MAX_BUF];
869  uint16_t flags;
870  uint8_t s;
871 
872  SockList_Init(&sl);
873  SockList_AddString(&sl, "stats ");
874 
875  if (pl->ob != NULL) {
876  AddIfShort(pl->last_stats.hp, pl->ob->stats.hp, &sl, CS_STAT_HP);
878  AddIfShort(pl->last_stats.sp, pl->ob->stats.sp, &sl, CS_STAT_SP);
882  AddIfShort(pl->last_stats.Str, pl->ob->stats.Str, &sl, CS_STAT_STR);
883  AddIfShort(pl->last_stats.Int, pl->ob->stats.Int, &sl, CS_STAT_INT);
884  AddIfShort(pl->last_stats.Pow, pl->ob->stats.Pow, &sl, CS_STAT_POW);
885  AddIfShort(pl->last_stats.Wis, pl->ob->stats.Wis, &sl, CS_STAT_WIS);
886  AddIfShort(pl->last_stats.Dex, pl->ob->stats.Dex, &sl, CS_STAT_DEX);
887  AddIfShort(pl->last_stats.Con, pl->ob->stats.Con, &sl, CS_STAT_CON);
888  AddIfShort(pl->last_stats.Cha, pl->ob->stats.Cha, &sl, CS_STAT_CHA);
889  }
890  if (pl->socket->extended_stats) {
891  int16_t golem_hp, golem_maxhp;
899  if (pl->ob != NULL) {
914  }
915  if (pl->ranges[range_golem]) {
916  object *golem = pl->ranges[range_golem];
917  if (QUERY_FLAG(golem, FLAG_REMOVED) || golem->count != pl->golem_count || QUERY_FLAG(golem, FLAG_FREED)) {
918  golem_hp = 0;
919  golem_maxhp = 0;
920  } else {
921  golem_hp = golem->stats.hp;
922  golem_maxhp = golem->stats.maxhp;
923  }
924  } else {
925  golem_hp = 0;
926  golem_maxhp = 0;
927  }
928  /* send first the maxhp, so the client can set up the display */
929  AddIfShort(pl->last_golem_maxhp, golem_maxhp, &sl, CS_STAT_GOLEM_MAXHP);
930  AddIfShort(pl->last_golem_hp, golem_hp, &sl, CS_STAT_GOLEM_HP);
931  }
932 
933  for (s = 0; s < MAX_SKILLS; s++) {
934  if (pl->last_skill_ob[s]) {
935  // Skill objects can be removed without updating last_skill_ob.
936  // Clean them up here if that's the case.
937  if (QUERY_FLAG(pl->last_skill_ob[s], FLAG_REMOVED)) {
938  LOG(llevDebug, "pruning removed object from last_skill_ob\n");
939  pl->last_skill_ob[s] = NULL;
940  continue;
941  }
942 
943  if (pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
944  /* Always send along the level if exp changes. This
945  * is only 1 extra byte, but keeps processing simpler.
946  */
948  SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
950  pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
951  }
952  }
953  }
954  AddIfInt64(pl->last_stats.exp, pl->ob->stats.exp, &sl, CS_STAT_EXP64);
955  AddIfShort(pl->last_level, (char)pl->ob->level, &sl, CS_STAT_LEVEL);
956  AddIfShort(pl->last_stats.wc, pl->ob->stats.wc, &sl, CS_STAT_WC);
957  AddIfShort(pl->last_stats.ac, pl->ob->stats.ac, &sl, CS_STAT_AC);
958  AddIfShort(pl->last_stats.dam, pl->ob->stats.dam, &sl, CS_STAT_DAM);
959  AddIfFloat(pl->last_speed, pl->ob->speed, &sl, CS_STAT_SPEED);
963  flags = 0;
964  if (pl->fire_on)
965  flags |= SF_FIREON;
966  if (pl->run_on)
967  flags |= SF_RUNON;
968 
970  if (pl->socket->sc_version < 1025) {
972  } else {
973  int i;
974 
975  for (i = 0; i < NROFATTACKS; i++) {
976  /* Skip ones we won't send */
977  if (atnr_cs_stat[i] == -1)
978  continue;
979  AddIfShort(pl->last_resist[i], pl->ob->resist[i], &sl, (char)atnr_cs_stat[i]);
980  }
981  }
982  if (pl->socket->monitor_spells) {
986  }
987  /* we want to use the new fire & run system in new client */
988  rangetostring(pl->ob, buf, sizeof(buf));
990  set_title(pl->ob, buf, sizeof(buf));
992 
993  send_extra_stats(&sl, pl);
994 
995  /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
996  if (sl.len > 8) {
997 #ifdef ESRV_DEBUG
998  LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
999 #endif
1000  Send_With_Handling(pl->socket, &sl);
1001  }
1002  SockList_Term(&sl);
1003 }
1004 
1008 void esrv_new_player(player *pl, uint32_t weight) {
1009  SockList sl;
1010 
1011  pl->last_weight = weight;
1012 
1013  if (!(pl->socket->faces_sent[pl->ob->face->number]&NS_FACESENT_FACE))
1014  esrv_send_face(pl->socket, pl->ob->face, 0);
1015 
1016  SockList_Init(&sl);
1017  SockList_AddString(&sl, "player ");
1018  SockList_AddInt(&sl, pl->ob->count);
1019  SockList_AddInt(&sl, weight);
1020  SockList_AddInt(&sl, pl->ob->face->number);
1021  SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
1022 
1023  Send_With_Handling(pl->socket, &sl);
1024  SockList_Term(&sl);
1026 }
1027 
1039  SockList sl;
1040  int i;
1041 
1042  if (anim == NULL) {
1043  LOG(llevError, "esrv_send_anim NULL??\n");
1044  return;
1045  }
1046 
1047  SockList_Init(&sl);
1048  SockList_AddString(&sl, "anim ");
1049  SockList_AddShort(&sl, anim->num);
1050  SockList_AddShort(&sl, 0); /* flags - not used right now */
1051  /* Build up the list of faces. Also, send any information (ie, the
1052  * the face itself) down to the client.
1053  */
1054  for (i = 0; i < anim->num_animations; i++) {
1055  if (!(ns->faces_sent[anim->faces[i]->number]&NS_FACESENT_FACE))
1056  esrv_send_face(ns, anim->faces[i], 0);
1057  /* flags - not used right now */
1058  SockList_AddShort(&sl, anim->faces[i]->number);
1059  }
1060  Send_With_Handling(ns, &sl);
1061  SockList_Term(&sl);
1062  ns->anims_sent[anim->num] = 1;
1063 }
1064 
1065 /****************************************************************************
1066  *
1067  * Start of map related commands.
1068  *
1069  ****************************************************************************/
1070 
1072 static void map_clearcell(struct map_cell_struct *cell, int face, int darkness) {
1073  cell->darkness = darkness;
1074  memset(cell->faces, face, sizeof(cell->faces));
1075 }
1076 
1077 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
1078 
1086 static const object *heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS];
1087 
1088 /****************************************************************************
1089  * This block is for map2 drawing related commands.
1090  * Note that the map2 still uses other functions.
1091  *
1092  ***************************************************************************/
1093 
1113 static int map2_add_ob(int ax, int ay, int layer, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int is_head) {
1114  uint8_t nlayer, smoothlevel = 0;
1115  const object *head;
1116 
1117  assert(ob != NULL);
1118 
1119  head = HEAD(ob);
1120  const Face *face = ob->face;
1121 
1122  /* This is a multipart object, and we are not at the lower
1123  * right corner. So we need to store away the lower right corner.
1124  */
1125  if (!is_head && (head->arch->tail_x || head->arch->tail_y)
1126  && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
1127  int bx, by, l;
1128 
1129  /* Basically figure out where the offset is from where we
1130  * are right now. the ob->arch->clone.{x,y} values hold
1131  * the offset that this current piece is from the head,
1132  * and the tail is where the tail is from the head.
1133  * Note that bx and by will equal sx and sy if we are
1134  * already working on the bottom right corner. If ob is
1135  * the head, the clone values will be zero, so the right
1136  * thing will still happen.
1137  */
1138  bx = ax+head->arch->tail_x-ob->arch->clone.x;
1139  by = ay+head->arch->tail_y-ob->arch->clone.y;
1140 
1141  /* I don't think this can ever happen, but better to check
1142  * for it just in case.
1143  */
1144  if (bx < ax || by < ay) {
1145  LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
1146  face = NULL;
1147  }
1148  /* the target position must be within +/-1 of our current
1149  * layer as the layers are defined. We are basically checking
1150  * to see if we have already stored this object away.
1151  */
1152  for (l = layer-1; l <= layer+1; l++) {
1153  if (l < 0 || l >= MAP_LAYERS)
1154  continue;
1155  if (heads[by][bx][l] == head)
1156  break;
1157  }
1158  /* Didn't find it. So we need to store it away. Try to store it
1159  * on our original layer, and then move up a layer.
1160  */
1161  if (l == layer+2) {
1162  if (!heads[by][bx][layer])
1163  heads[by][bx][layer] = head;
1164  else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
1165  heads[by][bx][layer+1] = head;
1166  }
1167  return 0;
1168  /* Ok - All done storing away the head for future use */
1169  } else {
1170  uint16_t face_num = face ? face->number : 0;
1171  (*has_obj)++;
1174  face_num = (ob->animation ? ob->animation->num : 0)|(1<<15);
1176  face_num |= ANIM_SYNC;
1177  else if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM))
1178  face_num |= ANIM_RANDOM;
1179  }
1180  /* Since face_num includes the bits for the animation tag,
1181  * and we will store that away in the faces[] array, below
1182  * check works fine _except_ for the case where animation
1183  * speed chances.
1184  */
1185  if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
1186  uint8_t len, anim_speed = 0, i;
1187 
1188  /* This block takes care of sending the actual face
1189  * to the client. */
1190  ns->lastmap.cells[ax][ay].faces[layer] = face_num;
1191 
1192  /* Now form the data packet */
1193  nlayer = MAP2_LAYER_START+layer;
1194 
1195  len = 2;
1196 
1197  if (ob->map && !MAP_NOSMOOTH(ob->map)) {
1198  smoothlevel = ob->smoothlevel;
1199  if (smoothlevel)
1200  len++;
1201  }
1202 
1205  len++;
1206  /* 1/0.004 == 250, so this is a good cap for an
1207  * upper limit */
1208  if (ob->anim_speed)
1209  anim_speed = ob->anim_speed;
1210  else if (FABS(ob->speed) < 0.004)
1211  anim_speed = 255;
1212  else if (FABS(ob->speed) >= 1.0)
1213  anim_speed = 1;
1214  else
1215  anim_speed = (int)(1.0/FABS(ob->speed));
1216 
1217  if (ob->animation && !ns->anims_sent[ob->animation->num])
1218  esrv_send_animation(ns, ob->animation);
1219 
1220  /* If smoothing, need to send smoothing information
1221  * for all faces in the animation sequence. Since
1222  * smoothlevel is an object attribute,
1223  * it applies to all faces.
1224  */
1225  if (smoothlevel) {
1226  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1227  if (!(ns->faces_sent[ob->animation->faces[i]->number]&NS_FACESENT_SMOOTH))
1228  send_smooth(ns, ob->animation->faces[i]);
1229  }
1230  }
1231  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1232  esrv_send_face(ns, face, 0);
1233  }
1234 
1235  if (smoothlevel
1236  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1237  send_smooth(ns, ob->face);
1238 
1239  /* Length of packet */
1240  nlayer |= len<<5;
1241 
1242  SockList_AddChar(sl, nlayer);
1243  SockList_AddShort(sl, face_num);
1244  if (anim_speed)
1245  SockList_AddChar(sl, anim_speed);
1246  if (smoothlevel)
1247  SockList_AddChar(sl, smoothlevel);
1248  return 1;
1249  } /* Face is different */
1250  }
1251  return 0;
1252 }
1253 
1254 /* This function is used see if a layer needs to be cleared.
1255  * It updates the socklist, and returns 1 if the update is
1256  * needed, 0 otherwise.
1257  */
1258 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1259  int nlayer;
1260 
1261  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1262  /* Now form the data packet */
1263  nlayer = 0x10+layer+(2<<5);
1264  SockList_AddChar(sl, nlayer);
1265  SockList_AddShort(sl, 0);
1266  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1267  return 1;
1268  }
1269  return 0;
1270 }
1271 
1283 static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1284  int got_one = 0, poisoned = 0, diseased = 0;
1285  char name[60];
1286  int value, granularity;
1287  const object *probe;
1288 
1289  /* send hp bar if needed */
1290  if ((*alive_layer) != -1 || ob->head || !CAN_PROBE(ob))
1291  return 0;
1292 
1293  if (settings.always_show_hp == 2) {
1294  /* global hp bars are enabled */
1295  granularity = 30;
1296  } else if (settings.always_show_hp == 1 && ob->stats.hp < ob->stats.maxhp) {
1297  granularity = 30;
1298  } else {
1299  /* only give hp bars to monsters that have been probed */
1300  if (!QUERY_FLAG(ob, FLAG_PROBE)) {
1301  return 0;
1302  }
1303  probe = object_find_by_type_and_name(ob, FORCE, "probe_force");
1304  if (probe == NULL || probe->level < 15) {
1305  /* if probe is not null, this is an error, but well */
1306  return 0;
1307  }
1308 
1309  granularity = (probe->level - 14) / 3;
1310  if (granularity <= 0)
1311  granularity = 1;
1312  else if (granularity > 30)
1313  granularity = 30;
1314  }
1315 
1316  if (ob->stats.maxhp > 0) {
1317  value = (ob->stats.hp * granularity) / (ob->stats.maxhp);
1318 
1319  if (value < 0)
1320  value = 0;
1321  else if (value > granularity)
1322  value = granularity;
1323  } else
1324  value = 30;
1325 
1326  value = (value * 30) / granularity;
1327 
1328  if (object_present_in_ob(POISONING, ob) != NULL)
1329  poisoned = 1;
1330  if (object_present_in_ob(DISEASE, ob) != NULL)
1331  diseased = 1;
1332 
1333  if (value > 0) {
1334  archetype *dummy;
1335 
1336  snprintf(name, sizeof(name), "hpbar%s%s%s_%d",
1337  poisoned ? "_poisoned" : "",
1338  diseased ? "_diseased" : "",
1339  (!poisoned && !diseased) ? "_standard" : "",
1340  value);
1341  dummy = try_find_archetype(name);
1342  if (dummy != NULL) {
1343  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1344  (*alive_layer) = MAP_LAYER_FLY2;
1345  }
1346  }
1347 
1348  return got_one;
1349 }
1350 
1351 static void map2_add_label(socket_struct *ns, SockList *sl, enum map2_label subtype, const char *label) {
1352  // protect old clients from label with additive length, which can cause them to crash
1353  if (ns->sc_version < 1030)
1354  return;
1355 
1356  int len = strlen(label);
1357  if (len > 256 - 2 - 1) {
1358  LOG(llevError, "The label '%s' is too long to send to the client.", label);
1359  return;
1360  }
1361  SockList_AddChar(sl, MAP2_ADD_LENGTH | MAP2_TYPE_LABEL); // label with additive length
1362  SockList_AddChar(sl, len + 2); // length of payload (subtype + lstring)
1363  SockList_AddChar(sl, subtype);
1364  SockList_AddChar(sl, len); // lstring length prefix
1365  SockList_AddString(sl, label);
1366 }
1367 
1368 static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer) {
1369  socket_struct *ns = plyr->socket;
1370  int got_one = check_probe(ax, ay, ob, sl, ns, has_obj, alive_layer);
1371  // add NPC speech bubble
1372  if (QUERY_FLAG(ob, FLAG_ALIVE) && (QUERY_FLAG(ob, FLAG_UNAGGRESSIVE) || QUERY_FLAG(ob, FLAG_FRIENDLY)) && ob->type != PLAYER) {
1373  if (ob->msg != NULL || object_find_by_arch_name(ob, NPC_DIALOG_ARCH)) {
1374  archetype *dummy = try_find_archetype("speechbubble");
1375  if (dummy != NULL) {
1376  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1377  (*alive_layer) = MAP_LAYER_FLY2;
1378  }
1379  }
1380  }
1381  // add player name label
1382  if (ob->type == PLAYER) {
1383  enum map2_label subtype = MAP2_LABEL_PLAYER;
1384  if (QUERY_FLAG(ob, FLAG_WIZ)) {
1385  subtype = MAP2_LABEL_DM;
1386  } else if (plyr->party) {
1387  if (ob->contr && ob->contr->party == plyr->party) {
1388  subtype = MAP2_LABEL_PLAYER_PARTY;
1389  }
1390  }
1391  map2_add_label(ns, sl, subtype, ob->name);
1392  got_one += 1;
1393  }
1394  return got_one;
1395 }
1396 
1397 /*
1398  * This function is used to check a space (ax, ay) whose only
1399  * data we may care about are any heads. Basically, this
1400  * space is out of direct view. This is only used with the
1401  * Map2 protocol.
1402  *
1403  * @param ax
1404  * viewport relative x-coordinate
1405  * @param ay
1406  * viewport relative y-coordinate
1407  * @param sl
1408  * the reply to append to
1409  * @param ns
1410  * the client socket
1411  */
1412 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1413  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1414  uint16_t coord;
1415 
1416  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1417  oldlen = sl->len;
1418  SockList_AddShort(sl, coord);
1419 
1420  for (layer = 0; layer < MAP_LAYERS; layer++) {
1421  const object *head;
1422 
1423  head = heads[ay][ax][layer];
1424  if (head) {
1425  /* in this context, got_one should always increase
1426  * because heads should always point to data to really send.
1427  */
1428  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1429  } else {
1430  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1431  }
1432  }
1433  /* Note - if/when lighting information is added, some code is
1434  * needed here - lighting sources that are out of sight may still
1435  * extend into the viewable area.
1436  */
1437 
1438  /* If nothing to do for this space, we
1439  * can erase the coordinate bytes
1440  */
1441  if (!del_one && !got_one) {
1442  sl->len = oldlen;
1443  } else if (del_one && !has_obj) {
1444  /* If we're only deleting faces and not adding, and there
1445  * are not any faces on the space we care about,
1446  * more efficient
1447  * to send 0 as the type/len field.
1448  */
1449  sl->len = oldlen+2; /* 2 bytes for coordinate */
1450  SockList_AddChar(sl, MAP2_TYPE_CLEAR); /* Clear byte */
1451  SockList_AddChar(sl, 255); /* Termination byte */
1452  // Reduce defreferences by passing the inner array offset instead of address of value
1453  map_clearcell(ns->lastmap.cells[ax] + ay, 0, 0);
1454  } else {
1455  SockList_AddChar(sl, 255); /* Termination byte */
1456  }
1457 }
1458 
1459 static void draw_client_map2(object *pl) {
1460  int x, y, ax, ay, darkness, min_x, max_x, min_y, max_y, oldlen, layer;
1461  size_t startlen;
1462  int16_t nx, ny;
1463  SockList sl;
1464  uint16_t coord;
1465  mapstruct *m;
1466  // Dereference once. It should not change in the middle of processing.
1467  player *plyr = pl->contr;
1468 
1469  SockList_Init(&sl);
1470  SockList_AddString(&sl, "map2 ");
1471  startlen = sl.len;
1472 
1473  handle_scroll(plyr->socket, &sl);
1474 
1475  /* Init data to zero */
1476  memset(heads, 0, sizeof(heads));
1477 
1478  /* We could do this logic as conditionals in the if statement,
1479  * but that started to get a bit messy to look at.
1480  */
1481  min_x = pl->x-plyr->socket->mapx/2;
1482  min_y = pl->y-plyr->socket->mapy/2;
1483  max_x = pl->x+(plyr->socket->mapx+1)/2+MAX_HEAD_OFFSET;
1484  max_y = pl->y+(plyr->socket->mapy+1)/2+MAX_HEAD_OFFSET;
1485 
1486  /* x, y are the real map locations. ax, ay are viewport relative
1487  * locations.
1488  */
1489  ay = 0;
1490  for (y = min_y; y < max_y; y++, ay++) {
1491  ax = 0;
1492  for (x = min_x; x < max_x; x++, ax++) {
1493  /* If this space is out of the normal viewable area,
1494  * we only check the heads value. This is used to
1495  * handle big images - if they extend to a viewable
1496  * portion, we need to send just the lower right corner.
1497  */
1498  if (ax >= plyr->socket->mapx || ay >= plyr->socket->mapy) {
1499  check_space_for_heads(ax, ay, &sl, plyr->socket);
1500  } else {
1501  /* This space is within the viewport of the client. Due
1502  * to walls or darkness, it may still not be visible.
1503  */
1504 
1505  /* Meaning of darkness (see defines in LOS_* in los.c):
1506  * LOS_NO_DARKNESS (0) - object is in plain sight, full brightness.
1507  * 1 - MAX_DARKNESS - how dark the space is - higher
1508  * value is darker space. If level is at max darkness,
1509  * you can't see the space (too dark)
1510  * LOS_BLOCKED (100) - space is blocked from sight.
1511  */
1512  darkness = plyr->blocked_los[ax][ay];
1513 
1514  /* If the coordinates are not valid, or it is too
1515  * dark to see, we tell the client as such
1516  */
1517  nx = x;
1518  ny = y;
1519  m = get_map_from_coord(pl->map, &nx, &ny);
1520  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1521 
1522  if (!m) {
1523  /* space is out of map. Update space and clear
1524  * values if this hasn't already been done.
1525  * If the space is out of the map, it shouldn't
1526  * have a head.
1527  */
1528  if (plyr->socket->lastmap.cells[ax][ay].darkness != 0) {
1529  SockList_AddShort(&sl, coord);
1531  SockList_AddChar(&sl, 255); /* Termination byte */
1532  // Reduce dereferences by passing the inner array offset instead of address of value
1533  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1534  }
1535  } else if (darkness >= MAX_LIGHT_RADII) {
1536  /* This block deals with spaces that are not
1537  * visible due to darkness or walls. Still
1538  * need to send the heads for this space.
1539  */
1540  check_space_for_heads(ax, ay, &sl, plyr->socket);
1541  } else {
1542  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1543 
1544  /* In this block, the space is visible. */
1545 
1546  /* Rather than try to figure out what everything
1547  * that we might need to send is, then form the
1548  * packet after that, we presume that we will in
1549  * fact form a packet, and update the bits by what
1550  * we do actually send. If we send nothing, we
1551  * just back out sl.len to the old value, and no
1552  * harm is done.
1553  * I think this is simpler than doing a bunch of
1554  * checks to see what if anything we need to send,
1555  * setting the bits, then doing those checks again
1556  * to add the real data.
1557  */
1558 
1559  oldlen = sl.len;
1560  SockList_AddShort(&sl, coord);
1561 
1562  /* Darkness changed */
1563  if (plyr->socket->lastmap.cells[ax][ay].darkness != darkness
1564  && plyr->socket->darkness) {
1565  plyr->socket->lastmap.cells[ax][ay].darkness = darkness;
1566  /* Darkness tag & length (length=1) */
1567  SockList_AddChar(&sl, MAP2_TYPE_DARKNESS|(1<<5));
1568 
1569  /* Convert darkness level (0-MAX_DARKNESS) to a value
1570  * from 1 (dark) to 255 (bright) for the client.
1571  * Darkness values of 0 (completely dark) are not sent,
1572  * as the space is completely dark.
1573  */
1574  SockList_AddChar(&sl, 255-darkness*(256/MAX_LIGHT_RADII));
1575  have_darkness = 1;
1576  }
1577 
1578  for (layer = 0; layer < MAP_LAYERS; layer++) {
1579  const object *ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1580 
1581  /* Special case: send player itself if invisible */
1582  if (!ob
1583  && x == pl->x
1584  && y == pl->y
1585  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1586  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1587  ob = pl;
1588 
1589  if (ob) {
1590  g1 = has_obj;
1591  old_got = got_one;
1592  got_one += map2_add_ob(ax, ay, layer, ob, &sl, plyr->socket, &has_obj, 0);
1593 
1594  /* if we added the face, or it is a monster's head, check probe spell */
1595  if (got_one != old_got || ob->head == NULL)
1596  got_one += annotate_ob(ax, ay, ob, &sl, plyr, &has_obj, &alive_layer);
1597 
1598  /* If we are just storing away the head
1599  * for future use, then effectively this
1600  * space/layer is blank, and we should clear
1601  * it if needed.
1602  */
1603  if (g1 == has_obj) {
1604  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1605  }
1606  } else {
1607  if (layer != alive_layer)
1608  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1609  }
1610  }
1611  /* If nothing to do for this space, we
1612  * can erase the coordinate bytes
1613  */
1614  if (!del_one && !got_one && !have_darkness) {
1615  sl.len = oldlen;
1616  } else if (del_one && !has_obj) {
1617  /* If we're only deleting faces and don't
1618  * have any objs we care about, just clear
1619  * space. Note it is possible we may have
1620  * darkness, but if there is nothing on the
1621  * space, darkness isn't all that interesting
1622  * - we can send it when an object shows up.
1623  */
1624  sl.len = oldlen+2; /* 2 bytes for coordinate */
1626  SockList_AddChar(&sl, 255); /* Termination byte */
1627  // Reduce dereferences by passing the inner array offset instead of address of value
1628  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1629  } else {
1630  SockList_AddChar(&sl, 255); /* Termination byte */
1631  }
1632  }
1633  } /* else this is a viewable space */
1634  } /* for x loop */
1635  } /* for y loop */
1636 
1637  /* Only send this if there are in fact some differences. */
1638  if (sl.len > startlen) {
1639  Send_With_Handling(plyr->socket, &sl);
1640  }
1641  SockList_Term(&sl);
1642 }
1643 
1647 void draw_client_map(object *pl) {
1648  int i, j;
1649  int16_t ax, ay;
1650  int mflags;
1651  mapstruct *m, *pm;
1652  int min_x, min_y, max_x, max_y;
1653 
1654  if (pl->type != PLAYER) {
1655  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1656  return;
1657  }
1658 
1659  if (pl->contr->transport) {
1660  pm = pl->contr->transport->map;
1661  } else
1662  pm = pl->map;
1663 
1664  /* If player is just joining the game, he isn't here yet, so
1665  * the map can get swapped out. If so, don't try to send them
1666  * a map. All will be OK once they really log in.
1667  */
1668  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1669  return;
1670 
1671  /*
1672  * This block just makes sure all the spaces are properly
1673  * updated in terms of what they look like.
1674  */
1675  min_x = pl->x-pl->contr->socket->mapx/2;
1676  min_y = pl->y-pl->contr->socket->mapy/2;
1677  max_x = pl->x+(pl->contr->socket->mapx+1)/2;
1678  max_y = pl->y+(pl->contr->socket->mapy+1)/2;
1679  for (j = min_y; j < max_y; j++) {
1680  for (i = min_x; i < max_x; i++) {
1681  ax = i;
1682  ay = j;
1683  m = pm;
1684  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1685  if (mflags&P_OUT_OF_MAP)
1686  continue;
1687  if (mflags&P_NEED_UPDATE)
1688  update_position(m, ax, ay);
1689  /* If a map is visible to the player, we don't want
1690  * to swap it out just to reload it. This should
1691  * really call something like swap_map, but this is
1692  * much more efficient and 'good enough'
1693  */
1694  if (mflags&P_NEW_MAP)
1695  map_reset_swap(m);
1696  }
1697  }
1698 
1699  /* do LOS after calls to update_position */
1700  if (pl->contr->do_los) {
1701  update_los(pl);
1702  pl->contr->do_los = 0;
1703  }
1704 
1705  draw_client_map2(pl);
1706 }
1707 
1708 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1709  struct Map newmap;
1710  int x, y, mx, my;
1711 
1712  ns->map_scroll_x += dx;
1713  ns->map_scroll_y += dy;
1714 
1715  mx = ns->mapx+MAX_HEAD_OFFSET;
1716  my = ns->mapy+MAX_HEAD_OFFSET;
1717 
1718  /* the x and y here are coordinates for the new map, i.e. if we moved
1719  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1720  * if the destination x or y coordinate is outside the viewable
1721  * area, we clear the values - otherwise, the old values
1722  * are preserved, and the check_head thinks it needs to clear them.
1723  */
1724  for (x = 0; x < mx; x++) {
1725  for (y = 0; y < my; y++) {
1726  if (x >= ns->mapx || y >= ns->mapy) {
1727  /* clear cells outside the viewable area */
1728  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1729  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1730  /* clear newly visible tiles within the viewable area */
1731  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1732  } else {
1733  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1734  }
1735  }
1736  }
1737 
1738  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1739 }
1740 
1746 void send_plugin_custom_message(object *pl, char *buf) {
1747  SockList sl;
1748 
1749  SockList_Init(&sl);
1750  SockList_AddString(&sl, buf);
1751  Send_With_Handling(pl->contr->socket, &sl);
1752  SockList_Term(&sl);
1753 }
1754 
1761  SockList sl;
1762  int flags = 0;
1763  client_spell *spell_info;
1764 
1765  if (!pl->socket || !pl->socket->monitor_spells)
1766  return;
1767 
1768  /* Handles problem at login, where this is called from fix_object
1769  * before we have had a chance to send spells to the player. It does seem
1770  * to me that there should never be a case where update_spells is called
1771  * before add_spells has been called. Add_spells() will update the
1772  * spell_state to non null.
1773  */
1774  if (!pl->spell_state)
1775  return;
1776 
1777  FOR_INV_PREPARE(pl->ob, spell) {
1778  if (spell->type == SPELL) {
1779  spell_info = get_client_spell_state(pl, spell);
1780  /* check if we need to update it*/
1781  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1782  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1783  flags |= UPD_SP_MANA;
1784  }
1785  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1787  flags |= UPD_SP_GRACE;
1788  }
1789  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1790  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1791  flags |= UPD_SP_DAMAGE;
1792  }
1793  if (flags != 0) {
1794  SockList_Init(&sl);
1795  SockList_AddString(&sl, "updspell ");
1796  SockList_AddChar(&sl, flags);
1797  SockList_AddInt(&sl, spell->count);
1798  if (flags&UPD_SP_MANA)
1799  SockList_AddShort(&sl, spell_info->last_sp);
1800  if (flags&UPD_SP_GRACE)
1801  SockList_AddShort(&sl, spell_info->last_grace);
1802  if (flags&UPD_SP_DAMAGE)
1803  SockList_AddShort(&sl, spell_info->last_dam);
1804  flags = 0;
1805  Send_With_Handling(pl->socket, &sl);
1806  SockList_Term(&sl);
1807  }
1808  }
1809  } FOR_INV_FINISH();
1810 }
1811 
1812 void esrv_remove_spell(player *pl, object *spell) {
1813  SockList sl;
1814 
1815  if (!pl || !spell || spell->env != pl->ob) {
1816  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1817  return;
1818  }
1819  if (!pl->socket->monitor_spells)
1820  return;
1821 
1822  SockList_Init(&sl);
1823  SockList_AddString(&sl, "delspell ");
1824  SockList_AddInt(&sl, spell->count);
1825  Send_With_Handling(pl->socket, &sl);
1826  SockList_Term(&sl);
1827 }
1828 
1836  SockList sl;
1837 
1838  if (!pl->socket->want_pickup)
1839  return;
1840  SockList_Init(&sl);
1841  SockList_AddString(&sl, "pickup ");
1842  SockList_AddInt(&sl, pl->mode);
1843  Send_With_Handling(pl->socket, &sl);
1844  SockList_Term(&sl);
1845 }
1846 
1855 static int spell_client_use(const object *spell) {
1856  switch (spell->subtype)
1857  {
1858  case SP_RAISE_DEAD:
1859  case SP_MAKE_MARK:
1860  return 3;
1861  case SP_RUNE:
1862  if (!spell->other_arch)
1863  return 1;
1864  break;
1865  case SP_CREATE_FOOD:
1866  case SP_CREATE_MISSILE:
1867  return 2;
1868  case SP_SUMMON_MONSTER:
1869  if (spell->randomitems != NULL)
1870  return 2;
1871  /* break; */// If add conditins below, use this break statement
1872  }
1873  // This is not in the switch statement so that it supports fallthrough logic
1874  // on the few spell types that have additional conditions attached.
1875  return 0;
1876 }
1877 
1879 static void append_spell(player *pl, SockList *sl, object *spell) {
1880  client_spell *spell_info;
1881  int len, i, skill = 0;
1882 
1883  if (!spell->name) {
1884  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1885  return;
1886  }
1887 
1888  if (spell->face && !(pl->socket->faces_sent[spell->face->number]&NS_FACESENT_FACE))
1889  esrv_send_face(pl->socket, spell->face, 0);
1890 
1891  spell_info = get_client_spell_state(pl, spell);
1892  SockList_AddInt(sl, spell->count);
1893  SockList_AddShort(sl, spell->level);
1894  SockList_AddShort(sl, spell->casting_time);
1895  /* store costs and damage in the object struct, to compare to later */
1896  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1898  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1899  /* send the current values */
1900  SockList_AddShort(sl, spell_info->last_sp);
1901  SockList_AddShort(sl, spell_info->last_grace);
1902  SockList_AddShort(sl, spell_info->last_dam);
1903 
1904  /* figure out which skill it uses, if it uses one */
1905  if (spell->skill) {
1906  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++)
1907  if (!strcmp(spell->skill, skill_names[i])) {
1909  break;
1910  }
1911  }
1912  SockList_AddChar(sl, skill);
1913 
1914  SockList_AddInt(sl, spell->path_attuned);
1915  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1916  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1917 
1918  if (!spell->msg) {
1919  SockList_AddShort(sl, 0);
1920  } else {
1921  len = strlen(spell->msg);
1922  SockList_AddShort(sl, len);
1923  SockList_AddData(sl, spell->msg, len);
1924  }
1925 
1926  /* Extended spell information available if the client wants it.
1927  */
1928  if (pl->socket->monitor_spells >= 2) {
1929  /* spellmon 2
1930  */
1931  sstring req = object_get_value(spell, "casting_requirements");
1932 
1933  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1934 
1935  if (req) { /* Requirements */
1936  SockList_AddLen8Data(sl, req, strlen(req));
1937  } else {
1938  SockList_AddChar(sl, 0);
1939  }
1940  /* end spellmon 2
1941  */
1942  }
1943 }
1944 
1949 void esrv_add_spells(player *pl, object *spell) {
1950  SockList sl;
1951  size_t size;
1952  sstring value;
1953 
1954  if (!pl) {
1955  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
1956  return;
1957  }
1958 
1959  if (!pl->socket->monitor_spells)
1960  return;
1961 
1962  SockList_Init(&sl);
1963  SockList_AddString(&sl, "addspell ");
1964  if (!spell) {
1965  FOR_INV_PREPARE(pl->ob, spell) {
1966  if (spell->type != SPELL)
1967  continue;
1968  /* Were we to simply keep appending data here, we could
1969  * exceed the SockList buffer if the player has enough spells
1970  * to add. We know that append_spell will always append
1971  * 23 data bytes, plus 3 length bytes and 2 strings
1972  * (because that is the spec) so we need to check that
1973  * the length of those 2 strings, plus the 26 bytes,
1974  * won't take us over the length limit for the socket.
1975  * If it does, we need to send what we already have,
1976  * and restart packet formation.
1977  */
1978  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
1979  if (pl->socket->monitor_spells >= 2) {
1981  value = object_get_value(spell, "casting_requirements");
1982  size += 2 + (value ? strlen(value) : 0);
1983  }
1984  if (SockList_Avail(&sl) < size) {
1985  Send_With_Handling(pl->socket, &sl);
1986  SockList_Reset(&sl);
1987  SockList_AddString(&sl, "addspell ");
1988  }
1989  append_spell(pl, &sl, spell);
1990  } FOR_INV_FINISH();
1991  } else if (spell->type != SPELL) {
1992  LOG(llevError, "Asked to send a non-spell object as a spell\n");
1993  return;
1994  } else
1995  append_spell(pl, &sl, spell);
1996  /* finally, we can send the packet */
1997  Send_With_Handling(pl->socket, &sl);
1998  SockList_Term(&sl);
1999 }
2000 
2001 /* sends a 'tick' information to the client.
2002  */
2003 void send_tick(player *pl) {
2004  SockList sl;
2005  SockList_Init(&sl);
2006  SockList_AddString(&sl, "tick ");
2007  SockList_AddInt(&sl, pticks);
2008  Send_With_Handling(pl->socket, &sl);
2009  SockList_Term(&sl);
2010 }
2011 
2024 static void add_char_field(SockList *sl, int type, const char *data)
2025 {
2026  int len;
2027 
2028  len = strlen(data);
2029 
2030  if (len) {
2031  /* one extra for length for the type byte */
2032  SockList_AddChar(sl, len+1);
2033  SockList_AddChar(sl, type);
2034  SockList_AddString(sl, data);
2035  }
2036 }
2037 
2059 {
2060  SockList sl;
2061  int num_chars;
2062  linked_char *extra;
2063 
2064  if (ns->account_chars) {
2066  }
2068 
2069  num_chars = 0;
2070  extra = account_get_additional_chars(ns->account_name, ns->account_chars, &num_chars);
2071 
2072  SockList_Init(&sl);
2073  SockList_AddString(&sl, "accountplayers ");
2074 
2075  SockList_AddChar(&sl, static_cast<char>(ns->account_chars->chars.size() + num_chars));
2076 
2077  /* Now add real character data */
2078  for (auto acn : ns->account_chars->chars) {
2079  uint16_t faceno = 0;
2080 
2081  /* Ignore a dead character. They don't need to show up. */
2082  if (acn->isDead) {
2083  continue;
2084  }
2085 
2086  add_char_field(&sl, ACL_NAME, acn->name);
2087  add_char_field(&sl, ACL_CLASS, acn->character_class);
2088  add_char_field(&sl, ACL_RACE, acn->race);
2089  add_char_field(&sl, ACL_FACE, acn->face);
2090  if (acn->face[0] != 0 ) {
2091  const Face *face = try_find_face(acn->face, NULL);
2092 
2093  if (face != NULL) {
2094  if (!(ns->faces_sent[face->number]&NS_FACESENT_FACE)) {
2095  esrv_send_face(ns, face, 0);
2096  }
2097  faceno = face->number;
2098  }
2099  }
2100 
2101  add_char_field(&sl, ACL_PARTY, acn->party);
2102  add_char_field(&sl, ACL_MAP, acn->map);
2103  SockList_AddChar(&sl, 3);
2105  SockList_AddShort(&sl, acn->level);
2106  if (faceno) {
2107  SockList_AddChar(&sl, 3);
2109  SockList_AddShort(&sl, faceno);
2110  }
2111 
2112  SockList_AddChar(&sl, 0);
2113  }
2114  /* Now for any characters where we just have the name */
2115  for (linked_char *e = extra; e != NULL; e = e->next) {
2116  add_char_field(&sl, ACL_NAME, e->name);
2117  SockList_AddChar(&sl, 0);
2118  }
2119 
2120  Send_With_Handling(ns, &sl);
2121  SockList_Term(&sl);
2122 
2123  if (extra) {
2124  free_charlinks(extra);
2125  }
2126 }
2127 
2149 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2150 {
2151  int nlen, plen;
2152 
2153  if (*len < 2) {
2154  return 1;
2155  }
2156 
2157  nlen = (unsigned char)buf[0];
2158  if (nlen >= MAX_BUF || nlen > *len-2) {
2159  return 1;
2160  }
2161  memcpy(name, buf+1, nlen);
2162  name[nlen] = 0;
2163 
2164  plen = (unsigned char)buf[nlen+1];
2165  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2166  return 2;
2167  }
2168  memcpy(password, buf+2+nlen, plen);
2169  password[plen] = 0;
2170 
2171  *len = nlen+plen+2;
2172 
2173  return 0;
2174 }
2185 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2186  char name[MAX_BUF], password[MAX_BUF];
2187  int status;
2188  SockList sl;
2189 
2190  if (len <= 0 || !buf) {
2191  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2192  return;
2193  }
2194 
2195  SockList_Init(&sl);
2196 
2197  status = decode_name_password(buf, &len, name, password);
2198 
2199  if (status == 1) {
2200  SockList_AddString(&sl, "failure accountlogin Name is too long");
2201  Send_With_Handling(ns, &sl);
2202  SockList_Term(&sl);
2203  return;
2204  }
2205  if (status == 2) {
2206  SockList_AddString(&sl, "failure accountlogin Password is too long");
2207  Send_With_Handling(ns, &sl);
2208  SockList_Term(&sl);
2209  return;
2210  }
2211 
2212  if (!account_exists(name)) {
2213  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2214  Send_With_Handling(ns, &sl);
2215  SockList_Term(&sl);
2216  return;
2217  }
2218 
2219  if (account_login(name, password)) {
2220  LOG(llevInfo, "Account login for '%s' from %s\n", name, ns->host);
2221 
2222  if (ns->account_name) free(ns->account_name);
2223  /* We want to store away official name so we do not
2224  * have any case sensitivity issues on the files.
2225  * because we have already checked password, we
2226  * know that account_exists should never return NULL in
2227  * this case.
2228  */
2230 
2232  } else {
2233  LOG(llevInfo, "Failed account login for '%s' from %s\n", name, ns->host);
2234  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2235  Send_With_Handling(ns, &sl);
2236  SockList_Term(&sl);
2237  }
2238 }
2239 
2248 static int account_block_create(const socket_struct *ns) {
2249  /* Check if account creation is blocked. */
2251  /* Account creation is allowed for everyone. */
2252  return 0;
2253  }
2254 
2255  /* Has the trusted host been defined? */
2256  if(settings.account_trusted_host == NULL) {
2257  /* No, allocate it and set it to localhost now. */
2259  }
2260 
2261  /* Return false if the client connected from the trusted host. */
2262  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2263  return 0;
2264  }
2265 
2266  /*
2267  * If we are here, then we are blocking account create and we do
2268  * not trust this client's IP address.
2269  */
2270  return 1;
2271 }
2272 
2284 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2285  char name[MAX_BUF], password[MAX_BUF];
2286  int status;
2287  SockList sl;
2288 
2289  if (len <= 0 || !buf) {
2290  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2291  return;
2292  }
2293 
2294  SockList_Init(&sl);
2295 
2296  status = decode_name_password(buf, &len, name, password);
2297 
2298  if (account_block_create(ns)) {
2299  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2300  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2301  Send_With_Handling(ns, &sl);
2302  SockList_Term(&sl);
2303  return;
2304  }
2305 
2306  if (status == 1) {
2307  SockList_AddString(&sl, "failure accountnew Name is too long");
2308  Send_With_Handling(ns, &sl);
2309  SockList_Term(&sl);
2310  return;
2311  }
2312  if (status == 2) {
2313  SockList_AddString(&sl, "failure accountnew Password is too long");
2314  Send_With_Handling(ns, &sl);
2315  SockList_Term(&sl);
2316  return;
2317  }
2318  /*The minimum length isn't exactly required, but in the current implementation,
2319  * client will send the same password for character for which there is a
2320  * 2 character minimum size. Thus an account with a one character password
2321  * won't be able to create a character. */
2322  if (strlen(name)<settings.min_name) {
2323  SockList_AddString(&sl, "failure accountnew Name is too short");
2324  Send_With_Handling(ns, &sl);
2325  SockList_Term(&sl);
2326  return;
2327  }
2328  if (strlen(password)<2) {
2329  SockList_AddString(&sl, "failure accountnew Password is too short");
2330  Send_With_Handling(ns, &sl);
2331  SockList_Term(&sl);
2332  return;
2333  }
2334 
2335  if (account_exists(name)) {
2336  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2337  Send_With_Handling(ns, &sl);
2338  SockList_Term(&sl);
2339  return;
2340  }
2341 
2342  status = account_check_string(name);
2343  if (status == 1) {
2344  SockList_AddString(&sl,
2345  "failure accountnew Choose a different account name. " VALIDCHAR_MSG);
2346  Send_With_Handling(ns, &sl);
2347  SockList_Term(&sl);
2348  return;
2349  }
2350 
2351  if (status == 2) {
2352  SockList_AddString(&sl,
2353  "failure accountnew That account name is too long");
2354  Send_With_Handling(ns, &sl);
2355  SockList_Term(&sl);
2356  return;
2357  }
2358 
2359  status = account_check_string(password);
2360  if (status == 1) {
2361  SockList_AddString(&sl,
2362  "failure accountnew Choose a different password. " VALIDCHAR_MSG);
2363  Send_With_Handling(ns, &sl);
2364  SockList_Term(&sl);
2365  return;
2366  }
2367 
2368  if (status == 2) {
2369  SockList_AddString(&sl,
2370  "failure accountnew That password is too long");
2371  Send_With_Handling(ns, &sl);
2372  SockList_Term(&sl);
2373  return;
2374  }
2375 
2376  /* If we got here, we passed all checks - so now add it */
2377  if (ns->account_name) free(ns->account_name);
2379  account_new(name, password);
2380  /* save account information */
2381  accounts_save();
2383 }
2384 
2398 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2399  char name[MAX_BUF], password[MAX_BUF];
2400  int status, force, nlen;
2401  SockList sl;
2402  const char *cp;
2403 
2404  if (len <= 0 || !buf) {
2405  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2406  return;
2407  }
2408 
2409  SockList_Init(&sl);
2410 
2411  if (ns->account_name == NULL) {
2412  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2413  Send_With_Handling(ns, &sl);
2414  SockList_Term(&sl);
2415  return;
2416  }
2417 
2418  force = buf[0];
2419  nlen = len - 1;
2420  status = decode_name_password(buf+1, &nlen, name, password);
2421  if (status == 1) {
2422  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2423  Send_With_Handling(ns, &sl);
2424  SockList_Term(&sl);
2425  return;
2426  }
2427  if (status == 2) {
2428  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2429  Send_With_Handling(ns, &sl);
2430  SockList_Term(&sl);
2431  return;
2432  }
2433 
2434  status = verify_player(name, password);
2435  if (status) {
2436  /* From a security standpoint, telling random folks if it
2437  * it as wrong password makes it easier to hack. However,
2438  * it is fairly easy to determine what characters exist on a server
2439  * (either by trying to create a new one and see if the name is in
2440  * in use, or just looking at the high score file), so this
2441  * really does not make things much less secure
2442  */
2443  if (status == 1)
2444  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2445  else
2446  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2447 
2448  Send_With_Handling(ns, &sl);
2449  SockList_Term(&sl);
2450  return;
2451  }
2452  /* Check to see if this character is associated with an account.
2453  */
2455  if (cp) {
2456  if (!strcmp(cp, ns->account_name)) {
2457  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2458  Send_With_Handling(ns, &sl);
2459  SockList_Term(&sl);
2460  return;
2461  } else {
2462  if (!force) {
2463  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2464  Send_With_Handling(ns, &sl);
2465  SockList_Term(&sl);
2466  return;
2467  } else if (account_is_logged_in(cp)) {
2468  /* We could be clever and try to handle this case, but it is
2469  * trickier. If the character is logged in, it has to
2470  * be logged out. And the socket holds some data which
2471  * needs to be cleaned up. Since it should be fairly
2472  * uncommon that users need to do this, just disallowing
2473  * it makes things a lot simpler.
2474  */
2475  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2476  Send_With_Handling(ns, &sl);
2477  SockList_Term(&sl);
2478  return;
2479  }
2480  }
2481  }
2482  /* If we have gotten this far, the name/password provided is OK,
2483  * and the character is not associated with a different account (or
2484  * force is true). Now try to add the character to this account.
2485  */
2486  status = account_link(ns->account_name, name);
2487 
2488  /* This should never happen, but check for it just in case -
2489  * if we were able to log in, the account should exist. but
2490  * if this fails, need to give the user some clue.
2491  */
2492  if (status==1) {
2493  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2494  Send_With_Handling(ns, &sl);
2495  SockList_Term(&sl);
2496  return;
2497  } else if (status == 2) {
2498  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2499  Send_With_Handling(ns, &sl);
2500  SockList_Term(&sl);
2501  return;
2502  }
2503 
2504  /* If cp is set, then this character used to belong to a different
2505  * account. Remove it now.
2506  */
2507  if (cp) {
2508  Account_Chars *chars;
2509 
2511  chars = account_char_load(cp);
2512  account_char_remove(chars, name);
2513  account_char_save(chars);
2514  account_char_free(chars);
2515  }
2516 
2518 
2519  /* store data so nothing is lost in case of crash */
2521 }
2522 
2527 void account_play_cmd(char *buf, int len, socket_struct *ns)
2528 {
2529  char **chars;
2530  int i;
2531  SockList sl;
2532  player *pl;
2533 
2534  if (len <= 0 || !buf) {
2535  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2536  return;
2537  }
2538 
2539  SockList_Init(&sl);
2540 
2541  if (ns->status != Ns_Add) {
2542  SockList_AddString(&sl, "failure accountplay Not allowed right now");
2543  Send_With_Handling(ns, &sl);
2544  SockList_Term(&sl);
2545  return;
2546  }
2547 
2548  if (!buf[0]) {
2549  SockList_AddString(&sl, "failure accountplay Malformed character name");
2550  Send_With_Handling(ns, &sl);
2551  SockList_Term(&sl);
2552  return;
2553  }
2554 
2555  if (ns->account_name == NULL) {
2556  SockList_AddString(&sl, "failure accountplay Not logged in");
2557  Send_With_Handling(ns, &sl);
2558  SockList_Term(&sl);
2559  return;
2560  }
2561 
2562  /* Make sure a client is not trying to spoof us here */
2564 
2565  for (i=0; chars[i]; i++) {
2566  if (strcmp(chars[i], buf) == 0)
2567  break;
2568  }
2569  if (!chars[i]) {
2570  SockList_AddPrintf(&sl,
2571  "failure accountplay Character %s is not associated with account %s",
2572  buf, ns->account_name);
2573  Send_With_Handling(ns, &sl);
2574  SockList_Term(&sl);
2575  return;
2576  }
2577 
2578  for (pl = first_player; pl; pl = pl->next) {
2579  if (pl->ob && pl->socket != ns && strcmp(buf, pl->ob->name) == 0 && pl->state != ST_PLAY_AGAIN && pl->state != ST_GET_NAME) {
2580  SockList_AddPrintf(&sl,
2581  "failure accountplay Character %s is already playing",
2582  buf);
2583  Send_With_Handling(ns, &sl);
2584  SockList_Term(&sl);
2585  return;
2586  }
2587  }
2588 
2589  /* from a protocol standpoint, accountplay can be used
2590  * before there is a player structure (first login) or after
2591  * (character has logged in and is changing characters).
2592  * Checkthe sockets for that second case - if so,
2593  * we don't need to make a new player object, etc.
2594  */
2595  for (pl=first_player; pl; pl=pl->next) {
2596  if (pl->socket == ns) {
2597  /* The player still in the socket must be saved first. */
2598  save_player(pl->ob, 0);
2599  break;
2600  }
2601  }
2602 
2603  /* Some of this logic is from add_player()
2604  * we just don't use add_player() as it does some other work
2605  * we don't really want to do.
2606  */
2607  if (!pl) {
2608  pl = get_player(NULL);
2609  set_player_socket(pl, ns);
2610  ns->status = Ns_Avail;
2611  ns->account_chars = NULL;
2613  } else {
2614  pl->state = ST_PLAYING;
2615  }
2616 
2617  pl->ob->name = add_string(buf);
2618  check_login(pl->ob, NULL);
2619 
2620  SockList_AddString(&sl, "addme_success");
2621  Send_With_Handling(ns, &sl);
2622  SockList_Term(&sl);
2623 }
2624 
2625 #define MAX_CHOICES 100
2626 
2632 void create_player_cmd(char *buf, int len, socket_struct *ns)
2633 {
2634  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2635  int status, nlen, choice_num=0, i;
2636  SockList sl;
2637  player *pl;
2638  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2639  living new_stats;
2640 
2641  if (len <= 0 || !buf) {
2642  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2643  return;
2644  }
2645 
2646  SockList_Init(&sl);
2647 
2648  if (ns->status != Ns_Add) {
2649  SockList_AddString(&sl, "failure createplayer Not allowed right now");
2650  Send_With_Handling(ns, &sl);
2651  SockList_Term(&sl);
2652  return;
2653  }
2654 
2655  nlen = len;
2656  status = decode_name_password(buf, &nlen, name, password);
2657  if (status == 1) {
2658  SockList_AddString(&sl, "failure createplayer Name is too long");
2659  Send_With_Handling(ns, &sl);
2660  SockList_Term(&sl);
2661  return;
2662  }
2663 
2664  /* Minimum character name limit (if set) */
2665  if (strlen(name)<settings.min_name) {
2666  SockList_AddString(&sl, "failure createplayer Name is too short");
2667  Send_With_Handling(ns, &sl);
2668  SockList_Term(&sl);
2669  return;
2670  }
2671 
2672  if (playername_ok(name) == 0) {
2673  SockList_AddString(&sl, "failure createplayer Player name contains invalid characters");
2674  Send_With_Handling(ns, &sl);
2675  SockList_Term(&sl);
2676  return;
2677  }
2678 
2679  /* 2 characters minimum for password */
2680  if (strlen(password)<2) {
2681  SockList_AddString(&sl, "failure createplayer Password is too short");
2682  Send_With_Handling(ns, &sl);
2683  SockList_Term(&sl);
2684  return;
2685  }
2686 
2688  if (status == 2) {
2689  SockList_AddString(&sl, "failure createplayer Password is too long");
2690  Send_With_Handling(ns, &sl);
2691  SockList_Term(&sl);
2692  return;
2693  }
2694 
2695  /* This is a fairly ugly solution - we're truncating the password.
2696  * however, the password information for characters is really
2697  * a legacy issue - when every character is associated with
2698  * an account, legacy login (character name/password) will get
2699  * removed, at which point the only use for password might be
2700  * to move characters from one account to another, but not sure
2701  * if that is something we want to allow.
2702  */
2703  if (strlen(password)>17)
2704  password[16] = 0;
2705 
2706  /* We just can't call check_name(), since that uses draw_info() to
2707  * report status. We are also more permissive on names, so we use
2708  * account_check_string() - if that is safe for account, also safe
2709  * for player names.
2710  */
2711  if (account_check_string(name)) {
2712  SockList_AddString(&sl, "failure createplayer Choose a different character name. " VALIDCHAR_MSG);
2713  Send_With_Handling(ns, &sl);
2714  SockList_Term(&sl);
2715  return;
2716  }
2717 
2718  /* 1 means no such player, 0 is correct name/password (which in this
2719  * case, is an error), and 2 is incorrect password. Only way we
2720  * go onward is if there is no such player.
2721  */
2722  if (verify_player(name, password) != 1) {
2723  SockList_AddString(&sl, "failure createplayer That name is already in use");
2724  Send_With_Handling(ns, &sl);
2725  SockList_Term(&sl);
2726  return;
2727  }
2728 
2729  /* from a protocol standpoint, accountplay can be used
2730  * before there is a player structure (first login) or after
2731  * (character has logged in and is changing characters).
2732  * Check the sockets for that second case - if so,
2733  * we don't need to make a new player object, etc.
2734  */
2735  for (pl=first_player; pl; pl=pl->next)
2736  if (pl->socket == ns) {
2737  if (pl->ob->name) {
2738  if (!strcmp(pl->ob->name, name)) {
2739  /* For some reason not only the socket is the same but also
2740  * the player is already playing. If this happens at this
2741  * point let's assume the character never was able to apply
2742  * a bet of reality to make a correct first-time save.
2743  * So, for safety remove it and start over.
2744  */
2745  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2746  object_remove(pl->ob);
2747  }
2748  else {
2749  /* If this is a different player on the same socket, then we
2750  * need to make sure that the old one is not connected to the player
2751  *
2752  * This prevents bizarre scenarios where the player is on the map
2753  * multiple times (from multiple createplayer commands), and
2754  * only one of them is controlled by the player.
2755  */
2756  if (pl->ob->contr == pl) {
2757  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2758  object_remove(pl->ob);
2759  }
2760  }
2761  }
2762  break;
2763  }
2764 
2765  /* In this mode, we have additional data
2766  * Note that because there are a lot of failure cases in here
2767  * (where we end up not creating the new player), the code
2768  * to create the new player is done within this routine
2769  * after all checks pass. Note that all of the checks
2770  * done are done without using the player structure,
2771  * as pl may be null right now.
2772  */
2773  if (ns->login_method >= 2) {
2774  int i, j, stat_total=0;
2775  char *key, *value, *race=NULL, *class_name=NULL;
2776 
2777  /* By setting this to zero, then we can easily
2778  * check to see if all stats have been set.
2779  */
2780  memset(&new_stats, 0, sizeof(living));
2781 
2782  while (nlen < len) {
2783  i = buf[nlen]; /* Length of this line */
2784  /* Sanity check from client - don't want to loop
2785  * forever if there is a 0 length, and don't
2786  * want to read beyond size of packet.
2787  * Likewise, client should have sent
2788  * the string to us already null terminated,
2789  * but we will just make sure.
2790  */
2791  if ((i == 0) || (nlen + i > len)) break;
2792  buf[nlen + i] = 0;
2793 
2794  /* What we have are a series of lines -
2795  * 'key value' format. Find that space,
2796  * and null it out so we can do strcasecmp.
2797  * If no space, abort processing
2798  */
2799  key = buf + nlen + 1;
2800  value = strchr(key, ' ');
2801  if (!value) break;
2802  *value = 0;
2803  value++;
2804 
2805  if (!strcasecmp(key,"race")) race = value;
2806  else if (!strcasecmp(key,"class")) class_name = value;
2807  else if (!strcasecmp(key,"starting_map")) {
2808  map = try_find_archetype(value);
2809  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2810  SockList_AddString(&sl,
2811  "failure createplayer Invalid starting map");
2812  Send_With_Handling(ns, &sl);
2813  SockList_Term(&sl);
2814  return;
2815  }
2816  }
2817  else if (!strcasecmp(key,"choice")) {
2818  /* In general, MAX_CHOICES should be large enough
2819  * to always handle the choices from the client - of
2820  * course, the client could be broken and send us many
2821  * more choices than we should have, so handle that.
2822  */
2823  if (choice_num == MAX_CHOICES) {
2824  LOG(llevError,
2825  "Number of choices receive exceed max value: %d>%d\n",
2826  choice_num, MAX_CHOICES);
2827  } else {
2828  choices[choice_num] = value;
2829  choice_num++;
2830  }
2831  }
2832  else {
2833  /* Do stat processing here */
2834  for (j=0; j < NUM_STATS; j++) {
2835  if (!strcasecmp(key,short_stat_name[j])) {
2836  int val = atoi(value);
2837 
2838  set_attr_value(&new_stats, j, val);
2839  break;
2840  }
2841  }
2842  if (j >= NUM_STATS) {
2843  /* Bad clients could do this - we should at least report
2844  * it, and useful when trying to add new parameters.
2845  */
2846  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2847  }
2848  }
2849  nlen += i + 1;
2850  }
2851  /* Do some sanity checking now. But checking the stat
2852  * values here, we will catch any 0 values since we do
2853  * a memset above. A properly behaving client should
2854  * never do any of these things, but we do not presume
2855  * clients will behave properly.
2856  */
2857  for (j=0; j<NUM_STATS; j++) {
2858  int val = get_attr_value(&new_stats, j);
2859 
2860  stat_total += val;
2861  if (val > settings.starting_stat_max ||
2862  val < settings.starting_stat_min) {
2863  SockList_AddPrintf(&sl,
2864  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2866  Send_With_Handling(ns, &sl);
2867  SockList_Term(&sl);
2868  return;
2869  }
2870  }
2871  if (stat_total > settings.starting_stat_points) {
2872  SockList_AddPrintf(&sl,
2873  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2874  stat_total, settings.starting_stat_points);
2875  Send_With_Handling(ns, &sl);
2876  SockList_Term(&sl);
2877  return;
2878  }
2879 
2880  if (race)
2881  race_a = try_find_archetype(race);
2882 
2883  if (class_name)
2884  class_a = try_find_archetype(class_name);
2885 
2886  /* This should never happen with a properly behaving client, so the error message
2887  * doesn't have to be that great.
2888  */
2889  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2890  SockList_AddString(&sl,
2891  "failure createplayer Invalid or unknown race or class");
2892  Send_With_Handling(ns, &sl);
2893  SockList_Term(&sl);
2894  return;
2895  }
2896 
2897  /* At current time, only way this can fail is if the adjusted
2898  * stat is less than 1.
2899  */
2900  if (check_race_and_class(&new_stats, race_a, class_a)) {
2901  SockList_AddString(&sl,
2902  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2903  Send_With_Handling(ns, &sl);
2904  SockList_Term(&sl);
2905  return;
2906  }
2907 
2908  if (!pl)
2910  // If we already have a player, we a replaying on the same connection.
2911  // Since add_player normally sets ns->status, we still need that to happen.
2912  else
2913  ns->status = Ns_Avail;
2914 
2915  // We need to copy the name in before apply_race_and_class() because it
2916  // tells the client our character name. If we don't update it, they get the old one.
2917  FREE_AND_COPY(pl->ob->name, name);
2918 
2919  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2920 
2921  } else {
2922  /* In thise case, old login method */
2923  if (!pl)
2924  pl = add_player(ns, ADD_PLAYER_NEW);
2925  // If we already have a player, we a replaying on the same connection.
2926  // Since add_player normally sets ns->status, we still need that to happen.
2927  else
2928  ns->status = Ns_Avail;
2929 
2930  // Make sure to do this on both code branches.
2931  FREE_AND_COPY(pl->ob->name, name);
2932 /* already done by add_player
2933  roll_again(pl->ob);
2934  pl->state = ST_ROLL_STAT;
2935  set_first_map(pl->ob);*/
2936  }
2937 
2938  /* add_player does a lot of the work, but there are a few
2939  * things we need to update, like starting name and
2940  * password.
2941  * This is done before processing in login_method>2.
2942  * The character creation process it does when
2943  * applying the race/class will use this
2944  * name information.
2945  */
2946  FREE_AND_COPY(pl->ob->name_pl, name);
2947  pl->name_changed = 1;
2948  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
2949 
2950  SockList_AddString(&sl, "addme_success");
2951  Send_With_Handling(ns, &sl);
2952  SockList_Term(&sl);
2953 
2954  if (ns->login_method >= 2) {
2955  /* The client could have provided us a map - if so, map will be set
2956  * and we don't want to overwrite it
2957  */
2958  if (!map)
2960  assert(map); // Existence checked in init_dynamic()
2961 
2962  enter_exit(pl->ob, &map->clone);
2963 
2964  if (pl->ob->map == NULL) {
2965  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
2966  abort();
2967  }
2968 
2969  /* copy information to bed of reality information, in case the player dies */
2970  safe_strncpy(pl->savebed_map, pl->ob->map->path, sizeof(pl->savebed_map));
2971  pl->bed_x = pl->ob->x;
2972  pl->bed_y = pl->ob->y;
2973 
2975  }
2976 
2977  /* We insert any objects after we have put the player on the map -
2978  * this makes things safer, as certain objects may expect a normal
2979  * environment. Note that choice_num will only be set in the
2980  * loginmethod > 2, which also checks (and errors out) if the
2981  * race/class is not set, which is why explicit checking for
2982  * those is not need.
2983  */
2984  for (i=0; i < choice_num; i++) {
2985  char *choiceval;
2986  const char *value, *cp;
2987  archetype *arch;
2988  object *op;
2989 
2990  choiceval = strchr(choices[i], ' ');
2991  if (!choiceval) {
2992  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
2993  continue;
2994  }
2995  *choiceval=0;
2996  choiceval++;
2997  value = object_get_value(&race_a->clone, choices[i]);
2998  if (!value)
2999  value = object_get_value(&class_a->clone, choices[i]);
3000 
3001  if (!value) {
3002  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
3003  continue;
3004  }
3005  cp = strstr(value, choiceval);
3006  if (!cp) {
3007  LOG(llevError, "Choice value not found in archetype: %s %s\n",
3008  choices[i], choiceval);
3009  continue;
3010  }
3011 
3012  /* Check to make sure that the matched string is an entire word,
3013  * and not a substring (eg, valid choice being great_sword but
3014  * we just get sword) - the space after the match should either be a
3015  * space or null, and space before match should also be a space
3016  * or the start of the string.
3017  */
3018  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
3019  (cp != value) && (*(cp-1) != ' ')) {
3020 
3021  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
3022  choiceval, value);
3023  continue;
3024  }
3025  arch = try_find_archetype(choiceval);
3026  if (!arch) {
3027  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
3028  continue;
3029  }
3030  op = arch_to_object(arch);
3031  op = object_insert_in_ob(op, pl->ob);
3032  if (QUERY_FLAG(op, FLAG_AUTO_APPLY))
3033  ob_apply(op, pl->ob, 0);
3034  }
3035 
3036  LOG(llevInfo, "new character %s from %s\n", pl->ob->name, pl->ob->contr->socket->host);
3039  "%s has entered the game.", pl->ob->name);
3040 }
3041 
3052 void account_password(char *buf, int len, socket_struct *ns) {
3053  char old[MAX_BUF], change[MAX_BUF];
3054  int status;
3055  SockList sl;
3056 
3057  if (len <= 0 || !buf) {
3058  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
3059  return;
3060  }
3061 
3062  SockList_Init(&sl);
3063 
3064  if (ns->account_name == NULL) {
3065  SockList_AddString(&sl, "failure accountpw Not logged in");
3066  Send_With_Handling(ns, &sl);
3067  SockList_Term(&sl);
3068  return;
3069  }
3070 
3071  status = decode_name_password(buf, &len, old, change);
3072  if (status == 1) {
3073  SockList_AddString(&sl, "failure accountpw Old password is too long");
3074  Send_With_Handling(ns, &sl);
3075  SockList_Term(&sl);
3076  return;
3077  }
3078  if (status == 2) {
3079  SockList_AddString(&sl, "failure accountpw New password is too long");
3080  Send_With_Handling(ns, &sl);
3081  SockList_Term(&sl);
3082  return;
3083  }
3084  /*The minimum length isn't exactly required, but in the current implementation,
3085  * client will send the same password for character for which there is a
3086  * 2 character minimum size. Thus an account with a one character password
3087  * won't be able to create a character. */
3088  if (strlen(change)<2) {
3089  SockList_AddString(&sl, "failure accountpw New password is too short");
3090  Send_With_Handling(ns, &sl);
3091  SockList_Term(&sl);
3092  return;
3093  }
3094 
3095  status = account_check_string(change);
3096  if (status == 1) {
3097  SockList_AddString(&sl,
3098  "failure accountpw Choose a different password. " VALIDCHAR_MSG);
3099  Send_With_Handling(ns, &sl);
3100  SockList_Term(&sl);
3101  return;
3102  }
3103 
3104  if (status == 2) {
3105  SockList_AddString(&sl,
3106  "failure accountpw That password is too long");
3107  Send_With_Handling(ns, &sl);
3108  SockList_Term(&sl);
3109  return;
3110  }
3111 
3112  status = account_change_password(ns->account_name, old, change);
3113  if (status != 0) {
3114  const char *error;
3115 
3116  if (status == 1) {
3117  error = "failure accountpw Illegal characters present";
3118  } else if (status == 2) {
3119  error = "failure accountpw Invalid account";
3120  } else {
3121  error = "failure accountpw Incorrect current password";
3122  }
3123 
3124  SockList_AddString(&sl, error);
3125  Send_With_Handling(ns, &sl);
3126  SockList_Term(&sl);
3127  return;
3128  }
3129 
3130  /* If we got here, we passed all checks, and password was changed */
3132 }
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:249
SF_FIREON
#define SF_FIREON
Definition: newclient.h:192
CF_BLIND
#define CF_BLIND
Blind.
Definition: newclient.h:203
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:2398
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:165
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:141
player::bed_y
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:111
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:208
socket_struct::tick
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:106
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:106
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:351
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:137
socket_struct::sc_version
uint32_t sc_version
Versions of the client.
Definition: newserver.h:113
first_player
player * first_player
First player.
Definition: init.cpp:106
ST_CHANGE_PASSWORD_OLD
#define ST_CHANGE_PASSWORD_OLD
Player is entering old password to change password.
Definition: define.h:544
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
CS_STAT_RACE_CON
#define CS_STAT_RACE_CON
Definition: newclient.h:124
print_ext_msg
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Draws an extended message on the client.
Definition: info.cpp:62
CS_STAT_GRACE
#define CS_STAT_GRACE
Definition: newclient.h:112
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
find_smooth
int find_smooth(const Face *face, const Face **smoothed)
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:112
SockList_AddInt64
void SockList_AddInt64(SockList *sl, uint64_t data)
Adds a 64 bit value.
Definition: lowlevel.cpp:140
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:541
ACL_FACE_NUM
#define ACL_FACE_NUM
Definition: newclient.h:227
FLAG_CONFUSED
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:311
CAN_PROBE
static bool CAN_PROBE(const object *ob)
Determine whether the given object can have an HP bar.
Definition: object.h:616
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:241
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:2058
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:136
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:499
player::mode
uint32_t mode
Mode of player for pickup.
Definition: player.h:123
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
send_query
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Asks the client to query the user.
Definition: request.cpp:745
Map
One map for a player.
Definition: newserver.h:48
account_play_cmd
void account_play_cmd(char *buf, int len, socket_struct *ns)
We have received an accountplay command.
Definition: request.cpp:2527
player::last_golem_hp
int16_t last_golem_hp
Last golem hp value sent to the client.
Definition: player.h:175
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
new_player_cmd
void new_player_cmd(uint8_t *buf, int len, player *pl)
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:164
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
player
One player.
Definition: player.h:105
CS_STAT_DAM
#define CS_STAT_DAM
Definition: newclient.h:104
strdup_local
#define strdup_local
Definition: compat.h:29
ACL_RACE
#define ACL_RACE
Definition: newclient.h:222
player::golem_count
uint32_t golem_count
To track the golem.
Definition: player.h:119
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
CS_STAT_RES_FIRE
#define CS_STAT_RES_FIRE
Definition: newclient.h:153
ask_smooth_cmd
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
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:226
newhash
char const * newhash(char const *password)
Definition: server.cpp:101
socket_struct::sound
uint32_t sound
Client sound mode.
Definition: newserver.h:111
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:140
CS_STAT_HP
#define CS_STAT_HP
Definition: newclient.h:90
socket_struct
Socket structure, represents a client-server connection.
Definition: newserver.h:89
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
player::spell_state
client_spell * spell_state
Spell information sent to client.
Definition: player.h:215
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:116
ST_GET_NAME
#define ST_GET_NAME
Player just connected.
Definition: define.h:540
map2_delete_layer
static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns)
Definition: request.cpp:1258
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:2130
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:122
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
player::bed_x
int16_t bed_x
Definition: player.h:111
command_execute
void command_execute(object *pl, char *command)
Handle a player-issued command.
Definition: commands.cpp:456
AddIfInt64
#define AddIfInt64(Old, New, sl, Type)
Definition: request.cpp:754
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:119
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:96
player::peaceful
uint32_t peaceful
If set, won't attack friendly creatures.
Definition: player.h:146
player::ob
object * ob
The object representing the player.
Definition: player.h:177
player::transport
object * transport
Transport the player is in.
Definition: player.h:214
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
CS_STAT_SPEED
#define CS_STAT_SPEED
Definition: newclient.h:106
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:109
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:95
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:1879
player::last_applied_stats
living last_applied_stats
Last applied stats sent to the client.
Definition: player.h:172
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:93
player::levhp
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:186
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
MIN
#define MIN(x, y)
Definition: compat.h:21
CS_STAT_BASE_DEX
#define CS_STAT_BASE_DEX
Definition: newclient.h:130
CS_STAT_RES_MAG
#define CS_STAT_RES_MAG
Definition: newclient.h:152
FIF
#define FIF(F, C)
MAP_LAYERS
#define MAP_LAYERS
Definition: map.h:32
player::last_path_denied
uint32_t last_path_denied
Last spell denied sent to client.
Definition: player.h:162
Settings::starting_stat_min
uint8_t starting_stat_min
Minimum value of a starting stat.
Definition: global.h:322
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:107
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:810
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
CS_STAT_SP
#define CS_STAT_SP
Definition: newclient.h:92
SP_CREATE_FOOD
#define SP_CREATE_FOOD
Definition: spells.h:96
ACL_NAME
#define ACL_NAME
Definition: newclient.h:220
player::last_level
int8_t last_level
Last level we sent to client.
Definition: player.h:134
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:187
CS_STAT_RES_HOLYWORD
#define CS_STAT_RES_HOLYWORD
Definition: newclient.h:167
annotate_ob
static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer)
Definition: request.cpp:1368
player::savebed_map
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:110
CS_STAT_GOLEM_HP
#define CS_STAT_GOLEM_HP
Golem's current hp, 0 if no golem.
Definition: newclient.h:141
CS_STAT_RES_CONF
#define CS_STAT_RES_CONF
Definition: newclient.h:156
NDI_RED
#define NDI_RED
Definition: newclient.h:248
MAX_HEAD_OFFSET
#define MAX_HEAD_OFFSET
This basically defines the largest size an archetype may be - it is used for allocation of some struc...
Definition: newserver.h:42
player::last_stats
living last_stats
Last stats as sent to client.
Definition: player.h:168
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:49
socket_struct::inbuf
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:99
CS_STAT_TURN_UNDEAD
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:163
ACL_CLASS
#define ACL_CLASS
Definition: newclient.h:221
SP_CREATE_MISSILE
#define SP_CREATE_MISSILE
Definition: spells.h:113
CF_NOT_PERFECT
#define CF_NOT_PERFECT
Can drink some improvement potions.
Definition: newclient.h:206
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
receive_play_again
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.cpp:964
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:532
map_clearcell
static void map_clearcell(struct map_cell_struct *cell, int face, int darkness)
Clears a map cell.
Definition: request.cpp:1072
CS_STAT_EXP64
#define CS_STAT_EXP64
Definition: newclient.h:116
map2_coord_valid
static bool map2_coord_valid(int x)
Definition: request.cpp:76
FLAG_PROBE
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:257
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:1746
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:143
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
socket_struct::map_scroll_x
int8_t map_scroll_x
Definition: newserver.h:94
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
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:327
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
FLAG_STEALTH
#define FLAG_STEALTH
Will wake monsters with less range.
Definition: define.h:312
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:171
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:1086
pticks
uint32_t pticks
Number of ticks since time reset.
Definition: time.cpp:47
buf
StringBuffer * buf
Definition: readable.cpp:1565
key_confirm_quit
void key_confirm_quit(object *op, char key)
We receive the reply to the 'quit confirmation' message.
Definition: player.cpp:1602
CS_STAT_APPLIED_DEX
#define CS_STAT_APPLIED_DEX
DEX changes from gear or skills.
Definition: newclient.h:137
add_player
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.cpp:468
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:2857
map2_add_label
static void map2_add_label(socket_struct *ns, SockList *sl, enum map2_label subtype, const char *label)
Definition: request.cpp:1351
POISONING
@ POISONING
Definition: object.h:223
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:407
MAX
#define MAX(x, y)
Definition: compat.h:24
CS_STAT_RACE_STR
#define CS_STAT_RACE_STR
Definition: newclient.h:120
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:142
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:58
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
ACL_MAP
#define ACL_MAP
Definition: newclient.h:226
linked_char
Definition: global.h:98
Account_Chars::chars
std::vector< Account_Char * > chars
Characters of the account.
Definition: account_char.h:30
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
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:104
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:329
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:422
AddIfShort
#define AddIfShort(Old, New, sl, Type)
Definition: request.cpp:768
socket_struct::account_chars
Account_Chars * account_chars
Detailed information on characters on this account.
Definition: newserver.h:127
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:1038
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:116
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:126
socket_struct::stats
struct statsinfo stats
Definition: newserver.h:98
Ns_Avail
@ Ns_Avail
Definition: newserver.h:65
CS_STAT_RACE_DEX
#define CS_STAT_RACE_DEX
Definition: newclient.h:123
CS_STAT_ARMOUR
#define CS_STAT_ARMOUR
Definition: newclient.h:105
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:334
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
CS_STAT_SPELL_REPEL
#define CS_STAT_SPELL_REPEL
Definition: newclient.h:118
CS_STAT_RACE_CHA
#define CS_STAT_RACE_CHA
Definition: newclient.h:125
P_NEW_MAP
#define P_NEW_MAP
Coordinates passed result in a new tiled map.
Definition: map.h:250
MAP2_ADD_LENGTH
#define MAP2_ADD_LENGTH
Definition: newclient.h:67
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:173
CS_STAT_LEVEL
#define CS_STAT_LEVEL
Definition: newclient.h:101
player::run_on
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:143
CS_STAT_CON
#define CS_STAT_CON
Definition: newclient.h:98
account_new_cmd
void account_new_cmd(char *buf, int len, socket_struct *ns)
Handles the account creation This function shares a fair amount of the same logic as account_login_cm...
Definition: request.cpp:2284
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:2185
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:225
CS_STAT_CHA
#define CS_STAT_CHA
Definition: newclient.h:99
CS_STAT_APPLIED_CHA
#define CS_STAT_APPLIED_CHA
CHA changes from gear or skills.
Definition: newclient.h:139
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:546
CS_STAT_RES_SLOW
#define CS_STAT_RES_SLOW
Definition: newclient.h:161
socket_struct::facecache
uint32_t facecache
If true, client is caching images.
Definition: newserver.h:102
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:1438
player::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:178
check_login
void check_login(object *op, const char *password)
Actually login a player, load from disk and such.
Definition: login.cpp:511
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:133
player::last_flags
uint16_t last_flags
Fire/run on flags for last tick.
Definition: player.h:157
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:151
Settings::account_block_create
uint8_t account_block_create
Definition: global.h:330
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:536
CS_STAT_GOD_NAME
#define CS_STAT_GOD_NAME
Name of the god the character worships.
Definition: newclient.h:144
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:116
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Do not set the first map.
Definition: player.h:248
map_cell_struct::darkness
int darkness
Cell's darkness.
Definition: newserver.h:33
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
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)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
draw_client_map
void draw_client_map(object *pl)
Draws client map.
Definition: request.cpp:1647
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:1077
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.cpp:116
ANIM_RANDOM
#define ANIM_RANDOM
Definition: newclient.h:350
CS_STAT_BASE_CHA
#define CS_STAT_BASE_CHA
Definition: newclient.h:132
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.cpp:4108
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
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
player::last_path_attuned
uint32_t last_path_attuned
Last spell attunment sent to client.
Definition: player.h:160
socket_struct::lastmap
struct Map lastmap
Definition: newserver.h:93
CF_POISONED
#define CF_POISONED
Poisoned.
Definition: newclient.h:202
MAP2_LAYER_START
#define MAP2_LAYER_START
Definition: newclient.h:66
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
object::face
const Face * face
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:163
CS_STAT_APPLIED_STR
#define CS_STAT_APPLIED_STR
STR changes from gear or skills.
Definition: newclient.h:134
socket_struct::host
char * host
Which host it is connected from (ip address).
Definition: newserver.h:100
player::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Last exp sent to client.
Definition: player.h:154
CS_STAT_RACE_POW
#define CS_STAT_RACE_POW
Definition: newclient.h:126
account_password
void account_password(char *buf, int len, socket_struct *ns)
Handles the account password change.
Definition: request.cpp:3052
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1708
GET_MAP_FACE_OBJ
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Gets the layer face of specified square.
Definition: map.h:182
socket_struct::account_name
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:126
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:188
CS_STAT_AC
#define CS_STAT_AC
Definition: newclient.h:103
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
client_spell::last_grace
int16_t last_grace
Last grace cost.
Definition: player.h:90
check_space_for_heads
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.cpp:1412
CS_STAT_OVERLOAD
#define CS_STAT_OVERLOAD
How much (0 to 1) the character is overloaded.
Definition: newclient.h:145
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
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:108
socket_struct::monitor_spells
uint32_t monitor_spells
Client wishes to be informed when their spell list changes.
Definition: newserver.h:110
FLAG_PARALYZED
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:371
CS_STAT_APPLIED_CON
#define CS_STAT_APPLIED_CON
CON changes from gear or skills.
Definition: newclient.h:138
MAP_LAYER_LIVING1
#define MAP_LAYER_LIVING1
Living creatures.
Definition: map.h:46
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:1760
skill_names
const char * skill_names[MAX_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.cpp:59
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:117
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:159
linked_char::next
struct linked_char * next
Definition: global.h:100
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
Definition: newclient.h:175
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
account_new
int account_new(const char *account_name, const char *account_password)
Adds an account.
Definition: account.cpp:399
ST_CHANGE_PASSWORD_NEW
#define ST_CHANGE_PASSWORD_NEW
Player is entering new password.
Definition: define.h:545
player::item_power
int16_t item_power
Total item power of objects equipped.
Definition: player.h:130
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
CS_STAT_RES_BLIND
#define CS_STAT_RES_BLIND
Definition: newclient.h:168
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:272
CF_DISEASED
#define CF_DISEASED
Has at least one disease.
Definition: newclient.h:205
MAP2_TYPE_DARKNESS
#define MAP2_TYPE_DARKNESS
Definition: newclient.h:43
socket_struct::map_scroll_y
int8_t map_scroll_y
Definition: newserver.h:94
MAP2_COORD_ENCODE
static uint16_t MAP2_COORD_ENCODE(int x, int y, int flags)
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
statsinfo::title
char * title
Definition: newserver.h:57
sproto.h
player::last_weight_limit
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:159
CS_STAT_RACE_INT
#define CS_STAT_RACE_INT
Definition: newclient.h:121
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:2334
VERSION_SC
#define VERSION_SC
Definition: newserver.h:150
get_face_by_id
const Face * get_face_by_id(uint16_t id)
Get a face from its unique identifier.
Definition: assets.cpp:314
player::last_race_stats
living last_race_stats
Last race stats sent to the client.
Definition: player.h:170
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:142
MAP_TYPE_CHOICE
#define MAP_TYPE_CHOICE
Choice of maps presented to player.
Definition: map.h:59
SockList_Init
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
SockList::len
size_t len
Definition: newclient.h:689
CS_STAT_BASE_WIS
#define CS_STAT_BASE_WIS
Definition: newclient.h:129
is_perfect
static uint8_t is_perfect(const player *pl)
Check whether the player is perfect relatively to improvement potions.
Definition: request.cpp:795
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:107
socket_struct::cs_version
uint32_t cs_version
Definition: newserver.h:113
player::last_item_power
uint16_t last_item_power
Last value for item_power.
Definition: player.h:164
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:153
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
CS_STAT_WEIGHT_LIM
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:115
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:158
Ns_Add
@ Ns_Add
Definition: newserver.h:66
CS_STAT_ITEM_POWER
#define CS_STAT_ITEM_POWER
Equipped item power.
Definition: newclient.h:146
CS_STAT_RES_POISON
#define CS_STAT_RES_POISON
Definition: newclient.h:160
receive_player_name
void receive_player_name(object *op, const char *name)
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:102
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:247
player::orig_stats
living orig_stats
Permanent real stats of player.
Definition: player.h:167
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:3168
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
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:176
AddIfInt
#define AddIfInt(Old, New, sl, Type)
Definition: request.cpp:761
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
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:346
CS_STAT_MAXGRACE
#define CS_STAT_MAXGRACE
Definition: newclient.h:113
key_roll_stat
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.cpp:1221
MAP2_TYPE_CLEAR
#define MAP2_TYPE_CLEAR
Definition: newclient.h:42
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Let client animate this, synchronized.
Definition: define.h:240
Settings::starting_stat_points
uint8_t starting_stat_points
How many stat points character starts with.
Definition: global.h:324
ST_PLAYING
#define ST_PLAYING
Usual state.
Definition: define.h:535
living::Wis
int8_t Wis
Definition: living.h:36
Settings
Server settings.
Definition: global.h:242
create_player_cmd
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.cpp:2632
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:94
apply_race_and_class
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
This is somewhat like key_change_class() above, except we know the race to change to,...
Definition: player.cpp:1488
CS_STAT_BASE_INT
#define CS_STAT_BASE_INT
Definition: newclient.h:128
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:538
CS_STAT_SPELL_ATTUNE
#define CS_STAT_SPELL_ATTUNE
Definition: newclient.h:117
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
SockList_AddData
void SockList_AddData(SockList *sl, const void *data, size_t len)
Adds a data block.
Definition: lowlevel.cpp:167
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
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
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
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:144
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:108
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:4252
AddIfFloat
#define AddIfFloat(Old, New, sl, Type)
Definition: request.cpp:775
MAP2_LABEL_DM
@ MAP2_LABEL_DM
Definition: newclient.h:59
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:542
send_tick
void send_tick(player *pl)
Definition: request.cpp:2003
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:1113
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:2248
living::maxsp
int16_t maxsp
Max spell points.
Definition: living.h:43
DISEASE
@ DISEASE
Definition: object.h:249
P_NEED_UPDATE
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:239
newserver.h
mapstruct
This is a game-map.
Definition: map.h:315
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:687
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:1949
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:266
socket_struct::status
enum Sock_Status status
Definition: newserver.h:90
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:155
FLAG_AUTO_APPLY
#define FLAG_AUTO_APPLY
Will be applied when created.
Definition: define.h:250
player::state
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:131
statsinfo::god
char * god
Definition: newserver.h:57
esrv_remove_spell
void esrv_remove_spell(player *pl, object *spell)
Definition: request.cpp:1812
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:335
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
MAP2_LABEL_PLAYER
@ MAP2_LABEL_PLAYER
Definition: newclient.h:57
Map::cells
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:49
CF_CONFUSED
#define CF_CONFUSED
Confused by a spell or an item.
Definition: newclient.h:201
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
text
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended text
Definition: media-tags.txt:35
Animations::num
uint16_t num
Where we are in the array.
Definition: face.h:29
living::ac
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:173
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.cpp:83
NDI_DK_ORANGE
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:251
socket_struct::anims_sent
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:97
player::last_orig_stats
living last_orig_stats
Last permanent stats sent to client.
Definition: player.h:169
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:96
player::last_resist
int16_t last_resist[NROFATTACKS]
last resist values sent to client.
Definition: player.h:174
CS_STAT_RES_DEATH
#define CS_STAT_RES_DEATH
Definition: newclient.h:166
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:203
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:1459
player::count
uint32_t count
Any numbers typed before a command.
Definition: player.h:122
strcasecmp
int strcasecmp(const char *s1, const char *s2)
ACL_LEVEL
#define ACL_LEVEL
Definition: newclient.h:223
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Arrows, etc.
Definition: map.h:49
CS_STAT_TITLE
#define CS_STAT_TITLE
Definition: newclient.h:110
MAP_TYPE_DEFAULT
#define MAP_TYPE_DEFAULT
If no map is specified, where character starts.
Definition: map.h:58
newclient.h
save_player
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:230
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:543
VERSION_CS
#define VERSION_CS
Version >= 1023 understand setup cmd.
Definition: newserver.h:149
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:328
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:111
skill
skill
Definition: arch-handbook.txt:585
CF_WIZARD
#define CF_WIZARD
Player is DM.
Definition: newclient.h:210
player::character_load
float character_load
Value between 0 and 1 indicating how much the character is overloaded.
Definition: player.h:135
esrv_send_pickup
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1835
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:1833
player_set_state
void player_set_state(player *pl, uint8_t state)
Set the player's state to the specified one.
Definition: player.cpp:4488
free_charlinks
void free_charlinks(linked_char *lc)
Frees a link structure and its next items.
Definition: utils.cpp:616
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:269
CS_STAT_RACE_WIS
#define CS_STAT_RACE_WIS
Definition: newclient.h:122
AddIfString
#define AddIfString(Old, New, sl, Type)
Definition: request.cpp:782
MAX_CHOICES
#define MAX_CHOICES
Definition: request.cpp:2625
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:285
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:161
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
MAP_LAYER_LIVING2
#define MAP_LAYER_LIVING2
Definition: map.h:47
socket_struct::login_method
uint8_t login_method
Login method this client is using.
Definition: newserver.h:128
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:1283
statsinfo::range
char * range
Definition: newserver.h:57
commands.h
ST_CONFIRM_QUIT
#define ST_CONFIRM_QUIT
Player used the 'quit' command, make sure that's ok.
Definition: define.h:539
player::password
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:193
CS_STAT_MAXHP
#define CS_STAT_MAXHP
Definition: newclient.h:91
move_cmd
void move_cmd(char *buf, int len, player *pl)
Moves an object (typically, container to inventory).
Definition: request.cpp:708
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:1297
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:1855
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:866
socket_struct::darkness
uint32_t darkness
True if client wants darkness information.
Definition: newserver.h:103
FLAG_XRAYS
#define FLAG_XRAYS
X-ray vision.
Definition: define.h:300
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:107
socket_struct::notifications
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:129
SF_RUNON
#define SF_RUNON
Definition: newclient.h:193
CS_STAT_RANGE
#define CS_STAT_RANGE
Definition: newclient.h:109
Settings::account_trusted_host
char * account_trusted_host
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:504
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.cpp:313
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:131
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:2024
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:97
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:275
player::last_weapon_sp
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h:156
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
ST_ROLL_STAT
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:537
SPELL
@ SPELL
Definition: object.h:219
CS_STAT_BASE_STR
#define CS_STAT_BASE_STR
Definition: newclient.h:127
smooth_face
const Face * smooth_face
Definition: image.cpp:36
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.cpp:1008
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:2149
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:145
CS_STAT_RES_DRAIN
#define CS_STAT_RES_DRAIN
Definition: newclient.h:158
MAP_NOSMOOTH
#define MAP_NOSMOOTH(m)
Definition: map.h:84
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:405
CF_HOSTILE
#define CF_HOSTILE
'hostile' flag is set.
Definition: newclient.h:207
SockList
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:684
map_reset_swap
void map_reset_swap(mapstruct *m)
Call this when an in-memory map is used or referenced.
Definition: map.cpp:1762
CF_PARALYZED
#define CF_PARALYZED
Player is paralyzed.
Definition: newclient.h:209
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:664
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:136
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:135
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:444
ACL_FACE
#define ACL_FACE
Definition: newclient.h:224
CF_XRAY
#define CF_XRAY
Has X-ray.
Definition: newclient.h:204
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Get player's current range attack in obuf.
Definition: info.cpp:264
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
NS_FACESENT_SMOOTH
#define NS_FACESENT_SMOOTH
Definition: newserver.h:138
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
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:162
Settings::starting_stat_max
uint8_t starting_stat_max
Maximum value of a starting stat.
Definition: global.h:323
CS_STAT_RES_ACID
#define CS_STAT_RES_ACID
Definition: newclient.h:157
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:154
CS_STAT_FLAGS
#define CS_STAT_FLAGS
Definition: newclient.h:114