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