Crossfire Server, Trunk  R20513
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) {
372  /* The space in the link isn't correct, but in my
373  * quick test with client 1.1.0, it didn't print it
374  * out correctly when done as a single line.
375  */
377  "Warning: Your client is too old to receive map data. Please update to a new client at http://sourceforge.net/project/showfiles.php ?group_id=13833");
378  }
379 
380  ns->status = Ns_Avail;
381  }
382  settings = oldsettings;
383 }
384 
392 static void send_smooth(socket_struct *ns, uint16_t face) {
393  uint16_t smoothface;
394  SockList sl;
395 
396  /* If we can't find a face, return and set it so we won't
397  * try to send this again.
398  */
399  if (!find_smooth(face, &smoothface)
400  && !find_smooth(smooth_face->number, &smoothface)) {
401  LOG(llevError, "could not findsmooth for %d. Neither default (%s)\n", face, smooth_face->name);
402  ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
403  return;
404  }
405 
406  if (!(ns->faces_sent[smoothface]&NS_FACESENT_FACE))
407  esrv_send_face(ns, smoothface, 0);
408 
409  ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
410 
411  SockList_Init(&sl);
412  SockList_AddString(&sl, "smooth ");
413  SockList_AddShort(&sl, face);
414  SockList_AddShort(&sl, smoothface);
415  Send_With_Handling(ns, &sl);
416  SockList_Term(&sl);
417 }
418 
423 void ask_smooth_cmd(char *buf, int len, socket_struct *ns) {
424  uint16_t facenbr;
425 
426  if (len <= 0 || !buf) {
427  LOG(llevDebug, "IP '%s' sent bogus ask_smooth_cmd information\n", ns->host);
428  return;
429  }
430 
431  facenbr = atoi(buf);
432  send_smooth(ns, facenbr);
433 }
434 
447 void new_player_cmd(uint8_t *buf, int len, player *pl) {
448  int time, repeat;
449  short packet;
450  char command[MAX_BUF];
451  SockList sl;
452 
453  if (len < 7) {
454  LOG(llevDebug, "Corrupt ncom command - not long enough - discarding\n");
455  return;
456  }
457 
458  packet = GetShort_String(buf);
459  repeat = GetInt_String(buf+2);
460  /* -1 is special - no repeat, but don't update */
461  if (repeat != -1) {
462  pl->count = repeat;
463  }
464  if (len-4 >= MAX_BUF)
465  len = MAX_BUF-5;
466 
467  strncpy(command, (char *)buf+6, len-4);
468  command[len-4] = '\0';
469 
470  /* The following should never happen with a proper or honest client.
471  * Therefore, the error message doesn't have to be too clear - if
472  * someone is playing with a hacked/non working client, this gives them
473  * an idea of the problem, but they deserve what they get
474  */
475  if (pl->state != ST_PLAYING) {
477  "You can not issue commands - state is not ST_PLAYING (%s)",
478  buf);
479  return;
480  }
481 
482  /* This should not happen anymore. */
483  if (pl->ob->speed_left < -1.0) {
484  LOG(llevError, "Player has negative time - shouldn't do command.\n");
485  }
486  /* In c_new.c */
487  execute_newserver_command(pl->ob, command);
488  /* Perhaps something better should be done with a left over count.
489  * Cleaning up the input should probably be done first - all actions
490  * for the command that issued the count should be done before
491  * any other commands.
492  */
493  pl->count = 0;
494 
495  /* Send confirmation of command execution now */
496  SockList_Init(&sl);
497  SockList_AddString(&sl, "comc ");
498  SockList_AddShort(&sl, packet);
499  if (FABS(pl->ob->speed) < 0.001)
500  time = MAX_TIME*100;
501  else
502  time = (int)(MAX_TIME/FABS(pl->ob->speed));
503  SockList_AddInt(&sl, time);
504  Send_With_Handling(&pl->socket, &sl);
505  SockList_Term(&sl);
506 }
507 
509 void reply_cmd(char *buf, int len, player *pl) {
510 
511  if (len <= 0 || !buf) {
512  LOG(llevDebug, "Player '%s' sent bogus reply_cmd information\n", pl->ob->name);
513  return;
514  }
515 
516  /* This is to synthesize how the data would be stored if it
517  * was normally entered. A bit of a hack, and should be cleaned up
518  * once all the X11 code is removed from the server.
519  *
520  * We pass 13 to many of the functions because this way they
521  * think it was the carriage return that was entered, and the
522  * function then does not try to do additional input.
523  */
524  snprintf(pl->write_buf, sizeof(pl->write_buf), ":%s", buf);
525 
526  /* this avoids any hacking here */
527 
528  switch (pl->state) {
529  case ST_PLAYING:
530  LOG(llevError, "Got reply message with ST_PLAYING input state\n");
531  break;
532 
533  case ST_PLAY_AGAIN:
534  /* We can check this for return value (2==quit). Maybe we
535  * should, and do something appropriate?
536  */
537  receive_play_again(pl->ob, buf[0]);
538  break;
539 
540  case ST_ROLL_STAT:
541  key_roll_stat(pl->ob, buf[0]);
542  break;
543 
544  case ST_CHANGE_CLASS:
545 
546  key_change_class(pl->ob, buf[0]);
547  break;
548 
549  case ST_CONFIRM_QUIT:
550  key_confirm_quit(pl->ob, buf[0]);
551  break;
552 
553  case ST_GET_NAME:
554  receive_player_name(pl->ob);
555  break;
556 
557  case ST_GET_PASSWORD:
558  case ST_CONFIRM_PASSWORD:
563  break;
564 
565  case ST_GET_PARTY_PASSWORD: /* Get password for party */
567  break;
568 
569  default:
570  LOG(llevError, "Unknown input state: %d\n", pl->state);
571  }
572 }
573 
581 void version_cmd(char *buf, int len, socket_struct *ns) {
582  char *rest;
583  char *cs_str = strtok_r(buf, " ", &rest);
584  char *sc_str = strtok_r(NULL, " ", &rest);
585 
586  if (cs_str == NULL || sc_str == NULL) {
587  LOG(llevError, "%s: sent invalid version string\n", ns->host);
588  return;
589  } else {
590  ns->cs_version = atoi(cs_str);
591  ns->sc_version = atoi(sc_str);
592  }
593 
594 #ifdef ESRV_DEBUG
595  if (VERSION_CS != ns->cs_version) {
596  LOG(llevDebug, "CS: csversion mismatch (%d,%d)\n", VERSION_CS, ns->cs_version);
597  }
598 
599  if (VERSION_SC != ns->sc_version) {
600  LOG(llevDebug, "CS: scversion mismatch (%d,%d)\n", VERSION_SC, ns->sc_version);
601  }
602 #endif
603 
604  if (rest != NULL) {
605  LOG(llevInfo, "%s: connected using '%s'\n", ns->host, rest);
606  }
607 }
608 
616  SockList sl;
617 
618  /* If getting a newmap command, this scroll information
619  * is no longer relevant.
620  */
621  ns->map_scroll_x = 0;
622  ns->map_scroll_y = 0;
623 
624 
625  memset(&ns->lastmap, 0, sizeof(ns->lastmap));
626  SockList_Init(&sl);
627  SockList_AddString(&sl, "newmap");
628  Send_With_Handling(ns, &sl);
629  SockList_Term(&sl);
630 }
631 
636 void move_cmd(char *buf, int len, player *pl) {
637  int vals[3], i;
638 
639  if (len <= 0 || !buf) {
640  LOG(llevDebug, "Player '%s' sent bogus move_cmd information\n", pl->ob->name);
641  return;
642  }
643 
644  /* A little funky here. We only cycle for 2 records, because
645  * we obviously am not going to find a space after the third
646  * record. Perhaps we should just replace this with a
647  * sscanf?
648  */
649  for (i = 0; i < 2; i++) {
650  vals[i] = atoi(buf);
651  if (!(buf = strchr(buf, ' '))) {
652  LOG(llevError, "Incomplete move command: %s\n", buf);
653  return;
654  }
655  buf++;
656  }
657  vals[2] = atoi(buf);
658 
659 /* LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
660  esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
661 }
662 
663 /***************************************************************************
664  *
665  * Start of commands the server sends to the client.
666  *
667  ***************************************************************************
668  */
669 
674 void send_query(socket_struct *ns, uint8_t flags, const char *text) {
675  SockList sl;
676 
677  SockList_Init(&sl);
678  SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
679  Send_With_Handling(ns, &sl);
680  SockList_Term(&sl);
681 }
682 
683 #define AddIfInt64(Old, New, Type) \
684  if (Old != New) { \
685  Old = New; \
686  SockList_AddChar(&sl, Type); \
687  SockList_AddInt64(&sl, New); \
688  }
689 
690 #define AddIfInt(Old, New, Type) \
691  if (Old != New) { \
692  Old = New; \
693  SockList_AddChar(&sl, Type); \
694  SockList_AddInt(&sl, New); \
695  }
696 
697 #define AddIfShort(Old, New, Type) \
698  if (Old != New) { \
699  Old = New; \
700  SockList_AddChar(&sl, Type); \
701  SockList_AddShort(&sl, New); \
702  }
703 
704 #define AddIfFloat(Old, New, Type) \
705  if (Old != New) { \
706  Old = New; \
707  SockList_AddChar(&sl, Type); \
708  SockList_AddInt(&sl, (long)(New*FLOAT_MULTI));\
709  }
710 
711 #define AddIfString(Old, New, Type) \
712  if (Old == NULL || strcmp(Old, New)) { \
713  free(Old); \
714  Old = strdup_local(New); \
715  SockList_AddChar(&sl, Type); \
716  SockList_AddLen8Data(&sl, New, strlen(New));\
717  }
718 
726  SockList sl;
727  char buf[MAX_BUF];
728  uint16_t flags;
729  uint8_t s;
730 
731  SockList_Init(&sl);
732  SockList_AddString(&sl, "stats ");
733 
734  if (pl->ob != NULL) {
748  }
749  if (pl->socket.extended_stats) {
750  int16_t golem_hp, golem_maxhp;
758  if (pl->ob != NULL) {
773  }
774  if (pl->ranges[range_golem]) {
775  object *golem = pl->ranges[range_golem];
776  if (QUERY_FLAG(golem, FLAG_REMOVED) || golem->count != pl->golem_count || QUERY_FLAG(golem, FLAG_FREED)) {
777  golem_hp = 0;
778  golem_maxhp = 0;
779  } else {
780  golem_hp = golem->stats.hp;
781  golem_maxhp = golem->stats.maxhp;
782  }
783  } else {
784  golem_hp = 0;
785  golem_maxhp = 0;
786  }
787  /* send first the maxhp, so the client can set up the display */
789  AddIfShort(pl->last_golem_hp, golem_hp, CS_STAT_GOLEM_HP);
790  }
791 
792  for (s = 0; s < NUM_SKILLS; s++) {
793  if (pl->last_skill_ob[s]
794  && pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
795  /* Always send along the level if exp changes. This
796  * is only 1 extra byte, but keeps processing simpler.
797  */
798  SockList_AddChar(&sl, (char)(s+CS_STAT_SKILLINFO));
799  SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
801  pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
802  }
803  }
805  AddIfShort(pl->last_level, (char)pl->ob->level, CS_STAT_LEVEL);
813  flags = 0;
814  if (pl->fire_on)
815  flags |= SF_FIREON;
816  if (pl->run_on)
817  flags |= SF_RUNON;
818 
819  AddIfShort(pl->last_flags, flags, CS_STAT_FLAGS);
820  if (pl->socket.sc_version < 1025) {
822  } else {
823  int i;
824 
825  for (i = 0; i < NROFATTACKS; i++) {
826  /* Skip ones we won't send */
827  if (atnr_cs_stat[i] == -1)
828  continue;
829  AddIfShort(pl->last_resist[i], pl->ob->resist[i], (char)atnr_cs_stat[i]);
830  }
831  }
832  if (pl->socket.monitor_spells) {
836  }
837  /* we want to use the new fire & run system in new client */
838  rangetostring(pl->ob, buf, sizeof(buf));
840  set_title(pl->ob, buf, sizeof(buf));
842 
843  /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
844  if (sl.len > 8) {
845 #ifdef ESRV_DEBUG
846  LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
847 #endif
848  Send_With_Handling(&pl->socket, &sl);
849  }
850  SockList_Term(&sl);
851 }
852 
857  SockList sl;
858 
859  pl->last_weight = weight;
860 
861  if (!(pl->socket.faces_sent[pl->ob->face->number]&NS_FACESENT_FACE))
862  esrv_send_face(&pl->socket, pl->ob->face->number, 0);
863 
864  SockList_Init(&sl);
865  SockList_AddString(&sl, "player ");
866  SockList_AddInt(&sl, pl->ob->count);
867  SockList_AddInt(&sl, weight);
868  SockList_AddInt(&sl, pl->ob->face->number);
869  SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
870 
871  Send_With_Handling(&pl->socket, &sl);
872  SockList_Term(&sl);
874 }
875 
883 void esrv_send_animation(socket_struct *ns, short anim_num) {
884  SockList sl;
885  int i;
886 
887  /* Do some checking on the anim_num we got. Note that the animations
888  * are added in contigous order, so if the number is in the valid
889  * range, it must be a valid animation.
890  */
891  if (anim_num < 0 || anim_num > num_animations) {
892  LOG(llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
893  return;
894  }
895 
896  SockList_Init(&sl);
897  SockList_AddString(&sl, "anim ");
898  SockList_AddShort(&sl, anim_num);
899  SockList_AddShort(&sl, 0); /* flags - not used right now */
900  /* Build up the list of faces. Also, send any information (ie, the
901  * the face itself) down to the client.
902  */
903  for (i = 0; i < animations[anim_num].num_animations; i++) {
904  if (!(ns->faces_sent[animations[anim_num].faces[i]->number]&NS_FACESENT_FACE))
905  esrv_send_face(ns, animations[anim_num].faces[i]->number, 0);
906  /* flags - not used right now */
907  SockList_AddShort(&sl, animations[anim_num].faces[i]->number);
908  }
909  Send_With_Handling(ns, &sl);
910  SockList_Term(&sl);
911  ns->anims_sent[anim_num] = 1;
912 }
913 
914 /****************************************************************************
915  *
916  * Start of map related commands.
917  *
918  ****************************************************************************/
919 
921 static void map_clearcell(struct map_cell_struct *cell, int face, int count) {
922  cell->darkness = count;
923  memset(cell->faces, face, sizeof(cell->faces));
924 }
925 
926 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
927 
935 static const object *heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS];
936 
937 /****************************************************************************
938  * This block is for map2 drawing related commands.
939  * Note that the map2 still uses other functions.
940  *
941  ***************************************************************************/
942 
962 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) {
963  uint16_t face_num;
964  uint8_t nlayer, smoothlevel = 0;
965  const object *head;
966 
967  assert(ob != NULL);
968 
969  head = HEAD(ob);
970  face_num = ob->face->number;
971 
972  /* This is a multipart object, and we are not at the lower
973  * right corner. So we need to store away the lower right corner.
974  */
975  if (!is_head && (head->arch->tail_x || head->arch->tail_y)
976  && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
977  int bx, by, l;
978 
979  /* Basically figure out where the offset is from where we
980  * are right now. the ob->arch->clone.{x,y} values hold
981  * the offset that this current piece is from the head,
982  * and the tail is where the tail is from the head.
983  * Note that bx and by will equal sx and sy if we are
984  * already working on the bottom right corner. If ob is
985  * the head, the clone values will be zero, so the right
986  * thing will still happen.
987  */
988  bx = ax+head->arch->tail_x-ob->arch->clone.x;
989  by = ay+head->arch->tail_y-ob->arch->clone.y;
990 
991  /* I don't think this can ever happen, but better to check
992  * for it just in case.
993  */
994  if (bx < ax || by < ay) {
995  LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
996  face_num = 0;
997  }
998  /* the target position must be within +/-1 of our current
999  * layer as the layers are defined. We are basically checking
1000  * to see if we have already stored this object away.
1001  */
1002  for (l = layer-1; l <= layer+1; l++) {
1003  if (l < 0 || l >= MAP_LAYERS)
1004  continue;
1005  if (heads[by][bx][l] == head)
1006  break;
1007  }
1008  /* Didn't find it. So we need to store it away. Try to store it
1009  * on our original layer, and then move up a layer.
1010  */
1011  if (l == layer+2) {
1012  if (!heads[by][bx][layer])
1013  heads[by][bx][layer] = head;
1014  else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
1015  heads[by][bx][layer+1] = head;
1016  }
1017  return 0;
1018  /* Ok - All done storing away the head for future use */
1019  } else {
1020  (*has_obj)++;
1023  face_num = ob->animation_id|(1<<15);
1025  face_num |= ANIM_SYNC;
1026  else if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM))
1027  face_num |= ANIM_RANDOM;
1028  }
1029  /* Since face_num includes the bits for the animation tag,
1030  * and we will store that away in the faces[] array, below
1031  * check works fine _except_ for the case where animation
1032  * speed chances.
1033  */
1034  if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
1035  uint8_t len, anim_speed = 0, i;
1036 
1037  /* This block takes care of sending the actual face
1038  * to the client. */
1039  ns->lastmap.cells[ax][ay].faces[layer] = face_num;
1040 
1041  /* Now form the data packet */
1042  nlayer = MAP2_LAYER_START+layer;
1043 
1044  len = 2;
1045 
1046  if (ob->map && !MAP_NOSMOOTH(ob->map)) {
1047  smoothlevel = ob->smoothlevel;
1048  if (smoothlevel)
1049  len++;
1050  }
1051 
1054  len++;
1055  /* 1/0.004 == 250, so this is a good cap for an
1056  * upper limit */
1057  if (ob->anim_speed)
1058  anim_speed = ob->anim_speed;
1059  else if (FABS(ob->speed) < 0.004)
1060  anim_speed = 255;
1061  else if (FABS(ob->speed) >= 1.0)
1062  anim_speed = 1;
1063  else
1064  anim_speed = (int)(1.0/FABS(ob->speed));
1065 
1066  if (!ns->anims_sent[ob->animation_id])
1068 
1069  /* If smoothing, need to send smoothing information
1070  * for all faces in the animation sequence. Since
1071  * smoothlevel is an object attribute,
1072  * it applies to all faces.
1073  */
1074  if (smoothlevel) {
1075  for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
1078  }
1079  }
1080  } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
1081  esrv_send_face(ns, face_num, 0);
1082  }
1083 
1084  if (smoothlevel
1085  && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
1086  send_smooth(ns, ob->face->number);
1087 
1088  /* Length of packet */
1089  nlayer |= len<<5;
1090 
1091  SockList_AddChar(sl, nlayer);
1092  SockList_AddShort(sl, face_num);
1093  if (anim_speed)
1094  SockList_AddChar(sl, anim_speed);
1095  if (smoothlevel)
1096  SockList_AddChar(sl, smoothlevel);
1097  return 1;
1098  } /* Face is different */
1099  }
1100  return 0;
1101 }
1102 
1103 /* This function is used see if a layer needs to be cleared.
1104  * It updates the socklist, and returns 1 if the update is
1105  * needed, 0 otherwise.
1106  */
1107 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
1108  int nlayer;
1109 
1110  if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
1111  /* Now form the data packet */
1112  nlayer = 0x10+layer+(2<<5);
1113  SockList_AddChar(sl, nlayer);
1114  SockList_AddShort(sl, 0);
1115  ns->lastmap.cells[ax][ay].faces[layer] = 0;
1116  return 1;
1117  }
1118  return 0;
1119 }
1120 
1132 static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer) {
1133  int got_one = 0, poisoned = 0, diseased = 0;
1134  char name[60];
1135  int value, granularity;
1136  const object *probe;
1137 
1138  /* send hp bar if needed */
1139  if (!QUERY_FLAG(ob, FLAG_PROBE) || (*alive_layer) != -1 || ob->head)
1140  return 0;
1141 
1142  probe = object_find_by_type_and_name(ob, FORCE, "probe_force");
1143  if (probe == NULL || probe->level < 15) {
1144  /* if probe is not null, this is an error, but well */
1145  return 0;
1146  }
1147 
1148  granularity = (probe->level - 14) / 3;
1149  if (granularity <= 0)
1150  granularity = 1;
1151  else if (granularity > 30)
1152  granularity = 30;
1153 
1154  if (ob->stats.maxhp > 0) {
1155  value = (ob->stats.hp * granularity) / (ob->stats.maxhp);
1156 
1157  if (value < 0)
1158  value = 0;
1159  else if (value > granularity)
1160  value = granularity;
1161  } else
1162  value = 30;
1163 
1164  value = (value * 30) / granularity;
1165 
1166  if (object_present_in_ob(POISONING, ob) != NULL)
1167  poisoned = 1;
1168  if (object_present_in_ob(DISEASE, ob) != NULL)
1169  diseased = 1;
1170 
1171  if (value > 0) {
1172  archetype *dummy;
1173 
1174  snprintf(name, sizeof(name), "hpbar%s%s%s_%d",
1175  poisoned ? "_poisoned" : "",
1176  diseased ? "_diseased" : "",
1177  (!poisoned && !diseased) ? "_standard" : "",
1178  value);
1179  dummy = try_find_archetype(name);
1180  if (dummy != NULL) {
1181  got_one += map2_add_ob(ax, ay, MAP_LAYER_FLY2, &dummy->clone, sl, ns, has_obj, 0);
1182  (*alive_layer) = MAP_LAYER_FLY2;
1183  }
1184  }
1185 
1186  return got_one;
1187 }
1188 
1189 /*
1190  * This function is used to check a space (ax, ay) whose only
1191  * data we may care about are any heads. Basically, this
1192  * space is out of direct view. This is only used with the
1193  * Map2 protocol.
1194  *
1195  * @param ax
1196  * viewport relative x-coordinate
1197  * @param ay
1198  * viewport relative y-coordinate
1199  * @param sl
1200  * the reply to append to
1201  * @param ns
1202  * the client socket
1203  */
1204 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
1205  int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
1206  uint16_t coord;
1207 
1208  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1209  oldlen = sl->len;
1210  SockList_AddShort(sl, coord);
1211 
1212  for (layer = 0; layer < MAP_LAYERS; layer++) {
1213  const object *head;
1214 
1215  head = heads[ay][ax][layer];
1216  if (head) {
1217  /* in this context, got_one should always increase
1218  * because heads should always point to data to really send.
1219  */
1220  got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
1221  } else {
1222  del_one += map2_delete_layer(ax, ay, layer, sl, ns);
1223  }
1224  }
1225  /* Note - if/when lighting information is added, some code is
1226  * needed here - lighting sources that are out of sight may still
1227  * extend into the viewable area.
1228  */
1229 
1230  /* If nothing to do for this space, we
1231  * can erase the coordinate bytes
1232  */
1233  if (!del_one && !got_one) {
1234  sl->len = oldlen;
1235  } else if (del_one && !has_obj) {
1236  /* If we're only deleting faces and not adding, and there
1237  * are not any faces on the space we care about,
1238  * more efficient
1239  * to send 0 as the type/len field.
1240  */
1241  sl->len = oldlen+2; /* 2 bytes for coordinate */
1242  SockList_AddChar(sl, 0); /* Clear byte */
1243  SockList_AddChar(sl, 255); /* Termination byte */
1244  map_clearcell(&ns->lastmap.cells[ax][ay], 0, 0);
1245  } else {
1246  SockList_AddChar(sl, 255); /* Termination byte */
1247  }
1248 }
1249 
1250 void draw_client_map2(object *pl) {
1251  int x, y, ax, ay, d, min_x, max_x, min_y, max_y, oldlen, layer;
1252  size_t startlen;
1253  int16_t nx, ny;
1254  SockList sl;
1255  uint16_t coord;
1256  mapstruct *m;
1257  object *ob;
1258 
1259  SockList_Init(&sl);
1260  SockList_AddString(&sl, "map2 ");
1261  startlen = sl.len;
1262 
1263  /* Handle map scroll */
1264  if (pl->contr->socket.map_scroll_x || pl->contr->socket.map_scroll_y) {
1266  pl->contr->socket.map_scroll_x = 0;
1267  pl->contr->socket.map_scroll_y = 0;
1268  SockList_AddShort(&sl, coord);
1269  }
1270 
1271  /* Init data to zero */
1272  memset(heads, 0, sizeof(heads));
1273 
1274  /* We could do this logic as conditionals in the if statement,
1275  * but that started to get a bit messy to look at.
1276  */
1277  min_x = pl->x-pl->contr->socket.mapx/2;
1278  min_y = pl->y-pl->contr->socket.mapy/2;
1279  max_x = pl->x+(pl->contr->socket.mapx+1)/2+MAX_HEAD_OFFSET;
1280  max_y = pl->y+(pl->contr->socket.mapy+1)/2+MAX_HEAD_OFFSET;
1281 
1282  /* x, y are the real map locations. ax, ay are viewport relative
1283  * locations.
1284  */
1285  ay = 0;
1286  for (y = min_y; y < max_y; y++, ay++) {
1287  ax = 0;
1288  for (x = min_x; x < max_x; x++, ax++) {
1289  /* If this space is out of the normal viewable area,
1290  * we only check the heads value. This is used to
1291  * handle big images - if they extend to a viewable
1292  * portion, we need to send just the lower right corner.
1293  */
1294  if (ax >= pl->contr->socket.mapx || ay >= pl->contr->socket.mapy) {
1295  check_space_for_heads(ax, ay, &sl, &pl->contr->socket);
1296  } else {
1297  /* This space is within the viewport of the client. Due
1298  * to walls or darkness, it may still not be visible.
1299  */
1300 
1301  /* Meaning of d:
1302  * 0 - object is in plain sight, full brightness.
1303  * 1 - MAX_DARKNESS - how dark the space is - higher
1304  * value is darker space. If level is at max darkness,
1305  * you can't see the space (too dark)
1306  * 100 - space is blocked from sight.
1307  */
1308  d = pl->contr->blocked_los[ax][ay];
1309 
1310  /* If the coordinates are not valid, or it is too
1311  * dark to see, we tell the client as such
1312  */
1313  nx = x;
1314  ny = y;
1315  m = get_map_from_coord(pl->map, &nx, &ny);
1316  coord = MAP2_COORD_ENCODE(ax, ay, 0);
1317 
1318  if (!m) {
1319  /* space is out of map. Update space and clear
1320  * values if this hasn't already been done.
1321  * If the space is out of the map, it shouldn't
1322  * have a head.
1323  */
1324  if (pl->contr->socket.lastmap.cells[ax][ay].darkness != 0) {
1325  SockList_AddShort(&sl, coord);
1327  SockList_AddChar(&sl, 255); /* Termination byte */
1328  map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
1329  }
1330  } else if (d >= MAX_LIGHT_RADII) {
1331  /* This block deals with spaces that are not
1332  * visible due to darkness or walls. Still
1333  * need to send the heads for this space.
1334  */
1335  check_space_for_heads(ax, ay, &sl, &pl->contr->socket);
1336  } else {
1337  int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1, alive_layer = -1, old_got;
1338 
1339  /* In this block, the space is visible. */
1340 
1341  /* Rather than try to figure out what everything
1342  * that we might need to send is, then form the
1343  * packet after that, we presume that we will in
1344  * fact form a packet, and update the bits by what
1345  * we do actually send. If we send nothing, we
1346  * just back out sl.len to the old value, and no
1347  * harm is done.
1348  * I think this is simpler than doing a bunch of
1349  * checks to see what if anything we need to send,
1350  * setting the bits, then doing those checks again
1351  * to add the real data.
1352  */
1353 
1354  oldlen = sl.len;
1355  SockList_AddShort(&sl, coord);
1356 
1357  /* Darkness changed */
1358  if (pl->contr->socket.lastmap.cells[ax][ay].darkness != d
1359  && pl->contr->socket.darkness) {
1360  pl->contr->socket.lastmap.cells[ax][ay].darkness = d;
1361  /* Darkness tag & length*/
1363  SockList_AddChar(&sl, 255-d*(256/MAX_LIGHT_RADII));
1364  have_darkness = 1;
1365  }
1366 
1367  for (layer = 0; layer < MAP_LAYERS; layer++) {
1368  ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
1369 
1370  /* Special case: send player itself if invisible */
1371  if (!ob
1372  && x == pl->x
1373  && y == pl->y
1374  && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
1375  && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
1376  ob = pl;
1377 
1378  if (ob) {
1379  g1 = has_obj;
1380  old_got = got_one;
1381  got_one += map2_add_ob(ax, ay, layer, ob, &sl, &pl->contr->socket, &has_obj, 0);
1382 
1383  /* if we added the face, or it is a monster's head, check probe spell */
1384  if (got_one != old_got || (ob->head == NULL && ob->more))
1385  got_one += check_probe(ax, ay, ob, &sl, &pl->contr->socket, &has_obj, &alive_layer);
1386 
1387  /* If we are just storing away the head
1388  * for future use, then effectively this
1389  * space/layer is blank, and we should clear
1390  * it if needed.
1391  */
1392  if (g1 == has_obj) {
1393  del_one += map2_delete_layer(ax, ay, layer, &sl, &pl->contr->socket);
1394  } else if (ob->head == NULL) {
1395  /* for single-part items */
1396  got_one += check_probe(ax, ay, ob, &sl, &pl->contr->socket, &has_obj, &alive_layer);
1397  }
1398  } else {
1399  if (layer != alive_layer)
1400  del_one += map2_delete_layer(ax, ay, layer, &sl, &pl->contr->socket);
1401  }
1402  }
1403  /* If nothing to do for this space, we
1404  * can erase the coordinate bytes
1405  */
1406  if (!del_one && !got_one && !have_darkness) {
1407  sl.len = oldlen;
1408  } else if (del_one && !has_obj) {
1409  /* If we're only deleting faces and don't
1410  * have any objs we care about, just clear
1411  * space. Note it is possible we may have
1412  * darkness, but if there is nothing on the
1413  * space, darkness isn't all that interesting
1414  * - we can send it when an object shows up.
1415  */
1416  sl.len = oldlen+2; /* 2 bytes for coordinate */
1418  SockList_AddChar(&sl, 255); /* Termination byte */
1419  map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
1420  } else {
1421  SockList_AddChar(&sl, 255); /* Termination byte */
1422  }
1423  }
1424  } /* else this is a viewable space */
1425  } /* for x loop */
1426  } /* for y loop */
1427 
1428  /* Only send this if there are in fact some differences. */
1429  if (sl.len > startlen) {
1430  Send_With_Handling(&pl->contr->socket, &sl);
1431  }
1432  SockList_Term(&sl);
1433 }
1434 
1438 void draw_client_map(object *pl) {
1439  int i, j;
1440  int16_t ax, ay;
1441  int mflags;
1442  mapstruct *m, *pm;
1443  int min_x, min_y, max_x, max_y;
1444 
1445  if (pl->type != PLAYER) {
1446  LOG(llevError, "draw_client_map called with non player/non eric-server\n");
1447  return;
1448  }
1449 
1450  if (pl->contr->transport) {
1451  pm = pl->contr->transport->map;
1452  } else
1453  pm = pl->map;
1454 
1455  /* If player is just joining the game, he isn't here yet, so
1456  * the map can get swapped out. If so, don't try to send them
1457  * a map. All will be OK once they really log in.
1458  */
1459  if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
1460  return;
1461 
1462  /*
1463  * This block just makes sure all the spaces are properly
1464  * updated in terms of what they look like.
1465  */
1466  min_x = pl->x-pl->contr->socket.mapx/2;
1467  min_y = pl->y-pl->contr->socket.mapy/2;
1468  max_x = pl->x+(pl->contr->socket.mapx+1)/2;
1469  max_y = pl->y+(pl->contr->socket.mapy+1)/2;
1470  for (j = min_y; j < max_y; j++) {
1471  for (i = min_x; i < max_x; i++) {
1472  ax = i;
1473  ay = j;
1474  m = pm;
1475  mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
1476  if (mflags&P_OUT_OF_MAP)
1477  continue;
1478  if (mflags&P_NEED_UPDATE)
1479  update_position(m, ax, ay);
1480  /* If a map is visible to the player, we don't want
1481  * to swap it out just to reload it. This should
1482  * really call something like swap_map, but this is
1483  * much more efficient and 'good enough'
1484  */
1485  if (mflags&P_NEW_MAP)
1486  m->timeout = 50;
1487  }
1488  }
1489 
1490  /* do LOS after calls to update_position */
1491  if (pl->contr->do_los) {
1492  update_los(pl);
1493  pl->contr->do_los = 0;
1494  }
1495 
1496  draw_client_map2(pl);
1497 }
1498 
1499 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
1500  struct Map newmap;
1501  int x, y, mx, my;
1502 
1503  ns->map_scroll_x += dx;
1504  ns->map_scroll_y += dy;
1505 
1506  mx = ns->mapx+MAX_HEAD_OFFSET;
1507  my = ns->mapy+MAX_HEAD_OFFSET;
1508 
1509  /* the x and y here are coordinates for the new map, i.e. if we moved
1510  * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
1511  * if the destination x or y coordinate is outside the viewable
1512  * area, we clear the values - otherwise, the old values
1513  * are preserved, and the check_head thinks it needs to clear them.
1514  */
1515  for (x = 0; x < mx; x++) {
1516  for (y = 0; y < my; y++) {
1517  if (x >= ns->mapx || y >= ns->mapy) {
1518  /* clear cells outside the viewable area */
1519  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1520  } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
1521  /* clear newly visible tiles within the viewable area */
1522  memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
1523  } else {
1524  memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
1525  }
1526  }
1527  }
1528 
1529  memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
1530 }
1531 
1537 void send_plugin_custom_message(object *pl, char *buf) {
1538  SockList sl;
1539 
1540  SockList_Init(&sl);
1541  SockList_AddString(&sl, buf);
1542  Send_With_Handling(&pl->contr->socket, &sl);
1543  SockList_Term(&sl);
1544 }
1545 
1552  SockList sl;
1553  int flags = 0;
1554  client_spell *spell_info;
1555 
1556  if (!pl->socket.monitor_spells)
1557  return;
1558 
1559  /* Handles problem at login, where this is called from fix_object
1560  * before we have had a chance to send spells to the player. It does seem
1561  * to me that there should never be a case where update_spells is called
1562  * before add_spells has been called. Add_spells() will update the
1563  * spell_state to non null.
1564  */
1565  if (!pl->spell_state)
1566  return;
1567 
1568  FOR_INV_PREPARE(pl->ob, spell) {
1569  if (spell->type == SPELL) {
1570  spell_info = get_client_spell_state(pl, spell);
1571  /* check if we need to update it*/
1572  if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
1573  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1574  flags |= UPD_SP_MANA;
1575  }
1576  if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
1577  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1578  flags |= UPD_SP_GRACE;
1579  }
1580  if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
1581  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1582  flags |= UPD_SP_DAMAGE;
1583  }
1584  if (flags != 0) {
1585  SockList_Init(&sl);
1586  SockList_AddString(&sl, "updspell ");
1587  SockList_AddChar(&sl, flags);
1588  SockList_AddInt(&sl, spell->count);
1589  if (flags&UPD_SP_MANA)
1590  SockList_AddShort(&sl, spell_info->last_sp);
1591  if (flags&UPD_SP_GRACE)
1592  SockList_AddShort(&sl, spell_info->last_grace);
1593  if (flags&UPD_SP_DAMAGE)
1594  SockList_AddShort(&sl, spell_info->last_dam);
1595  flags = 0;
1596  Send_With_Handling(&pl->socket, &sl);
1597  SockList_Term(&sl);
1598  }
1599  }
1600  } FOR_INV_FINISH();
1601 }
1602 
1603 void esrv_remove_spell(player *pl, object *spell) {
1604  SockList sl;
1605 
1606  if (!pl->socket.monitor_spells)
1607  return;
1608  if (!pl || !spell || spell->env != pl->ob) {
1609  LOG(llevError, "Invalid call to esrv_remove_spell\n");
1610  return;
1611  }
1612  SockList_Init(&sl);
1613  SockList_AddString(&sl, "delspell ");
1614  SockList_AddInt(&sl, spell->count);
1615  Send_With_Handling(&pl->socket, &sl);
1616  SockList_Term(&sl);
1617 }
1618 
1626  SockList sl;
1627 
1628  if (!pl->socket.want_pickup)
1629  return;
1630  SockList_Init(&sl);
1631  SockList_AddString(&sl, "pickup ");
1632  SockList_AddInt(&sl, pl->mode);
1633  Send_With_Handling(&pl->socket, &sl);
1634  SockList_Term(&sl);
1635 }
1636 
1645 static int spell_client_use(const object *spell) {
1646  if (spell->type == SP_RAISE_DEAD)
1647  return 3;
1648 
1649  if (spell->type == SP_RUNE && !spell->other_arch)
1650  return 1;
1651 
1652  if (spell->type == SP_MAKE_MARK)
1653  return 3;
1654 
1655  if (spell->type == SP_CREATE_FOOD)
1656  return 2;
1657 
1658  if (spell->type == SP_SUMMON_MONSTER && spell->randomitems != NULL)
1659  return 2;
1660 
1661  if (spell->type == SP_CREATE_MISSILE)
1662  return 2;
1663 
1664  return 0;
1665 }
1666 
1668 static void append_spell(player *pl, SockList *sl, object *spell) {
1669  client_spell *spell_info;
1670  int len, i, skill = 0;
1671 
1672  if (!spell->name) {
1673  LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
1674  return;
1675  }
1676 
1677  if (spell->face && !(pl->socket.faces_sent[spell->face->number]&NS_FACESENT_FACE))
1678  esrv_send_face(&pl->socket, spell->face->number, 0);
1679 
1680  spell_info = get_client_spell_state(pl, spell);
1681  SockList_AddInt(sl, spell->count);
1682  SockList_AddShort(sl, spell->level);
1683  SockList_AddShort(sl, spell->casting_time);
1684  /* store costs and damage in the object struct, to compare to later */
1685  spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
1686  spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
1687  spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
1688  /* send the current values */
1689  SockList_AddShort(sl, spell_info->last_sp);
1690  SockList_AddShort(sl, spell_info->last_grace);
1691  SockList_AddShort(sl, spell_info->last_dam);
1692 
1693  /* figure out which skill it uses, if it uses one */
1694  if (spell->skill) {
1695  for (i = 1; i < NUM_SKILLS; i++)
1696  if (!strcmp(spell->skill, skill_names[i])) {
1697  skill = i+CS_STAT_SKILLINFO;
1698  break;
1699  }
1700  }
1701  SockList_AddChar(sl, skill);
1702 
1703  SockList_AddInt(sl, spell->path_attuned);
1704  SockList_AddInt(sl, spell->face ? spell->face->number : 0);
1705  SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
1706 
1707  if (!spell->msg) {
1708  SockList_AddShort(sl, 0);
1709  } else {
1710  len = strlen(spell->msg);
1711  SockList_AddShort(sl, len);
1712  SockList_AddData(sl, spell->msg, len);
1713  }
1714 
1715  /* Extended spell information available if the client wants it.
1716  */
1717  if (pl->socket.monitor_spells >= 2) {
1718  /* spellmon 2
1719  */
1720  sstring req = object_get_value(spell, "casting_requirements");
1721 
1722  SockList_AddChar(sl, spell_client_use(spell)); /* Usage code */
1723 
1724  if (req) { /* Requirements */
1725  SockList_AddLen8Data(sl, req, strlen(req));
1726  } else {
1727  SockList_AddChar(sl, 0);
1728  }
1729  /* end spellmon 2
1730  */
1731  }
1732 }
1733 
1738 void esrv_add_spells(player *pl, object *spell) {
1739  SockList sl;
1740  size_t size;
1741  sstring value;
1742 
1743  if (!pl) {
1744  LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
1745  return;
1746  }
1747 
1748  if (!pl->socket.monitor_spells)
1749  return;
1750 
1751  SockList_Init(&sl);
1752  SockList_AddString(&sl, "addspell ");
1753  if (!spell) {
1754  FOR_INV_PREPARE(pl->ob, spell) {
1755  if (spell->type != SPELL)
1756  continue;
1757  /* Were we to simply keep appending data here, we could
1758  * exceed the SockList buffer if the player has enough spells
1759  * to add. We know that append_spell will always append
1760  * 23 data bytes, plus 3 length bytes and 2 strings
1761  * (because that is the spec) so we need to check that
1762  * the length of those 2 strings, plus the 26 bytes,
1763  * won't take us over the length limit for the socket.
1764  * If it does, we need to send what we already have,
1765  * and restart packet formation.
1766  */
1767  size = 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0);
1768  if (pl->socket.monitor_spells >= 2) {
1770  value = object_get_value(spell, "casting_requirements");
1771  size += 2 + (value ? strlen(value) : 0);
1772  }
1773  if (SockList_Avail(&sl) < size) {
1774  Send_With_Handling(&pl->socket, &sl);
1775  SockList_Reset(&sl);
1776  SockList_AddString(&sl, "addspell ");
1777  }
1778  append_spell(pl, &sl, spell);
1779  } FOR_INV_FINISH();
1780  } else if (spell->type != SPELL) {
1781  LOG(llevError, "Asked to send a non-spell object as a spell\n");
1782  return;
1783  } else
1784  append_spell(pl, &sl, spell);
1785  /* finally, we can send the packet */
1786  Send_With_Handling(&pl->socket, &sl);
1787  SockList_Term(&sl);
1788 }
1789 
1790 /* sends a 'tick' information to the client.
1791  * We also take the opportunity to toggle TCP_NODELAY -
1792  * this forces the data in the socket to be flushed sooner to the
1793  * client - otherwise, the OS tries to wait for full packets
1794  * and will this hold sending the data for some amount of time,
1795  * which thus adds some additional latency.
1796  */
1798  SockList sl;
1799  int tmp;
1800 
1801  SockList_Init(&sl);
1802  SockList_AddString(&sl, "tick ");
1803  SockList_AddInt(&sl, pticks);
1804  tmp = 1;
1805  if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
1806  LOG(llevError, "send_tick: Unable to turn on TCP_NODELAY\n");
1807 
1808  Send_With_Handling(&pl->socket, &sl);
1809  tmp = 0;
1810  if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
1811  LOG(llevError, "send_tick: Unable to turn off TCP_NODELAY\n");
1812  SockList_Term(&sl);
1813 }
1814 
1827 static void add_char_field(SockList *sl, int type, const char *data)
1828 {
1829  int len;
1830 
1831  len = strlen(data);
1832 
1833  if (len) {
1834  /* one extra for length for the type byte */
1835  SockList_AddChar(sl, len+1);
1836  SockList_AddChar(sl, type);
1837  SockList_AddString(sl, data);
1838  }
1839 }
1840 
1862 {
1863  SockList sl;
1864  Account_Char *acn;
1865  int i, num_chars, need_send[MAX_CHARACTERS_PER_ACCOUNT];
1866  char **chars;
1867 
1869 
1870  /*
1871  * The acocunt logic here is a little tricky - account_char_load()
1872  * is best source as it has a lot more data. However, if a user
1873  * has just added an player to an account, that will not be filled
1874  * in until the player has actually logged in with that character -
1875  * to fill the data in at time of adding the character to the account
1876  * requires a fair amount of work to check_login(), since the load
1877  * of the player file and other initialization is fairly closely
1878  * intertwined. So until that is done, we still at least have
1879  * account names we can get and send.
1880  * note: chars[] has the last entry NULL terminated - thus,
1881  * if there are 2 valid accounts, chars[0], chars[1] will be
1882  * set, and chars[2] will be NULL. chars[3...MAX] will have
1883  * undefined values.
1884  */
1886 
1887  SockList_Init(&sl);
1888  SockList_AddString(&sl, "accountplayers ");
1889  num_chars=0;
1890 
1891  /* First, set up an array so we know which character we may
1892  * need to send specially. Only non NULL values would
1893  * ever need to get sent.
1894  */
1895  for (i=0; i<MAX_CHARACTERS_PER_ACCOUNT; i++) {
1896  if (chars[i])
1897  need_send[i] = 1;
1898  else break;
1899  }
1900  /* This counts up the number of characters.
1901  * But also, we look and see if the character exists
1902  * in chars[i] - if so, we set need_send[i] to 0.
1903  */
1904  for (acn = ns->account_chars; acn; acn = acn->next) {
1905  num_chars++;
1906  for (i=0; i<MAX_CHARACTERS_PER_ACCOUNT; i++) {
1907  /* If this is NULL, we know there will not be
1908  * any more entries - so break out.
1909  */
1910  if (!chars[i]) break;
1911 
1912  if (!strcmp(chars[i], acn->name)) {
1913  need_send[i] = 0;
1914  break;
1915  }
1916  }
1917  }
1918 
1919  /* total up number with limited information */
1920  for (i=0; i< MAX_CHARACTERS_PER_ACCOUNT; i++) {
1921  if (!chars[i]) break;
1922 
1923  if (need_send[i])
1924  num_chars++;
1925  }
1926 
1927  SockList_AddChar(&sl, num_chars);
1928 
1929  /* Now add real character data */
1930  for (acn = ns->account_chars; acn; acn = acn->next) {
1931  uint16_t faceno;
1932 
1933  /* Ignore a dead character. They don't need to show up. */
1934  if (acn->isDead) {
1935  continue;
1936  }
1937 
1938  add_char_field(&sl, ACL_NAME, acn->name);
1940  add_char_field(&sl, ACL_RACE, acn->race);
1941  add_char_field(&sl, ACL_FACE, acn->face);
1942  if (acn->face[0] != 0 ) {
1943  faceno = find_face(acn->face, 0);
1944 
1945  if (faceno != 0) {
1946  if (!(ns->faces_sent[faceno]&NS_FACESENT_FACE)) {
1947  esrv_send_face(ns, faceno, 0);
1948  }
1949  }
1950  } else
1951  faceno=0;
1952 
1953  add_char_field(&sl, ACL_PARTY, acn->party);
1954  add_char_field(&sl, ACL_MAP, acn->map);
1955  SockList_AddChar(&sl, 3);
1957  SockList_AddShort(&sl, acn->level);
1958  if (faceno) {
1959  SockList_AddChar(&sl, 3);
1961  SockList_AddShort(&sl, faceno);
1962  }
1963 
1964  SockList_AddChar(&sl, 0);
1965  }
1966  /* Now for any characters where we just have the name */
1967  for (i=0; i< MAX_CHARACTERS_PER_ACCOUNT; i++) {
1968  if (!chars[i]) break;
1969 
1970  if (need_send[i]) {
1971  add_char_field(&sl, ACL_NAME, chars[i]);
1972  SockList_AddChar(&sl, 0);
1973  }
1974  }
1975 
1976  Send_With_Handling(ns, &sl);
1977  SockList_Term(&sl);
1978 }
1979 
2001 static int decode_name_password(const char *buf, int *len, char *name, char *password)
2002 {
2003  int nlen, plen;
2004 
2005  if (*len < 2) {
2006  return 1;
2007  }
2008 
2009  nlen = (unsigned char)buf[0];
2010  if (nlen >= MAX_BUF || nlen > *len-2) {
2011  return 1;
2012  }
2013  memcpy(name, buf+1, nlen);
2014  name[nlen] = 0;
2015 
2016  plen = (unsigned char)buf[nlen+1];
2017  if (plen >= MAX_BUF || plen > *len-2-nlen) {
2018  return 2;
2019  }
2020  memcpy(password, buf+2+nlen, plen);
2021  password[plen] = 0;
2022 
2023  *len = nlen+plen+2;
2024 
2025  return 0;
2026 }
2037 void account_login_cmd(char *buf, int len, socket_struct *ns) {
2038  char name[MAX_BUF], password[MAX_BUF];
2039  int status;
2040  SockList sl;
2041 
2042  if (len <= 0 || !buf) {
2043  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2044  return;
2045  }
2046 
2047  SockList_Init(&sl);
2048 
2049  status = decode_name_password(buf, &len, name, password);
2050 
2051  if (status == 1) {
2052  SockList_AddString(&sl, "failure accountlogin Name is too long");
2053  Send_With_Handling(ns, &sl);
2054  SockList_Term(&sl);
2055  return;
2056  }
2057  if (status == 2) {
2058  SockList_AddString(&sl, "failure accountlogin Password is too long");
2059  Send_With_Handling(ns, &sl);
2060  SockList_Term(&sl);
2061  return;
2062  }
2063 
2064  if (!account_exists(name)) {
2065  SockList_AddString(&sl, "failure accountlogin No such account name exists on this server");
2066  Send_With_Handling(ns, &sl);
2067  SockList_Term(&sl);
2068  return;
2069  }
2070 
2071  if (account_login(name, password)) {
2072  player *pl;
2073  socket_struct *tns;
2074 
2075  /* Checking against init_sockets must be done before
2076  * we set ns->account - otherwise we will match
2077  * that. What we are doing here is limiting the account
2078  * to only one login.
2079  */
2081  /* Other code will clean this up. We could try to
2082  * set the same state this other socket is in, but we
2083  * really don't know what that state is, and then
2084  * we would have to try to communicate that to the client
2085  * so it can activate the right dialogs. Simpler to
2086  * just go to a known state.
2087  */
2088  if (tns && tns != ns)
2089  tns->status = Ns_Dead;
2090 
2091  /* Same note as above applies - it can be simpler in
2092  * this case - we could check against the ST_PLAYING
2093  * value, but right now we don't have a method to
2094  * tell the client to go directly from login to playing.
2095  */
2096  pl = account_get_logged_in_player(name);
2097  if (pl)
2098  pl->socket.status = Ns_Dead;
2099 
2100 
2101  if (ns->account_name) free(ns->account_name);
2102  /* We want to store away official name so we do not
2103  * have any case sensitivity issues on the files.
2104  * because we have already checked password, we
2105  * know that account_exists should never return NULL in
2106  * this case.
2107  */
2109 
2111 
2112  } else {
2113  SockList_AddString(&sl, "failure accountlogin Incorrect password for account");
2114  Send_With_Handling(ns, &sl);
2115  SockList_Term(&sl);
2116  }
2117 }
2118 
2127 static int account_block_create(const socket_struct *ns) {
2128  /* Check if account creation is blocked. */
2130  /* Account creation is allowed for everyone. */
2131  return 0;
2132  }
2133 
2134  /* Has the trusted host been defined? */
2135  if(settings.account_trusted_host == NULL) {
2136  /* No, allocate it and set it to localhost now. */
2138  }
2139 
2140  /* Return false if the client connected from the trusted host. */
2141  if(strcmp(ns->host, settings.account_trusted_host) == 0){
2142  return 0;
2143  }
2144 
2145  /*
2146  * If we are here, then we are blocking account create and we do
2147  * not trust this client's IP address.
2148  */
2149  return 1;
2150 }
2151 
2163 void account_new_cmd(char *buf, int len, socket_struct *ns) {
2164  char name[MAX_BUF], password[MAX_BUF];
2165  int status;
2166  SockList sl;
2167 
2168  if (len <= 0 || !buf) {
2169  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2170  return;
2171  }
2172 
2173  SockList_Init(&sl);
2174 
2175  status = decode_name_password(buf, &len, name, password);
2176 
2177  if (account_block_create(ns)) {
2178  LOG(llevInfo, "Account create blocked from %s\n", ns->host);
2179  SockList_AddString(&sl, "failure accountnew Account creation is disabled");
2180  Send_With_Handling(ns, &sl);
2181  SockList_Term(&sl);
2182  return;
2183  }
2184 
2185  if (status == 1) {
2186  SockList_AddString(&sl, "failure accountnew Name is too long");
2187  Send_With_Handling(ns, &sl);
2188  SockList_Term(&sl);
2189  return;
2190  }
2191  if (status == 2) {
2192  SockList_AddString(&sl, "failure accountnew Password is too long");
2193  Send_With_Handling(ns, &sl);
2194  SockList_Term(&sl);
2195  return;
2196  }
2197  /*The minimum length isn't exactly required, but in the current implementation,
2198  * client will send the same password for character for which there is a
2199  * 2 character minimum size. Thus an account with a one character password
2200  * won't be able to create a character. */
2201  if (strlen(password)<2) {
2202  SockList_AddString(&sl, "failure accountnew Password is too short");
2203  Send_With_Handling(ns, &sl);
2204  SockList_Term(&sl);
2205  return;
2206  }
2207 
2208  if (account_exists(name)) {
2209  SockList_AddString(&sl, "failure accountnew That account already exists on this server");
2210  Send_With_Handling(ns, &sl);
2211  SockList_Term(&sl);
2212  return;
2213  }
2214 
2215  status = account_check_string(name);
2216  if (status == 1) {
2217  SockList_AddString(&sl,
2218  "failure accountnew That account name contains invalid characters.");
2219  Send_With_Handling(ns, &sl);
2220  SockList_Term(&sl);
2221  return;
2222  }
2223 
2224  if (status == 2) {
2225  SockList_AddString(&sl,
2226  "failure accountnew That account name is too long");
2227  Send_With_Handling(ns, &sl);
2228  SockList_Term(&sl);
2229  return;
2230  }
2231 
2232  status = account_check_string(password);
2233  if (status == 1) {
2234  SockList_AddString(&sl,
2235  "failure accountnew That password contains invalid characters.");
2236  Send_With_Handling(ns, &sl);
2237  SockList_Term(&sl);
2238  return;
2239  }
2240 
2241  if (status == 2) {
2242  SockList_AddString(&sl,
2243  "failure accountnew That password is too long");
2244  Send_With_Handling(ns, &sl);
2245  SockList_Term(&sl);
2246  return;
2247  }
2248 
2249  /* If we got here, we passed all checks - so now add it */
2250  if (ns->account_name) free(ns->account_name);
2251  ns->account_name = strdup_local(name);
2252  account_new(name, password);
2253  /* save account information */
2254  accounts_save();
2256 }
2257 
2271 void account_add_player_cmd(char *buf, int len, socket_struct *ns) {
2272  char name[MAX_BUF], password[MAX_BUF];
2273  int status, force, nlen;
2274  SockList sl;
2275  const char *cp;
2276 
2277  if (len <= 0 || !buf) {
2278  LOG(llevDebug, "IP '%s' sent bogus add_player_cmd information\n", ns->host);
2279  return;
2280  }
2281 
2282  SockList_Init(&sl);
2283 
2284  if (ns->account_name == NULL) {
2285  SockList_AddString(&sl, "failure accountaddplayer Not logged in");
2286  Send_With_Handling(ns, &sl);
2287  SockList_Term(&sl);
2288  return;
2289  }
2290 
2291  force = buf[0];
2292  nlen = len - 1;
2293  status = decode_name_password(buf+1, &nlen, name, password);
2294  if (status == 1) {
2295  SockList_AddString(&sl, "failure accountaddplayer Name is too long");
2296  Send_With_Handling(ns, &sl);
2297  SockList_Term(&sl);
2298  return;
2299  }
2300  if (status == 2) {
2301  SockList_AddString(&sl, "failure accountaddplayer Password is too long");
2302  Send_With_Handling(ns, &sl);
2303  SockList_Term(&sl);
2304  return;
2305  }
2306 
2307  status = verify_player(name, password);
2308  if (status) {
2309  /* From a security standpoint, telling random folks if it
2310  * it as wrong password makes it easier to hack. However,
2311  * it is fairly easy to determine what characters exist on a server
2312  * (either by trying to create a new one and see if the name is in
2313  * in use, or just looking at the high score file), so this
2314  * really does not make things much less secure
2315  */
2316  if (status == 1)
2317  SockList_AddString(&sl, "failure accountaddplayer 0 The character does not exist.");
2318  else
2319  SockList_AddString(&sl, "failure accountaddplayer 0 That password is incorrect.");
2320 
2321  Send_With_Handling(ns, &sl);
2322  SockList_Term(&sl);
2323  return;
2324  }
2325  /* Check to see if this character is associated with an account.
2326  */
2327  cp = account_get_account_for_char(name);
2328  if (cp) {
2329  if (!strcmp(cp, ns->account_name)) {
2330  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to this account.");
2331  Send_With_Handling(ns, &sl);
2332  SockList_Term(&sl);
2333  return;
2334  } else {
2335  if (!force) {
2336  SockList_AddString(&sl, "failure accountaddplayer 1 That character is already connected to a different account.");
2337  Send_With_Handling(ns, &sl);
2338  SockList_Term(&sl);
2339  return;
2340  } else if (account_is_logged_in(cp)) {
2341  /* We could be clever and try to handle this case, but it is
2342  * trickier. If the character is logged in, it has to
2343  * be logged out. And the socket holds some data which
2344  * needs to be cleaned up. Since it should be fairly
2345  * uncommon that users need to do this, just disallowing
2346  * it makes things a lot simpler.
2347  */
2348  SockList_AddString(&sl, "failure accountaddplayer 0 That character is already connected to a different account which is currently logged in.");
2349  Send_With_Handling(ns, &sl);
2350  SockList_Term(&sl);
2351  return;
2352  }
2353  }
2354  }
2355  /* If we have gotten this far, the name/password provided is OK,
2356  * and the character is not associated with a different account (or
2357  * force is true). Now try to add the character to this account.
2358  */
2359  status = account_link(ns->account_name, name);
2360 
2361  /* This should never happen, but check for it just in case -
2362  * if we were able to log in, the account should exist. but
2363  * if this fails, need to give the user some clue.
2364  */
2365  if (status==1) {
2366  SockList_AddString(&sl, "failure accountaddplayer 0 Could not find your account.");
2367  Send_With_Handling(ns, &sl);
2368  SockList_Term(&sl);
2369  return;
2370  } else if (status == 2) {
2371  SockList_AddString(&sl, "failure accountaddplayer 0 You have reached the maximum number of characters allowed per account.");
2372  Send_With_Handling(ns, &sl);
2373  SockList_Term(&sl);
2374  return;
2375  }
2376 
2377  /* If cp is set, then this character used to belong to a different
2378  * account. Remove it now.
2379  */
2380  if (cp) {
2381  Account_Char *chars;
2382 
2383  account_remove_player(cp, name);
2384  chars = account_char_load(cp);
2385  chars=account_char_remove(chars, name);
2386  account_char_save(cp, chars);
2387  account_char_free(chars);
2388  }
2389 
2391 
2392  /* store data so nothing is lost in case of crash */
2394 }
2395 
2400 void account_play_cmd(char *buf, int len, socket_struct *ns)
2401 {
2402  char **chars;
2403  int i;
2404  SockList sl;
2405  player *pl;
2406 
2407  if (len <= 0 || !buf) {
2408  LOG(llevDebug, "IP '%s' sent bogus account_play_cmd information\n", ns->host);
2409  return;
2410  }
2411 
2412  SockList_Init(&sl);
2413 
2414  if (!buf[0]) {
2415  SockList_AddString(&sl, "failure accountplay Malformed character name");
2416  Send_With_Handling(ns, &sl);
2417  SockList_Term(&sl);
2418  return;
2419  }
2420 
2421  if (ns->account_name == NULL) {
2422  SockList_AddString(&sl, "failure accountplay Not logged in");
2423  Send_With_Handling(ns, &sl);
2424  SockList_Term(&sl);
2425  return;
2426  }
2427 
2429 
2430  for (i=0; i<MAX_CHARACTERS_PER_ACCOUNT; i++) {
2431  if (!chars[i] || !strcmp(chars[i], buf)) break;
2432  }
2433  /* Make sure a client is not trying to spoof us here */
2434  if (i == MAX_CHARACTERS_PER_ACCOUNT || !chars[i]) {
2435  SockList_AddPrintf(&sl,
2436  "failure accountplay Character %s is not associated with account %s",
2437  buf, ns->account_name);
2438  Send_With_Handling(ns, &sl);
2439  SockList_Term(&sl);
2440  return;
2441  }
2442 
2443  /* from a protocol standpoint, accountplay can be used
2444  * before there is a player structure (first login) or after
2445  * (character has logged in and is changing characters).
2446  * Checkthe sockets for that second case - if so,
2447  * we don't need to make a new player object, etc.
2448  */
2449  for (pl=first_player; pl; pl=pl->next) {
2450  if (&pl->socket == ns) {
2451  /* The player still in the socket must be saved first. */
2452  save_player(pl->ob, 0);
2453  break;
2454  }
2455  }
2456 
2457  /* Some of this logic is from add_player()
2458  * we just don't use add_player() as it does some other work
2459  * we don't really want to do.
2460  */
2461  if (!pl) {
2462  pl = get_player(NULL);
2463  memcpy(&pl->socket, ns, sizeof(socket_struct));
2464  ns->faces_sent = NULL;
2466  } else {
2467  pl->state = ST_PLAYING;
2468  }
2469 
2470  pl->ob->name = add_string(buf);
2471  check_login(pl->ob, 0);
2472 
2473  SockList_AddString(&sl, "addme_success");
2474  Send_With_Handling(ns, &sl);
2475  SockList_Term(&sl);
2476 
2477  ns->status = Ns_Avail;
2478 }
2479 
2480 #define MAX_CHOICES 100
2481 
2487 void create_player_cmd(char *buf, int len, socket_struct *ns)
2488 {
2489  char name[MAX_BUF], password[MAX_BUF], *choices[MAX_CHOICES];
2490  int status, nlen, choice_num=0, i;
2491  SockList sl;
2492  player *pl;
2493  archetype *map=NULL, *race_a=NULL, *class_a=NULL;
2494  living new_stats;
2495 
2496  if (len <= 0 || !buf) {
2497  LOG(llevDebug, "IP '%s' sent bogus create_player_cmd information\n", ns->host);
2498  return;
2499  }
2500 
2501  SockList_Init(&sl);
2502 
2503  nlen = len;
2504  status = decode_name_password(buf, &nlen, name, password);
2505  if (status == 1) {
2506  SockList_AddString(&sl, "failure createplayer Name is too long");
2507  Send_With_Handling(ns, &sl);
2508  SockList_Term(&sl);
2509  return;
2510  }
2511 
2512  /* 2 characters minimum for password */
2513  if (strlen(password)<2) {
2514  SockList_AddString(&sl, "failure createplayer Password is too short");
2515  Send_With_Handling(ns, &sl);
2516  SockList_Term(&sl);
2517  return;
2518  }
2519 
2521  if (status == 2) {
2522  SockList_AddString(&sl, "failure createplayer Password is too long");
2523  Send_With_Handling(ns, &sl);
2524  SockList_Term(&sl);
2525  return;
2526  }
2527 
2528  /* This is a fairly ugly solution - we're truncating the password.
2529  * however, the password information for characters is really
2530  * a legacy issue - when every character is associated with
2531  * an account, legacy login (character name/password) will get
2532  * removed, at which point the only use for password might be
2533  * to move characters from one account to another, but not sure
2534  * if that is something we want to allow.
2535  */
2536  if (strlen(password)>17)
2537  password[16] = 0;
2538 
2539  /* We just can't call check_name(), since that uses draw_info() to
2540  * report status. We are also more permissive on names, so we use
2541  * account_check_string() - if that is safe for account, also safe
2542  * for player names.
2543  */
2544  if (account_check_string(name)) {
2545  SockList_AddString(&sl, "failure createplayer The name contains illegal characters");
2546  Send_With_Handling(ns, &sl);
2547  SockList_Term(&sl);
2548  return;
2549  }
2550 
2551  /* 1 means no such player, 0 is correct name/password (which in this
2552  * case, is an error), and 2 is incorrect password. Only way we
2553  * go onward is if there is no such player.
2554  */
2555  if (verify_player(name, password) != 1) {
2556  SockList_AddString(&sl, "failure createplayer That name is already in use");
2557  Send_With_Handling(ns, &sl);
2558  SockList_Term(&sl);
2559  return;
2560  }
2561 
2562  /* from a protocol standpoint, accountplay can be used
2563  * before there is a player structure (first login) or after
2564  * (character has logged in and is changing characters).
2565  * Check the sockets for that second case - if so,
2566  * we don't need to make a new player object, etc.
2567  */
2568  for (pl=first_player; pl; pl=pl->next)
2569  if (&pl->socket == ns) {
2570  if (pl->ob->name && !strcmp(pl->ob->name, name)) {
2571  /* For some reason not only the socket is the same but also
2572  * the player is already playing. If this happens at this
2573  * point let's assume the character never was able to apply
2574  * a bet of reality to make a correct first-time save.
2575  * So, for safety remove it and start over.
2576  */
2577  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED))
2578  object_remove(pl->ob);
2579  }
2580  break;
2581  }
2582 
2583  /* In this mode, we have additional data
2584  * Note that because there are a lot of failure cases in here
2585  * (where we end up not creating the new player), the code
2586  * to create the new player is done within this routine
2587  * after all checks pass. Note that all of the checks
2588  * done are done without using the player structure,
2589  * as pl may be null right now.
2590  */
2591  if (ns->login_method >= 2) {
2592  int i, j, stat_total=0;
2593  char *key, *value, *race=NULL, *class=NULL;
2594 
2595  /* By setting this to zero, then we can easily
2596  * check to see if all stats have been set.
2597  */
2598  memset(&new_stats, 0, sizeof(living));
2599 
2600  while (nlen < len) {
2601  i = buf[nlen]; /* Length of this line */
2602  /* Sanity check from client - don't want to loop
2603  * forever if there is a 0 length, and don't
2604  * want to read beyond size of packet.
2605  * Likewise, client should have sent
2606  * the string to us already null terminated,
2607  * but we will just make sure.
2608  */
2609  if ((i == 0) || (nlen + i > len)) break;
2610  buf[nlen + i] = 0;
2611 
2612  /* What we have are a series of lines -
2613  * 'key value' format. Find that space,
2614  * and null it out so we can do strcasecmp.
2615  * If no space, abort processing
2616  */
2617  key = buf + nlen + 1;
2618  value = strchr(key, ' ');
2619  if (!value) break;
2620  *value = 0;
2621  value++;
2622 
2623  if (!strcasecmp(key,"race")) race = value;
2624  else if (!strcasecmp(key,"class")) class = value;
2625  else if (!strcasecmp(key,"starting_map")) {
2626  map = try_find_archetype(value);
2627  if (!map || map->clone.type != MAP || map->clone.subtype !=MAP_TYPE_CHOICE) {
2628  SockList_AddString(&sl,
2629  "failure createplayer Invalid or map");
2630  Send_With_Handling(ns, &sl);
2631  SockList_Term(&sl);
2632  return;
2633  }
2634  }
2635  else if (!strcasecmp(key,"choice")) {
2636  /* In general, MAX_CHOICES should be large enough
2637  * to always handle the choices from the client - of
2638  * course, the client could be broken and send us many
2639  * more choices than we should have, so handle that.
2640  */
2641  if (choice_num == MAX_CHOICES) {
2642  LOG(llevError,
2643  "Number of choices receive exceed max value: %d>%d\n",
2644  choice_num, MAX_CHOICES);
2645  } else {
2646  choices[choice_num] = value;
2647  choice_num++;
2648  }
2649  }
2650  else {
2651  /* Do stat processing here */
2652  for (j=0; j < NUM_STATS; j++) {
2653  if (!strcasecmp(key,short_stat_name[j])) {
2654  int val = atoi(value);
2655 
2656  set_attr_value(&new_stats, j, val);
2657  break;
2658  }
2659  }
2660  if (j >= NUM_STATS) {
2661  /* Bad clients could do this - we should at least report
2662  * it, and useful when trying to add new parameters.
2663  */
2664  LOG(llevError, "Got unknown key/value from client: %s %s\n", key, value);
2665  }
2666  }
2667  nlen += i + 1;
2668  }
2669  /* Do some sanity checking now. But checking the stat
2670  * values here, we will catch any 0 values since we do
2671  * a memset above. A properly behaving client should
2672  * never do any of these things, but we do not presume
2673  * clients will behave properly.
2674  */
2675  for (j=0; j<NUM_STATS; j++) {
2676  int val = get_attr_value(&new_stats, j);
2677 
2678  stat_total += val;
2679  if (val > settings.starting_stat_max ||
2680  val < settings.starting_stat_min) {
2681  SockList_AddPrintf(&sl,
2682  "failure createplayer Stat value is out of range - %d must be between %d and %d",
2684  Send_With_Handling(ns, &sl);
2685  SockList_Term(&sl);
2686  return;
2687  }
2688  }
2689  if (stat_total > settings.starting_stat_points) {
2690  SockList_AddPrintf(&sl,
2691  "failure createplayer Total allocated statistics is higher than allowed (%d>%d)",
2692  stat_total, settings.starting_stat_points);
2693  Send_With_Handling(ns, &sl);
2694  SockList_Term(&sl);
2695  return;
2696  }
2697 
2698  if (race)
2699  race_a = try_find_archetype(race);
2700 
2701  if (class)
2702  class_a = try_find_archetype(class);
2703 
2704  /* This should never happen with a properly behaving client, so the error message
2705  * doesn't have to be that great.
2706  */
2707  if (!race_a || race_a->clone.type != PLAYER || !class_a || class_a->clone.type != CLASS) {
2708  SockList_AddString(&sl,
2709  "failure createplayer Invalid or unknown race or class");
2710  Send_With_Handling(ns, &sl);
2711  SockList_Term(&sl);
2712  return;
2713  }
2714 
2715  /* At current time, only way this can fail is if the adjusted
2716  * stat is less than 1.
2717  */
2718  if (check_race_and_class(&new_stats, race_a, class_a)) {
2719  SockList_AddString(&sl,
2720  "failure createplayer Unable to apply race or class - statistic is out of bounds");
2721  Send_With_Handling(ns, &sl);
2722  SockList_Term(&sl);
2723  return;
2724  }
2725 
2726  if (!pl)
2728 
2729  apply_race_and_class(pl->ob, race_a, class_a, &new_stats);
2730 
2731  } else {
2732  /* In thise case, old login method */
2733  if (!pl)
2734  pl = add_player(ns, ADD_PLAYER_NEW);
2735 /* already done by add_player
2736  roll_again(pl->ob);
2737  pl->state = ST_ROLL_STAT;
2738  set_first_map(pl->ob);*/
2739  }
2740 
2741  /* add_player does a lot of the work, but there are a few
2742  * things we need to update, like starting name and
2743  * password.
2744  * This is done before processing in login_method>2.
2745  * The character creation process it does when
2746  * applying the race/class will use this
2747  * name information.
2748  */
2749  FREE_AND_COPY(pl->ob->name, name);
2750  FREE_AND_COPY(pl->ob->name_pl, name);
2751  pl->name_changed = 1;
2752  safe_strncpy(pl->password, newhash(password), sizeof(pl->password));
2753 
2754  SockList_AddString(&sl, "addme_success");
2755  Send_With_Handling(ns, &sl);
2756  SockList_Term(&sl);
2757 
2758  if (ns->login_method >= 2) {
2759  /* The client could have provided us a map - if so, map will be set
2760  * and we don't want to overwrite it
2761  */
2762  if (!map)
2764 
2765  if (!map) {
2766  /* This should never happen - its not something that can
2767  * be easily worked around without other weird issues,
2768  * like having 2 classes.
2769  */
2770  LOG(llevError, "Can not find object of type MAP subtype MAP_TYPE_DEFAULT.\n");
2771  LOG(llevError, "Are the archetype files up to date? Can not continue.\n");
2772  abort();
2773  }
2774 
2775  enter_exit(pl->ob, &map->clone);
2776 
2777  if (pl->ob->map == NULL) {
2778  LOG(llevError, "Couldn't put player %s on start map %s!", pl->ob->name, map->name);
2779  abort();
2780  }
2781 
2782  /* copy information to bed of reality information, in case the player dies */
2783  snprintf(pl->savebed_map, sizeof(pl->savebed_map), "%s", pl->ob->map->path);
2784  pl->bed_x = pl->ob->x;
2785  pl->bed_y = pl->ob->y;
2786 
2788  }
2789 
2790  /* We insert any objects after we have put the player on the map -
2791  * this makes things safer, as certain objects may expect a normal
2792  * environment. Note that choice_num will only be set in the
2793  * loginmethod > 2, which also checks (and errors out) if the
2794  * race/class is not set, which is why explicit checking for
2795  * those is not need.
2796  */
2797  for (i=0; i < choice_num; i++) {
2798  char *choiceval, *cp;
2799  const char *value;
2800  archetype *arch;
2801  object *op;
2802 
2803  choiceval = strchr(choices[i], ' ');
2804  if (!choiceval) {
2805  LOG(llevError, "Choice does not specify value: %s\n", choices[i]);
2806  continue;
2807  }
2808  *choiceval=0;
2809  choiceval++;
2810  value = object_get_value(&race_a->clone, choices[i]);
2811  if (!value)
2812  value = object_get_value(&class_a->clone, choices[i]);
2813 
2814  if (!value) {
2815  LOG(llevError, "Choice not found in archetype: %s\n", choices[i]);
2816  continue;
2817  }
2818  cp = strstr(value, choiceval);
2819  if (!cp) {
2820  LOG(llevError, "Choice value not found in archetype: %s %s\n",
2821  choices[i], choiceval);
2822  continue;
2823  }
2824 
2825  /* Check to make sure that the matched string is an entire word,
2826  * and not a substring (eg, valid choice being great_sword but
2827  * we just get sword) - the space after the match should either be a
2828  * space or null, and space before match should also be a space
2829  * or the start of the string.
2830  */
2831  if ((cp[strlen(choiceval)] != ' ') && (cp[strlen(choiceval)] != 0) &&
2832  (cp != value) && (*(cp-1) != ' ')) {
2833 
2834  LOG(llevError, "Choice value matches substring but not entire word: %s substring %s\n",
2835  choiceval, value);
2836  continue;
2837  }
2838  arch = try_find_archetype(choiceval);
2839  if (!arch) {
2840  LOG(llevError, "Choice value can not find archetype %s\n", choiceval);
2841  continue;
2842  }
2843  op = arch_to_object(arch);
2844  op = object_insert_in_ob(op, pl->ob);
2845  if (QUERY_FLAG(op, FLAG_AUTO_APPLY))
2846  ob_apply(op, pl->ob, 0);
2847  }
2848 
2849  ns->status = Ns_Avail;
2850 }
2851 
2862 void account_password(char *buf, int len, socket_struct *ns) {
2863  char old[MAX_BUF], change[MAX_BUF];
2864  int status;
2865  SockList sl;
2866 
2867  if (len <= 0 || !buf) {
2868  LOG(llevDebug, "IP '%s' sent bogus account_password_cmd information\n", ns->host);
2869  return;
2870  }
2871 
2872  SockList_Init(&sl);
2873 
2874  if (ns->account_name == NULL) {
2875  SockList_AddString(&sl, "failure accountpw Not logged in");
2876  Send_With_Handling(ns, &sl);
2877  SockList_Term(&sl);
2878  return;
2879  }
2880 
2881  status = decode_name_password(buf, &len, old, change);
2882  if (status == 1) {
2883  SockList_AddString(&sl, "failure accountpw Old password is too long");
2884  Send_With_Handling(ns, &sl);
2885  SockList_Term(&sl);
2886  return;
2887  }
2888  if (status == 2) {
2889  SockList_AddString(&sl, "failure accountpw New password is too long");
2890  Send_With_Handling(ns, &sl);
2891  SockList_Term(&sl);
2892  return;
2893  }
2894  /*The minimum length isn't exactly required, but in the current implementation,
2895  * client will send the same password for character for which there is a
2896  * 2 character minimum size. Thus an account with a one character password
2897  * won't be able to create a character. */
2898  if (strlen(change)<2) {
2899  SockList_AddString(&sl, "failure accountpw New password is too short");
2900  Send_With_Handling(ns, &sl);
2901  SockList_Term(&sl);
2902  return;
2903  }
2904 
2905  status = account_check_string(change);
2906  if (status == 1) {
2907  SockList_AddString(&sl,
2908  "failure accountpw That password contains invalid characters.");
2909  Send_With_Handling(ns, &sl);
2910  SockList_Term(&sl);
2911  return;
2912  }
2913 
2914  if (status == 2) {
2915  SockList_AddString(&sl,
2916  "failure accountpw That password is too long");
2917  Send_With_Handling(ns, &sl);
2918  SockList_Term(&sl);
2919  return;
2920  }
2921 
2922  status = account_change_password(ns->account_name, old, change);
2923  if (status != 0) {
2924  const char *error;
2925 
2926  if (status == 1) {
2927  error = "failure accountpw Illegal characters present";
2928  } else if (status == 2) {
2929  error = "failure accountpw Invalid account";
2930  } else {
2931  error = "failure accountpw Incorrect current password";
2932  }
2933 
2934  SockList_AddString(&sl, error);
2935  Send_With_Handling(ns, &sl);
2936  SockList_Term(&sl);
2937  return;
2938  }
2939 
2940  /* If we got here, we passed all checks, and password was changed */
2942 }
void map_newmap_cmd(socket_struct *ns)
Sound related function.
Definition: request.c:615
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.c:3999
const char * party
Character this party belonged to.
Definition: account_char.h:32
uint8_t login_method
Login method this client is using.
Definition: newserver.h:140
#define CS_STAT_AC
Definition: newclient.h:100
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
#define ACL_CLASS
Definition: newclient.h:197
void set_attr_value(living *stats, int attr, int8_t value)
Sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on what attr is (STR to POW)...
Definition: living.c:218
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.c:194
int16_t last_golem_maxhp
Last golem max hp value sent to the client.
Definition: player.h:157
int8_t Int
Definition: living.h:35
#define CS_STAT_RES_GHOSTHIT
Definition: newclient.h:152
One player.
Definition: player.h:92
Sound-related defines.
#define CS_STAT_APPLIED_CON
CON changes from gear or skills.
Definition: newclient.h:135
uint8_t faceset
Set the client is using, default 0.
Definition: newserver.h:129
int8_t ac
Armour Class, how hard to hit, the lower the better.
Definition: living.h:37
int16_t last_sp
Last spell cost.
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:926
#define ST_GET_PARTY_PASSWORD
Player tried to join a password-protected party.
Definition: define.h:585
#define SP_MAKE_MARK
Definition: spells.h:77
uint32_t tick
Client wishes to get tick commands.
Definition: newserver.h:118
Information.
Definition: logger.h:12
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.c:66
int8_t tail_x
Definition: object.h:471
void new_player_cmd(uint8_t *buf, int len, player *pl)
This handles the commands issued by the player (ie, north, fire, cast, etc.).
Definition: request.c:447
void enter_exit(object *op, object *exit_ob)
Tries to move &#39;op&#39; to exit_ob.
Definition: server.c:706
void esrv_send_face(socket_struct *ns, uint16_t face_num, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.c:70
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:149
Definition: object.h:125
void esrv_add_spells(player *pl, object *spell)
This tells the client to add the spell *spell, if spell is NULL, then add all spells in the player&#39;s ...
Definition: request.c:1738
int account_login(const char *account_name, const char *account_password)
Check if the given account exists, and whether the password is correct.
Definition: account.c:332
const char * name
Name of this character/player.
Definition: account_char.h:27
uint32_t want_pickup
Client wants pickup information when logging in.
Definition: newserver.h:120
living last_race_stats
Last race stats sent to the client.
Definition: player.h:151
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:239
int16_t last_dam
Last damage.
Definition: player.h:78
int account_remove_player(const char *account_name, const char *player_name)
Removes a player name from an account.
Definition: account.c:496
char * account_name
Name of the account logged in on this socket.
Definition: newserver.h:138
#define CS_STAT_RES_POISON
Definition: newclient.h:153
#define MAX_LIGHT_RADII
Max radii for &#39;light&#39; object, really large values allow objects that can slow down the game...
Definition: define.h:466
#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:1107
void SockList_Init(SockList *sl)
Initializes the SockList instance.
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)
A player just entered her password, including for changing it.
Definition: c_misc.c:1905
uint8_t starting_stat_min
Minimum value of a starting stat.
Definition: global.h:318
#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
int16_t bed_x
Definition: player.h:98
uint32_t run_on
Player should keep moving in dir until run is off.
Definition: player.h:128
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
unsigned char uint8_t
Definition: win32.h:161
void SockList_ResetRead(SockList *sl)
Resets the length of the stored data for reading.
Definition: lowlevel.c:75
uint16_t animation_id
An index into the animation array.
Definition: object.h:416
int GetInt_String(const unsigned char *data)
Basically does the reverse of SockList_AddInt, but on strings instead.
Definition: lowlevel.c:246
EXTERN int num_animations
Definition: global.h:166
uint32_t name_changed
If true, the player has set a name.
Definition: player.h:130
#define strdup_local
Definition: compat.h:25
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:417
Defines various flags that both the new client and new server use.
#define ACL_FACE_NUM
Definition: newclient.h:203
int16_t last_resist[NROFATTACKS]
last resist values sent to client.
Definition: player.h:155
player * add_player(socket_struct *ns, int flags)
Tries to add player on the connection passwd in ns.
Definition: player.c:453
void send_account_players(socket_struct *ns)
Upon successful login/account creation, we send a list of characters associated with the account to t...
Definition: request.c:1861
#define UPD_SP_GRACE
updspell command flag value.
Definition: newclient.h:300
int account_change_password(const char *account_name, const char *current_password, const char *new_password)
Change an account password.
Definition: account.c:657
#define SND_EFFECTS
Those flags are for the &#39;socket.sound&#39; field.
Definition: sounds.h:12
#define CS_STAT_RES_CONF
Definition: newclient.h:149
const char * account_get_account_for_char(const char *charname)
This looks at all the accounts and sees if charname is associated with any of them.
Definition: account.c:561
int account_new(const char *account_name, const char *account_password)
Adds an account.
Definition: account.c:407
void send_tick(player *pl)
Definition: request.c:1797
#define ACL_LEVEL
Definition: newclient.h:199
#define SPELL_GRACE
Definition: spells.h:59
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.c:211
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:345
void account_play_cmd(char *buf, int len, socket_struct *ns)
We have received an accountplay command.
Definition: request.c:2400
int16_t maxgrace
Maximum grace.
Definition: living.h:44
void print_ext_msg(socket_struct *ns, int color, uint8_t type, uint8_t subtype, const char *message)
Draws an extended message on the client.
Definition: info.c:49
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.c:2366
#define CS_STAT_SPEED
Definition: newclient.h:103
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
struct Map lastmap
Definition: newserver.h:103
struct treasureliststruct * randomitems
Items to be generated.
Definition: object.h:385
void key_roll_stat(object *op, char key)
Player is currently swapping stats.
Definition: player.c:1184
uint32_t pticks
?
Definition: time.c:45
#define SND_MUTE
Don&#39;t sent anything for now.
Definition: sounds.h:14
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.c:108
#define ST_CHANGE_PASSWORD_CONFIRM
Player is confirming new password.
Definition: define.h:588
Socket structure, represents a client-server connection.
Definition: newserver.h:99
static int decode_name_password(const char *buf, int *len, char *name, char *password)
This is a basic routine which extracts the name/password from the buffer.
Definition: request.c:2001
object clone
An object from which to do object_copy()
Definition: object.h:470
#define MAP2_TYPE_CLEAR
Definition: newclient.h:42
socket_struct socket
Socket information for this player.
Definition: player.h:94
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
#define NS_FACESENT_SMOOTH
Definition: newserver.h:150
#define ST_CONFIRM_PASSWORD
New character, confirm password.
Definition: define.h:584
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it&#39;s increased effectiveness.
Definition: spell_util.c:277
#define CS_STAT_DEX
Definition: newclient.h:94
Object for applying character class modifications to someone.
Definition: object.h:138
const char * skill_names[NUM_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.c:57
object * ranges[range_size]
Object for each range.
Definition: player.h:103
void account_add_player_cmd(char *buf, int len, socket_struct *ns)
Handle accountaddplayer from server (add a character to this account).
Definition: request.c:2271
bool heartbeat
Client will send hearbeats.
Definition: newserver.h:124
uint8_t subtype
Subtype of object.
Definition: object.h:339
#define CS_STAT_BASE_STR
Definition: newclient.h:124
#define SF_RUNON
Definition: newclient.h:186
int is_valid_faceset(int fsn)
Checks specified faceset is valid.
Definition: image.c:563
int SP_level_dam_adjust(const object *caster, const object *spob)
Returns adjusted damage based on the caster.
Definition: spell_util.c:328
int64_t exp
Experience.
Definition: living.h:46
int16_t last_golem_hp
Last golem hp value sent to the client.
Definition: player.h:156
const char * account_exists(const char *account_name)
Checks the existing accounts, and see if this account exists.
Definition: account.c:308
#define AddIfInt64(Old, New, Type)
Definition: request.c:683
uint8_t starting_stat_max
Maximum value of a starting stat.
Definition: global.h:319
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.c:119
#define ST_CHANGE_PASSWORD_NEW
Player is entering new password.
Definition: define.h:587
#define CS_STAT_RES_DEATH
Definition: newclient.h:159
enum Sock_Status status
Definition: newserver.h:100
This stores, for a spell a player knows, the last sp/gr/dam information sent to client.
Definition: player.h:74
int verify_player(const char *name, char *password)
This verify that a character of name exits, and that it matches password.
Definition: login.c:109
Various statistics of objects.
Definition: living.h:34
#define ACL_FACE
Definition: newclient.h:200
int8_t get_attr_value(const living *stats, int attr)
Gets the value of a stat.
Definition: living.c:313
#define CS_STAT_MAXSP
Definition: newclient.h:90
const char * map
Last map this character was on.
Definition: account_char.h:33
#define CS_STAT_WIS
Definition: newclient.h:93
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:343
method_ret ob_apply(object *op, object *applier, int aflags)
Applies an object.
Definition: ob_methods.c:42
uint8_t level
Level of this character.
Definition: account_char.h:30
void account_char_free(Account_Char *chars)
This frees all data associated with the character information.
Definition: account_char.c:332
void esrv_remove_spell(player *pl, object *spell)
Definition: request.c:1603
int16_t sp
Spell points.
Definition: living.h:41
#define AddIfString(Old, New, Type)
Definition: request.c:711
uint32_t get_weight_limit(int stat)
Definition: living.c:2255
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
This is somewhat like key_change_class() above, except we know the race to change to...
Definition: player.c:1450
#define SP_CREATE_MISSILE
Definition: spells.h:113
uint8_t smoothlevel
how to smooth this square around
Definition: object.h:421
Global type definitions and header inclusions.
#define CS_STAT_FLAGS
Definition: newclient.h:111
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:344
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
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:413
#define ST_ROLL_STAT
New character, rolling stats.
Definition: define.h:579
One map cell, as sent to the client.
Definition: newserver.h:31
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
#define ST_PLAYING
Usual state.
Definition: define.h:577
char savebed_map[MAX_BUF]
Map where player will respawn after death.
Definition: player.h:97
char * host
Which host it is connected from (ip address).
Definition: newserver.h:110
int8_t tail_y
Where the lower right most portion of the object is in comparison to the head.
Definition: object.h:471
int16_t maxsp
Max spell points.
Definition: living.h:42
int8_t Con
Definition: living.h:35
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
int16_t hp
Hit Points.
Definition: living.h:39
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:112
#define VERSION_SC
Definition: newserver.h:162
uint16_t number
This is the image id.
Definition: face.h:15
#define MAP_LAYER_LIVING2
Definition: map.h:47
#define CS_STAT_EXP64
Definition: newclient.h:113
uint16_t notifications
Notifications this client wants to get.
Definition: newserver.h:141
#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)
Client tells its version.
Definition: request.c:581
client_spell * get_client_spell_state(player *pl, object *spell)
Gets the (client-side) spell state for specified 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)
Asks the client to query the user.
Definition: request.c:674
#define CS_STAT_WC
Definition: newclient.h:99
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Try to get information about a living thing.
Definition: spell_effect.c:683
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:130
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:115
uint32_t facecache
If true, client is caching images.
Definition: newserver.h:113
const char * name
Face name, as used by archetypes and such.
Definition: face.h:20
#define MAX_NUM_LOOK_OBJECTS
The upper bound for the number of objects to send for the &#39;look&#39; window (container or ground view)...
Definition: newserver.h:28
int16_t y
Position in the map for this object.
Definition: object.h:326
int16_t maxhp
Max hit points.
Definition: living.h:40
#define NDI_RED
Definition: newclient.h:224
living applied_stats
Stat changes due to gear or skills.
Definition: player.h:152
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:241
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:345
uint32_t sound
Client sound mode.
Definition: newserver.h:123
#define strtok_r(x, y, z)
Definition: win32.h:62
Account_Char * account_chars
Detailed information on characters on this account.
Definition: newserver.h:139
#define ADD_PLAYER_NO_STATS_ROLL
Stats provided from client.
Definition: player.h:224
uint32_t cs_version
Definition: newserver.h:125
void move_cmd(char *buf, int len, player *pl)
Moves an object (typically, container to inventory).
Definition: request.c:636
void SockList_AddData(SockList *sl, const void *data, size_t len)
Adds a data block.
Definition: lowlevel.c:159
int account_is_logged_in(const char *name)
This checkes if an account is logged in.
Definition: account.c:629
void accounts_save(void)
Save all the account information.
Definition: account.c:267
const char * name_pl
The plural name of the object.
Definition: object.h:315
#define CS_STAT_RES_FIRE
Definition: newclient.h:146
uint8_t num_look_objects
The maximum number of objects to show on the ground view; this number includes the prev/next group fa...
Definition: newserver.h:134
#define CS_STAT_RES_HOLYWORD
Definition: newclient.h:160
#define AddIfInt(Old, New, Type)
Definition: request.c:690
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
void key_change_class(object *op, char key)
This function takes the key that is passed, and does the appropriate action with it (change race...
Definition: player.c:1260
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:509
int8_t last_level
Last level we sent to client.
Definition: player.h:121
signed short int16_t
Definition: win32.h:160
#define FLAG_CLIENT_SENT
THIS IS A DEBUG FLAG ONLY.
Definition: define.h:349
void draw_client_map(object *pl)
Draws client map.
Definition: request.c:1438
uint16_t last_flags
Fire/run on flags for last tick.
Definition: player.h:141
#define ADD_PLAYER_NEW
Name/password provided, so skip to roll stats.
Definition: player.h:222
int8_t Wis
Definition: living.h:35
#define CS_STAT_LEVEL
Definition: newclient.h:98
static const short atnr_cs_stat[NROFATTACKS]
This table translates the attack numbers as used within the program to the value we use when sending ...
Definition: request.c:73
void receive_party_password(object *op)
Player entered a party password.
Definition: c_party.c:49
#define ST_CONFIRM_QUIT
Player used the &#39;quit&#39; command, make sure that&#39;s ok.
Definition: define.h:581
void key_confirm_quit(object *op, char key)
We receive the reply to the &#39;quit confirmation&#39; message.
Definition: player.c:1562
#define UPD_SP_DAMAGE
updspell command flag value.
Definition: newclient.h:301
#define BEAT_INTERVAL
Interval between heartbeat requests.
Definition: config.h:689
short GetShort_String(const unsigned char *data)
Definition: lowlevel.c:250
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.c:58
One map for a player.
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)
Set the player&#39;s state to the specified one.
Definition: player.c:4457
char const * newhash(char const password[static 1])
Definition: server.c:87
#define CS_STAT_APPLIED_INT
INT changes from gear or skills.
Definition: newclient.h:132
#define MAX_HEAD_OFFSET
This basically defines the largest size an archetype may be - it is used for allocation of some struc...
Definition: newserver.h:42
socket_struct * account_get_logged_in_init_socket(const char *name)
This is like the above routine, but checks the init_sockets (account in process of logging in)...
Definition: account.c:607
static int check_probe(int ax, int ay, const object *ob, SockList *sl, socket_struct *ns, int *has_obj, int *alive_layer)
Check if a hp bar should be added to the map square.
Definition: request.c:1132
#define FLAG_CLIENT_ANIM_SYNC
Let client animate this, synchronized.
Definition: define.h:240
static int spell_client_use(const object *spell)
Give the client-side use information for a spell, to know how to use a spell.
Definition: request.c:1645
object * transport
Transport the player is in.
Definition: player.h:195
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
Control golem.
Definition: player.h:21
void update_position(mapstruct *m, int x, int y)
This function updates various attributes about a specific space on the map (what it looks like...
Definition: map.c:2119
#define CS_STAT_BASE_CHA
Definition: newclient.h:129
int16_t dam
How much damage this object does when hitting.
Definition: living.h:45
#define MAP_LAYERS
Definition: map.h:32
int8_t map_scroll_y
Definition: newserver.h:104
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:257
uint32_t sc_version
Versions of the client.
Definition: newserver.h:125
const char * name
The name of the object, obviously...
Definition: object.h:311
int16_t bed_y
x,y - coordinates of respawn (savebed).
Definition: player.h:98
living orig_stats
Permanent real stats of player.
Definition: player.h:148
static void append_spell(player *pl, SockList *sl, object *spell)
appends the spell *spell to the Socklist we will send the data to.
Definition: request.c:1668
struct obj * env
Pointer to the object which is the environment.
Definition: object.h:293
living last_applied_stats
Last applied stats sent to the client.
Definition: player.h:153
#define MAX_TIME
If you feel the game is too fast or too slow, change MAX_TIME.
Definition: config.h:245
player * account_get_logged_in_player(const char *name)
This checks to see if the account is logged in with a player attached If so, it returns the player ob...
Definition: account.c:586
Account_Char * account_char_load(const char *account_name)
For a given account name, load the character information and return it.
Definition: account_char.c:79
#define CS_STAT_RACE_POW
Definition: newclient.h:123
#define CS_STAT_TURN_UNDEAD
Definition: newclient.h:156
One character account.
Definition: account_char.h:26
#define ST_PLAY_AGAIN
Player left through a bed of reality, and can login again.
Definition: define.h:578
uint8_t state
Input state of the player (name, password, etc).
Definition: player.h:118
object * object_present_in_ob(uint8_t type, const object *op)
Searches for any objects with a matching type variable in the inventory of the given object...
Definition: object.c:3001
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.c:149
#define AddIfFloat(Old, New, Type)
Definition: request.c:704
uint8_t num_animations
How many different faces to animate, size of the faces array.
Definition: face.h:28
int16_t last_grace
Last grace cost.
Definition: player.h:77
#define MAX_CHOICES
Definition: request.c:2480
int8_t Cha
Definition: living.h:35
Defines various structures and values that are used for the new client server communication method...
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:251
Number of statistics.
Definition: living.h:18
#define CS_STAT_CHA
Definition: newclient.h:96
EXTERN Animations * animations
Definition: global.h:165
player * get_player(player *p)
Create a player&#39;s object, initialize a player&#39;s structure.
Definition: player.c:280
New_Face * smooth_face
Definition: image.c:39
#define MAP_TYPE_DEFAULT
If no map is specified, where character starts.
Definition: map.h:58
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
Defines and structures related to commands the player can send.
void create_player_cmd(char *buf, int len, socket_struct *ns)
We have received a createplayer command.
Definition: request.c:2487
static void send_smooth(socket_struct *ns, uint16_t face)
A lot like the old AskSmooth (in fact, now called by AskSmooth).
Definition: request.c:392
void execute_newserver_command(object *pl, char *command)
Player issued a command, let&#39;s handle it.
Definition: c_new.c:83
int find_smooth(uint16_t face, uint16_t *smoothed)
Find the smooth face for a given face.
Definition: image.c:379
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.c:238
#define UPD_SP_MANA
updspell command flag value.
Definition: newclient.h:299
#define ATNR_PHYSICAL
Definition: attack.h:49
#define VERSION_CS
Version >= 1023 understand setup cmd.
Definition: newserver.h:161
int32_t last_weight_limit
Last weight limit transmitted to client.
Definition: player.h:143
archetype * try_find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:666
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:159
Server settings.
Definition: global.h:237
char * range
Definition: newserver.h:57
#define CS_STAT_APPLIED_POW
POW changes from gear or skills.
Definition: newclient.h:137
float speed
The overall speed of this object.
Definition: object.h:328
See Spell.
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
version info
Definition: newclient.h:479
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:594
struct map_cell_struct cells[MAX_CLIENT_X][MAX_CLIENT_Y]
Definition: newserver.h:49
uint32_t is_bot
Client shouldn&#39;t be reported to metaserver.
Definition: newserver.h:119
#define CS_STAT_FOOD
Definition: newclient.h:104
#define CS_STAT_APPLIED_DEX
DEX changes from gear or skills.
Definition: newclient.h:134
uint32_t golem_count
To track the golem.
Definition: player.h:106
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
void ask_smooth_cmd(char *buf, int len, socket_struct *ns)
Tells client the picture it has to use to smooth a picture number given as argument.
Definition: request.c:423
#define MIN_NUM_LOOK_OBJECTS
The lower bound for the number of objects to send for the &#39;look&#39; window (container or ground view)...
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)
This removes a character on this account.
Definition: account_char.c:296
int16_t x
Definition: object.h:326
uint32_t extended_stats
Client wants base and maximum statistics information.
Definition: newserver.h:121
const char * character_class
Class of this character.
Definition: account_char.h:28
void draw_client_map2(object *pl)
Definition: request.c:1250
#define AddIfShort(Old, New, Type)
Definition: request.c:697
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
uint8_t mapx
Definition: newserver.h:128
void add_me_cmd(char *buf, int len, socket_struct *ns)
The client has requested to be added to the game.
Definition: request.c:347
#define MAP_CLIENT_X
This determines the maximum map size the client can request (and thus what the server will send to th...
Definition: config.h:236
#define NUM_SKILLS
This is the highest number skill in the table +1 This is used to store pointers to the actual skills ...
Definition: skills.h:71
int8_t wc
Weapon Class, how skilled, the lower the better.
Definition: living.h:36
unsigned short uint16_t
Definition: win32.h:163
void SockList_AddChar(SockList *sl, char c)
Adds an 8 bit value.
Definition: lowlevel.c:98
static const flag_definition flags[]
Flag mapping.
#define ANIM_SYNC
Definition: newclient.h:323
uint8_t account_block_create
Definition: global.h:326
client_spell * spell_state
Spell information sent to client.
Definition: player.h:196
int8_t Str
Definition: living.h:35
void receive_player_name(object *op)
A player just entered her name.
Definition: c_misc.c:1887
#define CS_STAT_APPLIED_CHA
CHA changes from gear or skills.
Definition: newclient.h:136
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:341
#define CS_STAT_RES_PARA
Definition: newclient.h:155
object * ob
The object representing the player.
Definition: player.h:158
#define CS_STAT_RES_COLD
Definition: newclient.h:148
const char * sstring
Strings that should be manipulated through add_string() and free_string().
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)
object &#39;ob&#39; at &#39;ax,ay&#39; on &#39;layer&#39; is visible to the client.
Definition: request.c:962
const New_Face ** faces
The actual faces for the animation.
Definition: face.h:31
int32_t timeout
Swapout is set to this.
Definition: map.h:341
See Player.
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
uint32_t darkness
True if client wants darkness information.
Definition: newserver.h:114
#define GET_MAP_FACE_OBJ(M, X, Y, L)
Gets the layer face of specified square.
Definition: map.h:184
void esrv_draw_look(object *pl)
Send the look window.
Definition: item.c:187
int account_check_string(const char *str)
Checks a string to make sure it does not have any invalid characters.
Definition: account.c:368
int account_link(const char *account_name, const char *player_name)
Adds a player name to an account.
Definition: account.c:460
#define FLAG_AUTO_APPLY
Will be applied when created.
Definition: define.h:250
#define MAP2_TYPE_DARKNESS
Definition: newclient.h:43
#define P_NEW_MAP
Coordinates passed result in a new tiled map.
Definition: map.h:252
#define MAP_CLIENT_Y
Definition: config.h:237
#define MAP_LAYER_LIVING1
Living creatures.
Definition: map.h:46
void account_password(char *buf, int len, socket_struct *ns)
Handles the account password change.
Definition: request.c:2862
void set_up_cmd(char *buf, int len, socket_struct *ns)
This is the Setup cmd - easy first implementation.
Definition: request.c:93
float last_speed
Last speed as sent to client.
Definition: player.h:154
living last_stats
Last stats as sent to client.
Definition: player.h:149
#define CS_STAT_RES_ELEC
Definition: newclient.h:147
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:213
int16_t grace
Grace.
Definition: living.h:43
static int account_block_create(const socket_struct *ns)
Checks if account creation is blocked for this connection.
Definition: request.c:2127
#define CS_STAT_APPLIED_STR
STR changes from gear or skills.
Definition: newclient.h:131
#define NUM_ANIMATIONS(ob)
Definition: global.h:179
#define CS_STAT_SP
Definition: newclient.h:89
player * find_player_socket(const socket_struct *ns)
Return a player for a socket structure.
Definition: player.c:118
uint32_t fire_on
Player should fire object, not move.
Definition: player.h:127
archetype * get_archetype_by_type_subtype(int type, int subtype)
Retrieves an archetype by type and subtype.
Definition: arch.c:136
#define CS_STAT_RES_MAG
Definition: newclient.h:145
#define CS_STAT_GOLEM_HP
Golem&#39;s current hp, 0 if no golem.
Definition: newclient.h:138
void esrv_update_spells(player *pl)
This looks for any spells the player may have that have changed their stats.
Definition: request.c:1551
char password[16]
2 (seed) + 11 (crypted) + 1 (EOS) + 2 (safety) = 16
Definition: player.h:176
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:142
tag_t count
Unique object number for this object.
Definition: object.h:299
static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns)
Definition: request.c:1204
living stats
Str, Con, Dex, etc.
Definition: object.h:368
uint8_t starting_stat_points
How many stat points character starts with.
Definition: global.h:320
int darkness
Cell&#39;s darkness.
Definition: newserver.h:33
int8_t Dex
Definition: living.h:35
struct archt * arch
Pointer to archetype.
Definition: object.h:412
#define MAP_TYPE_CHOICE
Choice of maps presented to player.
Definition: map.h:59
float last_weapon_sp
if diff than weapon_sp, update client.
Definition: player.h:140
Only for debugging purposes.
Definition: logger.h:13
void send_plugin_custom_message(object *pl, char *buf)
GROS: The following one is used to allow a plugin to send a generic cmd to a player.
Definition: request.c:1537
void account_char_save(const char *account, Account_Char *chars)
Saves the character information for the given account.
Definition: account_char.c:145
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:107
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.c:1625
#define CS_STAT_RES_DEPLETE
Definition: newclient.h:158
struct statsinfo stats
Definition: newserver.h:108
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
void check_login(object *op, int check_pass)
Actually login a player, load from disk and such.
Definition: login.c:494
uint32_t do_los
If true, need to call update_los() in draw(), and clear.
Definition: player.h:126
uint32_t mode
Mode of player for pickup.
Definition: player.h:110
struct Settings settings
Server settings.
Definition: init.c:40
void esrv_new_player(player *pl, uint32_t weight)
Tells the client that here is a player it should start using.
Definition: request.c:856
uint32_t monitor_spells
Client wishes to be informed when their spell list changes.
Definition: newserver.h:122
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 8 bit length field.
Definition: lowlevel.c:171
#define CS_STAT_RES_FEAR
Definition: newclient.h:157
#define ADD_PLAYER_NO_MAP
Do not set the first 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)
Clears a map cell.
Definition: request.c:921
#define CS_STAT_APPLIED_WIS
WIS changes from gear or skills.
Definition: newclient.h:133
#define CS_STAT_ARMOUR
Definition: newclient.h:102
#define ST_CHANGE_PASSWORD_OLD
Player is entering old password to change password.
Definition: define.h:586
signed int int32_t
Definition: win32.h:159
#define CS_STAT_DAM
Definition: newclient.h:101
int64_t last_skill_exp[NUM_SKILLS]
Last exp sent to client.
Definition: player.h:138
#define MAX_CHARACTERS_PER_ACCOUNT
The maximum characters per account is really driven by the size of the buffer we use to read in the d...
Definition: account_char.h:20
#define ST_CHANGE_CLASS
New character, choosing class.
Definition: define.h:580
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
#define SP_SUMMON_MONSTER
Definition: spells.h:101
int16_t casting_time
Time left before spell goes off.
Definition: object.h:402
void update_los(object *op)
Recalculates the array which specifies what is visible for the given player-object.
Definition: los.c:455
void receive_play_again(object *op, char key)
Player replied to play again / disconnect.
Definition: player.c:930
#define CS_STAT_TITLE
Definition: newclient.h:107
void esrv_send_animation(socket_struct *ns, short anim_num)
Need to send an animation sequence to the client.
Definition: request.c:883
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
EXTERN player * first_player
First player.
Definition: global.h:117
#define CS_STAT_RACE_STR
Definition: newclient.h:117
struct pl * next
Pointer to next player, NULL if this is last.
Definition: player.h:93
int strcasecmp(const char *s1, const char *s2)
Case-insensitive comparaison of strings.
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)
Sends a statistics update.
Definition: request.c:725
int8_t Pow
Definition: living.h:35
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.c:302
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
static void add_char_field(SockList *sl, int type, const char *data)
Basic helper function which adds a piece of data for the accountplayers protocol command.
Definition: request.c:1827
uint32_t last_path_repelled
Last spell repelled sent to client.
Definition: player.h:145
struct obj * head
Points to the main object of a large body.
Definition: object.h:296
#define CS_STAT_RES_PHYS
Definition: newclient.h:144
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
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:104
#define CS_STAT_GOLEM_MAXHP
Golem&#39;s max hp, 0 if no golem.
Definition: newclient.h:139
void set_title(const object *pl, char *buf, size_t len)
Sets player title.
Definition: info.c:300
#define SND_MUSIC
Client wants background music info.
Definition: sounds.h:13
object * last_skill_ob[NUM_SKILLS]
Exp objects sent to client.
Definition: player.h:137
char ** account_get_players_for_account(const char *account_name)
Returns an array of strings for the characters on this account - the array is null terminated...
Definition: account.c:542
Structure containing object statistics.
#define CS_STAT_RANGE
Definition: newclient.h:106
uint32_t last_path_attuned
Last spell attunment sent to client.
Definition: player.h:144
#define SPELL_MANA
Definition: spells.h:58
#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)
Get player&#39;s current range attack in obuf.
Definition: info.c:230
#define CS_STAT_MAXHP
Definition: newclient.h:88
#define MAP_LAYER_FLY2
Arrows, etc.
Definition: map.h:49
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:680
void SockList_AddInt64(SockList *sl, uint64_t data)
Adds a 64 bit value.
Definition: lowlevel.c:132
This is a game-map.
Definition: map.h:325
#define ST_GET_NAME
Player just connected.
Definition: define.h:582
const New_Face * face
Face with colors.
Definition: object.h:332
char write_buf[MAX_BUF]
Holds arbitrary input from client.
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)
This is a reply to a previous query.
Definition: request.c:509
void account_login_cmd(char *buf, int len, socket_struct *ns)
Handles the account login.
Definition: request.c:2037
const char *const short_stat_name[NUM_STATS]
Short name of stats.
Definition: living.c:194
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:128
#define ACL_NAME
Definition: newclient.h:196
#define CS_STAT_MAXGRACE
Definition: newclient.h:110
int16_t level
Level of creature or object.
Definition: object.h:351
float weapon_speed
The overall speed of this object.
Definition: object.h:330
unsigned find_face(const char *name, unsigned error)
This returns an the face number of face &#39;name&#39;.
Definition: image.c:303
#define CS_STAT_RES_ACID
Definition: newclient.h:150
#define SP_CREATE_FOOD
Definition: spells.h:96
See Disease.
Definition: object.h:244
struct obj * more
Pointer to the rest of a large body of objects.
Definition: object.h:295
#define MAP2_LAYER_START
Definition: newclient.h:53
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
const char * face
Face of this character.
Definition: account_char.h:31
#define CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
Definition: newclient.h:168
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:106
#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)
This checks to see if the race and class are legal.
Definition: player.c:1400
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
static const object * heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS]
Using a global really isn&#39;t a good approach, but saves the over head of allocating and deallocating s...
Definition: request.c:935
#define MAP2_COORD_ENCODE(x, y, flags)
Encodes a (x, y) pair suitable for map2 parameters.
Definition: newclient.h:64
uint16_t faces[MAP_LAYERS]
Face numbers.
Definition: newserver.h:32
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1499
void account_new_cmd(char *buf, int len, socket_struct *ns)
Handles the account creation This function shares a fair amount of the same logic as account_login_cm...
Definition: request.c:2163
const char * race
Race of this character.
Definition: account_char.h:29
#define CS_STAT_GRACE
Definition: newclient.h:109
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
SockList inbuf
If we get an incomplete packet, this is used to hold the data.
Definition: newserver.h:109
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
uint32_t last_path_denied
Last spell denied sent to client.
Definition: player.h:146
living last_orig_stats
Last permanent stats sent to client.
Definition: player.h:150
#define ST_GET_PASSWORD
Name entered, now for password.
Definition: define.h:583
int32_t food
How much food in stomach.
Definition: living.h:47
uint8_t isDead
Should stay at zero if alive, anything else if dead (hopefully 1, but doesn&#39;t have to be) ...
Definition: account_char.h:34
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
uint32_t count
Any numbers typed before a command.
Definition: player.h:109
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.c:542
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)
Move an object to a new location.
Definition: item.c:843
char * account_trusted_host
Block account creation for untrusted hosts.
Definition: global.h:327