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 
1354 static bool map2_add_label(int ax, int ay, socket_struct *ns, SockList *sl, enum map2_label subtype, sstring label) {
1355  // label can only be null if subtype is none
1356  assert(subtype != MAP2_LABEL_NONE ? label != NULL : 1);
1357 
1358  // protect old clients from label with additive length, which can cause them to crash
1359  if (ns->sc_version < 1030)
1360  return false;
1361 
1362  // Check if there is any change to last sent data
1363  struct map_cell_struct *cell = &ns->lastmap.cells[ax][ay];
1364  if (cell->label_subtype == subtype &&
1365  (subtype == 0 || cell->label_text == label)) { // none label skips string comparison
1366  return false;
1367  }
1368 
1369  // Store change
1370  if (cell->label_subtype != MAP2_LABEL_NONE)
1371  free_string(cell->label_text);
1372  cell->label_subtype = subtype;
1373  cell->label_text = label;
1374 
1375  int len = 0;
1376  if (label) {
1377  add_refcount(label);
1378  len = strlen(label);
1379  if (len > 256 - 2 - 1) {
1380  LOG(llevError, "The label '%s' is too long to send to the client.", label);
1381  return false;
1382  }
1383  }
1384 
1385  // Send update
1386  SockList_AddChar(sl, MAP2_ADD_LENGTH | MAP2_TYPE_LABEL); // label with additive length
1387  SockList_AddChar(sl, len + 2); // length of payload (subtype + lstring)
1388  SockList_AddChar(sl, subtype);
1389  SockList_AddChar(sl, len); // lstring length prefix
1390  if (label)
1391  SockList_AddString(sl, label);
1392  return true;
1393 }
1394 
1395 static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer) {
1396  socket_struct *ns = plyr->socket;
1397  int got_one = check_probe(ax, ay, ob, sl, ns, has_obj, alive_layer);
1398  // add NPC speech bubble
1399  if (QUERY_FLAG(ob, FLAG_ALIVE) && (QUERY_FLAG(ob, FLAG_UNAGGRESSIVE) || QUERY_FLAG(ob, FLAG_FRIENDLY)) && ob->type != PLAYER) {
1400  if (ob->msg != NULL || object_find_by_arch_name(ob, NPC_DIALOG_ARCH)) {
1401  archetype *dummy = try_find_archetype("speechbubble");
1402  if (dummy != NULL) {
1403  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1404  (*alive_layer) = MAP_LAYER_FLY2;
1405  }
1406  }
1407  }
1408  return got_one;
1409 }
1410 
1414 static bool add_labels(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *got_one) {
1415  socket_struct *ns = plyr->socket;
1416  // add player name label
1417  if (ob->type == PLAYER) {
1418  enum map2_label subtype = MAP2_LABEL_PLAYER;
1419  if (QUERY_FLAG(ob, FLAG_WIZ)) {
1420  subtype = MAP2_LABEL_DM;
1421  } else if (plyr->party) {
1422  if (ob->contr && ob->contr->party == plyr->party) {
1423  subtype = MAP2_LABEL_PLAYER_PARTY;
1424  }
1425  }
1426  *got_one += map2_add_label(ax, ay, ns, sl, subtype, ob->name);
1427  return true;
1428  } else if (object_value_set(ob, "label")) {
1429  const char *label = object_get_value(ob, "label");
1430  *got_one += map2_add_label(ax, ay, ns, sl, MAP2_LABEL_SIGN, label);
1431  return true;
1432  }
1433  return false;
1434 }
1435 
1436 /*
1437  * This function is used to check a space (ax, ay) whose only
1438  * data we may care about are any heads. Basically, this
1439  * space is out of direct view. This is only used with the
1440  * Map2 protocol.
1441  *
1442  * @param ax
1443  * viewport relative x-coordinate
1444  * @param ay
1445  * viewport relative y-coordinate
1446  * @param sl
1447  * the reply to append to
1448  * @param ns
1449  * the client socket
1450  */
1451 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1452  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1453  uint16_t coord;
1454 
1455  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1456  oldlen = sl->len;
1457  SockList_AddShort(sl, coord);
1458 
1459  for (layer = 0; layer < MAP_LAYERS; layer++) {
1460  const object *head;
1461 
1462  head = heads[ay][ax][layer];
1463  if (head) {
1464  /* in this context, got_one should always increase
1465  * because heads should always point to data to really send.
1466  */
1467  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1468  } else {
1469  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1470  }
1471  }
1472  /* Note - if/when lighting information is added, some code is
1473  * needed here - lighting sources that are out of sight may still
1474  * extend into the viewable area.
1475  */
1476 
1477  /* If nothing to do for this space, we
1478  * can erase the coordinate bytes
1479  */
1480  if (!del_one && !got_one) {
1481  sl->len = oldlen;
1482  } else if (del_one && !has_obj) {
1483  /* If we're only deleting faces and not adding, and there
1484  * are not any faces on the space we care about,
1485  * more efficient
1486  * to send 0 as the type/len field.
1487  */
1488  sl->len = oldlen+2; /* 2 bytes for coordinate */
1489  SockList_AddChar(sl, MAP2_TYPE_CLEAR); /* Clear byte */
1490  SockList_AddChar(sl, 255); /* Termination byte */
1491  // Reduce defreferences by passing the inner array offset instead of address of value
1492  map_clearcell(ns->lastmap.cells[ax] + ay, 0, 0);
1493  } else {
1494  SockList_AddChar(sl, 255); /* Termination byte */
1495  }
1496 }
1497 
1498 static void draw_client_map2(object *pl) {
1499  int x, y, ax, ay, darkness, min_x, max_x, min_y, max_y, oldlen, layer;
1500  size_t startlen;
1501  int16_t nx, ny;
1502  SockList sl;
1503  uint16_t coord;
1504  mapstruct *m;
1505  // Dereference once. It should not change in the middle of processing.
1506  player *plyr = pl->contr;
1507 
1508  SockList_Init(&sl);
1509  SockList_AddString(&sl, "map2 ");
1510  startlen = sl.len;
1511 
1512  handle_scroll(plyr->socket, &sl);
1513 
1514  /* Init data to zero */
1515  memset(heads, 0, sizeof(heads));
1516 
1517  /* We could do this logic as conditionals in the if statement,
1518  * but that started to get a bit messy to look at.
1519  */
1520  min_x = pl->x-plyr->socket->mapx/2;
1521  min_y = pl->y-plyr->socket->mapy/2;
1522  max_x = pl->x+(plyr->socket->mapx+1)/2+MAX_HEAD_OFFSET;
1523  max_y = pl->y+(plyr->socket->mapy+1)/2+MAX_HEAD_OFFSET;
1524 
1525  /* x, y are the real map locations. ax, ay are viewport relative
1526  * locations.
1527  */
1528  ay = 0;
1529  for (y = min_y; y < max_y; y++, ay++) {
1530  ax = 0;
1531  for (x = min_x; x < max_x; x++, ax++) {
1532  /* If this space is out of the normal viewable area,
1533  * we only check the heads value. This is used to
1534  * handle big images - if they extend to a viewable
1535  * portion, we need to send just the lower right corner.
1536  */
1537  if (ax >= plyr->socket->mapx || ay >= plyr->socket->mapy) {
1538  check_space_for_heads(ax, ay, &sl, plyr->socket);
1539  } else {
1540  /* This space is within the viewport of the client. Due
1541  * to walls or darkness, it may still not be visible.
1542  */
1543 
1544  /* Meaning of darkness (see defines in LOS_* in los.c):
1545  * LOS_NO_DARKNESS (0) - object is in plain sight, full brightness.
1546  * 1 - MAX_DARKNESS - how dark the space is - higher
1547  * value is darker space. If level is at max darkness,
1548  * you can't see the space (too dark)
1549  * LOS_BLOCKED (100) - space is blocked from sight.
1550  */
1551  darkness = plyr->blocked_los[ax][ay];
1552 
1553  /* If the coordinates are not valid, or it is too
1554  * dark to see, we tell the client as such
1555  */
1556  nx = x;
1557  ny = y;
1558  m = get_map_from_coord(pl->map, &nx, &ny);
1559  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1560 
1561  if (!m) {
1562  /* space is out of map. Update space and clear
1563  * values if this hasn't already been done.
1564  * If the space is out of the map, it shouldn't
1565  * have a head.
1566  */
1567  if (plyr->socket->lastmap.cells[ax][ay].darkness != 0) {
1568  SockList_AddShort(&sl, coord);
1570  SockList_AddChar(&sl, 255); /* Termination byte */
1571  // Reduce dereferences by passing the inner array offset instead of address of value
1572  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1573  }
1574  } else if (darkness >= MAX_LIGHT_RADII) {
1575  /* This block deals with spaces that are not
1576  * visible due to darkness or walls. Still
1577  * need to send the heads for this space.
1578  */
1579  check_space_for_heads(ax, ay, &sl, plyr->socket);
1580  } else {
1581  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1582 
1583  /* In this block, the space is visible. */
1584 
1585  /* Rather than try to figure out what everything
1586  * that we might need to send is, then form the
1587  * packet after that, we presume that we will in
1588  * fact form a packet, and update the bits by what
1589  * we do actually send. If we send nothing, we
1590  * just back out sl.len to the old value, and no
1591  * harm is done.
1592  * I think this is simpler than doing a bunch of
1593  * checks to see what if anything we need to send,
1594  * setting the bits, then doing those checks again
1595  * to add the real data.
1596  */
1597 
1598  oldlen = sl.len;
1599  SockList_AddShort(&sl, coord);
1600 
1601  /* Darkness changed */
1602  if (plyr->socket->lastmap.cells[ax][ay].darkness != darkness
1603  && plyr->socket->darkness) {
1604  plyr->socket->lastmap.cells[ax][ay].darkness = darkness;
1605  /* Darkness tag & length (length=1) */
1606  SockList_AddChar(&sl, MAP2_TYPE_DARKNESS|(1<<5));
1607 
1608  /* Convert darkness level (0-MAX_DARKNESS) to a value
1609  * from 1 (dark) to 255 (bright) for the client.
1610  * Darkness values of 0 (completely dark) are not sent,
1611  * as the space is completely dark.
1612  */
1613  SockList_AddChar(&sl, 255-darkness*(256/MAX_LIGHT_RADII));
1614  have_darkness = 1;
1615  }
1616 
1617  int got_label = 0;
1618  for (layer = 0; layer < MAP_LAYERS; layer++) {
1619  const object *ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1620 
1621  /* Special case: send player itself if invisible */
1622  if (!ob
1623  && x == pl->x
1624  && y == pl->y
1625  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1626  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1627  ob = pl;
1628 
1629  if (ob) {
1630  g1 = has_obj;
1631  old_got = got_one;
1632  got_one += map2_add_ob(ax, ay, layer, ob, &sl, plyr->socket, &has_obj, 0);
1633 
1634  /* if we added the face, or it is a monster's head, check probe spell */
1635  if (got_one != old_got || ob->head == NULL) {
1636  got_one += annotate_ob(ax, ay, ob, &sl, plyr, &has_obj, &alive_layer);
1637  got_label += add_labels(ax, ay, ob, &sl, plyr, &got_one);
1638  }
1639 
1640  /* If we are just storing away the head
1641  * for future use, then effectively this
1642  * space/layer is blank, and we should clear
1643  * it if needed.
1644  */
1645  if (g1 == has_obj) {
1646  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1647  }
1648  } else {
1649  if (layer != alive_layer)
1650  del_one += map2_delete_layer(ax, ay, layer, &sl, plyr->socket);
1651  }
1652  }
1653  if (got_label == 0) {
1654  got_one += map2_add_label(ax, ay, plyr->socket, &sl, MAP2_LABEL_NONE, NULL);
1655  }
1656  /* If nothing to do for this space, we
1657  * can erase the coordinate bytes
1658  */
1659  if (!del_one && !got_one && !have_darkness) {
1660  sl.len = oldlen;
1661  } else if (del_one && !has_obj) {
1662  /* If we're only deleting faces and don't
1663  * have any objs we care about, just clear
1664  * space. Note it is possible we may have
1665  * darkness, but if there is nothing on the
1666  * space, darkness isn't all that interesting
1667  * - we can send it when an object shows up.
1668  */
1669  sl.len = oldlen+2; /* 2 bytes for coordinate */
1671  SockList_AddChar(&sl, 255); /* Termination byte */
1672  // Reduce dereferences by passing the inner array offset instead of address of value
1673  map_clearcell(plyr->socket->lastmap.cells[ax] + ay, 0, 0);
1674  } else {
1675  SockList_AddChar(&sl, 255); /* Termination byte */
1676  }
1677  }
1678  } /* else this is a viewable space */
1679  } /* for x loop */
1680  } /* for y loop */
1681 
1682  /* Only send this if there are in fact some differences. */
1683  if (sl.len > startlen) {
1684  Send_With_Handling(plyr->socket, &sl);
1685  }
1686  SockList_Term(&sl);
1687 }
1688 
1692 void draw_client_map(object *pl) {
1693  int i, j;
1694  int16_t ax, ay;
1695  int mflags;
1696  mapstruct *m, *pm;
1697  int min_x, min_y, max_x, max_y;
1698 
1699  if (pl->type != PLAYER) {
1700  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1701  return;
1702  }
1703 
1704  if (pl->contr->transport) {
1705  pm = pl->contr->transport->map;
1706  } else
1707  pm = pl->map;
1708 
1709  /* If player is just joining the game, he isn't here yet, so
1710  * the map can get swapped out. If so, don't try to send them
1711  * a map. All will be OK once they really log in.
1712  */
1713  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1714  return;
1715 
1716  /*
1717  * This block just makes sure all the spaces are properly
1718  * updated in terms of what they look like.
1719  */
1720  min_x = pl->x-pl->contr->socket->mapx/2;
1721  min_y = pl->y-pl->contr->socket->mapy/2;
1722  max_x = pl->x+(pl->contr->socket->mapx+1)/2;
1723  max_y = pl->y+(pl->contr->socket->mapy+1)/2;
1724  for (j = min_y; j < max_y; j++) {
1725  for (i = min_x; i < max_x; i++) {
1726  ax = i;
1727  ay = j;
1728  m = pm;
1729  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1730  if (mflags&P_OUT_OF_MAP)
1731  continue;
1732  if (mflags&P_NEED_UPDATE)
1733  update_position(m, ax, ay);
1734  /* If a map is visible to the player, we don't want
1735  * to swap it out just to reload it. This should
1736  * really call something like swap_map, but this is
1737  * much more efficient and 'good enough'
1738  */
1739  if (mflags&P_NEW_MAP)
1740  map_reset_swap(m);
1741  }
1742  }
1743 
1744  /* do LOS after calls to update_position */
1745  if (pl->contr->do_los) {
1746  update_los(pl);
1747  pl->contr->do_los = 0;
1748  }
1749 
1750  draw_client_map2(pl);
1751 }
1752 
1753 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1754  struct Map newmap;
1755  int x, y, mx, my;
1756 
1757  ns->map_scroll_x += dx;
1758  ns->map_scroll_y += dy;
1759 
1760  mx = ns->mapx+MAX_HEAD_OFFSET;
1761  my = ns->mapy+MAX_HEAD_OFFSET;
1762 
1763  /* the x and y here are coordinates for the new map, i.e. if we moved
1764  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1765  * if the destination x or y coordinate is outside the viewable
1766  * area, we clear the values - otherwise, the old values
1767  * are preserved, and the check_head thinks it needs to clear them.
1768  */
1769  for (x = 0; x < mx; x++) {
1770  for (y = 0; y < my; y++) {
1771  if (x >= ns->mapx || y >= ns->mapy) {
1772  /* clear cells outside the viewable area */
1773  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1774  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1775  /* clear newly visible tiles within the viewable area */
1776  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1777  } else {
1778  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1779  }
1780  }
1781  }
1782 
1783  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1784 }
1785 
1791 void send_plugin_custom_message(object *pl, char *buf) {
1792  SockList sl;
1793 
1794  SockList_Init(&sl);
1795  SockList_AddString(&sl, buf);
1796  Send_With_Handling(pl->contr->socket, &sl);
1797  SockList_Term(&sl);
1798 }
1799 
1806  SockList sl;
1807  int flags = 0;
1808  client_spell *spell_info;
1809 
1810  if (!pl->socket || !pl->socket->monitor_spells)
1811  return;
1812 
1813  /* Handles problem at login, where this is called from fix_object
1814  * before we have had a chance to send spells to the player. It does seem
1815  * to me that there should never be a case where update_spells is called
1816  * before add_spells has been called. Add_spells() will update the
1817  * spell_state to non null.
1818  */
1819  if (!pl->spell_state)
1820  return;
1821 
1822  FOR_INV_PREPARE(pl->ob, spell) {
1823  if (spell->type == SPELL) {
1824  spell_info = get_client_spell_state(pl, spell);
1825  /* check if we need to update it*/
1826  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1827  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1828  flags |= UPD_SP_MANA;
1829  }
1830  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1832  flags |= UPD_SP_GRACE;
1833  }
1834  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1835  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1836  flags |= UPD_SP_DAMAGE;
1837  }
1838  if (flags != 0) {
1839  SockList_Init(&sl);
1840  SockList_AddString(&sl, "updspell ");
1841  SockList_AddChar(&sl, flags);
1842  SockList_AddInt(&sl, spell->count);
1843  if (flags&UPD_SP_MANA)
1844  SockList_AddShort(&sl, spell_info->last_sp);
1845  if (flags&UPD_SP_GRACE)
1846  SockList_AddShort(&sl, spell_info->last_grace);
1847  if (flags&UPD_SP_DAMAGE)
1848  SockList_AddShort(&sl, spell_info->last_dam);
1849  flags = 0;
1850  Send_With_Handling(pl->socket, &sl);
1851  SockList_Term(&sl);
1852  }
1853  }
1854  } FOR_INV_FINISH();
1855 }
1856 
1857 void esrv_remove_spell(player *pl, object *spell) {
1858  SockList sl;
1859 
1860  if (!pl || !spell || spell->env != pl->ob) {
1861  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1862  return;
1863  }
1864  if (!pl->socket->monitor_spells)
1865  return;
1866 
1867  SockList_Init(&sl);
1868  SockList_AddString(&sl, "delspell ");
1869  SockList_AddInt(&sl, spell->count);
1870  Send_With_Handling(pl->socket, &sl);
1871  SockList_Term(&sl);
1872 }
1873 
1881  SockList sl;
1882 
1883  if (!pl->socket->want_pickup)
1884  return;
1885  SockList_Init(&sl);
1886  SockList_AddString(&sl, "pickup ");
1887  SockList_AddInt(&sl, pl->mode);
1888  Send_With_Handling(pl->socket, &sl);
1889  SockList_Term(&sl);
1890 }
1891 
1900 static int spell_client_use(const object *spell) {
1901  switch (spell->subtype)
1902  {
1903  case SP_RAISE_DEAD:
1904  case SP_MAKE_MARK:
1905  return 3;
1906  case SP_RUNE:
1907  if (!spell->other_arch)
1908  return 1;
1909  break;
1910  case SP_CREATE_FOOD:
1911  case SP_CREATE_MISSILE:
1912  return 2;
1913  case SP_SUMMON_MONSTER:
1914  if (spell->randomitems != NULL)
1915  return 2;
1916  /* break; */// If add conditins below, use this break statement
1917  }
1918  // This is not in the switch statement so that it supports fallthrough logic
1919  // on the few spell types that have additional conditions attached.
1920  return 0;
1921 }
1922 
1924 static void append_spell(player *pl, SockList *sl, object *spell) {
1925  client_spell *spell_info;
1926  int len, i, skill = 0;
1927 
1928  if (!spell->name) {
1929  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1930  return;
1931  }
1932 
1933  if (spell->face && !(pl->socket->faces_sent[spell->face->number]&NS_FACESENT_FACE))
1934  esrv_send_face(pl->socket, spell->face, 0);
1935 
1936  spell_info = get_client_spell_state(pl, spell);
1937  SockList_AddInt(sl, spell->count);
1938  SockList_AddShort(sl, spell->level);
1939  SockList_AddShort(sl, spell->casting_time);
1940  /* store costs and damage in the object struct, to compare to later */
1941  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1943  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1944  /* send the current values */
1945  SockList_AddShort(sl, spell_info->last_sp);
1946  SockList_AddShort(sl, spell_info->last_grace);
1947  SockList_AddShort(sl, spell_info->last_dam);
1948 
1949  /* figure out which skill it uses, if it uses one */
1950  if (spell->skill) {
1951  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++)
1952  if (!strcmp(spell->skill, skill_names[i])) {
1954  break;
1955  }
1956  }
1957  SockList_AddChar(sl, skill);
1958 
1959  SockList_AddInt(sl, spell->path_attuned);
1960  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1961  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1962 
1963  if (!spell->msg) {
1964  SockList_AddShort(sl, 0);
1965  } else {
1966  len = strlen(spell->msg);
1967  SockList_AddShort(sl, len);
1968  SockList_AddData(sl, spell->msg, len);
1969  }
1970 
1971  /* Extended spell information available if the client wants it.
1972  */
1973  if (pl->socket->monitor_spells >= 2) {
1974  /* spellmon 2
1975  */
1976  sstring req = object_get_value(spell, "casting_requirements");
1977 
1978  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1979 
1980  if (req) { /* Requirements */
1981  SockList_AddLen8Data(sl, req, strlen(req));
1982  } else {
1983  SockList_AddChar(sl, 0);
1984  }
1985  /* end spellmon 2
1986  */
1987  }
1988 }
1989 
1994 void esrv_add_spells(player *pl, object *spell) {
1995  SockList sl;
1996  size_t size;
1997  sstring value;
1998 
1999  if (!pl) {
2000  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
2001  return;
2002  }
2003 
2004  if (!pl->socket->monitor_spells)
2005  return;
2006 
2007  SockList_Init(&sl);
2008  SockList_AddString(&sl, "addspell ");
2009  if (!spell) {
2010  FOR_INV_PREPARE(pl->ob, spell) {
2011  if (spell->type != SPELL)
2012  continue;
2013  /* Were we to simply keep appending data here, we could
2014  * exceed the SockList buffer if the player has enough spells
2015  * to add. We know that append_spell will always append
2016  * 23 data bytes, plus 3 length bytes and 2 strings
2017  * (because that is the spec) so we need to check that
2018  * the length of those 2 strings, plus the 26 bytes,
2019  * won't take us over the length limit for the socket.
2020  * If it does, we need to send what we already have,
2021  * and restart packet formation.
2022  */
2023  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
2024  if (pl->socket->monitor_spells >= 2) {
2026  value = object_get_value(spell, "casting_requirements");
2027  size += 2 + (value ? strlen(value) : 0);
2028  }
2029  if (SockList_Avail(&sl) < size) {
2030  Send_With_Handling(pl->socket, &sl);
2031  SockList_Reset(&sl);
2032  SockList_AddString(&sl, "addspell ");
2033  }
2034  append_spell(pl, &sl, spell);
2035  } FOR_INV_FINISH();
2036  } else if (spell->type != SPELL) {
2037  LOG(llevError, "Asked to send a non-spell object as a spell\n");
2038  return;
2039  } else
2040  append_spell(pl, &sl, spell);
2041  /* finally, we can send the packet */
2042  Send_With_Handling(pl->socket, &sl);
2043  SockList_Term(&sl);
2044 }
2045 
2046 /* sends a 'tick' information to the client.
2047  */
2048 void send_tick(player *pl) {
2049  SockList sl;
2050  SockList_Init(&sl);
2051  SockList_AddString(&sl, "tick ");
2052  SockList_AddInt(&sl, pticks);
2053  Send_With_Handling(pl->socket, &sl);
2054  SockList_Term(&sl);
2055 }
2056 
2069 static void add_char_field(SockList *sl, int type, const char *data)
2070 {
2071  int len;
2072 
2073  len = strlen(data);
2074 
2075  if (len) {
2076  /* one extra for length for the type byte */
2077  SockList_AddChar(sl, len+1);
2078  SockList_AddChar(sl, type);
2079  SockList_AddString(sl, data);
2080  }
2081 }
2082 
2104 {
2105  SockList sl;
2106  int num_chars;
2107  linked_char *extra;
2108 
2109  if (ns->account_chars) {
2111  }
2113 
2114  num_chars = 0;
2115  extra = account_get_additional_chars(ns->account_name, ns->account_chars, &num_chars);
2116 
2117  SockList_Init(&sl);
2118  SockList_AddString(&sl, "accountplayers ");
2119 
2120  SockList_AddChar(&sl, static_cast<char>(ns->account_chars->chars.size() + num_chars));
2121 
2122  /* Now add real character data */
2123  for (auto acn : ns->account_chars->chars) {
2124  uint16_t faceno = 0;
2125 
2126  /* Ignore a dead character. They don't need to show up. */
2127  if (acn->isDead) {
2128  continue;
2129  }
2130 
2131  add_char_field(&sl, ACL_NAME, acn->name);
2132  add_char_field(&sl, ACL_CLASS, acn->character_class);
2133  add_char_field(&sl, ACL_RACE, acn->race);
2134  add_char_field(&sl, ACL_FACE, acn->face);
2135  if (acn->face[0] != 0 ) {
2136  const Face *face = try_find_face(acn->face, NULL);
2137 
2138  if (face != NULL) {
2139  if (!(ns->faces_sent[face->number]&NS_FACESENT_FACE)) {
2140  esrv_send_face(ns, face, 0);
2141  }
2142  faceno = face->number;
2143  }
2144  }
2145 
2146  add_char_field(&sl, ACL_PARTY, acn->party);
2147  add_char_field(&sl, ACL_MAP, acn->map);
2148  SockList_AddChar(&sl, 3);
2150  SockList_AddShort(&sl, acn->level);
2151  if (faceno) {
2152  SockList_AddChar(&sl, 3);
2154  SockList_AddShort(&sl, faceno);
2155  }
2156 
2157  SockList_AddChar(&sl, 0);
2158  }
2159  /* Now for any characters where we just have the name */
2160  for (linked_char *e = extra; e != NULL; e = e->next) {
2161  add_char_field(&sl, ACL_NAME, e->name);
2162  SockList_AddChar(&sl, 0);
2163  }
2164 
2165  Send_With_Handling(ns, &sl);
2166  SockList_Term(&sl);
2167 
2168  if (extra) {
2169  free_charlinks(extra);
2170  }
2171 }
2172 
2194 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2195 {
2196  int nlen, plen;
2197 
2198  if (*len < 2) {
2199  return 1;
2200  }
2201 
2202  nlen = (unsigned char)buf[0];
2203  if (nlen >= MAX_BUF || nlen > *len-2) {
2204  return 1;
2205  }
2206  memcpy(name, buf+1, nlen);
2207  name[nlen] = 0;
2208 
2209  plen = (unsigned char)buf[nlen+1];
2210  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2211  return 2;
2212  }
2213  memcpy(password, buf+2+nlen, plen);
2214  password[plen] = 0;
2215 
2216  *len = nlen+plen+2;
2217 
2218  return 0;
2219 }
2230 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2231  char name[MAX_BUF], password[MAX_BUF];
2232  int status;
2233  SockList sl;
2234 
2235  if (len <= 0 || !buf) {
2236  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2237  return;
2238  }
2239 
2240  SockList_Init(&sl);
2241 
2242  status = decode_name_password(buf, &len, name, password);
2243 
2244  if (status == 1) {
2245  SockList_AddString(&sl, "failure accountlogin Name is too long");
2246  Send_With_Handling(ns, &sl);
2247  SockList_Term(&sl);
2248  return;
2249  }
2250  if (status == 2) {
2251  SockList_AddString(&sl, "failure accountlogin Password is too long");
2252  Send_With_Handling(ns, &sl);
2253  SockList_Term(&sl);
2254  return;
2255  }
2256 
2257  if (!account_exists(name)) {
2258  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2259  Send_With_Handling(ns, &sl);
2260  SockList_Term(&sl);
2261  return;
2262  }
2263 
2264  if (account_login(name, password)) {
2265  LOG(llevInfo, "Account login for '%s' from %s\n", name, ns->host);
2266 
2267  if (ns->account_name) free(ns->account_name);
2268  /* We want to store away official name so we do not
2269  * have any case sensitivity issues on the files.
2270  * because we have already checked password, we
2271  * know that account_exists should never return NULL in
2272  * this case.
2273  */
2275 
2277  } else {
2278  LOG(llevInfo, "Failed account login for '%s' from %s\n", name, ns->host);
2279  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2280  Send_With_Handling(ns, &sl);
2281  SockList_Term(&sl);
2282  }
2283 }
2284 
2293 static int account_block_create(const socket_struct *ns) {
2294  /* Check if account creation is blocked. */
2296  /* Account creation is allowed for everyone. */
2297  return 0;
2298  }
2299 
2300  /* Has the trusted host been defined? */
2301  if(settings.account_trusted_host == NULL) {
2302  /* No, allocate it and set it to localhost now. */
2304  }
2305 
2306  /* Return false if the client connected from the trusted host. */
2307  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2308  return 0;
2309  }
2310 
2311  /*
2312  * If we are here, then we are blocking account create and we do
2313  * not trust this client's IP address.
2314  */
2315  return 1;
2316 }
2317 
2329 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2330  char name[MAX_BUF], password[MAX_BUF];
2331  int status;
2332  SockList sl;
2333 
2334  if (len <= 0 || !buf) {
2335  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2336  return;
2337  }
2338 
2339  SockList_Init(&sl);
2340 
2341  status = decode_name_password(buf, &len, name, password);
2342 
2343  if (account_block_create(ns)) {
2344  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2345  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2346  Send_With_Handling(ns, &sl);
2347  SockList_Term(&sl);
2348  return;
2349  }
2350 
2351  if (status == 1) {
2352  SockList_AddString(&sl, "failure accountnew Name is too long");
2353  Send_With_Handling(ns, &sl);
2354  SockList_Term(&sl);
2355  return;
2356  }
2357  if (status == 2) {
2358  SockList_AddString(&sl, "failure accountnew Password is too long");
2359  Send_With_Handling(ns, &sl);
2360  SockList_Term(&sl);
2361  return;
2362  }
2363  /*The minimum length isn't exactly required, but in the current implementation,
2364  * client will send the same password for character for which there is a
2365  * 2 character minimum size. Thus an account with a one character password
2366  * won't be able to create a character. */
2367  if (strlen(name)<settings.min_name) {
2368  SockList_AddString(&sl, "failure accountnew Name is too short");
2369  Send_With_Handling(ns, &sl);
2370  SockList_Term(&sl);
2371  return;
2372  }
2373  if (strlen(password)<2) {
2374  SockList_AddString(&sl, "failure accountnew Password is too short");
2375  Send_With_Handling(ns, &sl);
2376  SockList_Term(&sl);
2377  return;
2378  }
2379 
2380  if (account_exists(name)) {
2381  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2382  Send_With_Handling(ns, &sl);
2383  SockList_Term(&sl);
2384  return;
2385  }
2386 
2387  status = account_check_string(name);
2388  if (status == 1) {
2389  SockList_AddString(&sl,
2390  "failure accountnew Choose a different account name. " VALIDCHAR_MSG);
2391  Send_With_Handling(ns, &sl);
2392  SockList_Term(&sl);
2393  return;
2394  }
2395 
2396  if (status == 2) {
2397  SockList_AddString(&sl,
2398  "failure accountnew That account name is too long");
2399  Send_With_Handling(ns, &sl);
2400  SockList_Term(&sl);
2401  return;
2402  }
2403 
2404  status = account_check_string(password);
2405  if (status == 1) {
2406  SockList_AddString(&sl,
2407  "failure accountnew Choose a different password. " VALIDCHAR_MSG);
2408  Send_With_Handling(ns, &sl);
2409  SockList_Term(&sl);
2410  return;
2411  }
2412 
2413  if (status == 2) {
2414  SockList_AddString(&sl,
2415  "failure accountnew That password is too long");
2416  Send_With_Handling(ns, &sl);
2417  SockList_Term(&sl);
2418  return;
2419  }
2420 
2421  /* If we got here, we passed all checks - so now add it */
2422  if (ns->account_name) free(ns->account_name);
2424  account_new(name, password);
2425  /* save account information */
2426  accounts_save();
2428 }
2429 
2443 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2444  char name[MAX_BUF], password[MAX_BUF];
2445  int status, force, nlen;
2446  SockList sl;
2447  const char *cp;
2448 
2449  if (len <= 0 || !buf) {
2450  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2451  return;
2452  }
2453 
2454  SockList_Init(&sl);
2455 
2456  if (ns->account_name == NULL) {
2457  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2458  Send_With_Handling(ns, &sl);
2459  SockList_Term(&sl);
2460  return;
2461  }
2462 
2463  force = buf[0];
2464  nlen = len - 1;
2465  status = decode_name_password(buf+1, &nlen, name, password);
2466  if (status == 1) {
2467  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2468  Send_With_Handling(ns, &sl);
2469  SockList_Term(&sl);
2470  return;
2471  }
2472  if (status == 2) {
2473  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2474  Send_With_Handling(ns, &sl);
2475  SockList_Term(&sl);
2476  return;
2477  }
2478 
2479  status = verify_player(name, password);
2480  if (status) {
2481  /* From a security standpoint, telling random folks if it
2482  * it as wrong password makes it easier to hack. However,
2483  * it is fairly easy to determine what characters exist on a server
2484  * (either by trying to create a new one and see if the name is in
2485  * in use, or just looking at the high score file), so this
2486  * really does not make things much less secure
2487  */
2488  if (status == 1)
2489  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2490  else
2491  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2492 
2493  Send_With_Handling(ns, &sl);
2494  SockList_Term(&sl);
2495  return;
2496  }
2497  /* Check to see if this character is associated with an account.
2498  */
2500  if (cp) {
2501  if (!strcmp(cp, ns->account_name)) {
2502  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2503  Send_With_Handling(ns, &sl);
2504  SockList_Term(&sl);
2505  return;
2506  } else {
2507  if (!force) {
2508  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2509  Send_With_Handling(ns, &sl);
2510  SockList_Term(&sl);
2511  return;
2512  } else if (account_is_logged_in(cp)) {
2513  /* We could be clever and try to handle this case, but it is
2514  * trickier. If the character is logged in, it has to
2515  * be logged out. And the socket holds some data which
2516  * needs to be cleaned up. Since it should be fairly
2517  * uncommon that users need to do this, just disallowing
2518  * it makes things a lot simpler.
2519  */
2520  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2521  Send_With_Handling(ns, &sl);
2522  SockList_Term(&sl);
2523  return;
2524  }
2525  }
2526  }
2527  /* If we have gotten this far, the name/password provided is OK,
2528  * and the character is not associated with a different account (or
2529  * force is true). Now try to add the character to this account.
2530  */
2531  status = account_link(ns->account_name, name);
2532 
2533  /* This should never happen, but check for it just in case -
2534  * if we were able to log in, the account should exist. but
2535  * if this fails, need to give the user some clue.
2536  */
2537  if (status==1) {
2538  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2539  Send_With_Handling(ns, &sl);
2540  SockList_Term(&sl);
2541  return;
2542  } else if (status == 2) {
2543  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2544  Send_With_Handling(ns, &sl);
2545  SockList_Term(&sl);
2546  return;
2547  }
2548 
2549  /* If cp is set, then this character used to belong to a different
2550  * account. Remove it now.
2551  */
2552  if (cp) {
2553  Account_Chars *chars;
2554 
2556  chars = account_char_load(cp);
2557  account_char_remove(chars, name);
2558  account_char_save(chars);
2559  account_char_free(chars);
2560  }
2561 
2563 
2564  /* store data so nothing is lost in case of crash */
2566 }
2567 
2572 void account_play_cmd(char *buf, int len, socket_struct *ns)
2573 {
2574  char **chars;
2575  int i;
2576  SockList sl;
2577  player *pl;
2578 
2579  if (len <= 0 || !buf) {
2580  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2581  return;
2582  }
2583 
2584  SockList_Init(&sl);
2585 
2586  if (ns->status != Ns_Add) {
2587  SockList_AddString(&sl, "failure accountplay Not allowed right now");
2588  Send_With_Handling(ns, &sl);
2589  SockList_Term(&sl);
2590  return;
2591  }
2592 
2593  if (!buf[0]) {
2594  SockList_AddString(&sl, "failure accountplay Malformed character name");
2595  Send_With_Handling(ns, &sl);
2596  SockList_Term(&sl);
2597  return;
2598  }
2599 
2600  if (ns->account_name == NULL) {
2601  SockList_AddString(&sl, "failure accountplay Not logged in");
2602  Send_With_Handling(ns, &sl);
2603  SockList_Term(&sl);
2604  return;
2605  }
2606 
2607  /* Make sure a client is not trying to spoof us here */
2609 
2610  for (i=0; chars[i]; i++) {
2611  if (strcmp(chars[i], buf) == 0)
2612  break;
2613  }
2614  if (!chars[i]) {
2615  SockList_AddPrintf(&sl,
2616  "failure accountplay Character %s is not associated with account %s",
2617  buf, ns->account_name);
2618  Send_With_Handling(ns, &sl);
2619  SockList_Term(&sl);
2620  return;
2621  }
2622 
2623  for (pl = first_player; pl; pl = pl->next) {
2624  if (pl->ob && pl->socket != ns && strcmp(buf, pl->ob->name) == 0 && pl->state != ST_PLAY_AGAIN && pl->state != ST_GET_NAME) {
2625  SockList_AddPrintf(&sl,
2626  "failure accountplay Character %s is already playing",
2627  buf);
2628  Send_With_Handling(ns, &sl);
2629  SockList_Term(&sl);
2630  return;
2631  }
2632  }
2633 
2634  /* from a protocol standpoint, accountplay can be used
2635  * before there is a player structure (first login) or after
2636  * (character has logged in and is changing characters).
2637  * Checkthe sockets for that second case - if so,
2638  * we don't need to make a new player object, etc.
2639  */
2640  for (pl=first_player; pl; pl=pl->next) {
2641  if (pl->socket == ns) {
2642  /* The player still in the socket must be saved first. */
2643  save_player(pl->ob, 0);
2644  break;
2645  }
2646  }
2647 
2648  /* Some of this logic is from add_player()
2649  * we just don't use add_player() as it does some other work
2650  * we don't really want to do.
2651  */
2652  if (!pl) {
2653  pl = get_player(NULL);
2654  set_player_socket(pl, ns);
2655  ns->status = Ns_Avail;
2656  ns->account_chars = NULL;
2658  } else {
2659  pl->state = ST_PLAYING;
2660  }
2661 
2662  pl->ob->name = add_string(buf);
2663  check_login(pl->ob, NULL);
2664 
2665  SockList_AddString(&sl, "addme_success");
2666  Send_With_Handling(ns, &sl);
2667  SockList_Term(&sl);
2668 }
2669 
2670 #define MAX_CHOICES 100
2671 
2677 void create_player_cmd(char *buf, int len, socket_struct *ns)
2678 {
2679  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2680  int status, nlen, choice_num=0, i;
2681  SockList sl;
2682  player *pl;
2683  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2684  living new_stats;
2685 
2686  if (len <= 0 || !buf) {
2687  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2688  return;
2689  }
2690 
2691  SockList_Init(&sl);
2692 
2693  if (ns->status != Ns_Add) {
2694  SockList_AddString(&sl, "failure createplayer Not allowed right now");
2695  Send_With_Handling(ns, &sl);
2696  SockList_Term(&sl);
2697  return;
2698  }
2699 
2700  nlen = len;
2701  status = decode_name_password(buf, &nlen, name, password);
2702  if (status == 1) {
2703  SockList_AddString(&sl, "failure createplayer Name is too long");
2704  Send_With_Handling(ns, &sl);
2705  SockList_Term(&sl);
2706  return;
2707  }
2708 
2709  /* Minimum character name limit (if set) */
2710  if (strlen(name)<settings.min_name) {
2711  SockList_AddString(&sl, "failure createplayer Name is too short");
2712  Send_With_Handling(ns, &sl);
2713  SockList_Term(&sl);
2714  return;
2715  }
2716 
2717  if (playername_ok(name) == 0) {
2718  SockList_AddString(&sl, "failure createplayer Player name contains invalid characters");
2719  Send_With_Handling(ns, &sl);
2720  SockList_Term(&sl);
2721  return;
2722  }
2723 
2724  /* 2 characters minimum for password */
2725  if (strlen(password)<2) {
2726  SockList_AddString(&sl, "failure createplayer Password is too short");
2727  Send_With_Handling(ns, &sl);
2728  SockList_Term(&sl);
2729  return;
2730  }
2731 
2733  if (status == 2) {
2734  SockList_AddString(&sl, "failure createplayer Password is too long");
2735  Send_With_Handling(ns, &sl);
2736  SockList_Term(&sl);
2737  return;
2738  }
2739 
2740  /* This is a fairly ugly solution - we're truncating the password.
2741  * however, the password information for characters is really
2742  * a legacy issue - when every character is associated with
2743  * an account, legacy login (character name/password) will get
2744  * removed, at which point the only use for password might be
2745  * to move characters from one account to another, but not sure
2746  * if that is something we want to allow.
2747  */
2748  if (strlen(password)>17)
2749  password[16] = 0;
2750 
2751  /* We just can't call check_name(), since that uses draw_info() to
2752  * report status. We are also more permissive on names, so we use
2753  * account_check_string() - if that is safe for account, also safe
2754  * for player names.
2755  */
2756  if (account_check_string(name)) {
2757  SockList_AddString(&sl, "failure createplayer Choose a different character name. " VALIDCHAR_MSG);
2758  Send_With_Handling(ns, &sl);
2759  SockList_Term(&sl);
2760  return;
2761  }
2762 
2763  /* 1 means no such player, 0 is correct name/password (which in this
2764  * case, is an error), and 2 is incorrect password. Only way we
2765  * go onward is if there is no such player.
2766  */
2767  if (verify_player(name, password) != 1) {
2768  SockList_AddString(&sl, "failure createplayer That name is already in use");
2769  Send_With_Handling(ns, &sl);
2770  SockList_Term(&sl);
2771  return;
2772  }
2773 
2774  /* from a protocol standpoint, accountplay can be used
2775  * before there is a player structure (first login) or after
2776  * (character has logged in and is changing characters).
2777  * Check the sockets for that second case - if so,
2778  * we don't need to make a new player object, etc.
2779  */
2780  for (pl=first_player; pl; pl=pl->next)
2781  if (pl->socket == ns) {
2782  if (pl->ob->name) {
2783  if (!strcmp(pl->ob->name, name)) {
2784  /* For some reason not only the socket is the same but also
2785  * the player is already playing. If this happens at this
2786  * point let's assume the character never was able to apply
2787  * a bet of reality to make a correct first-time save.
2788  * So, for safety remove it and start over.
2789  */
2790  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2791  object_remove(pl->ob);
2792  }
2793  else {
2794  /* If this is a different player on the same socket, then we
2795  * need to make sure that the old one is not connected to the player
2796  *
2797  * This prevents bizarre scenarios where the player is on the map
2798  * multiple times (from multiple createplayer commands), and
2799  * only one of them is controlled by the player.
2800  */
2801  if (pl->ob->contr == pl) {
2802  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2803  object_remove(pl->ob);
2804  }
2805  }
2806  }
2807  break;
2808  }
2809 
2810  /* In this mode, we have additional data
2811  * Note that because there are a lot of failure cases in here
2812  * (where we end up not creating the new player), the code
2813  * to create the new player is done within this routine
2814  * after all checks pass. Note that all of the checks
2815  * done are done without using the player structure,
2816  * as pl may be null right now.
2817  */
2818  if (ns->login_method >= 2) {
2819  int i, j, stat_total=0;
2820  char *key, *value, *race=NULL, *class_name=NULL;
2821 
2822  /* By setting this to zero, then we can easily
2823  * check to see if all stats have been set.
2824  */
2825  memset(&new_stats, 0, sizeof(living));
2826 
2827  while (nlen < len) {
2828  i = buf[nlen]; /* Length of this line */
2829  /* Sanity check from client - don't want to loop
2830  * forever if there is a 0 length, and don't
2831  * want to read beyond size of packet.
2832  * Likewise, client should have sent
2833  * the string to us already null terminated,
2834  * but we will just make sure.
2835  */
2836  if ((i == 0) || (nlen + i > len)) break;
2837  buf[nlen + i] = 0;
2838 
2839  /* What we have are a series of lines -
2840  * 'key value' format. Find that space,
2841  * and null it out so we can do strcasecmp.
2842  * If no space, abort processing
2843  */
2844  key = buf + nlen + 1;
2845  value = strchr(key, ' ');
2846  if (!value) break;
2847  *value = 0;
2848  value++;
2849 
2850  if (!strcasecmp(key,"race")) race = value;
2851  else if (!strcasecmp(key,"class")) class_name = value;
2852  else if (!strcasecmp(key,"starting_map")) {
2853  map = try_find_archetype(value);
2854  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2855  SockList_AddString(&sl,
2856  "failure createplayer Invalid starting map");
2857  Send_With_Handling(ns, &sl);
2858  SockList_Term(&sl);
2859  return;
2860  }
2861  }
2862  else if (!strcasecmp(key,"choice")) {
2863  /* In general, MAX_CHOICES should be large enough
2864  * to always handle the choices from the client - of
2865  * course, the client could be broken and send us many
2866  * more choices than we should have, so handle that.
2867  */
2868  if (choice_num == MAX_CHOICES) {
2869  LOG(llevError,
2870  "Number of choices receive exceed max value: %d>%d\n",
2871  choice_num, MAX_CHOICES);
2872  } else {
2873  choices[choice_num] = value;
2874  choice_num++;
2875  }
2876  }
2877  else {
2878  /* Do stat processing here */
2879  for (j=0; j < NUM_STATS; j++) {
2880  if (!strcasecmp(key,short_stat_name[j])) {
2881  int val = atoi(value);
2882 
2883  set_attr_value(&new_stats, j, val);
2884  break;
2885  }
2886  }
2887  if (j >= NUM_STATS) {
2888  /* Bad clients could do this - we should at least report
2889  * it, and useful when trying to add new parameters.
2890  */
2891  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2892  }
2893  }
2894  nlen += i + 1;
2895  }
2896  /* Do some sanity checking now. But checking the stat
2897  * values here, we will catch any 0 values since we do
2898  * a memset above. A properly behaving client should
2899  * never do any of these things, but we do not presume
2900  * clients will behave properly.
2901  */
2902  for (j=0; j<NUM_STATS; j++) {
2903  int val = get_attr_value(&new_stats, j);
2904 
2905  stat_total += val;
2906  if (val > settings.starting_stat_max ||
2907  val < settings.starting_stat_min) {
2908  SockList_AddPrintf(&sl,
2909  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2911  Send_With_Handling(ns, &sl);
2912  SockList_Term(&sl);
2913  return;
2914  }
2915  }
2916  if (stat_total > settings.starting_stat_points) {
2917  SockList_AddPrintf(&sl,
2918  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2919  stat_total, settings.starting_stat_points);
2920  Send_With_Handling(ns, &sl);
2921  SockList_Term(&sl);
2922  return;
2923  }
2924 
2925  if (race)
2926  race_a = try_find_archetype(race);
2927 
2928  if (class_name)
2929  class_a = try_find_archetype(class_name);
2930 
2931  /* This should never happen with a properly behaving client, so the error message
2932  * doesn't have to be that great.
2933  */
2934  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2935  SockList_AddString(&sl,
2936  "failure createplayer Invalid or unknown race or class");
2937  Send_With_Handling(ns, &sl);
2938  SockList_Term(&sl);
2939  return;
2940  }
2941 
2942  /* At current time, only way this can fail is if the adjusted
2943  * stat is less than 1.
2944  */
2945  if (check_race_and_class(&new_stats, race_a, class_a)) {
2946  SockList_AddString(&sl,
2947  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2948  Send_With_Handling(ns, &sl);
2949  SockList_Term(&sl);
2950  return;
2951  }
2952 
2953  if (!pl)
2955  // If we already have a player, we a replaying on the same connection.
2956  // Since add_player normally sets ns->status, we still need that to happen.
2957  else
2958  ns->status = Ns_Avail;
2959 
2960  // We need to copy the name in before apply_race_and_class() because it
2961  // tells the client our character name. If we don't update it, they get the old one.
2962  FREE_AND_COPY(pl->ob->name, name);
2963 
2964  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2965 
2966  } else {
2967  /* In thise case, old login method */
2968  if (!pl)
2969  pl = add_player(ns, ADD_PLAYER_NEW);
2970  // If we already have a player, we a replaying on the same connection.
2971  // Since add_player normally sets ns->status, we still need that to happen.
2972  else
2973  ns->status = Ns_Avail;
2974 
2975  // Make sure to do this on both code branches.
2976  FREE_AND_COPY(pl->ob->name, name);
2977 /* already done by add_player
2978  roll_again(pl->ob);
2979  pl->state = ST_ROLL_STAT;
2980  set_first_map(pl->ob);*/
2981  }
2982 
2983  /* add_player does a lot of the work, but there are a few
2984  * things we need to update, like starting name and
2985  * password.
2986  * This is done before processing in login_method>2.
2987  * The character creation process it does when
2988  * applying the race/class will use this
2989  * name information.
2990  */
2991  FREE_AND_COPY(pl->ob->name_pl, name);
2992  pl->name_changed = 1;
2993  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
2994 
2995  SockList_AddString(&sl, "addme_success");
2996  Send_With_Handling(ns, &sl);
2997  SockList_Term(&sl);
2998 
2999  if (ns->login_method >= 2) {
3000  /* The client could have provided us a map - if so, map will be set
3001  * and we don't want to overwrite it
3002  */
3003  if (!map)
3005  assert(map); // Existence checked in init_dynamic()
3006 
3007  enter_exit(pl->ob, &map->clone);
3008 
3009  if (pl->ob->map == NULL) {
3010  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
3011  abort();
3012  }
3013 
3014  /* copy information to bed of reality information, in case the player dies */
3015  safe_strncpy(pl->savebed_map, pl->ob->map->path, sizeof(pl->savebed_map));
3016  pl->bed_x = pl->ob->x;
3017  pl->bed_y = pl->ob->y;
3018 
3020  }
3021 
3022  /* We insert any objects after we have put the player on the map -
3023  * this makes things safer, as certain objects may expect a normal
3024  * environment. Note that choice_num will only be set in the
3025  * loginmethod > 2, which also checks (and errors out) if the
3026  * race/class is not set, which is why explicit checking for
3027  * those is not need.
3028  */
3029  for (i=0; i < choice_num; i++) {
3030  char *choiceval;
3031  const char *value, *cp;
3032  archetype *arch;
3033  object *op;
3034 
3035  choiceval = strchr(choices[i], ' ');
3036  if (!choiceval) {
3037  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
3038  continue;
3039  }
3040  *choiceval=0;
3041  choiceval++;
3042  value = object_get_value(&race_a->clone, choices[i]);
3043  if (!value)
3044  value = object_get_value(&class_a->clone, choices[i]);
3045 
3046  if (!value) {
3047  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
3048  continue;
3049  }
3050  cp = strstr(value, choiceval);
3051  if (!cp) {
3052  LOG(llevError, "Choice value not found in archetype: %s %s\n",
3053  choices[i], choiceval);
3054  continue;
3055  }
3056 
3057  /* Check to make sure that the matched string is an entire word,
3058  * and not a substring (eg, valid choice being great_sword but
3059  * we just get sword) - the space after the match should either be a
3060  * space or null, and space before match should also be a space
3061  * or the start of the string.
3062  */
3063  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
3064  (cp != value) && (*(cp-1) != ' ')) {
3065 
3066  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
3067  choiceval, value);
3068  continue;
3069  }
3070  arch = try_find_archetype(choiceval);
3071  if (!arch) {
3072  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
3073  continue;
3074  }
3075  op = arch_to_object(arch);
3076  op = object_insert_in_ob(op, pl->ob);
3077  if (QUERY_FLAG(op, FLAG_AUTO_APPLY))
3078  ob_apply(op, pl->ob, 0);
3079  }
3080 
3081  LOG(llevInfo, "new character %s from %s\n", pl->ob->name, pl->ob->contr->socket->host);
3084  "%s has entered the game.", pl->ob->name);
3085 }
3086 
3097 void account_password(char *buf, int len, socket_struct *ns) {
3098  char old[MAX_BUF], change[MAX_BUF];
3099  int status;
3100  SockList sl;
3101 
3102  if (len <= 0 || !buf) {
3103  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
3104  return;
3105  }
3106 
3107  SockList_Init(&sl);
3108 
3109  if (ns->account_name == NULL) {
3110  SockList_AddString(&sl, "failure accountpw Not logged in");
3111  Send_With_Handling(ns, &sl);
3112  SockList_Term(&sl);
3113  return;
3114  }
3115 
3116  status = decode_name_password(buf, &len, old, change);
3117  if (status == 1) {
3118  SockList_AddString(&sl, "failure accountpw Old password is too long");
3119  Send_With_Handling(ns, &sl);
3120  SockList_Term(&sl);
3121  return;
3122  }
3123  if (status == 2) {
3124  SockList_AddString(&sl, "failure accountpw New password is too long");
3125  Send_With_Handling(ns, &sl);
3126  SockList_Term(&sl);
3127  return;
3128  }
3129  /*The minimum length isn't exactly required, but in the current implementation,
3130  * client will send the same password for character for which there is a
3131  * 2 character minimum size. Thus an account with a one character password
3132  * won't be able to create a character. */
3133  if (strlen(change)<2) {
3134  SockList_AddString(&sl, "failure accountpw New password is too short");
3135  Send_With_Handling(ns, &sl);
3136  SockList_Term(&sl);
3137  return;
3138  }
3139 
3140  status = account_check_string(change);
3141  if (status == 1) {
3142  SockList_AddString(&sl,
3143  "failure accountpw Choose a different password. " VALIDCHAR_MSG);
3144  Send_With_Handling(ns, &sl);
3145  SockList_Term(&sl);
3146  return;
3147  }
3148 
3149  if (status == 2) {
3150  SockList_AddString(&sl,
3151  "failure accountpw That password is too long");
3152  Send_With_Handling(ns, &sl);
3153  SockList_Term(&sl);
3154  return;
3155  }
3156 
3157  status = account_change_password(ns->account_name, old, change);
3158  if (status != 0) {
3159  const char *error;
3160 
3161  if (status == 1) {
3162  error = "failure accountpw Illegal characters present";
3163  } else if (status == 2) {
3164  error = "failure accountpw Invalid account";
3165  } else {
3166  error = "failure accountpw Incorrect current password";
3167  }
3168 
3169  SockList_AddString(&sl, error);
3170  Send_With_Handling(ns, &sl);
3171  SockList_Term(&sl);
3172  return;
3173  }
3174 
3175  /* If we got here, we passed all checks, and password was changed */
3177 }
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
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
SF_FIREON
#define SF_FIREON
Definition: newclient.h:193
CF_BLIND
#define CF_BLIND
Blind.
Definition: newclient.h:204
account_add_player_cmd
void account_add_player_cmd(char *buf, int len, socket_struct *ns)
Handle accountaddplayer from server (add a character to this account).
Definition: request.cpp:2443
CLASS
@ CLASS
Object for applying character class modifications to someone.
Definition: object.h:143
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
CS_STAT_RES_DEPLETE
#define CS_STAT_RES_DEPLETE
Definition: newclient.h:166
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
player::do_los
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h: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:209
socket_struct::tick
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:110
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:352
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:141
socket_struct::sc_version
uint32_t sc_version
Versions of the client.
Definition: newserver.h:117
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
Global settings.
Definition: init.cpp:139
CS_STAT_RACE_CON
#define CS_STAT_RACE_CON
Definition: newclient.h:125
print_ext_msg
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Draws an extended message on the client.
Definition: info.cpp:62
CS_STAT_GRACE
#define CS_STAT_GRACE
Definition: newclient.h:113
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
find_smooth
int find_smooth(const Face *face, const Face **smoothed)
Find the smooth face for a given face.
Definition: image.cpp:102
MAP
@ MAP
Definition: object.h:130
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
socket_struct::heartbeat
bool heartbeat
Client will send hearbeats.
Definition: newserver.h:116
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:228
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:2103
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
CS_STAT_APPLIED_WIS
#define CS_STAT_APPLIED_WIS
WIS changes from gear or skills.
Definition: newclient.h:137
MAP2_COORD_MAX
static const int MAP2_COORD_MAX
Definition: request.cpp:74
ssop_t
int ssop_t
Parameter type for setsockopt, different between WIN32 and Linux.
Definition: request.cpp:58
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:500
player::mode
uint32_t mode
Mode of player for pickup.
Definition: player.h: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:52
account_play_cmd
void account_play_cmd(char *buf, int len, socket_struct *ns)
We have received an accountplay command.
Definition: request.cpp:2572
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:165
MAP2_COORD_OFFSET
#define MAP2_COORD_OFFSET
How much the x,y coordinates in the map2 are off from actual upper left corner.
Definition: newclient.h:32
player
One player.
Definition: player.h:105
CS_STAT_DAM
#define CS_STAT_DAM
Definition: newclient.h:105
strdup_local
#define strdup_local
Definition: compat.h:29
ACL_RACE
#define ACL_RACE
Definition: newclient.h:223
player::golem_count
uint32_t golem_count
To track the golem.
Definition: player.h: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:154
ask_smooth_cmd
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
Tells client the picture it has to use to smooth a picture number given as argument.
Definition: request.cpp:503
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
newhash
char const * newhash(char const *password)
Definition: server.cpp:101
socket_struct::sound
uint32_t sound
Client sound mode.
Definition: newserver.h:115
command
same as sound ncom command like but with extra the client want tick commands so it knows animation timing the client wants to be informed of pickup mode changes Mode will be sent when the player successfully logs and afterward any time the value is but over many options have become defaults This documents those now obsolete client can handle the bit exp values that are now used values are sent as bit Setting this flag also means that skill exp will be and it will be sent in revised method as described in the stats command Value is an integer in string format else Deprecated client should presume all servers support this server will return FALSE Deprecated replaced with sound2 setup command
Definition: protocol.txt:461
account_get_additional_chars
linked_char * account_get_additional_chars(const char *account_name, const Account_Chars *chars, int *count)
Get a list of character names linked to the specified account which are not listed in chars.
Definition: account.cpp:550
CS_STAT_APPLIED_POW
#define CS_STAT_APPLIED_POW
POW changes from gear or skills.
Definition: newclient.h:141
CS_STAT_HP
#define CS_STAT_HP
Definition: newclient.h:91
socket_struct
Socket structure, represents a client-server connection.
Definition: newserver.h:93
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:120
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:2148
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:126
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:120
account_get_players_for_account
char ** account_get_players_for_account(const char *account_name)
Returns an array of strings for the characters on this account - the array is null terminated.
Definition: account.cpp:519
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
accounts_save
void accounts_save(void)
Save all the account information.
Definition: account.cpp:255
living::Dex
int8_t Dex
Definition: living.h:36
object::x
int16_t x
Definition: object.h:335
CS_STAT_WIS
#define CS_STAT_WIS
Definition: newclient.h:97
player::peaceful
uint32_t peaceful
If set, won't attack friendly creatures.
Definition: player.h: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
map_cell_struct::label_text
sstring label_text
Definition: newserver.h:35
reply_cmd
void reply_cmd(char *buf, int len, player *pl)
This is a reply to a previous query.
Definition: request.cpp:589
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
CS_STAT_SPEED
#define CS_STAT_SPEED
Definition: newclient.h:107
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
socket_struct::extended_stats
uint32_t extended_stats
Client wants base and maximum statistics information.
Definition: newserver.h:113
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:96
append_spell
static void append_spell(player *pl, SockList *sl, object *spell)
appends the spell *spell to the Socklist we will send the data to.
Definition: request.cpp:1924
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:331
SK_PRAYING
@ SK_PRAYING
Praying.
Definition: skills.h:49
CS_STAT_MAXSP
#define CS_STAT_MAXSP
Definition: newclient.h:94
player::levhp
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h: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
MAP2_LABEL_SIGN
@ MAP2_LABEL_SIGN
Definition: newclient.h:62
CS_STAT_BASE_DEX
#define CS_STAT_BASE_DEX
Definition: newclient.h:131
CS_STAT_RES_MAG
#define CS_STAT_RES_MAG
Definition: newclient.h:153
FIF
#define FIF(F, C)
MAP_LAYERS
#define MAP_LAYERS
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:321
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
client_spell::last_sp
int16_t last_sp
Last spell cost.
Definition: player.h:89
socket_struct::is_bot
uint32_t is_bot
Client shouldn't be reported to metaserver.
Definition: newserver.h:111
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:93
SP_CREATE_FOOD
#define SP_CREATE_FOOD
Definition: spells.h:96
ACL_NAME
#define ACL_NAME
Definition: newclient.h:221
player::last_level
int8_t last_level
Last level we sent to client.
Definition: player.h: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:168
annotate_ob
static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *has_obj, int *alive_layer)
Definition: request.cpp:1395
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:142
CS_STAT_RES_CONF
#define CS_STAT_RES_CONF
Definition: newclient.h:157
NDI_RED
#define NDI_RED
Definition: newclient.h:249
MAX_HEAD_OFFSET
#define MAX_HEAD_OFFSET
This basically defines the largest size an archetype may be - it is used for allocation of some struc...
Definition: newserver.h:46
player::last_stats
living last_stats
Last stats as sent to client.
Definition: player.h: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:103
CS_STAT_TURN_UNDEAD
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:164
ACL_CLASS
#define ACL_CLASS
Definition: newclient.h:222
SP_CREATE_MISSILE
#define SP_CREATE_MISSILE
Definition: spells.h:113
CF_NOT_PERFECT
#define CF_NOT_PERFECT
Can drink some improvement potions.
Definition: newclient.h:207
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
receive_play_again
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.cpp:961
set_player_socket
void set_player_socket(player *p, socket_struct *ns)
This copies the data from the socket into the player structure.
Definition: player.cpp:421
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can't use command.
Definition: newclient.h:533
map_clearcell
static void map_clearcell(struct map_cell_struct *cell, int face, int darkness)
Clears a map cell.
Definition: request.cpp:1072
CS_STAT_EXP64
#define CS_STAT_EXP64
Definition: newclient.h:117
map2_coord_valid
static bool map2_coord_valid(int x)
Definition: request.cpp:76
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:1791
SockList_Reset
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.cpp:74
CS_STAT_CHARACTER_FLAGS
#define CS_STAT_CHARACTER_FLAGS
Character flags, like 'confused' and such.
Definition: newclient.h:144
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
socket_struct::map_scroll_x
int8_t map_scroll_x
Definition: newserver.h:98
set_up_cmd
void set_up_cmd(char *buf, int len, socket_struct *ns)
This is the Setup cmd - easy first implementation.
Definition: request.cpp:143
UPD_SP_MANA
#define UPD_SP_MANA
updspell command flag value.
Definition: newclient.h:328
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
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:1599
CS_STAT_APPLIED_DEX
#define CS_STAT_APPLIED_DEX
DEX changes from gear or skills.
Definition: newclient.h:138
add_player
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.cpp: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:2842
POISONING
@ POISONING
Definition: object.h:223
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:408
MAX
#define MAX(x, y)
Definition: compat.h:24
CS_STAT_RACE_STR
#define CS_STAT_RACE_STR
Definition: newclient.h:121
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
CS_STAT_GOLEM_MAXHP
#define CS_STAT_GOLEM_MAXHP
Golem's max hp, 0 if no golem.
Definition: newclient.h:143
SND_EFFECTS
#define SND_EFFECTS
Those flags are for the 'socket.sound' field.
Definition: sounds.h:12
MAP2_LABEL_PLAYER_PARTY
@ MAP2_LABEL_PLAYER_PARTY
Definition: newclient.h:59
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
ACL_MAP
#define ACL_MAP
Definition: newclient.h:227
linked_char
Definition: global.h:98
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:108
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.cpp:246
GetShort_String
short GetShort_String(const unsigned char *data)
Definition: lowlevel.cpp:258
short_stat_name
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.cpp:194
SP_SUMMON_MONSTER
#define SP_SUMMON_MONSTER
Definition: spells.h:101
UPD_SP_DAMAGE
#define UPD_SP_DAMAGE
updspell command flag value.
Definition: newclient.h:330
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
object::path_repelled
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:354
m
static event_registration m
Definition: citylife.cpp:424
AddIfShort
#define AddIfShort(Old, New, sl, Type)
Definition: request.cpp:768
socket_struct::account_chars
Account_Chars * account_chars
Detailed information on characters on this account.
Definition: newserver.h:131
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:120
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:126
socket_struct::stats
struct statsinfo stats
Definition: newserver.h:102
Ns_Avail
@ Ns_Avail
Definition: newserver.h:69
CS_STAT_RACE_DEX
#define CS_STAT_RACE_DEX
Definition: newclient.h:124
CS_STAT_ARMOUR
#define CS_STAT_ARMOUR
Definition: newclient.h:106
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
set_title
void set_title(const object *pl, char *buf, size_t len)
Sets player title.
Definition: info.cpp: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:119
CS_STAT_RACE_CHA
#define CS_STAT_RACE_CHA
Definition: newclient.h:126
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:68
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
player::last_speed
float last_speed
Last speed as sent to client.
Definition: player.h:173
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
CS_STAT_LEVEL
#define CS_STAT_LEVEL
Definition: newclient.h:102
player::run_on
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:143
CS_STAT_CON
#define CS_STAT_CON
Definition: newclient.h:99
account_new_cmd
void account_new_cmd(char *buf, int len, socket_struct *ns)
Handles the account creation This function shares a fair amount of the same logic as account_login_cm...
Definition: request.cpp:2329
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:2230
playername_ok
int playername_ok(const char *cp)
Is the player name valid.
Definition: player.cpp:257
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.cpp:72
client_spell::last_dam
int16_t last_dam
Last damage.
Definition: player.h:91
ACL_PARTY
#define ACL_PARTY
Definition: newclient.h:226
CS_STAT_CHA
#define CS_STAT_CHA
Definition: newclient.h:100
CS_STAT_APPLIED_CHA
#define CS_STAT_APPLIED_CHA
CHA changes from gear or skills.
Definition: newclient.h:140
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:162
add_labels
static bool add_labels(int ax, int ay, const object *ob, SockList *sl, player *plyr, int *got_one)
Return true if there is a label present on this square.
Definition: request.cpp:1414
socket_struct::facecache
uint32_t facecache
If true, client is caching images.
Definition: newserver.h:106
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:1435
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:522
object::weapon_speed
float weapon_speed
The overall speed of this object.
Definition: object.h:339
CS_STAT_BASE_POW
#define CS_STAT_BASE_POW
Definition: newclient.h:134
player::last_flags
uint16_t last_flags
Fire/run on flags for last tick.
Definition: player.h: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:152
Settings::account_block_create
uint8_t account_block_create
Definition: global.h:328
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:145
Face::number
uint16_t number
This is the image unique identifier.
Definition: face.h:15
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h: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
MAP2_LABEL_NONE
@ MAP2_LABEL_NONE
Definition: newclient.h:57
send_smooth
static void send_smooth(socket_struct *ns, const Face *face)
A lot like the old AskSmooth (in fact, now called by AskSmooth).
Definition: request.cpp:459
handle_scroll
static void handle_scroll(socket_struct *socket, SockList *sl)
As part of sending the map2 command, send one or more scroll commands to update the client map to mat...
Definition: request.cpp:104
add_string
sstring add_string(const char *str)
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:1692
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:351
CS_STAT_BASE_CHA
#define CS_STAT_BASE_CHA
Definition: newclient.h:133
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.cpp:4093
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on what attr is (STR to POW).
Definition: living.cpp:218
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:97
CF_POISONED
#define CF_POISONED
Poisoned.
Definition: newclient.h:203
MAP2_LAYER_START
#define MAP2_LAYER_START
Definition: newclient.h:67
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
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:135
socket_struct::host
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
player::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Last exp sent to client.
Definition: player.h:154
CS_STAT_RACE_POW
#define CS_STAT_RACE_POW
Definition: newclient.h:127
account_password
void account_password(char *buf, int len, socket_struct *ns)
Handles the account password change.
Definition: request.cpp:3097
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1753
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:130
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:104
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
client_spell::last_grace
int16_t last_grace
Last grace cost.
Definition: player.h:90
check_space_for_heads
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.cpp:1451
CS_STAT_OVERLOAD
#define CS_STAT_OVERLOAD
How much (0 to 1) the character is overloaded.
Definition: newclient.h:146
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
CS_STAT_WEAP_SP
#define CS_STAT_WEAP_SP
Definition: newclient.h:109
socket_struct::monitor_spells
uint32_t monitor_spells
Client wishes to be informed when their spell list changes.
Definition: newserver.h:114
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:139
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:1805
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:121
spell
with a maximum of six This is not so if you are wearing plate you receive no benefit Armour is additive with all the supplementry forms of which means that it lasts until the next semi permanent spell effect is cast upon the character spell
Definition: tome-of-magic.txt:44
CS_STAT_RES_GHOSTHIT
#define CS_STAT_RES_GHOSTHIT
Definition: newclient.h:160
linked_char::next
struct linked_char * next
Definition: global.h:100
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
Definition: newclient.h:176
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h: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:169
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:206
MAP2_TYPE_DARKNESS
#define MAP2_TYPE_DARKNESS
Definition: newclient.h:43
socket_struct::map_scroll_y
int8_t map_scroll_y
Definition: newserver.h:98
MAP2_COORD_ENCODE
static uint16_t MAP2_COORD_ENCODE(int x, int y, int flags)
Encodes a (x, y) pair suitable for map2 parameters.
Definition: request.cpp:89
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
statsinfo::title
char * title
Definition: newserver.h:61
sproto.h
player::last_weight_limit
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:159
CS_STAT_RACE_INT
#define CS_STAT_RACE_INT
Definition: newclient.h:122
living::sp
int16_t sp
Spell points.
Definition: living.h:42
SND_MUTE
#define SND_MUTE
Don't sent anything for now.
Definition: sounds.h:14
MAX_SKILLS
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.cpp:2352
VERSION_SC
#define VERSION_SC
Definition: newserver.h:154
get_face_by_id
const Face * get_face_by_id(uint16_t id)
Get a face from its unique identifier.
Definition: assets.cpp:315
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:690
CS_STAT_BASE_WIS
#define CS_STAT_BASE_WIS
Definition: newclient.h:130
is_perfect
static uint8_t is_perfect(const player *pl)
Check whether the player is perfect relatively to improvement potions.
Definition: request.cpp: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:108
socket_struct::cs_version
uint32_t cs_version
Definition: newserver.h:117
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:116
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
player::last_weight
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:158
Ns_Add
@ Ns_Add
Definition: newserver.h:70
CS_STAT_ITEM_POWER
#define CS_STAT_ITEM_POWER
Equipped item power.
Definition: newclient.h:147
CS_STAT_RES_POISON
#define CS_STAT_RES_POISON
Definition: newclient.h:161
receive_player_name
void receive_player_name(object *op, const char *name)
A player just entered her name.
Definition: c_misc.cpp:1935
is_valid_faceset
int is_valid_faceset(int fsn)
Checks specified faceset is valid.
Definition: image.cpp:117
CS_STAT_WC
#define CS_STAT_WC
Definition: newclient.h:103
object::head
object * head
Points to the main object of a large body.
Definition: object.h:304
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h: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:3153
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
map2_add_label
static bool map2_add_label(int ax, int ay, socket_struct *ns, SockList *sl, enum map2_label subtype, sstring label)
Return true if an update was sent to the client.
Definition: request.cpp:1354
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:114
key_roll_stat
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.cpp:1218
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:323
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:241
create_player_cmd
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.cpp:2677
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:95
apply_race_and_class
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
This is somewhat like key_change_class() above, except we know the race to change to,...
Definition: player.cpp:1485
CS_STAT_BASE_INT
#define CS_STAT_BASE_INT
Definition: newclient.h:129
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:118
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:266
esrv_move_object
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Move an object to a new location.
Definition: item.cpp:899
Animations::faces
const Face ** faces
The actual faces for the animation.
Definition: face.h:30
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:112
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Find object in inventory by archetype name.
Definition: object.cpp:4237
AddIfFloat
#define AddIfFloat(Old, New, sl, Type)
Definition: request.cpp:775
MAP2_LABEL_DM
@ MAP2_LABEL_DM
Definition: newclient.h:60
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:2048
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:2293
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:1994
SND_MUSIC
#define SND_MUSIC
Client wants background music info.
Definition: sounds.h:13
sstring
const typedef char * sstring
Definition: sstring.h:2
living::Cha
int8_t Cha
Definition: living.h:36
NDI_ALL
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:267
socket_struct::status
enum Sock_Status status
Definition: newserver.h:94
Animations
This represents one animation.
Definition: face.h:25
MAP_CLIENT_Y_MINIMUM
#define MAP_CLIENT_Y_MINIMUM
Definition: config.h:246
CS_STAT_RES_COLD
#define CS_STAT_RES_COLD
Definition: newclient.h:156
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:61
esrv_remove_spell
void esrv_remove_spell(player *pl, object *spell)
Definition: request.cpp:1857
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
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
MAP2_LABEL_PLAYER
@ MAP2_LABEL_PLAYER
Definition: newclient.h:58
Map::cells
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:53
CF_CONFUSED
#define CF_CONFUSED
Confused by a spell or an item.
Definition: newclient.h:202
ob_apply
method_ret ob_apply(object *op, object *applier, int aflags)
Apply an object by running an event hook or an object method.
Definition: ob_methods.cpp:44
text
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended text
Definition: media-tags.txt:35
Animations::num
uint16_t num
Where we are in the array.
Definition: face.h:29
living::ac
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:173
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.cpp:83
NDI_DK_ORANGE
#define NDI_DK_ORANGE
DarkOrange2.
Definition: newclient.h:252
socket_struct::anims_sent
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:101
player::last_orig_stats
living last_orig_stats
Last permanent stats sent to client.
Definition: player.h: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:100
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:167
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
player::party
partylist * party
Party this player is part of.
Definition: player.h: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:1498
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:224
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Arrows, etc.
Definition: map.h:49
CS_STAT_TITLE
#define CS_STAT_TITLE
Definition: newclient.h:111
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:239
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:153
Account_Chars
Structure handling character information for an account.
Definition: account_char.h:27
UPD_SP_GRACE
#define UPD_SP_GRACE
updspell command flag value.
Definition: newclient.h:329
get_archetype_by_type_subtype
archetype * get_archetype_by_type_subtype(int type, int subtype)
Retrieves an archetype by type and subtype.
Definition: arch.cpp:97
CS_STAT_POW
#define CS_STAT_POW
Definition: newclient.h:112
skill
skill
Definition: arch-handbook.txt:585
CF_WIZARD
#define CF_WIZARD
Player is DM.
Definition: newclient.h:211
player::character_load
float character_load
Value between 0 and 1 indicating how much the character is overloaded.
Definition: player.h:135
esrv_send_pickup
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1880
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1818
player_set_state
void player_set_state(player *pl, uint8_t state)
Set the player's state to the specified one.
Definition: player.cpp:4485
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:270
map_cell_struct::label_subtype
enum map2_label label_subtype
Definition: newserver.h:34
CS_STAT_RACE_WIS
#define CS_STAT_RACE_WIS
Definition: newclient.h:123
AddIfString
#define AddIfString(Old, New, sl, Type)
Definition: request.cpp:782
MAX_CHOICES
#define MAX_CHOICES
Definition: request.cpp:2670
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:286
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:132
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:61
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:92
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:1294
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:1900
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:107
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:133
SF_RUNON
#define SF_RUNON
Definition: newclient.h:194
CS_STAT_RANGE
#define CS_STAT_RANGE
Definition: newclient.h:110
Settings::account_trusted_host
char * account_trusted_host
Block account creation for untrusted hosts.
Definition: global.h:329
living::grace
int16_t grace
Grace.
Definition: living.h:44
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
MSG_TYPE_ADMIN_VERSION
#define MSG_TYPE_ADMIN_VERSION
version info
Definition: newclient.h:505
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.cpp:313
update_los
void update_los(object *op)
Recalculates the array which specifies what is visible for the given player-object.
Definition: los.cpp:509
CS_STAT_BASE_CON
#define CS_STAT_BASE_CON
Definition: newclient.h:132
add_char_field
static void add_char_field(SockList *sl, int type, const char *data)
Basic helper function which adds a piece of data for the accountplayers protocol command.
Definition: request.cpp:2069
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:98
account_login
int account_login(const char *account_name, const char *account_password)
Check if the given account exists, and whether the password is correct.
Definition: account.cpp:318
Settings::always_show_hp
uint8_t always_show_hp
'probe' spell HP bars for all living things (0, 1, or 2)
Definition: global.h:274
player::last_weapon_sp
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h: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:128
smooth_face
const Face * smooth_face
Definition: image.cpp:36
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.cpp: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:2194
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:159
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:406
CF_HOSTILE
#define CF_HOSTILE
'hostile' flag is set.
Definition: newclient.h:208
SockList
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:685
map_reset_swap
void map_reset_swap(mapstruct *m)
Call this when an in-memory map is used or referenced.
Definition: map.cpp:1760
CF_PARALYZED
#define CF_PARALYZED
Player is paralyzed.
Definition: newclient.h:210
NUM_STATS
@ NUM_STATS
Number of statistics.
Definition: living.h:18
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h: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:136
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Max radii for 'light' object, really large values allow objects that can slow down the game.
Definition: define.h:444
ACL_FACE
#define ACL_FACE
Definition: newclient.h:225
CF_XRAY
#define CF_XRAY
Has X-ray.
Definition: newclient.h:205
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Get player's current range attack in obuf.
Definition: info.cpp:264
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
NS_FACESENT_SMOOTH
#define NS_FACESENT_SMOOTH
Definition: newserver.h:142
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
account_exists
const char * account_exists(const char *account_name)
Checks the existing accounts, and see if this account exists.
Definition: account.cpp:296
living::Con
int8_t Con
Definition: living.h:36
face
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the and treasurelist definitions into a single or trs file and the graphics into a face(metadata) and .tar(bitmaps) file
CS_STAT_RES_PARA
#define CS_STAT_RES_PARA
Definition: newclient.h:163
Settings::starting_stat_max
uint8_t starting_stat_max
Maximum value of a starting stat.
Definition: global.h:322
CS_STAT_RES_ACID
#define CS_STAT_RES_ACID
Definition: newclient.h:158
living::Str
int8_t Str
Definition: living.h:36
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
CS_STAT_RES_ELEC
#define CS_STAT_RES_ELEC
Definition: newclient.h:155
CS_STAT_FLAGS
#define CS_STAT_FLAGS
Definition: newclient.h:115