Crossfire Server, Trunk
request.c
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 #else
59 #include <winsock2.h>
60 #endif /* win32 */
61 
62 #include "commands.h"
63 #include "living.h"
64 #include "newserver.h"
65 #include "shared/newclient.h"
66 #include "sounds.h"
67 #include "sproto.h"
68 
75 static const short atnr_cs_stat[NROFATTACKS] = {
80  CS_STAT_RES_DRAIN, -1 /* weaponmagic */,
84  CS_STAT_RES_FEAR, -1 /* Cancellation */,
86  -1 /* Chaos */, -1 /* Counterspell */,
87  -1 /* Godpower */, CS_STAT_RES_HOLYWORD,
89  -1, /* Internal */
90  -1, /* life stealing */
91  -1 /* Disease - not fully done yet */
92 };
93 
95 void set_up_cmd(char *buf, int len, socket_struct *ns) {
96  int s = 0;
97  char *cmd, *param;
98  SockList sl;
99 
100  if (len <= 0 || !buf) {
101  LOG(llevDebug, "IP '%s' sent bogus set_up_cmd information\n", ns->host);
102  return;
103  }
104 
105  /* run through the cmds of setup
106  * syntax is setup <cmdname1> <parameter> <cmdname2> <parameter> ...
107  *
108  * we send the status of the cmd back, or a FALSE is the cmd
109  * is the server unknown
110  * The client then must sort this out
111  */
112 
113  LOG(llevDebug, "setup: %s\n", buf);
114  SockList_Init(&sl);
115  SockList_AddString(&sl, "setup");
116  while (s < len) {
117  cmd = &buf[s];
118 
119  /* find the next space, and put a null there */
120  for (; buf[s] && buf[s] != ' '; s++)
121  ;
122  if (s >= len)
123  break;
124  buf[s++] = 0;
125 
126  while (buf[s] == ' ')
127  s++;
128  if (s >= len)
129  break;
130  param = &buf[s];
131 
132  for (; buf[s] && buf[s] != ' '; s++)
133  ;
134  buf[s++] = 0;
135 
136  while (s < len && buf[s] == ' ')
137  s++;
138 
139  SockList_AddPrintf(&sl, " %s ", cmd);
140 
141  if (!strcmp(cmd, "sound2")) {
142  ns->sound = atoi(param)&(SND_EFFECTS|SND_MUSIC|SND_MUTE);
143  SockList_AddString(&sl, param);
144  } else if (!strcmp(cmd, "spellmon")) {
145  int monitor_spells;
146 
147  monitor_spells = atoi(param);
148  if (monitor_spells < 0 || monitor_spells > 2) {
149  SockList_AddString(&sl, "FALSE");
150  } else {
151  ns->monitor_spells = monitor_spells;
152  SockList_AddPrintf(&sl, "%d", monitor_spells);
153  }
154  } else if (!strcmp(cmd, "darkness")) {
155  int darkness;
156 
157  darkness = atoi(param);
158  if (darkness != 0 && darkness != 1) {
159  SockList_AddString(&sl, "FALSE");
160  } else {
161  ns->darkness = darkness;
162  SockList_AddPrintf(&sl, "%d", darkness);
163  }
164  } else if (!strcmp(cmd, "map2cmd")) {
165  int map2cmd;
166 
167  map2cmd = atoi(param);
168  if (map2cmd != 1) {
169  SockList_AddString(&sl, "FALSE");
170  } else {
171  SockList_AddString(&sl, "1");
172  }
173  } else if (!strcmp(cmd, "facecache")) {
174  int facecache;
175 
176  facecache = atoi(param);
177  if (facecache != 0 && facecache != 1) {
178  SockList_AddString(&sl, "FALSE");
179  } else {
180  ns->facecache = facecache;
181  SockList_AddPrintf(&sl, "%d", facecache);
182  }
183  } else if (!strcmp(cmd, "faceset")) {
184  int q = atoi(param);
185 
186  if (is_valid_faceset(q))
187  ns->faceset = q;
188  SockList_AddPrintf(&sl, "%d", ns->faceset);
189  } else if (!strcmp(cmd, "mapsize")) {
190  int x, y, n;
191 
192  if (sscanf(param, "%dx%d%n", &x, &y, &n) != 2 || n != (int)strlen(param)) {
193  x = 0;
194  y = 0;
195  }
196  if (x < 9 || y < 9 || x > MAP_CLIENT_X || y > MAP_CLIENT_Y) {
198  } else {
199  player *pl;
200  ns->mapx = x;
201  ns->mapy = y;
202  /* better to send back what we are really using and not the
203  * param as given to us in case it gets parsed differently.
204  */
205  SockList_AddPrintf(&sl, "%dx%d", x, y);
206  /* need to update the los, else the view jumps */
207  pl = find_player_socket(ns);
208  if (pl)
209  update_los(pl->ob);
210 
211  /* Client and server need to resynchronize on data - treating it as
212  * a new map is best way to go.
213  */
214  map_newmap_cmd(ns);
215  }
216  } else if (!strcmp(cmd, "tick")) {
217  int tick;
218 
219  tick = atoi(param);
220  if (tick != 0 && tick != 1) {
221  SockList_AddString(&sl, "FALSE");
222  } else {
223  ns->tick = tick;
224  SockList_AddPrintf(&sl, "%d", tick);
225  }
226  } else if (!strcmp(cmd, "bot")) {
227  int is_bot;
228 
229  is_bot = atoi(param);
230  if (is_bot != 0 && is_bot != 1) {
231  SockList_AddString(&sl, "FALSE");
232  } else {
233  ns->is_bot = is_bot;
234  SockList_AddPrintf(&sl, "%d", is_bot);
235  }
236  } else if (!strcmp(cmd, "want_pickup")) {
237  int want_pickup;
238 
239  want_pickup = atoi(param);
240  if (want_pickup != 0 && want_pickup != 1) {
241  SockList_AddString(&sl, "FALSE");
242  } else {
243  ns->want_pickup = want_pickup;
244  SockList_AddPrintf(&sl, "%d", want_pickup);
245  }
246  } else if (!strcmp(cmd, "num_look_objects")) {
247  int tmp;
248  player *pl;
249 
250  tmp = atoi(param);
251  if (tmp < MIN_NUM_LOOK_OBJECTS) {
253  } else if (tmp > MAX_NUM_LOOK_OBJECTS) {
255  }
256  ns->num_look_objects = (uint8_t)tmp;
257  SockList_AddPrintf(&sl, "%d", tmp);
258 
259  pl = find_player_socket(ns);
260  if (pl && pl->ob) {
261  ns->update_look = 1;
262  esrv_draw_look(pl->ob);
263  }
264  } else if (!strcmp(cmd, "extended_stats")) {
265  int extended_stats;
266 
267  extended_stats = atoi(param);
268  if (extended_stats != 0 && extended_stats != 1) {
269  SockList_AddString(&sl, "FALSE");
270  } else {
271  ns->extended_stats = extended_stats;
272  SockList_AddPrintf(&sl, "%d", extended_stats);
273  }
274  } else if (!strcmp(cmd, "beat")) {
275  int use_beat = atoi(param);
276 
277  if (use_beat != 0 && use_beat != 1) {
278  SockList_AddString(&sl, "FALSE");
279  } else {
280  ns->heartbeat = use_beat ? true : false;
281 
282  // Send setup command with standard beat interval.
283  SockList_AddPrintf(&sl, "%d", BEAT_INTERVAL);
284  }
285  } else if (!strcmp(cmd, "loginmethod")) {
286  int loginmethod;
287 
288  loginmethod = atoi(param);
289 
290  /* Only support basic login right now */
291  if (loginmethod > 2) loginmethod=2;
292 
293  ns->login_method = loginmethod;
294  SockList_AddPrintf(&sl, "%d", loginmethod);
295 
296  } else if (!strcmp(cmd, "notifications")) {
297  int notifications;
298 
299  notifications = atoi(param);
300 
301  ns->notifications = MIN(notifications, 3);
302  SockList_AddPrintf(&sl, "%d", ns->notifications);
303 
304  } else if (!strcmp(cmd, "newmapcmd")) {
305  /* newmapcmd is deprecated (now standard part), but some
306  * clients still use this setup option, and if the server
307  * doesn't respond, erroneously report that the client is
308  * too old. Since it is always on, regardless of what is
309  * request, send back one.
310  */
311  SockList_AddString(&sl, "1");
312  } else if (!strcmp(cmd, "extendedTextInfos")) {
313  /* like newmapcmd above, extendedTextInfos is
314  * obsolete, but we respond for the same reason as we do
315  * in newmapcmd
316  */
317  SockList_AddString(&sl, "1");
318  } else if (!strcmp(cmd, "itemcmd")) {
319  /* like newmapcmd above, itemcmd is
320  * obsolete, but we respond for the same reason as we do
321  * in newmapcmd
322  */
323  SockList_AddString(&sl, "2");
324  } else if (!strcmp(cmd, "exp64")) {
325  /* like newmapcmd above, exp64 is
326  * obsolete, but we respond for the same reason as we do
327  * in newmapcmd
328  */
329  SockList_AddString(&sl, "1");
330  } else {
331  /* Didn't get a setup command we understood -
332  * report a failure to the client.
333  */
334  SockList_AddString(&sl, "FALSE");
335  }
336  } /* for processing all the setup commands */
337  Send_With_Handling(ns, &sl);
338  SockList_Term(&sl);
339 }
340 
349 void add_me_cmd(char *buf, int len, socket_struct *ns) {
350  Settings oldsettings;
351  SockList sl;
352  (void)buf;
353  (void)len;
354 
355  oldsettings = settings;
356  if (ns->status != Ns_Add) {
357  SockList_Init(&sl);
358  SockList_AddString(&sl, "addme_failed");
359  Send_With_Handling(ns, &sl);
360  SockList_Term(&sl);
361  } else if (find_player_socket(ns) == NULL) {
362  /* if there is already a player for this socket (add_me was already called),
363  * just ignore, else weird issues. */
364 
365  add_player(ns, 0);
366  /* Basically, the add_player copies the socket structure into
367  * the player structure, so this one (which is from init_sockets)
368  * is not needed anymore. The write below should still work,
369  * as the stuff in ns is still relevant.
370  */
371  SockList_Init(&sl);
372  SockList_AddString(&sl, "addme_success");
373  Send_With_Handling(ns, &sl);
374  SockList_Term(&sl);
375  if (ns->sc_version < 1027 || ns->cs_version < 1023) {
377  "Warning: Your client is too old to receive map data. Please update to a new client at: "
378  "https://sourceforge.net/projects/crossfire/");
379  }
380  }
381  settings = oldsettings;
382 }
383 
393 static void send_smooth(socket_struct *ns, const Face *face) {
394  const Face *smoothface;
395  SockList sl;
396 
397  // A malicious client can send bogus asksmooth commands that don't
398  // translate to any face. Catch those here before the message below
399  // in order to avoid a segfault.
400  if (!face) {
401  LOG(llevError, "Tried to smooth null face.\n");
402  return;
403  }
404 
405  // Try to find a smoothing face, or the default smoothing face. If this
406  // fails, set NS_FACESENT_SMOOTH so we don't try to send it again.
407  //
408  // Failures are usually due to map makers changing the face of a ground
409  // tile, but forgetting to unset smoothlevel.
410  if (!find_smooth(face, &smoothface)
411  && !find_smooth(smooth_face, &smoothface)) {
412  LOG(llevInfo,
413  "Could not smooth face %s. "
414  "Check that this face has a smoothing pixmap, or remove its smoothlevel.\n",
415  face->name);
416  ns->faces_sent[face->number] |= NS_FACESENT_SMOOTH;
417  return;
418  }
419 
420  if (!(ns->faces_sent[smoothface->number]&NS_FACESENT_FACE))
421  esrv_send_face(ns, smoothface, 0);
422 
423  ns->faces_sent[face->number] |= NS_FACESENT_SMOOTH;
424 
425  SockList_Init(&sl);
426  SockList_AddString(&sl, "smooth ");
427  SockList_AddShort(&sl, face->number);
428  SockList_AddShort(&sl, smoothface->number);
429  Send_With_Handling(ns, &sl);
430  SockList_Term(&sl);
431 }
432 
437 void ask_smooth_cmd(char *buf, int len, socket_struct *ns) {
438  uint16_t facenid;
439 
440  if (len <= 0 || !buf) {
441  LOG(llevDebug, "IP '%s' sent bogus ask_smooth_cmd information\n", ns->host);
442  return;
443  }
444 
445  facenid = atoi(buf);
446  send_smooth(ns, get_face_by_id(facenid));
447 }
448 
461 void new_player_cmd(uint8_t *buf, int len, player *pl) {
462  int time, repeat;
463  short packet;
464  char command[MAX_BUF];
465  SockList sl;
466 
467  if (len < 7) {
468  LOG(llevDebug, "Corrupt ncom command - not long enough - discarding\n");
469  return;
470  }
471 
472  packet = GetShort_String(buf);
473  repeat = GetInt_String(buf+2);
474  /* -1 is special - no repeat, but don't update */
475  if (repeat != -1) {
476  pl->count = repeat;
477  }
478  if (len-4 >= MAX_BUF)
479  len = MAX_BUF-5;
480 
481  strncpy(command, (char *)buf+6, len-4);
482  command[len-4] = '\0';
483 
484  /* The following should never happen with a proper or honest client.
485  * Therefore, the error message doesn't have to be too clear - if
486  * someone is playing with a hacked/non working client, this gives them
487  * an idea of the problem, but they deserve what they get
488  */
489  if (pl->state != ST_PLAYING) {
491  "You can not issue commands - state is not ST_PLAYING (%s)",
492  buf);
493  return;
494  }
495 
496  /* This should not happen anymore. */
497  if (pl->ob->speed_left < 0) {
498  LOG(llevError, "Player has negative time - shouldn't do command.\n");
499  }
501  /* Perhaps something better should be done with a left over count.
502  * Cleaning up the input should probably be done first - all actions
503  * for the command that issued the count should be done before
504  * any other commands.
505  */
506  pl->count = 0;
507 
508  /* Send confirmation of command execution now */
509  SockList_Init(&sl);
510  SockList_AddString(&sl, "comc ");
511  SockList_AddShort(&sl, packet);
512  if (FABS(pl->ob->speed) < 0.001)
513  time = MAX_TIME*100;
514  else
515  time = (int)(MAX_TIME/FABS(pl->ob->speed));
516  SockList_AddInt(&sl, time);
517  Send_With_Handling(&pl->socket, &sl);
518  SockList_Term(&sl);
519 }
520 
522 void reply_cmd(char *buf, int len, player *pl) {
523 
524  if (len <= 0 || !buf) {
525  LOG(llevDebug, "Player '%s' sent bogus reply_cmd information\n", pl->ob->name);
526  return;
527  }
528 
529  /* this avoids any hacking here */
530 
531  switch (pl->state) {
532  case ST_PLAYING:
533  LOG(llevError, "Got reply message with ST_PLAYING input state\n");
534  break;
535 
536  case ST_PLAY_AGAIN:
537  /* We can check this for return value (2==quit). Maybe we
538  * should, and do something appropriate?
539  */
540  receive_play_again(pl->ob, buf[0]);
541  break;
542 
543  case ST_ROLL_STAT:
544  key_roll_stat(pl->ob, buf[0]);
545  break;
546 
547  case ST_CHANGE_CLASS:
548 
549  key_change_class(pl->ob, buf[0]);
550  break;
551 
552  case ST_CONFIRM_QUIT:
553  key_confirm_quit(pl->ob, buf[0]);
554  break;
555 
556  case ST_GET_NAME:
558  break;
559 
560  case ST_GET_PASSWORD:
561  case ST_CONFIRM_PASSWORD:
566  break;
567 
568  case ST_GET_PARTY_PASSWORD: /* Get password for party */
570  break;
571 
572  default:
573  LOG(llevError, "Unknown input state: %d\n", pl->state);
574  }
575 }
576 
584 void version_cmd(char *buf, int len, socket_struct *ns) {
585  char *rest;
586  char *cs_str = strtok_r(buf, " ", &rest);
587  char *sc_str = strtok_r(NULL, " ", &rest);
588  (void)len;
589 
590  if (cs_str == NULL || sc_str == NULL) {
591  LOG(llevError, "%s: sent invalid version string\n", ns->host);
592  return;
593  } else {
594  ns->cs_version = atoi(cs_str);
595  ns->sc_version = atoi(sc_str);
596  }
597 
598 #ifdef ESRV_DEBUG
599  if (VERSION_CS != ns->cs_version) {
600  LOG(llevDebug, "CS: csversion mismatch (%d,%d)\n", VERSION_CS, ns->cs_version);
601  }
602 
603  if (VERSION_SC != ns->sc_version) {
604  LOG(llevDebug, "CS: scversion mismatch (%d,%d)\n", VERSION_SC, ns->sc_version);
605  }
606 #endif
607 
608  if (rest != NULL) {
609  LOG(llevInfo, "Connection from %s (%s), CS %d, SC %d\n",
610  ns->host, rest, ns->cs_version, ns->sc_version);
611  }
612 }
613 
621  SockList sl;
622 
623  /* If getting a newmap command, this scroll information
624  * is no longer relevant.
625  */
626  ns->map_scroll_x = 0;
627  ns->map_scroll_y = 0;
628 
629 
630  memset(&ns->lastmap, 0, sizeof(ns->lastmap));
631  SockList_Init(&sl);
632  SockList_AddString(&sl, "newmap");
633  Send_With_Handling(ns, &sl);
634  SockList_Term(&sl);
635 }
636 
641 void move_cmd(char *buf, int len, player *pl) {
642  int vals[3], i;
643 
644  if (len <= 0 || !buf) {
645  LOG(llevDebug, "Player '%s' sent bogus move_cmd information\n", pl->ob->name);
646  return;
647  }
648 
649  /* A little funky here. We only cycle for 2 records, because
650  * we obviously am not going to find a space after the third
651  * record. Perhaps we should just replace this with a
652  * sscanf?
653  */
654  for (i = 0; i < 2; i++) {
655  vals[i] = atoi(buf);
656  if (!(buf = strchr(buf, ' '))) {
657  LOG(llevError, "Incomplete move command: %s\n", buf);
658  return;
659  }
660  buf++;
661  }
662  vals[2] = atoi(buf);
663 
664 /* LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
665  esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
666 }
667 
668 /***************************************************************************
669  *
670  * Start of commands the server sends to the client.
671  *
672  ***************************************************************************
673  */
674 
679 void send_query(socket_struct *ns, uint8_t flags, const char *text) {
680  SockList sl;
681 
682  SockList_Init(&sl);
683  SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
684  Send_With_Handling(ns, &sl);
685  SockList_Term(&sl);
686 }
687 
688 #define AddIfInt64(Old, New, sl, Type) \
689  if (Old != New) { \
690  Old = New; \
691  SockList_AddChar(sl, Type); \
692  SockList_AddInt64(sl, New); \
693  }
694 
695 #define AddIfInt(Old, New, sl, Type) \
696  if (Old != New) { \
697  Old = New; \
698  SockList_AddChar(sl, Type); \
699  SockList_AddInt(sl, New); \
700  }
701 
702 #define AddIfShort(Old, New, sl, Type) \
703  if (Old != New) { \
704  Old = New; \
705  SockList_AddChar(sl, Type); \
706  SockList_AddShort(sl, New); \
707  }
708 
709 #define AddIfFloat(Old, New, sl, Type) \
710  if (Old != New) { \
711  Old = New; \
712  SockList_AddChar(sl, Type); \
713  SockList_AddInt(sl, (long)(New*FLOAT_MULTI));\
714  }
715 
716 #define AddIfString(Old, New, sl, Type) \
717  if (Old == NULL || strcmp(Old, New)) { \
718  free(Old); \
719  Old = strdup_local(New); \
720  SockList_AddChar(sl, Type); \
721  SockList_AddLen8Data(sl, New, strlen(New)); \
722  }
723 
729 static uint8_t is_perfect(const player *pl) {
730  const int16_t until = MIN(11, pl->ob->level);
731  for (int16_t i = 1; i < until; i++) {
732  if (pl->levhp[i] < 9 || pl->levsp[i] < 6 || pl->levgrace[i] < 3) {
733  return 0;
734  }
735  }
736  return 1;
737 }
738 
744 static void send_extra_stats(SockList *sl, player *pl) {
745  uint32_t uflags = 0;
746  const char *god = "none";
747 
748  if (pl->socket.notifications < 3) {
749  return;
750  }
751 
752  if (!pl->peaceful) {
753  uflags |= CF_HOSTILE;
754  }
755  if (!is_perfect(pl)) {
756  uflags |= CF_NOT_PERFECT;
757  }
758 
759 #define FIF(F, C) \
760  if (QUERY_FLAG(pl->ob, F)) { \
761  uflags |= C; \
762  }
764  FIF(FLAG_CONFUSED, CF_CONFUSED); // If confused by an item
768 
770  if (item->type == DISEASE && !QUERY_FLAG(item, FLAG_STARTEQUIP)) {
771  uflags |= CF_DISEASED;
772  }
773  if (strcmp(item->arch->name, "poisoning") == 0) {
774  uflags |= CF_POISONED;
775  }
776  if (strcmp(item->arch->name, "blindness") == 0) {
777  uflags |= CF_BLIND;
778  }
779  if (item->type == FORCE && strcmp(item->name, "confusion") == 0) {
780  uflags |= CF_CONFUSED;
781  }
782  if (item->type == SKILL && item->subtype == SK_PRAYING && item->title) {
783  god = item->title;
784  }
785  }
786  FOR_INV_FINISH();
787 
792 }
793 
801  SockList sl;
802  char buf[MAX_BUF];
803  uint16_t flags;
804  uint8_t s;
805 
806  SockList_Init(&sl);
807  SockList_AddString(&sl, "stats ");
808 
809  if (pl->ob != NULL) {
823  }
824  if (pl->socket.extended_stats) {
825  int16_t golem_hp, golem_maxhp;
833  if (pl->ob != NULL) {
848  }
849  if (pl->ranges[range_golem]) {
850  object *golem = pl->ranges[range_golem];
851  if (QUERY_FLAG(golem, FLAG_REMOVED) || golem->count != pl->golem_count || QUERY_FLAG(golem, FLAG_FREED)) {
852  golem_hp = 0;
853  golem_maxhp = 0;
854  } else {
855  golem_hp = golem->stats.hp;
856  golem_maxhp = golem->stats.maxhp;
857  }
858  } else {
859  golem_hp = 0;
860  golem_maxhp = 0;
861  }
862  /* send first the maxhp, so the client can set up the display */
863  AddIfShort(pl->last_golem_maxhp, golem_maxhp, &sl, CS_STAT_GOLEM_MAXHP);
864  AddIfShort(pl->last_golem_hp, golem_hp, &sl, CS_STAT_GOLEM_HP);
865  }
866 
867  for (s = 0; s < MAX_SKILLS; s++) {
868  if (pl->last_skill_ob[s]) {
869  // Skill objects can be removed without updating last_skill_ob.
870  // Clean them up here if that's the case.
872  LOG(llevDebug, "pruning removed object from last_skill_ob\n");
873  pl->last_skill_ob[s] = NULL;
874  continue;
875  }
876 
877  if (pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
878  /* Always send along the level if exp changes. This
879  * is only 1 extra byte, but keeps processing simpler.
880  */
882  SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
885  }
886  }
887  }
889  AddIfShort(pl->last_level, (char)pl->ob->level, &sl, CS_STAT_LEVEL);
897  flags = 0;
898  if (pl->fire_on)
899  flags |= SF_FIREON;
900  if (pl->run_on)
901  flags |= SF_RUNON;
902 
904  if (pl->socket.sc_version < 1025) {
906  } else {
907  int i;
908 
909  for (i = 0; i < NROFATTACKS; i++) {
910  /* Skip ones we won't send */
911  if (atnr_cs_stat[i] == -1)
912  continue;
913  AddIfShort(pl->last_resist[i], pl->ob->resist[i], &sl, (char)atnr_cs_stat[i]);
914  }
915  }
916  if (pl->socket.monitor_spells) {
920  }
921  /* we want to use the new fire & run system in new client */
922  rangetostring(pl->ob, buf, sizeof(buf));
924  set_title(pl->ob, buf, sizeof(buf));
926 
927  send_extra_stats(&sl, pl);
928 
929  /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
930  if (sl.len > 8) {
931 #ifdef ESRV_DEBUG
932  LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
933 #endif
934  Send_With_Handling(&pl->socket, &sl);
935  }
936  SockList_Term(&sl);
937 }
938 
942 void esrv_new_player(player *pl, uint32_t weight) {
943  SockList sl;
944 
945  pl->last_weight = weight;
946 
948  esrv_send_face(&pl->socket, pl->ob->face, 0);
949 
950  SockList_Init(&sl);
951  SockList_AddString(&sl, "player ");
952  SockList_AddInt(&sl, pl->ob->count);
953  SockList_AddInt(&sl, weight);
954  SockList_AddInt(&sl, pl->ob->face->number);
955  SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
956 
957  Send_With_Handling(&pl->socket, &sl);
958  SockList_Term(&sl);
960 }
961 
973  SockList sl;
974  int i;
975 
976  if (anim == NULL) {
977  LOG(llevError, "esrv_send_anim NULL??\n");
978  return;
979  }
980 
981  SockList_Init(&sl);
982  SockList_AddString(&sl, "anim ");
983  SockList_AddShort(&sl, anim->num);
984  SockList_AddShort(&sl, 0); /* flags - not used right now */
985  /* Build up the list of faces. Also, send any information (ie, the
986  * the face itself) down to the client.
987  */
988  for (i = 0; i < anim->num_animations; i++) {
989  if (!(ns->faces_sent[anim->faces[i]->number]&NS_FACESENT_FACE))
990  esrv_send_face(ns, anim->faces[i], 0);
991  /* flags - not used right now */
992  SockList_AddShort(&sl, anim->faces[i]->number);
993  }
994  Send_With_Handling(ns, &sl);
995  SockList_Term(&sl);
996  ns->anims_sent[anim->num] = 1;
997 }
998 
999 /****************************************************************************
1000  *
1001  * Start of map related commands.
1002  *
1003  ****************************************************************************/
1004 
1006 static void map_clearcell(struct map_cell_struct *cell, int face, int count) {
1007  cell->darkness = count;
1008  memset(cell->faces, face, sizeof(cell->faces));
1009 }
1010 
1011 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
1012 
1020 static const object *heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS];
1021 
1022 /****************************************************************************
1023  * This block is for map2 drawing related commands.
1024  * Note that the map2 still uses other functions.
1025  *
1026  ***************************************************************************/
1027 
1047 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) {
1048  uint8_t nlayer, smoothlevel = 0;
1049  const object *head;
1050 
1051  assert(ob != NULL);
1052 
1053  head = HEAD(ob);
1054  const Face *face = ob->face;
1055 
1056  /* This is a multipart object, and we are not at the lower
1057  * right corner. So we need to store away the lower right corner.
1058  */
1059  if (!is_head && (head->arch->tail_x || head->arch->tail_y)
1060  && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
1061  int bx, by, l;
1062 
1063  /* Basically figure out where the offset is from where we
1064  * are right now. the ob->arch->clone.{x,y} values hold
1065  * the offset that this current piece is from the head,
1066  * and the tail is where the tail is from the head.
1067  * Note that bx and by will equal sx and sy if we are
1068  * already working on the bottom right corner. If ob is
1069  * the head, the clone values will be zero, so the right
1070  * thing will still happen.
1071  */
1072  bx = ax+head->arch->tail_x-ob->arch->clone.x;
1073  by = ay+head->arch->tail_y-ob->arch->clone.y;
1074 
1075  /* I don't think this can ever happen, but better to check
1076  * for it just in case.
1077  */
1078  if (bx < ax || by < ay) {
1079  LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
1080  face = NULL;
1081  }
1082  /* the target position must be within +/-1 of our current
1083  * layer as the layers are defined. We are basically checking
1084  * to see if we have already stored this object away.
1085  */
1086  for (l = layer-1; l <= layer+1; l++) {
1087  if (l < 0 || l >= MAP_LAYERS)
1088  continue;
1089  if (heads[by][bx][l] == head)
1090  break;
1091  }
1092  /* Didn't find it. So we need to store it away. Try to store it
1093  * on our original layer, and then move up a layer.
1094  */
1095  if (l == layer+2) {
1096  if (!heads[by][bx][layer])
1097  heads[by][bx][layer] = head;
1098  else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
1099  heads[by][bx][layer+1] = head;
1100  }
1101  return 0;
1102  /* Ok - All done storing away the head for future use */
1103  } else {
1104  uint16_t face_num = face ? face->number : 0;
1105  (*has_obj)++;
1108  face_num = (ob->animation ? ob->animation->num : 0)|(1<<15);
1110  face_num |= ANIM_SYNC;
1112  face_num |= ANIM_RANDOM;
1113  }
1114  /* Since face_num includes the bits for the animation tag,
1115  * and we will store that away in the faces[] array, below
1116  * check works fine _except_ for the case where animation
1117  * speed chances.
1118  */
1119  if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
1120  uint8_t len, anim_speed = 0, i;
1121 
1122  /* This block takes care of sending the actual face
1123  * to the client. */
1124  ns->lastmap.cells[ax][ay].faces[layer] = face_num;
1125 
1126  /* Now form the data packet */
1127  nlayer = MAP2_LAYER_START+layer;
1128 
1129  len = 2;
1130 
1131  if (ob->map && !MAP_NOSMOOTH(ob->map)) {
1132  smoothlevel = ob->smoothlevel;
1133  if (smoothlevel)
1134  len++;
1135  }
1136 
1139  len++;
1140  /* 1/0.004 == 250, so this is a good cap for an
1141  * upper limit */
1142  if (ob->anim_speed)
1143  anim_speed = ob->anim_speed;
1144  else if (FABS(ob->speed) < 0.004)
1145  anim_speed = 255;
1146  else if (FABS(ob->speed) >= 1.0)
1147  anim_speed = 1;
1148  else
1149  anim_speed = (int)(1.0/FABS(ob->speed));
1150 
1151  if (ob->animation && !ns->anims_sent[ob->animation->num])
1152  esrv_send_animation(ns, ob->animation);
1153 
1154  /* If smoothing, need to send smoothing information
1155  * for all faces in the animation sequence. Since
1156  * smoothlevel is an object attribute,
1157  * it applies to all faces.
1158  */
1159  if (smoothlevel) {
1160  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1161  if (!(ns->faces_sent[ob->animation->faces[i]->number]&NS_FACESENT_SMOOTH))
1162  send_smooth(ns, ob->animation->faces[i]);
1163  }
1164  }
1165  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1166  esrv_send_face(ns, face, 0);
1167  }
1168 
1169  if (smoothlevel
1170  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1171  send_smooth(ns, ob->face);
1172 
1173  /* Length of packet */
1174  nlayer |= len<<5;
1175 
1176  SockList_AddChar(sl, nlayer);
1177  SockList_AddShort(sl, face_num);
1178  if (anim_speed)
1179  SockList_AddChar(sl, anim_speed);
1180  if (smoothlevel)
1181  SockList_AddChar(sl, smoothlevel);
1182  return 1;
1183  } /* Face is different */
1184  }
1185  return 0;
1186 }
1187 
1188 /* This function is used see if a layer needs to be cleared.
1189  * It updates the socklist, and returns 1 if the update is
1190  * needed, 0 otherwise.
1191  */
1192 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1193  int nlayer;
1194 
1195  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1196  /* Now form the data packet */
1197  nlayer = 0x10+layer+(2<<5);
1198  SockList_AddChar(sl, nlayer);
1199  SockList_AddShort(sl, 0);
1200  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1201  return 1;
1202  }
1203  return 0;
1204 }
1205 
1217 static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1218  int got_one = 0, poisoned = 0, diseased = 0;
1219  char name[60];
1220  int value, granularity;
1221  const object *probe;
1222 
1223  /* send hp bar if needed */
1224  if ((*alive_layer) != -1 || ob->head || !CAN_PROBE(ob))
1225  return 0;
1226 
1227  if (settings.always_show_hp == 2) {
1228  /* global hp bars are enabled */
1229  granularity = 30;
1230  } else if (settings.always_show_hp == 1 && ob->stats.hp < ob->stats.maxhp) {
1231  granularity = 30;
1232  } else {
1233  /* only give hp bars to monsters that have been probed */
1234  if (!QUERY_FLAG(ob, FLAG_PROBE)) {
1235  return 0;
1236  }
1237  probe = object_find_by_type_and_name(ob, FORCE, "probe_force");
1238  if (probe == NULL || probe->level < 15) {
1239  /* if probe is not null, this is an error, but well */
1240  return 0;
1241  }
1242 
1243  granularity = (probe->level - 14) / 3;
1244  if (granularity <= 0)
1245  granularity = 1;
1246  else if (granularity > 30)
1247  granularity = 30;
1248  }
1249 
1250  if (ob->stats.maxhp > 0) {
1251  value = (ob->stats.hp * granularity) / (ob->stats.maxhp);
1252 
1253  if (value < 0)
1254  value = 0;
1255  else if (value > granularity)
1256  value = granularity;
1257  } else
1258  value = 30;
1259 
1260  value = (value * 30) / granularity;
1261 
1262  if (object_present_in_ob(POISONING, ob) != NULL)
1263  poisoned = 1;
1264  if (object_present_in_ob(DISEASE, ob) != NULL)
1265  diseased = 1;
1266 
1267  if (value > 0) {
1268  archetype *dummy;
1269 
1270  snprintf(name, sizeof(name), "hpbar%s%s%s_%d",
1271  poisoned ? "_poisoned" : "",
1272  diseased ? "_diseased" : "",
1273  (!poisoned && !diseased) ? "_standard" : "",
1274  value);
1275  dummy = try_find_archetype(name);
1276  if (dummy != NULL) {
1277  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1278  (*alive_layer) = MAP_LAYER_FLY2;
1279  }
1280  }
1281 
1282  return got_one;
1283 }
1284 
1285 static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1286  int got_one = check_probe(ax, ay, ob, sl, ns, has_obj, alive_layer);
1288  if (ob->msg != NULL || object_find_by_arch_name(ob, "npc_dialog")) {
1289  archetype *dummy = try_find_archetype("speechbubble");
1290  if (dummy != NULL) {
1291  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1292  (*alive_layer) = MAP_LAYER_FLY2;
1293  }
1294  }
1295  }
1296  return got_one;
1297 }
1298 
1299 /*
1300  * This function is used to check a space (ax, ay) whose only
1301  * data we may care about are any heads. Basically, this
1302  * space is out of direct view. This is only used with the
1303  * Map2 protocol.
1304  *
1305  * @param ax
1306  * viewport relative x-coordinate
1307  * @param ay
1308  * viewport relative y-coordinate
1309  * @param sl
1310  * the reply to append to
1311  * @param ns
1312  * the client socket
1313  */
1314 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1315  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1316  uint16_t coord;
1317 
1318  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1319  oldlen = sl->len;
1320  SockList_AddShort(sl, coord);
1321 
1322  for (layer = 0; layer < MAP_LAYERS; layer++) {
1323  const object *head;
1324 
1325  head = heads[ay][ax][layer];
1326  if (head) {
1327  /* in this context, got_one should always increase
1328  * because heads should always point to data to really send.
1329  */
1330  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1331  } else {
1332  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1333  }
1334  }
1335  /* Note - if/when lighting information is added, some code is
1336  * needed here - lighting sources that are out of sight may still
1337  * extend into the viewable area.
1338  */
1339 
1340  /* If nothing to do for this space, we
1341  * can erase the coordinate bytes
1342  */
1343  if (!del_one && !got_one) {
1344  sl->len = oldlen;
1345  } else if (del_one && !has_obj) {
1346  /* If we're only deleting faces and not adding, and there
1347  * are not any faces on the space we care about,
1348  * more efficient
1349  * to send 0 as the type/len field.
1350  */
1351  sl->len = oldlen+2; /* 2 bytes for coordinate */
1352  SockList_AddChar(sl, 0); /* Clear byte */
1353  SockList_AddChar(sl, 255); /* Termination byte */
1354  // Reduce defreferences by passing the inner array offset instead of address of value
1355  map_clearcell(ns->lastmap.cells[ax] + ay, 0, 0);
1356  } else {
1357  SockList_AddChar(sl, 255); /* Termination byte */
1358  }
1359 }
1360 
1361 static void draw_client_map2(object *pl) {
1362  int x, y, ax, ay, d, min_x, max_x, min_y, max_y, oldlen, layer;
1363  size_t startlen;
1364  int16_t nx, ny;
1365  SockList sl;
1366  uint16_t coord;
1367  mapstruct *m;
1368  // Dereference once. It should not change in the middle of processing.
1369  player *plyr = pl->contr;
1370 
1371  SockList_Init(&sl);
1372  SockList_AddString(&sl, "map2 ");
1373  startlen = sl.len;
1374 
1375  /* Handle map scroll */
1376  if (plyr->socket.map_scroll_x || plyr->socket.map_scroll_y) {
1378  plyr->socket.map_scroll_x = 0;
1379  plyr->socket.map_scroll_y = 0;
1380  SockList_AddShort(&sl, coord);
1381  }
1382 
1383  /* Init data to zero */
1384  memset(heads, 0, sizeof(heads));
1385 
1386  /* We could do this logic as conditionals in the if statement,
1387  * but that started to get a bit messy to look at.
1388  */
1389  min_x = pl->x-plyr->socket.mapx/2;
1390  min_y = pl->y-plyr->socket.mapy/2;
1391  max_x = pl->x+(plyr->socket.mapx+1)/2+MAX_HEAD_OFFSET;
1392  max_y = pl->y+(plyr->socket.mapy+1)/2+MAX_HEAD_OFFSET;
1393 
1394  /* x, y are the real map locations. ax, ay are viewport relative
1395  * locations.
1396  */
1397  ay = 0;
1398  for (y = min_y; y < max_y; y++, ay++) {
1399  ax = 0;
1400  for (x = min_x; x < max_x; x++, ax++) {
1401  /* If this space is out of the normal viewable area,
1402  * we only check the heads value. This is used to
1403  * handle big images - if they extend to a viewable
1404  * portion, we need to send just the lower right corner.
1405  */
1406  if (ax >= plyr->socket.mapx || ay >= plyr->socket.mapy) {
1407  check_space_for_heads(ax, ay, &sl, &plyr->socket);
1408  } else {
1409  /* This space is within the viewport of the client. Due
1410  * to walls or darkness, it may still not be visible.
1411  */
1412 
1413  /* Meaning of d:
1414  * 0 - object is in plain sight, full brightness.
1415  * 1 - MAX_DARKNESS - how dark the space is - higher
1416  * value is darker space. If level is at max darkness,
1417  * you can't see the space (too dark)
1418  * 100 - space is blocked from sight.
1419  */
1420  d = plyr->blocked_los[ax][ay];
1421 
1422  /* If the coordinates are not valid, or it is too
1423  * dark to see, we tell the client as such
1424  */
1425  nx = x;
1426  ny = y;
1427  m = get_map_from_coord(pl->map, &nx, &ny);
1428  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1429 
1430  if (!m) {
1431  /* space is out of map. Update space and clear
1432  * values if this hasn't already been done.
1433  * If the space is out of the map, it shouldn't
1434  * have a head.
1435  */
1436  if (plyr->socket.lastmap.cells[ax][ay].darkness != 0) {
1437  SockList_AddShort(&sl, coord);
1439  SockList_AddChar(&sl, 255); /* Termination byte */
1440  // Reduce dereferences by passing the inner array offset instead of address of value
1441  map_clearcell(plyr->socket.lastmap.cells[ax] + ay, 0, 0);
1442  }
1443  } else if (d >= MAX_LIGHT_RADII) {
1444  /* This block deals with spaces that are not
1445  * visible due to darkness or walls. Still
1446  * need to send the heads for this space.
1447  */
1448  check_space_for_heads(ax, ay, &sl, &plyr->socket);
1449  } else {
1450  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1451 
1452  /* In this block, the space is visible. */
1453 
1454  /* Rather than try to figure out what everything
1455  * that we might need to send is, then form the
1456  * packet after that, we presume that we will in
1457  * fact form a packet, and update the bits by what
1458  * we do actually send. If we send nothing, we
1459  * just back out sl.len to the old value, and no
1460  * harm is done.
1461  * I think this is simpler than doing a bunch of
1462  * checks to see what if anything we need to send,
1463  * setting the bits, then doing those checks again
1464  * to add the real data.
1465  */
1466 
1467  oldlen = sl.len;
1468  SockList_AddShort(&sl, coord);
1469 
1470  /* Darkness changed */
1471  if (plyr->socket.lastmap.cells[ax][ay].darkness != d
1472  && plyr->socket.darkness) {
1473  plyr->socket.lastmap.cells[ax][ay].darkness = d;
1474  /* Darkness tag & length*/
1476  SockList_AddChar(&sl, 255-d*(256/MAX_LIGHT_RADII));
1477  have_darkness = 1;
1478  }
1479 
1480  for (layer = 0; layer < MAP_LAYERS; layer++) {
1481  const object *ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1482 
1483  /* Special case: send player itself if invisible */
1484  if (!ob
1485  && x == pl->x
1486  && y == pl->y
1487  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1488  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1489  ob = pl;
1490 
1491  if (ob) {
1492  g1 = has_obj;
1493  old_got = got_one;
1494  got_one += map2_add_ob(ax, ay, layer, ob, &sl, &plyr->socket, &has_obj, 0);
1495 
1496  /* if we added the face, or it is a monster's head, check probe spell */
1497  if (got_one != old_got || (ob->head == NULL && ob->more))
1498  got_one += annotate_ob(ax, ay, ob, &sl, &plyr->socket, &has_obj, &alive_layer);
1499 
1500  /* If we are just storing away the head
1501  * for future use, then effectively this
1502  * space/layer is blank, and we should clear
1503  * it if needed.
1504  */
1505  if (g1 == has_obj) {
1506  del_one += map2_delete_layer(ax, ay, layer, &sl, &plyr->socket);
1507  } else if (ob->head == NULL) {
1508  /* for single-part items */
1509  got_one += annotate_ob(ax, ay, ob, &sl, &plyr->socket, &has_obj, &alive_layer);
1510  }
1511  } else {
1512  if (layer != alive_layer)
1513  del_one += map2_delete_layer(ax, ay, layer, &sl, &plyr->socket);
1514  }
1515  }
1516  /* If nothing to do for this space, we
1517  * can erase the coordinate bytes
1518  */
1519  if (!del_one && !got_one && !have_darkness) {
1520  sl.len = oldlen;
1521  } else if (del_one && !has_obj) {
1522  /* If we're only deleting faces and don't
1523  * have any objs we care about, just clear
1524  * space. Note it is possible we may have
1525  * darkness, but if there is nothing on the
1526  * space, darkness isn't all that interesting
1527  * - we can send it when an object shows up.
1528  */
1529  sl.len = oldlen+2; /* 2 bytes for coordinate */
1531  SockList_AddChar(&sl, 255); /* Termination byte */
1532  // Reduce dereferences by passing the inner array offset instead of address of value
1533  map_clearcell(plyr->socket.lastmap.cells[ax] + ay, 0, 0);
1534  } else {
1535  SockList_AddChar(&sl, 255); /* Termination byte */
1536  }
1537  }
1538  } /* else this is a viewable space */
1539  } /* for x loop */
1540  } /* for y loop */
1541 
1542  /* Only send this if there are in fact some differences. */
1543  if (sl.len > startlen) {
1544  Send_With_Handling(&plyr->socket, &sl);
1545  }
1546  SockList_Term(&sl);
1547 }
1548 
1552 void draw_client_map(object *pl) {
1553  int i, j;
1554  int16_t ax, ay;
1555  int mflags;
1556  mapstruct *m, *pm;
1557  int min_x, min_y, max_x, max_y;
1558 
1559  if (pl->type != PLAYER) {
1560  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1561  return;
1562  }
1563 
1564  if (pl->contr->transport) {
1565  pm = pl->contr->transport->map;
1566  } else
1567  pm = pl->map;
1568 
1569  /* If player is just joining the game, he isn't here yet, so
1570  * the map can get swapped out. If so, don't try to send them
1571  * a map. All will be OK once they really log in.
1572  */
1573  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1574  return;
1575 
1576  /*
1577  * This block just makes sure all the spaces are properly
1578  * updated in terms of what they look like.
1579  */
1580  min_x = pl->x-pl->contr->socket.mapx/2;
1581  min_y = pl->y-pl->contr->socket.mapy/2;
1582  max_x = pl->x+(pl->contr->socket.mapx+1)/2;
1583  max_y = pl->y+(pl->contr->socket.mapy+1)/2;
1584  for (j = min_y; j < max_y; j++) {
1585  for (i = min_x; i < max_x; i++) {
1586  ax = i;
1587  ay = j;
1588  m = pm;
1589  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1590  if (mflags&P_OUT_OF_MAP)
1591  continue;
1592  if (mflags&P_NEED_UPDATE)
1593  update_position(m, ax, ay);
1594  /* If a map is visible to the player, we don't want
1595  * to swap it out just to reload it. This should
1596  * really call something like swap_map, but this is
1597  * much more efficient and 'good enough'
1598  */
1599  if (mflags&P_NEW_MAP)
1600  m->timeout = 50;
1601  }
1602  }
1603 
1604  /* do LOS after calls to update_position */
1605  if (pl->contr->do_los) {
1606  update_los(pl);
1607  pl->contr->do_los = 0;
1608  }
1609 
1611 }
1612 
1613 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1614  struct Map newmap;
1615  int x, y, mx, my;
1616 
1617  ns->map_scroll_x += dx;
1618  ns->map_scroll_y += dy;
1619 
1620  mx = ns->mapx+MAX_HEAD_OFFSET;
1621  my = ns->mapy+MAX_HEAD_OFFSET;
1622 
1623  /* the x and y here are coordinates for the new map, i.e. if we moved
1624  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1625  * if the destination x or y coordinate is outside the viewable
1626  * area, we clear the values - otherwise, the old values
1627  * are preserved, and the check_head thinks it needs to clear them.
1628  */
1629  for (x = 0; x < mx; x++) {
1630  for (y = 0; y < my; y++) {
1631  if (x >= ns->mapx || y >= ns->mapy) {
1632  /* clear cells outside the viewable area */
1633  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1634  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1635  /* clear newly visible tiles within the viewable area */
1636  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1637  } else {
1638  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1639  }
1640  }
1641  }
1642 
1643  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1644 }
1645 
1651 void send_plugin_custom_message(object *pl, char *buf) {
1652  SockList sl;
1653 
1654  SockList_Init(&sl);
1655  SockList_AddString(&sl, buf);
1656  Send_With_Handling(&pl->contr->socket, &sl);
1657  SockList_Term(&sl);
1658 }
1659 
1666  SockList sl;
1667  int flags = 0;
1668  client_spell *spell_info;
1669 
1670  if (!pl->socket.monitor_spells)
1671  return;
1672 
1673  /* Handles problem at login, where this is called from fix_object
1674  * before we have had a chance to send spells to the player. It does seem
1675  * to me that there should never be a case where update_spells is called
1676  * before add_spells has been called. Add_spells() will update the
1677  * spell_state to non null.
1678  */
1679  if (!pl->spell_state)
1680  return;
1681 
1682  FOR_INV_PREPARE(pl->ob, spell) {
1683  if (spell->type == SPELL) {
1684  spell_info = get_client_spell_state(pl, spell);
1685  /* check if we need to update it*/
1686  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1687  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1688  flags |= UPD_SP_MANA;
1689  }
1690  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1691  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1692  flags |= UPD_SP_GRACE;
1693  }
1694  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1695  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1696  flags |= UPD_SP_DAMAGE;
1697  }
1698  if (flags != 0) {
1699  SockList_Init(&sl);
1700  SockList_AddString(&sl, "updspell ");
1701  SockList_AddChar(&sl, flags);
1702  SockList_AddInt(&sl, spell->count);
1703  if (flags&UPD_SP_MANA)
1704  SockList_AddShort(&sl, spell_info->last_sp);
1705  if (flags&UPD_SP_GRACE)
1706  SockList_AddShort(&sl, spell_info->last_grace);
1707  if (flags&UPD_SP_DAMAGE)
1708  SockList_AddShort(&sl, spell_info->last_dam);
1709  flags = 0;
1710  Send_With_Handling(&pl->socket, &sl);
1711  SockList_Term(&sl);
1712  }
1713  }
1714  } FOR_INV_FINISH();
1715 }
1716 
1717 void esrv_remove_spell(player *pl, object *spell) {
1718  SockList sl;
1719 
1720  if (!pl || !spell || spell->env != pl->ob) {
1721  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1722  return;
1723  }
1724  if (!pl->socket.monitor_spells)
1725  return;
1726 
1727  SockList_Init(&sl);
1728  SockList_AddString(&sl, "delspell ");
1729  SockList_AddInt(&sl, spell->count);
1730  Send_With_Handling(&pl->socket, &sl);
1731  SockList_Term(&sl);
1732 }
1733 
1741  SockList sl;
1742 
1743  if (!pl->socket.want_pickup)
1744  return;
1745  SockList_Init(&sl);
1746  SockList_AddString(&sl, "pickup ");
1747  SockList_AddInt(&sl, pl->mode);
1748  Send_With_Handling(&pl->socket, &sl);
1749  SockList_Term(&sl);
1750 }
1751 
1760 static int spell_client_use(const object *spell) {
1761  switch (spell->type)
1762  {
1763  case SP_RAISE_DEAD:
1764  case SP_MAKE_MARK:
1765  return 3;
1766  case SP_RUNE:
1767  if (!spell->other_arch)
1768  return 1;
1769  break;
1770  case SP_CREATE_FOOD:
1771  case SP_CREATE_MISSILE:
1772  return 2;
1773  case SP_SUMMON_MONSTER:
1774  if (spell->randomitems != NULL)
1775  return 2;
1776  /* break; */// If add conditins below, use this break statement
1777  }
1778  // This is not in the switch statement so that it supports fallthrough logic
1779  // on the few spell types that have additional conditions attached.
1780  return 0;
1781 }
1782 
1784 static void append_spell(player *pl, SockList *sl, object *spell) {
1785  client_spell *spell_info;
1786  int len, i, skill = 0;
1787 
1788  if (!spell->name) {
1789  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1790  return;
1791  }
1792 
1793  if (spell->face && !(pl->socket.faces_sent[spell->face->number]&NS_FACESENT_FACE))
1794  esrv_send_face(&pl->socket, spell->face, 0);
1795 
1796  spell_info = get_client_spell_state(pl, spell);
1797  SockList_AddInt(sl, spell->count);
1798  SockList_AddShort(sl, spell->level);
1799  SockList_AddShort(sl, spell->casting_time);
1800  /* store costs and damage in the object struct, to compare to later */
1801  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1802  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1803  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1804  /* send the current values */
1805  SockList_AddShort(sl, spell_info->last_sp);
1806  SockList_AddShort(sl, spell_info->last_grace);
1807  SockList_AddShort(sl, spell_info->last_dam);
1808 
1809  /* figure out which skill it uses, if it uses one */
1810  if (spell->skill) {
1811  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++)
1812  if (!strcmp(spell->skill, skill_names[i])) {
1813  skill = i+CS_STAT_SKILLINFO;
1814  break;
1815  }
1816  }
1817  SockList_AddChar(sl, skill);
1818 
1819  SockList_AddInt(sl, spell->path_attuned);
1820  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1821  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1822 
1823  if (!spell->msg) {
1824  SockList_AddShort(sl, 0);
1825  } else {
1826  len = strlen(spell->msg);
1827  SockList_AddShort(sl, len);
1828  SockList_AddData(sl, spell->msg, len);
1829  }
1830 
1831  /* Extended spell information available if the client wants it.
1832  */
1833  if (pl->socket.monitor_spells >= 2) {
1834  /* spellmon 2
1835  */
1836  sstring req = object_get_value(spell, "casting_requirements");
1837 
1838  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1839 
1840  if (req) { /* Requirements */
1841  SockList_AddLen8Data(sl, req, strlen(req));
1842  } else {
1843  SockList_AddChar(sl, 0);
1844  }
1845  /* end spellmon 2
1846  */
1847  }
1848 }
1849 
1854 void esrv_add_spells(player *pl, object *spell) {
1855  SockList sl;
1856  size_t size;
1857  sstring value;
1858 
1859  if (!pl) {
1860  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
1861  return;
1862  }
1863 
1864  if (!pl->socket.monitor_spells)
1865  return;
1866 
1867  SockList_Init(&sl);
1868  SockList_AddString(&sl, "addspell ");
1869  if (!spell) {
1870  FOR_INV_PREPARE(pl->ob, spell) {
1871  if (spell->type != SPELL)
1872  continue;
1873  /* Were we to simply keep appending data here, we could
1874  * exceed the SockList buffer if the player has enough spells
1875  * to add. We know that append_spell will always append
1876  * 23 data bytes, plus 3 length bytes and 2 strings
1877  * (because that is the spec) so we need to check that
1878  * the length of those 2 strings, plus the 26 bytes,
1879  * won't take us over the length limit for the socket.
1880  * If it does, we need to send what we already have,
1881  * and restart packet formation.
1882  */
1883  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
1884  if (pl->socket.monitor_spells >= 2) {
1886  value = object_get_value(spell, "casting_requirements");
1887  size += 2 + (value ? strlen(value) : 0);
1888  }
1889  if (SockList_Avail(&sl) < size) {
1890  Send_With_Handling(&pl->socket, &sl);
1891  SockList_Reset(&sl);
1892  SockList_AddString(&sl, "addspell ");
1893  }
1894  append_spell(pl, &sl, spell);
1895  } FOR_INV_FINISH();
1896  } else if (spell->type != SPELL) {
1897  LOG(llevError, "Asked to send a non-spell object as a spell\n");
1898  return;
1899  } else
1900  append_spell(pl, &sl, spell);
1901  /* finally, we can send the packet */
1902  Send_With_Handling(&pl->socket, &sl);
1903  SockList_Term(&sl);
1904 }
1905 
1906 /* sends a 'tick' information to the client.
1907  * We also take the opportunity to toggle TCP_NODELAY -
1908  * this forces the data in the socket to be flushed sooner to the
1909  * client - otherwise, the OS tries to wait for full packets
1910  * and will this hold sending the data for some amount of time,
1911  * which thus adds some additional latency.
1912  */
1914  SockList sl;
1915 #ifdef WIN32
1916  char tmp;
1917 #else
1918  int tmp;
1919 #endif
1920 
1921  SockList_Init(&sl);
1922  SockList_AddString(&sl, "tick ");
1923  SockList_AddInt(&sl, pticks);
1924  tmp = 1;
1925  if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
1926  LOG(llevError, "send_tick: Unable to turn on TCP_NODELAY\n");
1927 
1928  Send_With_Handling(&pl->socket, &sl);
1929  tmp = 0;
1930  if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
1931  LOG(llevError, "send_tick: Unable to turn off TCP_NODELAY\n");
1932  SockList_Term(&sl);
1933 }
1934 
1947 static void add_char_field(SockList *sl, int type, const char *data)
1948 {
1949  int len;
1950 
1951  len = strlen(data);
1952 
1953  if (len) {
1954  /* one extra for length for the type byte */
1955  SockList_AddChar(sl, len+1);
1956  SockList_AddChar(sl, type);
1957  SockList_AddString(sl, data);
1958  }
1959 }
1960 
1982 {
1983  SockList sl;
1984  Account_Char *acn;
1985  int num_chars;
1986  linked_char *extra;
1987 
1989 
1990  num_chars = 0;
1991  extra = account_get_additional_chars(ns->account_name, ns->account_chars, &num_chars);
1992 
1993  SockList_Init(&sl);
1994  SockList_AddString(&sl, "accountplayers ");
1995 
1996  for (acn = ns->account_chars; acn; acn = acn->next) {
1997  num_chars++;
1998  }
1999 
2000  SockList_AddChar(&sl, num_chars);
2001 
2002  /* Now add real character data */
2003  for (acn = ns->account_chars; acn; acn = acn->next) {
2004  uint16_t faceno = 0;
2005 
2006  /* Ignore a dead character. They don't need to show up. */
2007  if (acn->isDead) {
2008  continue;
2009  }
2010 
2011  add_char_field(&sl, ACL_NAME, acn->name);
2013  add_char_field(&sl, ACL_RACE, acn->race);
2014  add_char_field(&sl, ACL_FACE, acn->face);
2015  if (acn->face[0] != 0 ) {
2016  const Face *face = try_find_face(acn->face, NULL);
2017 
2018  if (face != NULL) {
2019  if (!(ns->faces_sent[face->number]&NS_FACESENT_FACE)) {
2020  esrv_send_face(ns, face, 0);
2021  }
2022  faceno = face->number;
2023  }
2024  }
2025 
2026  add_char_field(&sl, ACL_PARTY, acn->party);
2027  add_char_field(&sl, ACL_MAP, acn->map);
2028  SockList_AddChar(&sl, 3);
2030  SockList_AddShort(&sl, acn->level);
2031  if (faceno) {
2032  SockList_AddChar(&sl, 3);
2034  SockList_AddShort(&sl, faceno);
2035  }
2036 
2037  SockList_AddChar(&sl, 0);
2038  }
2039  /* Now for any characters where we just have the name */
2040  for (linked_char *e = extra; e != NULL; e = e->next) {
2041  add_char_field(&sl, ACL_NAME, e->name);
2042  SockList_AddChar(&sl, 0);
2043  }
2044 
2045  Send_With_Handling(ns, &sl);
2046  SockList_Term(&sl);
2047 
2048  if (extra) {
2049  free_charlinks(extra);
2050  }
2051 }
2052 
2074 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2075 {
2076  int nlen, plen;
2077 
2078  if (*len < 2) {
2079  return 1;
2080  }
2081 
2082  nlen = (unsigned char)buf[0];
2083  if (nlen >= MAX_BUF || nlen > *len-2) {
2084  return 1;
2085  }
2086  memcpy(name, buf+1, nlen);
2087  name[nlen] = 0;
2088 
2089  plen = (unsigned char)buf[nlen+1];
2090  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2091  return 2;
2092  }
2093  memcpy(password, buf+2+nlen, plen);
2094  password[plen] = 0;
2095 
2096  *len = nlen+plen+2;
2097 
2098  return 0;
2099 }
2110 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2111  char name[MAX_BUF], password[MAX_BUF];
2112  int status;
2113  SockList sl;
2114 
2115  if (len <= 0 || !buf) {
2116  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2117  return;
2118  }
2119 
2120  SockList_Init(&sl);
2121 
2122  status = decode_name_password(buf, &len, name, password);
2123 
2124  if (status == 1) {
2125  SockList_AddString(&sl, "failure accountlogin Name is too long");
2126  Send_With_Handling(ns, &sl);
2127  SockList_Term(&sl);
2128  return;
2129  }
2130  if (status == 2) {
2131  SockList_AddString(&sl, "failure accountlogin Password is too long");
2132  Send_With_Handling(ns, &sl);
2133  SockList_Term(&sl);
2134  return;
2135  }
2136 
2137  if (!account_exists(name)) {
2138  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2139  Send_With_Handling(ns, &sl);
2140  SockList_Term(&sl);
2141  return;
2142  }
2143 
2144  if (account_login(name, password)) {
2145  LOG(llevInfo, "Account login for '%s' from %s\n", name, ns->host);
2146  player *pl;
2147  socket_struct *tns;
2148 
2149  /* Checking against init_sockets must be done before
2150  * we set ns->account - otherwise we will match
2151  * that. What we are doing here is limiting the account
2152  * to only one login.
2153  */
2155  /* Other code will clean this up. We could try to
2156  * set the same state this other socket is in, but we
2157  * really don't know what that state is, and then
2158  * we would have to try to communicate that to the client
2159  * so it can activate the right dialogs. Simpler to
2160  * just go to a known state.
2161  */
2162  if (tns && tns != ns)
2163  tns->status = Ns_Dead;
2164 
2165  /* Same note as above applies - it can be simpler in
2166  * this case - we could check against the ST_PLAYING
2167  * value, but right now we don't have a method to
2168  * tell the client to go directly from login to playing.
2169  */
2171  if (pl)
2172  pl->socket.status = Ns_Dead;
2173 
2174 
2175  if (ns->account_name) free(ns->account_name);
2176  /* We want to store away official name so we do not
2177  * have any case sensitivity issues on the files.
2178  * because we have already checked password, we
2179  * know that account_exists should never return NULL in
2180  * this case.
2181  */
2183 
2185  } else {
2186  LOG(llevInfo, "Failed account login for '%s' from %s\n", name, ns->host);
2187  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2188  Send_With_Handling(ns, &sl);
2189  SockList_Term(&sl);
2190  }
2191 }
2192 
2201 static int account_block_create(const socket_struct *ns) {
2202  /* Check if account creation is blocked. */
2204  /* Account creation is allowed for everyone. */
2205  return 0;
2206  }
2207 
2208  /* Has the trusted host been defined? */
2209  if(settings.account_trusted_host == NULL) {
2210  /* No, allocate it and set it to localhost now. */
2212  }
2213 
2214  /* Return false if the client connected from the trusted host. */
2215  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2216  return 0;
2217  }
2218 
2219  /*
2220  * If we are here, then we are blocking account create and we do
2221  * not trust this client's IP address.
2222  */
2223  return 1;
2224 }
2225 
2237 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2238  char name[MAX_BUF], password[MAX_BUF];
2239  int status;
2240  SockList sl;
2241 
2242  if (len <= 0 || !buf) {
2243  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2244  return;
2245  }
2246 
2247  SockList_Init(&sl);
2248 
2249  status = decode_name_password(buf, &len, name, password);
2250 
2251  if (account_block_create(ns)) {
2252  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2253  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2254  Send_With_Handling(ns, &sl);
2255  SockList_Term(&sl);
2256  return;
2257  }
2258 
2259  if (status == 1) {
2260  SockList_AddString(&sl, "failure accountnew Name is too long");
2261  Send_With_Handling(ns, &sl);
2262  SockList_Term(&sl);
2263  return;
2264  }
2265  if (status == 2) {
2266  SockList_AddString(&sl, "failure accountnew Password is too long");
2267  Send_With_Handling(ns, &sl);
2268  SockList_Term(&sl);
2269  return;
2270  }
2271  /*The minimum length isn't exactly required, but in the current implementation,
2272  * client will send the same password for character for which there is a
2273  * 2 character minimum size. Thus an account with a one character password
2274  * won't be able to create a character. */
2275  if (strlen(name)<settings.min_name) {
2276  SockList_AddString(&sl, "failure accountnew Name is too short");
2277  Send_With_Handling(ns, &sl);
2278  SockList_Term(&sl);
2279  return;
2280  }
2281  if (strlen(password)<2) {
2282  SockList_AddString(&sl, "failure accountnew Password is too short");
2283  Send_With_Handling(ns, &sl);
2284  SockList_Term(&sl);
2285  return;
2286  }
2287 
2288  if (account_exists(name)) {
2289  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2290  Send_With_Handling(ns, &sl);
2291  SockList_Term(&sl);
2292  return;
2293  }
2294 
2296  if (status == 1) {
2297  SockList_AddString(&sl,
2298  "failure accountnew That account name contains invalid characters.");
2299  Send_With_Handling(ns, &sl);
2300  SockList_Term(&sl);
2301  return;
2302  }
2303 
2304  if (status == 2) {
2305  SockList_AddString(&sl,
2306  "failure accountnew That account name is too long");
2307  Send_With_Handling(ns, &sl);
2308  SockList_Term(&sl);
2309  return;
2310  }
2311 
2312  status = account_check_string(password);
2313  if (status == 1) {
2314  SockList_AddString(&sl,
2315  "failure accountnew That password contains invalid characters.");
2316  Send_With_Handling(ns, &sl);
2317  SockList_Term(&sl);
2318  return;
2319  }
2320 
2321  if (status == 2) {
2322  SockList_AddString(&sl,
2323  "failure accountnew That password is too long");
2324  Send_With_Handling(ns, &sl);
2325  SockList_Term(&sl);
2326  return;
2327  }
2328 
2329  /* If we got here, we passed all checks - so now add it */
2330  if (ns->account_name) free(ns->account_name);
2332  account_new(name, password);
2333  /* save account information */
2334  accounts_save();
2336 }
2337 
2351 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2352  char name[MAX_BUF], password[MAX_BUF];
2353  int status, force, nlen;
2354  SockList sl;
2355  const char *cp;
2356 
2357  if (len <= 0 || !buf) {
2358  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2359  return;
2360  }
2361 
2362  SockList_Init(&sl);
2363 
2364  if (ns->account_name == NULL) {
2365  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2366  Send_With_Handling(ns, &sl);
2367  SockList_Term(&sl);
2368  return;
2369  }
2370 
2371  force = buf[0];
2372  nlen = len - 1;
2373  status = decode_name_password(buf+1, &nlen, name, password);
2374  if (status == 1) {
2375  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2376  Send_With_Handling(ns, &sl);
2377  SockList_Term(&sl);
2378  return;
2379  }
2380  if (status == 2) {
2381  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2382  Send_With_Handling(ns, &sl);
2383  SockList_Term(&sl);
2384  return;
2385  }
2386 
2387  status = verify_player(name, password);
2388  if (status) {
2389  /* From a security standpoint, telling random folks if it
2390  * it as wrong password makes it easier to hack. However,
2391  * it is fairly easy to determine what characters exist on a server
2392  * (either by trying to create a new one and see if the name is in
2393  * in use, or just looking at the high score file), so this
2394  * really does not make things much less secure
2395  */
2396  if (status == 1)
2397  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2398  else
2399  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2400 
2401  Send_With_Handling(ns, &sl);
2402  SockList_Term(&sl);
2403  return;
2404  }
2405  /* Check to see if this character is associated with an account.
2406  */
2408  if (cp) {
2409  if (!strcmp(cp, ns->account_name)) {
2410  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2411  Send_With_Handling(ns, &sl);
2412  SockList_Term(&sl);
2413  return;
2414  } else {
2415  if (!force) {
2416  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2417  Send_With_Handling(ns, &sl);
2418  SockList_Term(&sl);
2419  return;
2420  } else if (account_is_logged_in(cp)) {
2421  /* We could be clever and try to handle this case, but it is
2422  * trickier. If the character is logged in, it has to
2423  * be logged out. And the socket holds some data which
2424  * needs to be cleaned up. Since it should be fairly
2425  * uncommon that users need to do this, just disallowing
2426  * it makes things a lot simpler.
2427  */
2428  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2429  Send_With_Handling(ns, &sl);
2430  SockList_Term(&sl);
2431  return;
2432  }
2433  }
2434  }
2435  /* If we have gotten this far, the name/password provided is OK,
2436  * and the character is not associated with a different account (or
2437  * force is true). Now try to add the character to this account.
2438  */
2440 
2441  /* This should never happen, but check for it just in case -
2442  * if we were able to log in, the account should exist. but
2443  * if this fails, need to give the user some clue.
2444  */
2445  if (status==1) {
2446  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2447  Send_With_Handling(ns, &sl);
2448  SockList_Term(&sl);
2449  return;
2450  } else if (status == 2) {
2451  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2452  Send_With_Handling(ns, &sl);
2453  SockList_Term(&sl);
2454  return;
2455  }
2456 
2457  /* If cp is set, then this character used to belong to a different
2458  * account. Remove it now.
2459  */
2460  if (cp) {
2461  Account_Char *chars;
2462 
2464  chars = account_char_load(cp);
2465  chars=account_char_remove(chars, name);
2466  account_char_save(cp, chars);
2467  account_char_free(chars);
2468  }
2469 
2471 
2472  /* store data so nothing is lost in case of crash */
2474 }
2475 
2480 void account_play_cmd(char *buf, int len, socket_struct *ns)
2481 {
2482  char **chars;
2483  int i;
2484  SockList sl;
2485  player *pl;
2486 
2487  if (len <= 0 || !buf) {
2488  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2489  return;
2490  }
2491 
2492  SockList_Init(&sl);
2493 
2494  if (ns->status != Ns_Add) {
2495  SockList_AddString(&sl, "failure accountplay Not allowed right now");
2496  Send_With_Handling(ns, &sl);
2497  SockList_Term(&sl);
2498  return;
2499  }
2500 
2501  if (!buf[0]) {
2502  SockList_AddString(&sl, "failure accountplay Malformed character name");
2503  Send_With_Handling(ns, &sl);
2504  SockList_Term(&sl);
2505  return;
2506  }
2507 
2508  if (ns->account_name == NULL) {
2509  SockList_AddString(&sl, "failure accountplay Not logged in");
2510  Send_With_Handling(ns, &sl);
2511  SockList_Term(&sl);
2512  return;
2513  }
2514 
2515  /* Make sure a client is not trying to spoof us here */
2517 
2518  for (i=0; chars[i]; i++) {
2519  if (strcmp(chars[i], buf) == 0)
2520  break;
2521  }
2522  if (!chars[i]) {
2523  SockList_AddPrintf(&sl,
2524  "failure accountplay Character %s is not associated with account %s",
2525  buf, ns->account_name);
2526  Send_With_Handling(ns, &sl);
2527  SockList_Term(&sl);
2528  return;
2529  }
2530 
2531  /* from a protocol standpoint, accountplay can be used
2532  * before there is a player structure (first login) or after
2533  * (character has logged in and is changing characters).
2534  * Checkthe sockets for that second case - if so,
2535  * we don't need to make a new player object, etc.
2536  */
2537  for (pl=first_player; pl; pl=pl->next) {
2538  if (&pl->socket == ns) {
2539  /* The player still in the socket must be saved first. */
2540  save_player(pl->ob, 0);
2541  break;
2542  }
2543  }
2544 
2545  /* Some of this logic is from add_player()
2546  * we just don't use add_player() as it does some other work
2547  * we don't really want to do.
2548  */
2549  if (!pl) {
2550  pl = get_player(NULL);
2551  ns->status = Ns_Avail;
2552  memcpy(&pl->socket, ns, sizeof(socket_struct));
2553  ns->faces_sent = NULL;
2555  } else {
2556  pl->state = ST_PLAYING;
2557  }
2558 
2559  pl->ob->name = add_string(buf);
2560  check_login(pl->ob, NULL);
2561 
2562  SockList_AddString(&sl, "addme_success");
2563  Send_With_Handling(ns, &sl);
2564  SockList_Term(&sl);
2565 }
2566 
2567 #define MAX_CHOICES 100
2568 
2574 void create_player_cmd(char *buf, int len, socket_struct *ns)
2575 {
2576  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2577  int status, nlen, choice_num=0, i;
2578  SockList sl;
2579  player *pl;
2580  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2581  living new_stats;
2582 
2583  if (len <= 0 || !buf) {
2584  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2585  return;
2586  }
2587 
2588  SockList_Init(&sl);
2589 
2590  if (ns->status != Ns_Add) {
2591  SockList_AddString(&sl, "failure createplayer Not allowed right now");
2592  Send_With_Handling(ns, &sl);
2593  SockList_Term(&sl);
2594  return;
2595  }
2596 
2597  nlen = len;
2598  status = decode_name_password(buf, &nlen, name, password);
2599  if (status == 1) {
2600  SockList_AddString(&sl, "failure createplayer Name is too long");
2601  Send_With_Handling(ns, &sl);
2602  SockList_Term(&sl);
2603  return;
2604  }
2605 
2606  /* Minimum character name limit (if set) */
2607  if (strlen(name)<settings.min_name) {
2608  SockList_AddString(&sl, "failure createplayer Name is too short");
2609  Send_With_Handling(ns, &sl);
2610  SockList_Term(&sl);
2611  return;
2612  }
2613 
2614  if (playername_ok(name) == 0) {
2615  SockList_AddString(&sl, "failure createplayer Player name contains invalid characters");
2616  Send_With_Handling(ns, &sl);
2617  SockList_Term(&sl);
2618  return;
2619  }
2620 
2621  /* 2 characters minimum for password */
2622  if (strlen(password)<2) {
2623  SockList_AddString(&sl, "failure createplayer Password is too short");
2624  Send_With_Handling(ns, &sl);
2625  SockList_Term(&sl);
2626  return;
2627  }
2628 
2630  if (status == 2) {
2631  SockList_AddString(&sl, "failure createplayer Password is too long");
2632  Send_With_Handling(ns, &sl);
2633  SockList_Term(&sl);
2634  return;
2635  }
2636 
2637  /* This is a fairly ugly solution - we're truncating the password.
2638  * however, the password information for characters is really
2639  * a legacy issue - when every character is associated with
2640  * an account, legacy login (character name/password) will get
2641  * removed, at which point the only use for password might be
2642  * to move characters from one account to another, but not sure
2643  * if that is something we want to allow.
2644  */
2645  if (strlen(password)>17)
2646  password[16] = 0;
2647 
2648  /* We just can't call check_name(), since that uses draw_info() to
2649  * report status. We are also more permissive on names, so we use
2650  * account_check_string() - if that is safe for account, also safe
2651  * for player names.
2652  */
2653  if (account_check_string(name)) {
2654  SockList_AddString(&sl, "failure createplayer The name contains illegal characters");
2655  Send_With_Handling(ns, &sl);
2656  SockList_Term(&sl);
2657  return;
2658  }
2659 
2660  /* 1 means no such player, 0 is correct name/password (which in this
2661  * case, is an error), and 2 is incorrect password. Only way we
2662  * go onward is if there is no such player.
2663  */
2664  if (verify_player(name, password) != 1) {
2665  SockList_AddString(&sl, "failure createplayer That name is already in use");
2666  Send_With_Handling(ns, &sl);
2667  SockList_Term(&sl);
2668  return;
2669  }
2670 
2671  /* from a protocol standpoint, accountplay can be used
2672  * before there is a player structure (first login) or after
2673  * (character has logged in and is changing characters).
2674  * Check the sockets for that second case - if so,
2675  * we don't need to make a new player object, etc.
2676  */
2677  for (pl=first_player; pl; pl=pl->next)
2678  if (&pl->socket == ns) {
2679  if (pl->ob->name) {
2680  if (!strcmp(pl->ob->name, name)) {
2681  /* For some reason not only the socket is the same but also
2682  * the player is already playing. If this happens at this
2683  * point let's assume the character never was able to apply
2684  * a bet of reality to make a correct first-time save.
2685  * So, for safety remove it and start over.
2686  */
2687  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2688  object_remove(pl->ob);
2689  }
2690  else {
2691  /* If this is a different player on the same socket, then we
2692  * need to make sure that the old one is not connected to the player
2693  *
2694  * This prevents bizarre scenarios where the player is on the map
2695  * multiple times (from multiple createplayer commands), and
2696  * only one of them is controlled by the player.
2697  */
2698  if (pl->ob->contr == pl) {
2699  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2700  object_remove(pl->ob);
2701  }
2702  }
2703  }
2704  break;
2705  }
2706 
2707  /* In this mode, we have additional data
2708  * Note that because there are a lot of failure cases in here
2709  * (where we end up not creating the new player), the code
2710  * to create the new player is done within this routine
2711  * after all checks pass. Note that all of the checks
2712  * done are done without using the player structure,
2713  * as pl may be null right now.
2714  */
2715  if (ns->login_method >= 2) {
2716  int i, j, stat_total=0;
2717  char *key, *value, *race=NULL, *class=NULL;
2718 
2719  /* By setting this to zero, then we can easily
2720  * check to see if all stats have been set.
2721  */
2722  memset(&new_stats, 0, sizeof(living));
2723 
2724  while (nlen < len) {
2725  i = buf[nlen]; /* Length of this line */
2726  /* Sanity check from client - don't want to loop
2727  * forever if there is a 0 length, and don't
2728  * want to read beyond size of packet.
2729  * Likewise, client should have sent
2730  * the string to us already null terminated,
2731  * but we will just make sure.
2732  */
2733  if ((i == 0) || (nlen + i > len)) break;
2734  buf[nlen + i] = 0;
2735 
2736  /* What we have are a series of lines -
2737  * 'key value' format. Find that space,
2738  * and null it out so we can do strcasecmp.
2739  * If no space, abort processing
2740  */
2741  key = buf + nlen + 1;
2742  value = strchr(key, ' ');
2743  if (!value) break;
2744  *value = 0;
2745  value++;
2746 
2747  if (!strcasecmp(key,"race")) race = value;
2748  else if (!strcasecmp(key,"class")) class = value;
2749  else if (!strcasecmp(key,"starting_map")) {
2751  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2752  SockList_AddString(&sl,
2753  "failure createplayer Invalid starting map");
2754  Send_With_Handling(ns, &sl);
2755  SockList_Term(&sl);
2756  return;
2757  }
2758  }
2759  else if (!strcasecmp(key,"choice")) {
2760  /* In general, MAX_CHOICES should be large enough
2761  * to always handle the choices from the client - of
2762  * course, the client could be broken and send us many
2763  * more choices than we should have, so handle that.
2764  */
2765  if (choice_num == MAX_CHOICES) {
2766  LOG(llevError,
2767  "Number of choices receive exceed max value: %d>%d\n",
2768  choice_num, MAX_CHOICES);
2769  } else {
2770  choices[choice_num] = value;
2771  choice_num++;
2772  }
2773  }
2774  else {
2775  /* Do stat processing here */
2776  for (j=0; j < NUM_STATS; j++) {
2777  if (!strcasecmp(key,short_stat_name[j])) {
2778  int val = atoi(value);
2779 
2780  set_attr_value(&new_stats, j, val);
2781  break;
2782  }
2783  }
2784  if (j >= NUM_STATS) {
2785  /* Bad clients could do this - we should at least report
2786  * it, and useful when trying to add new parameters.
2787  */
2788  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2789  }
2790  }
2791  nlen += i + 1;
2792  }
2793  /* Do some sanity checking now. But checking the stat
2794  * values here, we will catch any 0 values since we do
2795  * a memset above. A properly behaving client should
2796  * never do any of these things, but we do not presume
2797  * clients will behave properly.
2798  */
2799  for (j=0; j<NUM_STATS; j++) {
2800  int val = get_attr_value(&new_stats, j);
2801 
2802  stat_total += val;
2803  if (val > settings.starting_stat_max ||
2804  val < settings.starting_stat_min) {
2805  SockList_AddPrintf(&sl,
2806  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2808  Send_With_Handling(ns, &sl);
2809  SockList_Term(&sl);
2810  return;
2811  }
2812  }
2813  if (stat_total > settings.starting_stat_points) {
2814  SockList_AddPrintf(&sl,
2815  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2816  stat_total, settings.starting_stat_points);
2817  Send_With_Handling(ns, &sl);
2818  SockList_Term(&sl);
2819  return;
2820  }
2821 
2822  if (race)
2823  race_a = try_find_archetype(race);
2824 
2825  if (class)
2826  class_a = try_find_archetype(class);
2827 
2828  /* This should never happen with a properly behaving client, so the error message
2829  * doesn't have to be that great.
2830  */
2831  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2832  SockList_AddString(&sl,
2833  "failure createplayer Invalid or unknown race or class");
2834  Send_With_Handling(ns, &sl);
2835  SockList_Term(&sl);
2836  return;
2837  }
2838 
2839  /* At current time, only way this can fail is if the adjusted
2840  * stat is less than 1.
2841  */
2842  if (check_race_and_class(&new_stats, race_a, class_a)) {
2843  SockList_AddString(&sl,
2844  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2845  Send_With_Handling(ns, &sl);
2846  SockList_Term(&sl);
2847  return;
2848  }
2849 
2850  if (!pl)
2852  // If we already have a player, we a replaying on the same connection.
2853  // Since add_player normally sets ns->status, we still need that to happen.
2854  else
2855  ns->status = Ns_Avail;
2856 
2857  // We need to copy the name in before apply_race_and_class() because it
2858  // tells the client our character name. If we don't update it, they get the old one.
2859  FREE_AND_COPY(pl->ob->name, name);
2860 
2861  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2862 
2863  } else {
2864  /* In thise case, old login method */
2865  if (!pl)
2866  pl = add_player(ns, ADD_PLAYER_NEW);
2867  // If we already have a player, we a replaying on the same connection.
2868  // Since add_player normally sets ns->status, we still need that to happen.
2869  else
2870  ns->status = Ns_Avail;
2871 
2872  // Make sure to do this on both code branches.
2873  FREE_AND_COPY(pl->ob->name, name);
2874 /* already done by add_player
2875  roll_again(pl->ob);
2876  pl->state = ST_ROLL_STAT;
2877  set_first_map(pl->ob);*/
2878  }
2879 
2880  /* add_player does a lot of the work, but there are a few
2881  * things we need to update, like starting name and
2882  * password.
2883  * This is done before processing in login_method>2.
2884  * The character creation process it does when
2885  * applying the race/class will use this
2886  * name information.
2887  */
2889  pl->name_changed = 1;
2890  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
2891 
2892  SockList_AddString(&sl, "addme_success");
2893  Send_With_Handling(ns, &sl);
2894  SockList_Term(&sl);
2895 
2896  if (ns->login_method >= 2) {
2897  /* The client could have provided us a map - if so, map will be set
2898  * and we don't want to overwrite it
2899  */
2900  if (!map)
2902  assert(map); // Existence checked in init_dynamic()
2903 
2904  enter_exit(pl->ob, &map->clone);
2905 
2906  if (pl->ob->map == NULL) {
2907  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
2908  abort();
2909  }
2910 
2911  /* copy information to bed of reality information, in case the player dies */
2912  safe_strncpy(pl->savebed_map, pl->ob->map->path, sizeof(pl->savebed_map));
2913  pl->bed_x = pl->ob->x;
2914  pl->bed_y = pl->ob->y;
2915 
2917  }
2918 
2919  /* We insert any objects after we have put the player on the map -
2920  * this makes things safer, as certain objects may expect a normal
2921  * environment. Note that choice_num will only be set in the
2922  * loginmethod > 2, which also checks (and errors out) if the
2923  * race/class is not set, which is why explicit checking for
2924  * those is not need.
2925  */
2926  for (i=0; i < choice_num; i++) {
2927  char *choiceval, *cp;
2928  const char *value;
2929  archetype *arch;
2930  object *op;
2931 
2932  choiceval = strchr(choices[i], ' ');
2933  if (!choiceval) {
2934  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
2935  continue;
2936  }
2937  *choiceval=0;
2938  choiceval++;
2939  value = object_get_value(&race_a->clone, choices[i]);
2940  if (!value)
2941  value = object_get_value(&class_a->clone, choices[i]);
2942 
2943  if (!value) {
2944  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
2945  continue;
2946  }
2947  cp = strstr(value, choiceval);
2948  if (!cp) {
2949  LOG(llevError, "Choice value not found in archetype: %s %s\n",
2950  choices[i], choiceval);
2951  continue;
2952  }
2953 
2954  /* Check to make sure that the matched string is an entire word,
2955  * and not a substring (eg, valid choice being great_sword but
2956  * we just get sword) - the space after the match should either be a
2957  * space or null, and space before match should also be a space
2958  * or the start of the string.
2959  */
2960  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
2961  (cp != value) && (*(cp-1) != ' ')) {
2962 
2963  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
2964  choiceval, value);
2965  continue;
2966  }
2967  arch = try_find_archetype(choiceval);
2968  if (!arch) {
2969  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
2970  continue;
2971  }
2972  op = arch_to_object(arch);
2973  op = object_insert_in_ob(op, pl->ob);
2975  ob_apply(op, pl->ob, 0);
2976  }
2977 
2978  LOG(llevInfo, "new character %s from %s\n", pl->ob->name, pl->ob->contr->socket.host);
2981  "%s has entered the game.", pl->ob->name);
2982 }
2983 
2994 void account_password(char *buf, int len, socket_struct *ns) {
2995  char old[MAX_BUF], change[MAX_BUF];
2996  int status;
2997  SockList sl;
2998 
2999  if (len <= 0 || !buf) {
3000  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
3001  return;
3002  }
3003 
3004  SockList_Init(&sl);
3005 
3006  if (ns->account_name == NULL) {
3007  SockList_AddString(&sl, "failure accountpw Not logged in");
3008  Send_With_Handling(ns, &sl);
3009  SockList_Term(&sl);
3010  return;
3011  }
3012 
3013  status = decode_name_password(buf, &len, old, change);
3014  if (status == 1) {
3015  SockList_AddString(&sl, "failure accountpw Old password is too long");
3016  Send_With_Handling(ns, &sl);
3017  SockList_Term(&sl);
3018  return;
3019  }
3020  if (status == 2) {
3021  SockList_AddString(&sl, "failure accountpw New password is too long");
3022  Send_With_Handling(ns, &sl);
3023  SockList_Term(&sl);
3024  return;
3025  }
3026  /*The minimum length isn't exactly required, but in the current implementation,
3027  * client will send the same password for character for which there is a
3028  * 2 character minimum size. Thus an account with a one character password
3029  * won't be able to create a character. */
3030  if (strlen(change)<2) {
3031  SockList_AddString(&sl, "failure accountpw New password is too short");
3032  Send_With_Handling(ns, &sl);
3033  SockList_Term(&sl);
3034  return;
3035  }
3036 
3037  status = account_check_string(change);
3038  if (status == 1) {
3039  SockList_AddString(&sl,
3040  "failure accountpw That password contains invalid characters.");
3041  Send_With_Handling(ns, &sl);
3042  SockList_Term(&sl);
3043  return;
3044  }
3045 
3046  if (status == 2) {
3047  SockList_AddString(&sl,
3048  "failure accountpw That password is too long");
3049  Send_With_Handling(ns, &sl);
3050  SockList_Term(&sl);
3051  return;
3052  }
3053 
3054  status = account_change_password(ns->account_name, old, change);
3055  if (status != 0) {
3056  const char *error;
3057 
3058  if (status == 1) {
3059  error = "failure accountpw Illegal characters present";
3060  } else if (status == 2) {
3061  error = "failure accountpw Invalid account";
3062  } else {
3063  error = "failure accountpw Incorrect current password";
3064  }
3065 
3066  SockList_AddString(&sl, error);
3067  Send_With_Handling(ns, &sl);
3068  SockList_Term(&sl);
3069  return;
3070  }
3071 
3072  /* If we got here, we passed all checks, and password was changed */
3074 }
find_player_socket
player * find_player_socket(const socket_struct *ns)
Definition: player.c:120
ADD_PLAYER_NO_STATS_ROLL
#define ADD_PLAYER_NO_STATS_ROLL
Definition: player.h:232
obj::weapon_speed
float weapon_speed
Definition: object.h:332
SF_FIREON
#define SF_FIREON
Definition: newclient.h:189
CF_BLIND
#define CF_BLIND
Definition: newclient.h:200
Face::name
sstring name
Definition: face.h:19
socket_struct::account_chars
Account_Char * account_chars
Definition: newserver.h:127
CLASS
@ CLASS
Definition: object.h:138
CS_STAT_RES_DEPLETE
#define CS_STAT_RES_DEPLETE
Definition: newclient.h:162
Face
Definition: face.h:14
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.c:2362
map2_delete_layer
static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns)
Definition: request.c:1192
MAP_CLIENT_X
#define MAP_CLIENT_X
Definition: config.h:237
CF_STEALTHY
#define CF_STEALTHY
Definition: newclient.h:205
socket_struct::tick
uint32_t tick
Definition: newserver.h:106
PLAYER
@ PLAYER
Definition: object.h:107
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:124
global.h
ANIM_SYNC
#define ANIM_SYNC
Definition: newclient.h:348
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
socket_struct::sc_version
uint32_t sc_version
Definition: newserver.h:113
ST_CHANGE_PASSWORD_OLD
#define ST_CHANGE_PASSWORD_OLD
Definition: define.h:550
liv::dam
int16_t dam
Definition: living.h:46
CS_STAT_RACE_CON
#define CS_STAT_RACE_CON
Definition: newclient.h:121
print_ext_msg
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Definition: info.c:62
banquet.l
l
Definition: banquet.py:164
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
pl::count
uint32_t count
Definition: player.h:109
CS_STAT_GRACE
#define CS_STAT_GRACE
Definition: newclient.h:109
object_remove
void object_remove(object *op)
Definition: object.c:1806
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
MAP
@ MAP
Definition: object.h:125
pl::golem_count
uint32_t golem_count
Definition: player.h:106
is_perfect
static uint8_t is_perfect(const player *pl)
Definition: request.c:729
socket_struct::heartbeat
bool heartbeat
Definition: newserver.h:112
SockList_AddInt64
void SockList_AddInt64(SockList *sl, uint64_t data)
Definition: lowlevel.c:137
pl::transport
object * transport
Definition: player.h:199
account_char_struct::isDead
uint8_t isDead
Definition: account_char.h:20
obj::face
const Face * face
Definition: object.h:334
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Definition: define.h:547
ACL_FACE_NUM
#define ACL_FACE_NUM
Definition: newclient.h:224
FLAG_CONFUSED
#define FLAG_CONFUSED
Definition: define.h:311
CAN_PROBE
static bool CAN_PROBE(const object *ob)
Definition: object.h:603
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:241
reply_cmd
void reply_cmd(char *buf, int len, player *pl)
Definition: request.c:522
CS_STAT_APPLIED_WIS
#define CS_STAT_APPLIED_WIS
Definition: newclient.h:133
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:496
Map
Definition: newserver.h:48
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
client_spell
Definition: player.h:74
CS_STAT_RES_FEAR
#define CS_STAT_RES_FEAR
Definition: newclient.h:161
account_login_cmd
void account_login_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:2110
CS_STAT_DAM
#define CS_STAT_DAM
Definition: newclient.h:101
strdup_local
#define strdup_local
Definition: compat.h:29
ACL_RACE
#define ACL_RACE
Definition: newclient.h:219
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
CS_STAT_RES_FIRE
#define CS_STAT_RES_FIRE
Definition: newclient.h:150
obj::count
tag_t count
Definition: object.h:300
account_play_cmd
void account_play_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:2480
obj::map
struct mapdef * map
Definition: object.h:298
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
newhash
char const * newhash(char const *password)
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
archt::tail_x
int8_t tail_x
Definition: object.h:473
liv::maxgrace
int16_t maxgrace
Definition: living.h:45
socket_struct::sound
uint32_t sound
Definition: newserver.h:111
pl::peaceful
uint32_t peaceful
Definition: player.h:133
pl::last_race_stats
living last_race_stats
Definition: player.h:155
CS_STAT_APPLIED_POW
#define CS_STAT_APPLIED_POW
Definition: newclient.h:137
liv::wc
int8_t wc
Definition: living.h:37
CS_STAT_HP
#define CS_STAT_HP
Definition: newclient.h:87
socket_struct
Definition: newserver.h:89
account_new_cmd
void account_new_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:2237
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
get_skill_client_code
int get_skill_client_code(const char *skill_name)
Definition: skill_util.c:107
account_char_struct::level
uint8_t level
Definition: account_char.h:16
ST_GET_NAME
#define ST_GET_NAME
Definition: define.h:546
liv::Str
int8_t Str
Definition: living.h:36
MAX_NUM_LOOK_OBJECTS
#define MAX_NUM_LOOK_OBJECTS
Definition: newserver.h:28
socket_struct::num_look_objects
uint8_t num_look_objects
Definition: newserver.h:122
account_char_struct::map
sstring map
Definition: account_char.h:19
command_execute
void command_execute(object *pl, char *command)
Definition: commands.cpp:412
object_find_by_arch_name
object * object_find_by_arch_name(const object *who, const char *name)
Definition: object.c:4260
obj::path_attuned
uint32_t path_attuned
Definition: object.h:346
liv::maxhp
int16_t maxhp
Definition: living.h:41
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:154
pl::socket
socket_struct socket
Definition: player.h:94
ring_occidental_mages.rest
rest
Definition: ring_occidental_mages.py:16
account_get_logged_in_player
player * account_get_logged_in_player(const char *name)
Definition: account.c:614
MAX_TIME
#define MAX_TIME
Definition: config.h:246
CS_STAT_SPELL_DENY
#define CS_STAT_SPELL_DENY
Definition: newclient.h:116
account_get_players_for_account
char ** account_get_players_for_account(const char *account_name)
Definition: account.c:525
pl
Definition: player.h:92
accounts_save
void accounts_save(void)
Definition: account.c:260
CS_STAT_WIS
#define CS_STAT_WIS
Definition: newclient.h:93
pl::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:163
pl::name_changed
uint32_t name_changed
Definition: player.h:132
CS_STAT_SPEED
#define CS_STAT_SPEED
Definition: newclient.h:103
socket_struct::extended_stats
uint32_t extended_stats
Definition: newserver.h:109
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:92
guildjoin.ob
ob
Definition: guildjoin.py:42
Settings::min_name
uint8_t min_name
Definition: global.h:327
SK_PRAYING
@ SK_PRAYING
Definition: skills.h:49
CS_STAT_MAXSP
#define CS_STAT_MAXSP
Definition: newclient.h:90
liv::hp
int16_t hp
Definition: living.h:40
pl::last_golem_hp
int16_t last_golem_hp
Definition: player.h:160
send_tick
void send_tick(player *pl)
Definition: request.c:1913
pl::mode
uint32_t mode
Definition: player.h:110
mapdef::in_memory
uint32_t in_memory
Definition: map.h:344
MIN
#define MIN(x, y)
Definition: compat.h:21
CS_STAT_BASE_DEX
#define CS_STAT_BASE_DEX
Definition: newclient.h:127
MAX_HEAD_POS
#define MAX_HEAD_POS
Definition: request.c:1011
CS_STAT_RES_MAG
#define CS_STAT_RES_MAG
Definition: newclient.h:149
pl::ob
object * ob
Definition: player.h:162
MAP_LAYERS
#define MAP_LAYERS
Definition: map.h:32
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.c:1854
Settings::starting_stat_min
uint8_t starting_stat_min
Definition: global.h:316
archt::tail_y
int8_t tail_y
Definition: object.h:473
SKILL
@ SKILL
Definition: object.h:143
client_spell::last_sp
int16_t last_sp
Definition: player.h:76
socket_struct::is_bot
uint32_t is_bot
Definition: newserver.h:107
get_player
player * get_player(player *p)
Definition: player.c:282
CS_STAT_SP
#define CS_STAT_SP
Definition: newclient.h:89
SP_CREATE_FOOD
#define SP_CREATE_FOOD
Definition: spells.h:96
ACL_NAME
#define ACL_NAME
Definition: newclient.h:217
CS_STAT_RES_HOLYWORD
#define CS_STAT_RES_HOLYWORD
Definition: newclient.h:164
account_char_struct::name
sstring name
Definition: account_char.h:13
obj::path_denied
uint32_t path_denied
Definition: object.h:348
Ice.tmp
int tmp
Definition: Ice.py:207
CS_STAT_GOLEM_HP
#define CS_STAT_GOLEM_HP
Definition: newclient.h:138
CS_STAT_RES_CONF
#define CS_STAT_RES_CONF
Definition: newclient.h:153
NDI_RED
#define NDI_RED
Definition: newclient.h:245
MAX_HEAD_OFFSET
#define MAX_HEAD_OFFSET
Definition: newserver.h:42
account_link
int account_link(const char *account_name, const char *player_name)
Definition: account.c:447
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
socket_struct::inbuf
SockList inbuf
Definition: newserver.h:99
CS_STAT_TURN_UNDEAD
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:160
ACL_CLASS
#define ACL_CLASS
Definition: newclient.h:218
SP_CREATE_MISSILE
#define SP_CREATE_MISSILE
Definition: spells.h:113
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.c:101
move_cmd
void move_cmd(char *buf, int len, player *pl)
Definition: request.c:641
CF_NOT_PERFECT
#define CF_NOT_PERFECT
Definition: newclient.h:203
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
obj::msg
sstring msg
Definition: object.h:323
decode_name_password
static int decode_name_password(const char *buf, int *len, char *name, char *password)
Definition: request.c:2074
receive_play_again
void receive_play_again(object *op, char key)
Definition: player.c:937
pl::last_resist
int16_t last_resist[NROFATTACKS]
Definition: player.h:159
draw_client_map
void draw_client_map(object *pl)
Definition: request.c:1552
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:529
CS_STAT_EXP64
#define CS_STAT_EXP64
Definition: newclient.h:113
FLAG_PROBE
#define FLAG_PROBE
Definition: define.h:257
pl::last_weapon_sp
float last_weapon_sp
Definition: player.h:142
range_golem
@ range_golem
Definition: player.h:21
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:71
CS_STAT_CHARACTER_FLAGS
#define CS_STAT_CHARACTER_FLAGS
Definition: newclient.h:140
socket_struct::map_scroll_x
int8_t map_scroll_x
Definition: newserver.h:94
account_get_additional_chars
linked_char * account_get_additional_chars(const char *account_name, const Account_Char *chars, int *count)
Definition: account.c:559
UPD_SP_MANA
#define UPD_SP_MANA
Definition: newclient.h:324
is_valid_faceset
int is_valid_faceset(int fsn)
Definition: image.c:116
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
account_char_struct
Definition: account_char.h:12
send_account_players
void send_account_players(socket_struct *ns)
Definition: request.c:1981
pl::last_speed
float last_speed
Definition: player.h:158
obj::randomitems
struct treasureliststruct * randomitems
Definition: object.h:389
key_confirm_quit
void key_confirm_quit(object *op, char key)
Definition: player.c:1568
CS_STAT_APPLIED_DEX
#define CS_STAT_APPLIED_DEX
Definition: newclient.h:134
add_player
player * add_player(socket_struct *ns, int flags)
Definition: player.c:455
check_probe
static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer)
Definition: request.c:1217
POISONING
@ POISONING
Definition: object.h:218
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:404
CS_STAT_RACE_STR
#define CS_STAT_RACE_STR
Definition: newclient.h:117
CS_STAT_GOLEM_MAXHP
#define CS_STAT_GOLEM_MAXHP
Definition: newclient.h:139
spell_client_use
static int spell_client_use(const object *spell)
Definition: request.c:1760
ob_apply
method_ret ob_apply(object *op, object *applier, int aflags)
Definition: ob_methods.c:44
SND_EFFECTS
#define SND_EFFECTS
Definition: sounds.h:12
ACL_MAP
#define ACL_MAP
Definition: newclient.h:223
linked_char
Definition: global.h:86
archt
Definition: object.h:468
settings
struct Settings settings
Definition: init.c:39
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
Ns_Dead
@ Ns_Dead
Definition: newserver.h:67
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:243
GetShort_String
short GetShort_String(const unsigned char *data)
Definition: lowlevel.c:255
pl::levsp
int8_t levsp[11]
Definition: player.h:172
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4354
SP_SUMMON_MONSTER
#define SP_SUMMON_MONSTER
Definition: spells.h:101
UPD_SP_DAMAGE
#define UPD_SP_DAMAGE
Definition: newclient.h:326
esrv_remove_spell
void esrv_remove_spell(player *pl, object *spell)
Definition: request.c:1717
pl::item_power
int16_t item_power
Definition: player.h:117
m
static event_registration m
Definition: citylife.cpp:425
liv::maxsp
int16_t maxsp
Definition: living.h:43
socket_struct::mapy
uint8_t mapy
Definition: newserver.h:116
pl::savebed_map
char savebed_map[MAX_BUF]
Definition: player.h:97
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:131
liv::exp
int64_t exp
Definition: living.h:47
socket_struct::stats
struct statsinfo stats
Definition: newserver.h:98
Ns_Avail
@ Ns_Avail
Definition: newserver.h:65
CS_STAT_RACE_DEX
#define CS_STAT_RACE_DEX
Definition: newclient.h:120
CS_STAT_ARMOUR
#define CS_STAT_ARMOUR
Definition: newclient.h:102
positioning_system.coord
coord
Definition: positioning_system.py:26
pl::next
struct pl * next
Definition: player.h:93
item.q
q
Definition: item.py:32
set_title
void set_title(const object *pl, char *buf, size_t len)
Definition: info.c:333
map_cell_struct
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:115
disinfect.map
map
Definition: disinfect.py:4
CS_STAT_RACE_CHA
#define CS_STAT_RACE_CHA
Definition: newclient.h:122
P_NEW_MAP
#define P_NEW_MAP
Definition: map.h:251
send_extra_stats
static void send_extra_stats(SockList *sl, player *pl)
Definition: request.c:744
obj::name
sstring name
Definition: object.h:312
CS_STAT_LEVEL
#define CS_STAT_LEVEL
Definition: newclient.h:98
esrv_send_animation
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Definition: request.c:972
pl::state
uint8_t state
Definition: player.h:118
account_add_player_cmd
void account_add_player_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:2351
CS_STAT_CON
#define CS_STAT_CON
Definition: newclient.h:95
playername_ok
int playername_ok(const char *cp)
Definition: player.c:254
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.c:71
client_spell::last_dam
int16_t last_dam
Definition: player.h:78
ACL_PARTY
#define ACL_PARTY
Definition: newclient.h:222
CS_STAT_CHA
#define CS_STAT_CHA
Definition: newclient.h:96
CS_STAT_APPLIED_CHA
#define CS_STAT_APPLIED_CHA
Definition: newclient.h:136
ST_CHANGE_PASSWORD_CONFIRM
#define ST_CHANGE_PASSWORD_CONFIRM
Definition: define.h:552
CS_STAT_RES_SLOW
#define CS_STAT_RES_SLOW
Definition: newclient.h:158
socket_struct::facecache
uint32_t facecache
Definition: newserver.h:102
check_race_and_class
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
Definition: player.c:1405
check_login
void check_login(object *op, const char *password)
Definition: login.c:519
pl::last_orig_stats
living last_orig_stats
Definition: player.h:154
CS_STAT_BASE_POW
#define CS_STAT_BASE_POW
Definition: newclient.h:130
send_query
void send_query(socket_struct *ns, uint8_t flags, const char *text)
Definition: request.c:679
account_get_account_for_char
const char * account_get_account_for_char(const char *charname)
Definition: account.c:589
obj::path_repelled
uint32_t path_repelled
Definition: object.h:347
CS_STAT_RES_PHYS
#define CS_STAT_RES_PHYS
Definition: newclient.h:148
Settings::account_block_create
uint8_t account_block_create
Definition: global.h:324
ST_PLAY_AGAIN
#define ST_PLAY_AGAIN
Definition: define.h:542
CS_STAT_GOD_NAME
#define CS_STAT_GOD_NAME
Definition: newclient.h:141
Face::number
uint16_t number
Definition: face.h:15
AddIfFloat
#define AddIfFloat(Old, New, sl, Type)
Definition: request.c:709
ADD_PLAYER_NO_MAP
#define ADD_PLAYER_NO_MAP
Definition: player.h:231
map_cell_struct::darkness
int darkness
Definition: newserver.h:33
liv::Cha
int8_t Cha
Definition: living.h:36
account_remove_player
int account_remove_player(const char *account_name, const char *player_name)
Definition: account.c:479
obj::name_pl
sstring name_pl
Definition: object.h:316
HEAD
#define HEAD(op)
Definition: object.h:594
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.c:113
AddIfString
#define AddIfString(Old, New, sl, Type)
Definition: request.c:716
ANIM_RANDOM
#define ANIM_RANDOM
Definition: newclient.h:347
obj::speed_left
float speed_left
Definition: object.h:331
CS_STAT_BASE_CHA
#define CS_STAT_BASE_CHA
Definition: newclient.h:129
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:103
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
socket_struct::lastmap
struct Map lastmap
Definition: newserver.h:93
CF_POISONED
#define CF_POISONED
Definition: newclient.h:199
MAP2_LAYER_START
#define MAP2_LAYER_START
Definition: newclient.h:53
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
CS_STAT_APPLIED_STR
#define CS_STAT_APPLIED_STR
Definition: newclient.h:131
socket_struct::host
char * host
Definition: newserver.h:100
pl::last_path_attuned
uint32_t last_path_attuned
Definition: player.h:146
object_present_in_ob
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.c:3118
CS_STAT_RACE_POW
#define CS_STAT_RACE_POW
Definition: newclient.h:123
GET_MAP_FACE_OBJ
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Definition: map.h:185
socket_struct::account_name
char * account_name
Definition: newserver.h:126
CS_STAT_AC
#define CS_STAT_AC
Definition: newclient.h:100
pl::last_character_flags
uint32_t last_character_flags
Definition: player.h:149
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:202
client_spell::last_grace
int16_t last_grace
Definition: player.h:77
first_player
EXTERN player * first_player
Definition: global.h:115
CS_STAT_OVERLOAD
#define CS_STAT_OVERLOAD
Definition: newclient.h:142
obj::x
int16_t x
Definition: object.h:328
version_cmd
void version_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:584
CS_STAT_WEAP_SP
#define CS_STAT_WEAP_SP
Definition: newclient.h:105
socket_struct::monitor_spells
uint32_t monitor_spells
Definition: newserver.h:110
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
CS_STAT_APPLIED_CON
#define CS_STAT_APPLIED_CON
Definition: newclient.h:135
MAP_LAYER_LIVING1
#define MAP_LAYER_LIVING1
Definition: map.h:46
pl::levgrace
int8_t levgrace[11]
Definition: player.h:173
navar-midane_time.data
data
Definition: navar-midane_time.py:11
add_me_cmd
void add_me_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:349
send_smooth
static void send_smooth(socket_struct *ns, const Face *face)
Definition: request.c:393
skill_names
const char * skill_names[MAX_SKILLS]
Definition: skill_util.c:59
map_cell_struct::faces
uint16_t faces[MAP_LAYERS]
Definition: newserver.h:32
socket_struct::faceset
uint8_t faceset
Definition: newserver.h:117
CS_STAT_RES_GHOSTHIT
#define CS_STAT_RES_GHOSTHIT
Definition: newclient.h:156
linked_char::next
struct linked_char * next
Definition: global.h:88
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
Definition: newclient.h:172
obj::other_arch
struct archt * other_arch
Definition: object.h:417
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:675
account_char_struct::race
sstring race
Definition: account_char.h:15
account_new
int account_new(const char *account_name, const char *account_password)
Definition: account.c:401
annotate_ob
static int annotate_ob(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer)
Definition: request.c:1285
ST_CHANGE_PASSWORD_NEW
#define ST_CHANGE_PASSWORD_NEW
Definition: define.h:551
pl::last_character_load
float last_character_load
Definition: player.h:123
CS_STAT_RES_BLIND
#define CS_STAT_RES_BLIND
Definition: newclient.h:165
sstring
const typedef char * sstring
Definition: global.h:40
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
disinfect.count
int count
Definition: disinfect.py:7
obj::speed
float speed
Definition: object.h:330
CF_DISEASED
#define CF_DISEASED
Definition: newclient.h:202
pl::run_on
uint32_t run_on
Definition: player.h:130
MAP2_TYPE_DARKNESS
#define MAP2_TYPE_DARKNESS
Definition: newclient.h:43
socket_struct::map_scroll_y
int8_t map_scroll_y
Definition: newserver.h:94
obj::env
struct obj * env
Definition: object.h:294
account_char_struct::next
struct account_char_struct * next
Definition: account_char.h:21
liv::Con
int8_t Con
Definition: living.h:36
statsinfo::title
char * title
Definition: newserver.h:57
sproto.h
liv::food
int32_t food
Definition: living.h:48
CS_STAT_RACE_INT
#define CS_STAT_RACE_INT
Definition: newclient.h:118
SND_MUTE
#define SND_MUTE
Definition: sounds.h:14
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
pl::last_golem_maxhp
int16_t last_golem_maxhp
Definition: player.h:161
draw_client_map2
static void draw_client_map2(object *pl)
Definition: request.c:1361
VERSION_SC
#define VERSION_SC
Definition: newserver.h:150
animate.anim
string anim
Definition: animate.py:20
get_face_by_id
const Face * get_face_by_id(uint16_t id)
Definition: assets.cpp:339
devourers.command
command
Definition: devourers.py:16
pl::last_path_denied
uint32_t last_path_denied
Definition: player.h:148
mapdef
Definition: map.h:324
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.c:235
get_client_spell_state
client_spell * get_client_spell_state(player *pl, object *spell)
Definition: player.c:147
account_is_logged_in
int account_is_logged_in(const char *name)
Definition: account.c:657
liv::Int
int8_t Int
Definition: living.h:36
MAP_TYPE_CHOICE
#define MAP_TYPE_CHOICE
Definition: map.h:59
liv
Definition: living.h:35
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.c:52
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
SockList::len
size_t len
Definition: newclient.h:686
CS_STAT_BASE_WIS
#define CS_STAT_BASE_WIS
Definition: newclient.h:126
MAX_CHOICES
#define MAX_CHOICES
Definition: request.c:2567
CS_STAT_FOOD
#define CS_STAT_FOOD
Definition: newclient.h:104
pl::bed_x
int16_t bed_x
Definition: player.h:98
append_spell
static void append_spell(player *pl, SockList *sl, object *spell)
Definition: request.c:1784
socket_struct::cs_version
uint32_t cs_version
Definition: newserver.h:113
guild_entry.text
text
Definition: guild_entry.py:44
FIF
#define FIF(F, C)
free_charlinks
void free_charlinks(linked_char *lc)
Definition: utils.c:623
account_char_remove
Account_Char * account_char_remove(Account_Char *chars, const char *pl_name)
Definition: account_char.c:298
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
account_char_save
void account_char_save(const char *account, Account_Char *chars)
Definition: account_char.c:146
CS_STAT_WEIGHT_LIM
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:112
MAX_BUF
#define MAX_BUF
Definition: define.h:35
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.c:1740
Ns_Add
@ Ns_Add
Definition: newserver.h:66
CS_STAT_ITEM_POWER
#define CS_STAT_ITEM_POWER
Definition: newclient.h:143
CS_STAT_RES_POISON
#define CS_STAT_RES_POISON
Definition: newclient.h:157
receive_player_name
void receive_player_name(object *op, const char *name)
Definition: c_misc.c:1929
atnr_cs_stat
static const short atnr_cs_stat[NROFATTACKS]
Definition: request.c:75
CS_STAT_WC
#define CS_STAT_WC
Definition: newclient.h:99
ADD_PLAYER_NEW
#define ADD_PLAYER_NEW
Definition: player.h:230
pl::levhp
int8_t levhp[11]
Definition: player.h:171
pl::last_weight
int32_t last_weight
Definition: player.h:144
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.c:62
account_char_free
void account_char_free(Account_Char *chars)
Definition: account_char.c:334
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)
Definition: request.c:1047
probe
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Definition: spell_effect.c:707
FLAG_CLIENT_SENT
#define FLAG_CLIENT_SENT
Definition: define.h:346
CS_STAT_MAXGRACE
#define CS_STAT_MAXGRACE
Definition: newclient.h:110
key_roll_stat
void key_roll_stat(object *op, char key)
Definition: player.c:1189
MAP2_TYPE_CLEAR
#define MAP2_TYPE_CLEAR
Definition: newclient.h:42
FLAG_CLIENT_ANIM_SYNC
#define FLAG_CLIENT_ANIM_SYNC
Definition: define.h:240
Settings::starting_stat_points
uint8_t starting_stat_points
Definition: global.h:318
pl::spell_state
client_spell * spell_state
Definition: player.h:200
obj::y
int16_t y
Definition: object.h:328
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
obj::arch
struct archt * arch
Definition: object.h:416
MAP2_COORD_ENCODE
#define MAP2_COORD_ENCODE(x, y, flags)
Definition: newclient.h:64
Settings
Definition: global.h:237
pl::bed_y
int16_t bed_y
Definition: player.h:98
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:91
apply_race_and_class
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
Definition: player.c:1455
CS_STAT_BASE_INT
#define CS_STAT_BASE_INT
Definition: newclient.h:125
animations_struct
Definition: face.h:25
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
pl::last_applied_stats
living last_applied_stats
Definition: player.h:157
account_get_logged_in_init_socket
socket_struct * account_get_logged_in_init_socket(const char *name)
Definition: account.c:635
account_password
void account_password(char *buf, int len, socket_struct *ns)
Definition: request.c:2994
ST_CHANGE_CLASS
#define ST_CHANGE_CLASS
Definition: define.h:544
CS_STAT_SPELL_ATTUNE
#define CS_STAT_SPELL_ATTUNE
Definition: newclient.h:114
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
llevInfo
@ llevInfo
Definition: logger.h:12
obj::type
uint8_t type
Definition: object.h:341
SockList_AddData
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:164
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
pticks
uint32_t pticks
Definition: time.c:45
esrv_move_object
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.c:863
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
obj::stats
living stats
Definition: object.h:371
SP_level_dam_adjust
int SP_level_dam_adjust(const object *caster, const object *spob)
Definition: spell_util.c:286
socket_struct::want_pickup
uint32_t want_pickup
Definition: newserver.h:108
ask_smooth_cmd
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:437
archt::clone
object clone
Definition: object.h:472
add_char_field
static void add_char_field(SockList *sl, int type, const char *data)
Definition: request.c:1947
obj::contr
struct pl * contr
Definition: object.h:277
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
Definition: define.h:548
liv::Dex
int8_t Dex
Definition: living.h:36
pl::fire_on
uint32_t fire_on
Definition: player.h:129
item
Definition: item.py:1
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
DISEASE
@ DISEASE
Definition: object.h:244
pl::password
char password[16]
Definition: player.h:178
pl::last_skill_exp
int64_t last_skill_exp[MAX_SKILLS]
Definition: player.h:140
P_NEED_UPDATE
#define P_NEED_UPDATE
Definition: map.h:240
newserver.h
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.c:721
SP_RUNE
#define SP_RUNE
Definition: spells.h:76
BEAT_INTERVAL
#define BEAT_INTERVAL
Definition: config.h:628
liv::Wis
int8_t Wis
Definition: living.h:36
SND_MUSIC
#define SND_MUSIC
Definition: sounds.h:13
liv::grace
int16_t grace
Definition: living.h:44
esrv_update_stats
void esrv_update_stats(player *pl)
Definition: request.c:800
give.op
op
Definition: give.py:33
NDI_ALL
#define NDI_ALL
Definition: newclient.h:263
create_player_cmd
void create_player_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:2574
socket_struct::status
enum Sock_Status status
Definition: newserver.h:90
autojail.value
value
Definition: autojail.py:6
account_char_struct::party
sstring party
Definition: account_char.h:18
CS_STAT_RES_COLD
#define CS_STAT_RES_COLD
Definition: newclient.h:152
FLAG_AUTO_APPLY
#define FLAG_AUTO_APPLY
Definition: define.h:250
account_char_struct::character_class
sstring character_class
Definition: account_char.h:14
pl::do_los
uint32_t do_los
Definition: player.h:128
pl::last_weight_limit
int32_t last_weight_limit
Definition: player.h:145
pl::last_skill_ob
object * last_skill_ob[MAX_SKILLS]
Definition: player.h:139
statsinfo::god
char * god
Definition: newserver.h:57
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:176
receive_player_password
void receive_player_password(object *op, const char *password)
Definition: c_misc.c:1949
esrv_draw_look
void esrv_draw_look(object *pl)
Definition: item.c:192
obj::casting_time
int16_t casting_time
Definition: object.h:406
diamondslots.y
y
Definition: diamondslots.py:16
Map::cells
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:49
CF_CONFUSED
#define CF_CONFUSED
Definition: newclient.h:198
buf
StringBuffer * buf
Definition: readable.c:1606
account_char_load
Account_Char * account_char_load(const char *account_name)
Definition: account_char.c:80
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:219
AddIfInt64
#define AddIfInt64(Old, New, sl, Type)
Definition: request.c:688
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:169
pl::last_stats
living last_stats
Definition: player.h:153
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2820
SockList_ResetRead
void SockList_ResetRead(SockList *sl)
Definition: lowlevel.c:80
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.c:195
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:248
socket_struct::anims_sent
uint8_t anims_sent[MAXANIMNUM]
Definition: newserver.h:97
account_change_password
int account_change_password(const char *account_name, const char *current_password, const char *new_password)
Definition: account.c:685
AddIfShort
#define AddIfShort(Old, New, sl, Type)
Definition: request.c:702
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
account_char_struct::face
sstring face
Definition: account_char.h:17
check_space_for_heads
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.c:1314
set_up_cmd
void set_up_cmd(char *buf, int len, socket_struct *ns)
Definition: request.c:95
CS_STAT_RES_DEATH
#define CS_STAT_RES_DEATH
Definition: newclient.h:163
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
pl::ranges
object * ranges[range_size]
Definition: player.h:103
GetInt_String
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:251
strcasecmp
int strcasecmp(const char *s1, const char *s2)
castle_read.key
key
Definition: castle_read.py:64
make_face_from_files.int
int
Definition: make_face_from_files.py:26
ACL_LEVEL
#define ACL_LEVEL
Definition: newclient.h:220
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Definition: map.h:49
send_plugin_custom_message
void send_plugin_custom_message(object *pl, char *buf)
Definition: request.c:1651
liv::ac
int8_t ac
Definition: living.h:38
obj::skill
sstring skill
Definition: object.h:322
CS_STAT_TITLE
#define CS_STAT_TITLE
Definition: newclient.h:107
MAP_TYPE_DEFAULT
#define MAP_TYPE_DEFAULT
Definition: map.h:58
newclient.h
save_player
int save_player(object *op, int flag)
Definition: login.c:230
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1613
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Definition: define.h:549
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.c:314
VERSION_CS
#define VERSION_CS
Definition: newserver.h:149
update_position
void update_position(mapstruct *m, int x, int y)
Definition: map.c:2123
UPD_SP_GRACE
#define UPD_SP_GRACE
Definition: newclient.h:325
get_archetype_by_type_subtype
archetype * get_archetype_by_type_subtype(int type, int subtype)
Definition: arch.cpp:101
CS_STAT_POW
#define CS_STAT_POW
Definition: newclient.h:108
CF_WIZARD
#define CF_WIZARD
Definition: newclient.h:207
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.c:4428
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:282
CS_STAT_RACE_WIS
#define CS_STAT_RACE_WIS
Definition: newclient.h:119
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:306
SP_RAISE_DEAD
#define SP_RAISE_DEAD
Definition: spells.h:75
MIN_NUM_LOOK_OBJECTS
#define MIN_NUM_LOOK_OBJECTS
Definition: newserver.h:16
SP_MAKE_MARK
#define SP_MAKE_MARK
Definition: spells.h:77
socket_struct::fd
int fd
Definition: newserver.h:91
MAP_LAYER_LIVING2
#define MAP_LAYER_LIVING2
Definition: map.h:47
socket_struct::login_method
uint8_t login_method
Definition: newserver.h:128
map_newmap_cmd
void map_newmap_cmd(socket_struct *ns)
Definition: request.c:620
statsinfo::range
char * range
Definition: newserver.h:57
commands.h
ST_CONFIRM_QUIT
#define ST_CONFIRM_QUIT
Definition: define.h:545
account_block_create
static int account_block_create(const socket_struct *ns)
Definition: request.c:2201
CS_STAT_MAXHP
#define CS_STAT_MAXHP
Definition: newclient.h:88
key_change_class
void key_change_class(object *op, char key)
Definition: player.c:1265
receive_party_password
void receive_party_password(object *op, const char *password)
Definition: c_party.c:53
account_check_string
int account_check_string(const char *str)
Definition: account.c:362
socket_struct::darkness
uint32_t darkness
Definition: newserver.h:103
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.c:4116
socket_struct::notifications
uint16_t notifications
Definition: newserver.h:129
SF_RUNON
#define SF_RUNON
Definition: newclient.h:190
CS_STAT_RANGE
#define CS_STAT_RANGE
Definition: newclient.h:106
Settings::account_trusted_host
char * account_trusted_host
Definition: global.h:325
esrv_update_spells
void esrv_update_spells(player *pl)
Definition: request.c:1665
AddIfInt
#define AddIfInt(Old, New, sl, Type)
Definition: request.c:695
MSG_TYPE_ADMIN_VERSION
#define MSG_TYPE_ADMIN_VERSION
Definition: newclient.h:501
find_smooth
int find_smooth(const Face *face, const Face **smoothed)
Definition: image.c:101
CS_STAT_BASE_CON
#define CS_STAT_BASE_CON
Definition: newclient.h:128
mapdef::path
char path[HUGE_BUF]
Definition: map.h:364
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:94
account_login
int account_login(const char *account_name, const char *account_password)
Definition: account.c:326
pl::character_load
float character_load
Definition: player.h:122
Settings::always_show_hp
uint8_t always_show_hp
Definition: global.h:269
verify_player
int verify_player(const char *name, char *password)
Definition: login.c:111
heads
static const object * heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS]
Definition: request.c:1020
ST_ROLL_STAT
#define ST_ROLL_STAT
Definition: define.h:543
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:311
SPELL
@ SPELL
Definition: object.h:214
CS_STAT_BASE_STR
#define CS_STAT_BASE_STR
Definition: newclient.h:124
liv::sp
int16_t sp
Definition: living.h:42
map_clearcell
static void map_clearcell(struct map_cell_struct *cell, int face, int count)
Definition: request.c:1006
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.c:942
CS_STAT_RES_DRAIN
#define CS_STAT_RES_DRAIN
Definition: newclient.h:155
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
MAP_NOSMOOTH
#define MAP_NOSMOOTH(m)
Definition: map.h:89
living.h
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:344
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:440
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.c:2375
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:402
CF_HOSTILE
#define CF_HOSTILE
Definition: newclient.h:204
SockList
Definition: newclient.h:681
CF_PARALYZED
#define CF_PARALYZED
Definition: newclient.h:206
NUM_STATS
@ NUM_STATS
Definition: living.h:18
pl::applied_stats
living applied_stats
Definition: player.h:156
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:668
takeitem.status
status
Definition: takeitem.py:35
FORCE
@ FORCE
Definition: object.h:224
pl::last_level
int8_t last_level
Definition: player.h:121
CS_STAT_APPLIED_INT
#define CS_STAT_APPLIED_INT
Definition: newclient.h:132
smooth_face
const Face * smooth_face
Definition: image.c:35
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Definition: define.h:450
liv::Pow
int8_t Pow
Definition: living.h:36
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,...)
Definition: main.c:319
pl::last_flags
uint16_t last_flags
Definition: player.h:143
update_los
void update_los(object *op)
Definition: los.c:459
obj::level
int16_t level
Definition: object.h:354
ACL_FACE
#define ACL_FACE
Definition: newclient.h:221
CF_XRAY
#define CF_XRAY
Definition: newclient.h:201
rangetostring
void rangetostring(const object *pl, char *obuf, size_t len)
Definition: info.c:263
llevDebug
@ llevDebug
Definition: logger.h:13
pl::orig_stats
living orig_stats
Definition: player.h:152
NS_FACESENT_SMOOTH
#define NS_FACESENT_SMOOTH
Definition: newserver.h:138
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:199
account_exists
const char * account_exists(const char *account_name)
Definition: account.c:302
pl::last_item_power
uint16_t last_item_power
Definition: player.h:150
give.name
name
Definition: give.py:27
CS_STAT_RES_PARA
#define CS_STAT_RES_PARA
Definition: newclient.h:159
Settings::starting_stat_max
uint8_t starting_stat_max
Definition: global.h:317
CS_STAT_RES_ACID
#define CS_STAT_RES_ACID
Definition: newclient.h:154
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
dragon_attune.force
force
Definition: dragon_attune.py:45
pl::last_path_repelled
uint32_t last_path_repelled
Definition: player.h:147
new_player_cmd
void new_player_cmd(uint8_t *buf, int len, player *pl)
Definition: request.c:461
CS_STAT_RES_ELEC
#define CS_STAT_RES_ELEC
Definition: newclient.h:151
CS_STAT_FLAGS
#define CS_STAT_FLAGS
Definition: newclient.h:111