Crossfire Server, Trunk
login.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2022 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 
19 #include "global.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 
25 #include "define.h"
26 #include "loader.h"
27 #include "output_file.h"
28 #include "spells.h"
29 #include "sproto.h"
30 #include "server.h"
31 
32 static void copy_file(const char *filename, FILE *fpout);
33 
41 void emergency_save(int flag) {
42 #ifndef NO_EMERGENCY_SAVE
43  player *pl;
44 
46  LOG(llevError, "Emergency save: ");
47  for (pl = first_player; pl != NULL; pl = pl->next) {
48  if (!pl->ob) {
49  LOG(llevError, "No name, ignoring this.\n");
50  continue;
51  }
52  LOG(llevError, "%s ", pl->ob->name);
54  "Emergency save...");
55 
56  /* If we are not exiting the game (ie, this is sort of a backup save), then
57  * don't change the location back to the village. Note that there are other
58  * options to have backup saves be done at the starting village
59  */
60  if (!flag) {
61  strcpy(pl->maplevel, first_map_path);
62  if (pl->ob->map != NULL)
63  pl->ob->map = NULL;
64  pl->ob->x = -1;
65  pl->ob->y = -1;
66  }
67  if (!save_player(pl->ob, flag)) {
68  LOG(llevError, "(failed) ");
70  "Emergency save failed, checking score...");
71  }
72  hiscore_check(pl->ob, 1);
73  }
74  LOG(llevError, "\n");
75 #else
76  (void)flag;
77  LOG(llevInfo, "Emergency saves disabled, no save attempted\n");
78 #endif
79 }
80 
88 void delete_character(const char *name) {
89  char buf[MAX_BUF];
90 
91  snprintf(buf, sizeof(buf), "%s/%s/%s", settings.localdir, settings.playerdir, name);
92  /* this effectively does an rm -rf on the directory */
94 }
95 
111 int verify_player(const char *name, char *password) {
112  char buf[MAX_BUF];
113  FILE *fp;
114  player *pltmp;
115 
116  if (strpbrk(name, "/.\\") != NULL) {
117  LOG(llevError, "Username contains illegal characters: %s\n", name);
118  return 1;
119  }
120 
121  /* Make sure we don't have a character that has just been loaded into the game with this name.
122  * It is possible for that character to not have been saved yet, and yet a character exists
123  * with that name.
124  * Creating a second character of the same name makes the game *really* confused, so don't
125  * let that happen.
126  *
127  * Daniel Hawkins 2021-07-26
128  */
129  for (pltmp = first_player; pltmp != NULL; pltmp = pltmp->next) {
130  if (pltmp->ob->name != NULL && !strcmp(pltmp->ob->name, name)) {
131  // If we find a player already playing with that name, then disallow it.
132  return 2;
133  }
134  }
135 
136  // There is no unsaved player with that name, check the files
137  snprintf(buf, sizeof(buf), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, name, name);
138  if (strlen(buf) >= sizeof(buf)-1) {
139  LOG(llevError, "Username too long: %s\n", name);
140  return 1;
141  }
142 
143  fp = fopen(buf, "r");
144  if (fp == NULL)
145  return 1;
146 
147  /* Read in the file until we find the password line. Our logic could
148  * be a bit better on cleaning up the password from the file, but since
149  * it is written by the program, I think it is fair to assume that the
150  * syntax should be pretty standard.
151  */
152  while (fgets(buf, MAX_BUF-1, fp) != NULL) {
153  if (!strncmp(buf, "password ", 9)) {
154  buf[strlen(buf)-1] = 0; /* remove newline */
155  if (check_password(password, buf+9)) {
156  fclose(fp);
157  return 0;
158  }
159 
160  fclose(fp);
161  return 2;
162  }
163  }
164  LOG(llevDebug, "Could not find a password line in player %s\n", name);
165  fclose(fp);
166  return 1;
167 }
168 
181 int check_name(player *me, const char *name) {
182  if (*name == '\0') {
184  "Your username cannot be blank.");
185  return 0;
186  }
187 
188  if (!playername_ok(name)) {
190  "That name contains illegal characters. Use letters, hyphens and underscores only. Hyphens and underscores are not allowed as the first character.");
191  return 0;
192  }
193  if (strlen(name) >= MAX_NAME) {
195  "That name is too long. (Max length: %d characters)", MAX_NAME);
196  return 0;
197  }
198 
199  return 1;
200 }
201 
209 void destroy_object(object *op) {
210  while (op->inv != NULL)
211  destroy_object(op->inv);
212 
213  if (!QUERY_FLAG(op, FLAG_REMOVED))
214  object_remove(op);
216 }
217 
230 int save_player(object *op, int flag) {
231  FILE *fp;
232  OutputFile of;
233  char filename[MAX_BUF], *tmpfilename;
234  object *container = NULL;
235  player *pl = op->contr;
236  int i, wiz = QUERY_FLAG(op, FLAG_WIZ);
237  long checksum;
238 #ifdef BACKUP_SAVE_AT_HOME
239  int16_t backup_x, backup_y;
240 #endif
241 
242  PROFILE_BEGIN();
243  if (!op->stats.exp)
244  return 0; /* no experience, no save */
245 
246  flag &= 1;
247 
248  if (!pl->name_changed) {
249  if (!flag) {
251  "Your game is not valid, game not saved.");
252  }
253  return 0;
254  }
255 
256  /* Sanity check - some stuff changes this when player is exiting */
257  if (op->type != PLAYER)
258  return 0;
259 
260  /* Prevent accidental saves if connection is reset after player has
261  * mostly exited.
262  */
264  return 0;
265 
266  if (flag == 0)
268 
269  /* Update information on this character. Only do it if it is eligible for
270  * for saving.
271  */
272  if (pl->socket.account_name) {
275  /* Add this character to the account. This really only comes up
276  * for new characters, at which time we want to wait until save -
277  * otherwise there is a good chance that character will be
278  * terminated.
279  */
282  }
283 
284 
285  snprintf(filename, sizeof(filename), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, op->name, op->name);
287  fp = tempnam_secure(settings.tmpdir, NULL, &tmpfilename);
288  if (!fp) {
290  "Can't get secure temporary file for save.");
291  LOG(llevDebug, "Can't get secure temporary file for save.\n");
292  return 0;
293  }
294 
295  /* Eneq(@csd.uu.se): If we have an open container hide it. */
296  if (op->container) {
297  container = op->container;
298  op->container = NULL;
299  }
300 
301  fprintf(fp, "password %s\n", pl->password);
302  if (settings.set_title == TRUE)
304  fprintf(fp, "title %s\n", player_get_own_title(pl));
305 
306  fprintf(fp, "gen_hp %d\n", pl->gen_hp);
307  fprintf(fp, "gen_sp %d\n", pl->gen_sp);
308  fprintf(fp, "gen_grace %d\n", pl->gen_grace);
309  fprintf(fp, "listening %d\n", pl->listening);
310  fprintf(fp, "shoottype %d\n", pl->shoottype);
311  fprintf(fp, "bowtype %d\n", pl->bowtype);
312  fprintf(fp, "petmode %d\n", pl->petmode);
313  fprintf(fp, "peaceful %d\n", pl->peaceful);
314  fprintf(fp, "no_shout %d\n", pl->no_shout);
315  fprintf(fp, "digestion %d\n", pl->digestion);
316  fprintf(fp, "pickup %u\n", pl->mode);
317  fprintf(fp, "partial_commands %u\n", pl->partial_commands);
318  /*
319  * outputs_sync and outputs_count are now unused in favor of the facility
320  * being supported on the client instead of in the server, but for now,
321  * set sane values in case an older server is run on a new player file.
322  * Once the server is officially 2.x, this should likely be removed.
323  */
324  fprintf(fp, "outputs_sync %d\n", 16);
325  fprintf(fp, "outputs_count %d\n", 1);
326  /* Match the enumerations but in string form */
327  fprintf(fp, "usekeys %s\n", pl->usekeys == key_inventory ? "key_inventory" : (pl->usekeys == keyrings ? "keyrings" : "containers"));
328  /* Match the enumerations but in string form */
329  fprintf(fp, "unapply %s\n", pl->unapply == unapply_nochoice ? "unapply_nochoice" : (pl->unapply == unapply_never ? "unapply_never" : "unapply_always"));
330  if (pl->unarmed_skill) fprintf(fp, "unarmed_skill %s\n", pl->unarmed_skill);
331 
332 #ifdef BACKUP_SAVE_AT_HOME
333  if (op->map != NULL && flag == 0)
334 #else
335  if (op->map != NULL)
336 #endif
337  fprintf(fp, "map %s\n", op->map->path);
338  else
339  fprintf(fp, "map %s\n", settings.emergency_mapname);
340 
341  fprintf(fp, "savebed_map %s\n", pl->savebed_map);
342  fprintf(fp, "bed_x %d\nbed_y %d\n", pl->bed_x, pl->bed_y);
343  fprintf(fp, "Str %d\n", pl->orig_stats.Str);
344  fprintf(fp, "Dex %d\n", pl->orig_stats.Dex);
345  fprintf(fp, "Con %d\n", pl->orig_stats.Con);
346  fprintf(fp, "Int %d\n", pl->orig_stats.Int);
347  fprintf(fp, "Pow %d\n", pl->orig_stats.Pow);
348  fprintf(fp, "Wis %d\n", pl->orig_stats.Wis);
349  fprintf(fp, "Cha %d\n", pl->orig_stats.Cha);
350 
351  fprintf(fp, "lev_array %d\n", MIN(op->level, 10));
352  for (i = 1; i <= MIN(op->level, 10) && i <= 10; i++) {
353  fprintf(fp, "%d\n", pl->levhp[i]);
354  fprintf(fp, "%d\n", pl->levsp[i]);
355  fprintf(fp, "%d\n", pl->levgrace[i]);
356  }
357  fprintf(fp, "party_rejoin_mode %d\n", pl->rejoin_party);
358  if (pl->party != NULL) {
359  fprintf(fp, "party_rejoin_name %s\n", pl->party->partyname);
360  fprintf(fp, "party_rejoin_password %s\n", party_get_password(pl->party));
361  }
362  fprintf(fp, "language %s\n", i18n_get_language_code(pl->language));
363  fprintf(fp, "ticks_played %u\n", pl->ticks_played);
364  fprintf(fp, "endplst\n");
365 
368 #ifdef BACKUP_SAVE_AT_HOME
369  if (flag) {
370  backup_x = op->x;
371  backup_y = op->y;
372  op->x = -1;
373  op->y = -1;
374  }
375  /* Save objects, but not unpaid objects. Don't remove objects from
376  * inventory.
377  */
379  if (flag) {
380  op->x = backup_x;
381  op->y = backup_y;
382  }
383 #else
384  i = save_object(fp, op, SAVE_FLAG_SAVE_UNPAID|SAVE_FLAG_NO_REMOVE); /* don't check and don't remove */
385 #endif
386 
387  if (wiz)
388  SET_FLAG(op, FLAG_WIZ);
389 
390  if (fclose(fp) != 0 || i != SAVE_ERROR_OK) { /* make sure the write succeeded */
392  "Can't save character!");
393  draw_ext_info_format(NDI_ALL_DMS|NDI_RED, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_LOADSAVE, "Save failure for player %s!", op->name);
394  unlink(tmpfilename);
395  free(tmpfilename);
396  return 0;
397  }
398 
400 
401  if (!flag) {
402  // Clear last_skill_ob before removing inventory. This prevents us
403  // from accessing removed skill objects during cleanup.
404  for (int i = 0; i < MAX_SKILLS; i++) {
405  op->contr->last_skill_ob[i] = NULL;
406  }
407 
408  while (op->inv != NULL)
409  destroy_object(op->inv);
410 
411  /* destroying objects will most likely destroy the pointer
412  * in op->contr->ranges[], so clear the range to a safe value.
413  */
414  op->contr->shoottype = range_none;
415  }
416 
417  checksum = 0;
418  fp = of_open(&of, filename);
419  if (fp == NULL) {
421  "Can't open file for save.");
422  unlink(tmpfilename);
423  free(tmpfilename);
424  return 0;
425  }
426  fprintf(fp, "checksum %lx\n", checksum);
427  copy_file(tmpfilename, fp);
428  unlink(tmpfilename);
429  free(tmpfilename);
430  if (!of_close(&of)) {
432  "Can't close file for save.");
433  return 0;
434  }
435 
436  /* Eneq(@csd.uu.se): Reveal the container if we have one. */
437  if (flag && container != NULL)
438  op->container = container;
439 
440  if (!flag)
442 
443  if (chmod(filename, SAVE_MODE) != 0) {
444  LOG(llevError, "Could not set permissions on '%s'\n", filename);
445  }
446 
447  /* if this is the first player save, quest or knowledge states can be unsaved */
448  if (!op->contr->has_directory) {
449  op->contr->has_directory = 1;
451  quest_first_player_save(op->contr);
452  }
453 
454  PROFILE_END(diff, LOG(llevDebug, "Saved player %s (%d ms)\n", op->name, diff/1000));
455  return 1;
456 }
457 
466 static void copy_file(const char *filename, FILE *fpout) {
467  FILE *fp;
468  char buf[MAX_BUF];
469 
470  fp = fopen(filename, "r");
471  if (fp == NULL) {
472  LOG(llevError, "copy_file failed to open \"%s\", player file(s) may be corrupt.\n", filename);
473  return;
474  }
475  while (fgets(buf, MAX_BUF, fp) != NULL)
476  fputs(buf, fpout);
477  fclose(fp);
478 }
479 
487 static void wrong_password(object *op) {
489  "\nA character with this name already exists. "
490  "Please choose another name, or make sure you entered your "
491  "password correctly.\n");
492 
493  FREE_AND_COPY(op->name, "noname");
494  FREE_AND_COPY(op->name_pl, "noname");
495 
496  op->contr->socket.password_fails++;
497  if (op->contr->socket.password_fails >= MAX_PASSWORD_FAILURES) {
499  "You gave an incorrect password too many times, "
500  "you will now be dropped from the server.");
501 
502  LOG(llevInfo, "A player connecting from %s has been dropped for password failure\n",
503  op->contr->socket.host);
504 
505  op->contr->socket.status = Ns_Dead; /* the socket loop should handle the rest for us */
506  } else
507  get_name(op);
508 }
509 
522 void check_login(object *op, const char *password) {
523  FILE *fp;
524  char filename[MAX_BUF];
525  char buf[MAX_BUF], bufall[MAX_BUF];
526  int i, value;
527  uint32_t uvalue;
528  player *pl = op->contr, *pltmp;
529  int correct = 0;
530  time_t elapsed_save_time = 0;
531  struct stat statbuf;
532  char *party_name = NULL, party_password[9];
533 
534  strcpy(pl->maplevel, first_map_path);
535  party_password[0] = 0;
536 
537  /* Check if this matches a connected player, and if yes disconnect old / connect new. */
538  for (pltmp = first_player; pltmp != NULL; pltmp = pltmp->next) {
539  if (pltmp != pl && pltmp->ob->name != NULL && !strcmp(pltmp->ob->name, op->name)) {
540  if (!password || check_password(password, pltmp->password)) {
541  /* We could try and be more clever and re-assign the existing
542  * object to the new player, etc. However, I'm concerned that
543  * there may be a lot of other state that still needs to be sent
544  * in that case (we can't make any assumptions on what the
545  * client knows, as maybe the client crashed), so treating it
546  * as just a normal login is the safest and easiest thing to do.
547  */
548 
549  pltmp->socket.status = Ns_Dead;
550 
551  save_player(pltmp->ob, 0);
552  leave(pltmp, 1);
553  final_free_player(pltmp);
554  break;
555  }
556  if (password) {
558  return;
559  }
560  }
561  }
562 
563  snprintf(filename, sizeof(filename), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, op->name, op->name);
564 
565  /* If no file, must be a new player, so lets get confirmation of
566  * the password. Return control to the higher level dispatch,
567  * since the rest of this just deals with loading of the file.
568  */
569  fp = fopen(filename, "r");
570  if (fp == NULL) {
572  return;
573  }
574  if (fstat(fileno(fp), &statbuf)) {
575  LOG(llevError, "Unable to stat %s?\n", filename);
576  elapsed_save_time = 0;
577  } else {
578  elapsed_save_time = time(NULL)-statbuf.st_mtime;
579  if (elapsed_save_time < 0) {
580  LOG(llevError, "Player file %s was saved in the future? (%ld time)\n", filename, (long)elapsed_save_time);
581  elapsed_save_time = 0;
582  }
583  }
584 
585  if (fgets(bufall, MAX_BUF, fp) != NULL) {
586  if (!strncmp(bufall, "checksum ", 9)) {
587  if ( fgets(bufall, MAX_BUF, fp) == NULL ) {
588  bufall[0]=0; /* should never happen */
589  }
590  }
591  if (sscanf(bufall, "password %s\n", buf)) {
592  /* New password scheme: */
593  correct = password && check_password(password, buf);
594  if (!password) {
595  /* We want to preserve the password. Normally,
596  * pl->password is filled in when user enters
597  * data in the password prompt, but with new login,
598  * there is no password prompt.
599  */
600  strncpy(pl->password, buf, 15);
601  pl->password[15] = 0;
602  }
603  }
604  /* Old password mode removed - I have no idea what it
605  * was, and the current password mechanism has been used
606  * for at least several years.
607  */
608  }
609  if (!correct && password) {
611  fclose(fp);
612  return;
613  }
614 
615 #ifdef SAVE_INTERVAL
616  pl->last_save_time = time(NULL);
617 #endif /* SAVE_INTERVAL */
618  pl->party = NULL;
619  if (settings.search_items == TRUE)
620  pl->search_str[0] = '\0';
621  pl->name_changed = 1;
622  pl->orig_stats.Str = 0;
623  pl->orig_stats.Dex = 0;
624  pl->orig_stats.Con = 0;
625  pl->orig_stats.Int = 0;
626  pl->orig_stats.Pow = 0;
627  pl->orig_stats.Wis = 0;
628  pl->orig_stats.Cha = 0;
629  strcpy(pl->savebed_map, first_map_path);
630  pl->bed_x = 0,
631  pl->bed_y = 0;
632  pl->spellparam[0] = '\0';
633 
634  /* Loop through the file, loading the rest of the values */
635  while (fgets(bufall, MAX_BUF, fp) != NULL) {
636  char *val_string, *p;
637 
638  sscanf(bufall, "%s %d\n", buf, &value);
639 
640  val_string = bufall + strlen(buf) +1;
641  p = strchr(val_string, '\n');
642  if (p != NULL)
643  *p = '\0';
644 
645  /* uvalue is an unsigned value. Since at least a
646  * couple different things want an usigned value, cleaner
647  * to just do it once here vs everyplace it may be needed.
648  */
649 
650  uvalue = strtoul(val_string, (char **)NULL, 10);
651 
652  if (!strcmp(buf, "endplst"))
653  break;
654  if (!strcmp(buf, "title") && settings.set_title == TRUE)
655  player_set_own_title(pl, val_string);
656  else if (!strcmp(buf, "unarmed_skill"))
657  pl->unarmed_skill = add_string(val_string);
658  else if (!strcmp(buf, "explore"))
659  ; /* ignore: explore mode has been removed */
660  else if (!strcmp(buf, "gen_hp"))
661  pl->gen_hp = value;
662  else if (!strcmp(buf, "shoottype"))
664  else if (!strcmp(buf, "bowtype"))
666  else if (!strcmp(buf, "petmode"))
668  else if (!strcmp(buf, "gen_sp"))
669  pl->gen_sp = value;
670  else if (!strcmp(buf, "gen_grace"))
671  pl->gen_grace = value;
672  else if (!strcmp(buf, "listening"))
673  pl->listening = value;
674  else if (!strcmp(buf, "peaceful"))
675  pl->peaceful = value;
676  else if (!strcmp(buf, "no_shout"))
677  pl->no_shout = value;
678  else if (!strcmp(buf, "digestion"))
679  pl->digestion = value;
680  else if (!strcmp(buf, "pickup")) {
681  pl->mode = uvalue;
682  } else if (!strcmp(buf, "partial_commands")) {
683  pl->partial_commands = uvalue;
684  }
685  else if (!strcmp(buf, "map"))
686  strlcpy(pl->maplevel, val_string, sizeof(pl->maplevel));
687  else if (!strcmp(buf, "savebed_map"))
688  strlcpy(pl->savebed_map, val_string, sizeof(pl->savebed_map));
689  else if (!strcmp(buf, "bed_x"))
690  pl->bed_x = value;
691  else if (!strcmp(buf, "bed_y"))
692  pl->bed_y = value;
693  else if (!strcmp(buf, "Str"))
694  pl->orig_stats.Str = value;
695  else if (!strcmp(buf, "Dex"))
696  pl->orig_stats.Dex = value;
697  else if (!strcmp(buf, "Con"))
698  pl->orig_stats.Con = value;
699  else if (!strcmp(buf, "Int"))
700  pl->orig_stats.Int = value;
701  else if (!strcmp(buf, "Pow"))
702  pl->orig_stats.Pow = value;
703  else if (!strcmp(buf, "Wis"))
704  pl->orig_stats.Wis = value;
705  else if (!strcmp(buf, "Cha"))
706  pl->orig_stats.Cha = value;
707  else if (!strcmp(buf, "usekeys")) {
708  if (!strcmp(val_string, "key_inventory"))
710  else if (!strcmp(val_string, "keyrings"))
711  pl->usekeys = keyrings;
712  else if (!strcmp(val_string, "containers"))
713  pl->usekeys = containers;
714  else
715  LOG(llevDebug, "load_player: got unknown usekeys type: %s\n", val_string);
716  } else if (!strcmp(buf, "unapply")) {
717  if (!strcmp(val_string, "unapply_nochoice"))
719  else if (!strcmp(val_string, "unapply_never"))
721  else if (!strcmp(val_string, "unapply_always"))
723  else
724  LOG(llevDebug, "load_player: got unknown unapply type: %s\n", val_string);
725  } else if (!strcmp(buf, "lev_array")) {
726  for (i = 1; i <= value; i++) {
727  int j;
728  int count=0;
729 
730  count = fscanf(fp, "%d\n", &j);
731  if ( !count ) j=0; // sanity; should never happen
732  if (j < 3)
733  j = 3;
734  else if (j > 9)
735  j = 9;
736  pl->levhp[i] = j;
737  count = fscanf(fp, "%d\n", &j);
738  if ( !count ) j=0; // sanity; should never happen
739  if (j < 2)
740  j = 2;
741  else if (j > 6)
742  j = 6;
743  pl->levsp[i] = j;
744  count = fscanf(fp, "%d\n", &j);
745  if ( !count ) j=0; // sanity; should never happen
746  if (j < 1)
747  j = 1;
748  else if (j > 3)
749  j = 3;
750  pl->levgrace[i] = j;
751  }
752  } else if (!strcmp(buf, "party_rejoin_mode"))
754  else if (!strcmp(buf, "party_rejoin_name"))
755  party_name = strdup_local(val_string);
756  else if (!strcmp(buf, "party_rejoin_password")) {
757  strncpy(party_password, val_string, sizeof(party_password));
758  party_password[sizeof(party_password) - 1] = 0;
759  } else if (!strcmp(buf, "language")) {
760  pl->language = i18n_get_language_by_code(val_string);
761  }
762  else if (!strcmp(buf, "ticks_played")) {
763  pl->ticks_played = uvalue;
764  }
765  } /* End of loop loading the character file */
766 
767  /* on first login via account, this player does not exist anyplace -
768  * so don't remove them.
769  */
770  if (!QUERY_FLAG(op, FLAG_REMOVED))
771  object_remove(op);
772  op->speed = 0;
774  /*FIXME dangerous call, object_reset() should be used to init freshly allocated obj struct!*/
775  object_reset(op);
776  op->contr = pl;
777  pl->ob = op;
778  /* this loads the standard objects values. */
779  PROFILE_BEGIN();
780  load_object(fp, op, LO_NEWFILE, 0);
781  PROFILE_END(diff, LOG(llevDebug, "Loaded player file for %s (%d ms)\n", op->name, diff/1000));
782  fclose(fp);
783 
785 
786  LOG(llevInfo, "login: %s from %s\n", op->name, op->contr->socket.host);
787  strncpy(pl->title, op->arch->clone.name, sizeof(pl->title)-1);
788  pl->title[sizeof(pl->title)-1] = '\0';
789 
790  /* If the map where the person was last saved does not exist,
791  * restart them on their home-savebed. This is good for when
792  * maps change between versions
793  * First, we check for partial path, then check to see if the full
794  * path (for unique player maps)
795  */
796  if (has_been_loaded(pl->maplevel) == NULL
797  && check_path(pl->maplevel, 1) == -1
798  && check_path(pl->maplevel, 0) == -1) {
799  strcpy(pl->maplevel, pl->savebed_map);
800  op->x = pl->bed_x,
801  op->y = pl->bed_y;
802  /* if the map was a shop, the player can have unpaid items, remove them. */
803  remove_unpaid_objects(op, NULL, 1);
804  }
805 
806  /* If player saved beyond some time ago, and the feature is
807  * enabled, put the player back on his savebed map.
808  */
809  if ((settings.reset_loc_time > 0) && (elapsed_save_time > settings.reset_loc_time)) {
810  strcpy(pl->maplevel, pl->savebed_map);
811  op->x = pl->bed_x, op->y = pl->bed_y;
812  /* if the map was a shop, the player can have unpaid items, remove them. */
813  remove_unpaid_objects(op, NULL, 1);
814  }
815 
816  /* make sure he's a player--needed because of class change. */
817  op->type = PLAYER;
819 
820  pl->name_changed = 1;
822 #ifdef AUTOSAVE
823  pl->last_save_tick = pticks;
824 #endif
825  op->carrying = object_sum_weight(op);
826 
828 
829  if (!legal_range(op, op->contr->shoottype))
830  op->contr->shoottype = range_none;
831 
832  /* if it's a dragon player, set the correct title here */
833  if (is_dragon_pl(op) && op->inv != NULL) {
834  object *abil, *skin;
835 
836  abil = object_find_by_type_and_arch_name(op, FORCE, "dragon_ability_force");
837  skin = object_find_by_type_and_arch_name(op, FORCE, "dragon_skin_force");
838  set_dragon_name(op, abil, skin);
839  }
840 
842  "Welcome Back!");
845  "%s has entered the game.",
846  pl->ob->name);
848 
850  op->contr->socket.update_look = 1;
851  /* If the player should be dead, call kill_player for them
852  * Only check for hp - if player lacks food, let the normal
853  * logic for that to take place. If player is permanently
854  * dead, and not using permadeath mode, the kill_player will
855  * set the play_again flag, so return.
856  */
857  if (op->stats.hp < 0) {
859  "Your character was dead last time you played.");
860  kill_player(op, NULL);
861  if (pl->state != ST_PLAYING)
862  {
863  // Prevent memory leak from strdup-ed party_name.
864  if (party_name)
865  free(party_name);
866  return;
867  }
868  }
869 
870  /* Do this after checking for death - no reason sucking up bandwidth if
871  * the data isn't needed.
872  */
873  esrv_new_player(op->contr, op->weight+op->carrying);
874  /* Need to do these after esvr_new_player, as once the client
875  * sees that, it wipes any info it has about the player.
876  */
877  esrv_add_spells(op->contr, NULL);
878 
879  /* Need to call fix_object now - program modified so that it is not
880  * called during the load process (FLAG_NO_FIX_PLAYER set when
881  * saved)
882  * Moved ahead of the esrv functions, so proper weights will be
883  * sent to the client. Needs to be after esvr_add_spells, otherwise
884  * we'll try to update spells from fix_object.
885  */
886  fix_object(op);
887 
888  pl->has_directory = 1;
889 
894 
896 
897  /* can_use_shield is a new flag. However, the can_use.. seems to largely come
898  * from the class, and not race. I don't see any way to get the class information
899  * to then update this. I don't think this will actually break anything - anyone
900  * that can use armour should be able to use a shield. What this may 'break'
901  * are features new characters get, eg, if someone starts up with a Q, they
902  * should be able to use a shield. However, old Q's won't get that advantage.
903  */
906 
907  /* Rejoin party if needed. */
908  if (pl->rejoin_party != party_rejoin_no && party_name != NULL) {
909  partylist *party;
910 
911  party = party_find(party_name);
912  if (!party && pl->rejoin_party == party_rejoin_always) {
913  party = party_form(op, party_name);
914  if (party)
915  party_set_password(party, party_password);
916  }
917  if (party && !pl->party && party_confirm_password(party, party_password)) {
918  party_join(op, party);
919  }
920 
921  if (pl->party)
922  snprintf(buf, MAX_BUF, "Rejoined party %s.", party->partyname);
923  else
924  snprintf(buf, MAX_BUF, "Couldn't rejoin party %s: %s.", party_name, party ? "invalid password." : "no such party.");
926  buf);
927  }
928  free(party_name);
929 }
party_rejoin_no
@ party_rejoin_no
Definition: player.h:99
PLAYER
@ PLAYER
Definition: object.h:107
output_file.h
global.h
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
object_remove
void object_remove(object *op)
Definition: object.c:1819
SAVE_MODE
#define SAVE_MODE
Definition: config.h:555
pets_terminate_all
void pets_terminate_all(object *owner)
Definition: pets.c:225
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.c:572
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:530
llevError
@ llevError
Definition: logger.h:11
set_dragon_name
void set_dragon_name(object *pl, const object *abil, const object *skin)
Definition: living.c:1679
pl::spellparam
char spellparam[MAX_BUF]
Definition: player.h:113
object_reset
void object_reset(object *op)
Definition: object.c:938
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:496
check_path
int check_path(const char *name, int prepend_dir)
Definition: map.c:202
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
object_find_by_type_and_arch_name
object * object_find_by_type_and_arch_name(const object *who, int type, const char *name)
Definition: object.c:4248
load_object
int load_object(FILE *fp, object *op, int bufstate, int map_flags)
Definition: loader.c:5205
strdup_local
#define strdup_local
Definition: compat.h:29
SAVE_FLAG_NO_REMOVE
#define SAVE_FLAG_NO_REMOVE
Definition: map.h:112
obj::map
struct mapdef * map
Definition: object.h:300
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
login_check_shutdown
void login_check_shutdown(object *const op)
Definition: server.c:1476
Settings::set_title
uint8_t set_title
Definition: global.h:260
destroy_object
void destroy_object(object *op)
Definition: login.c:209
pl::peaceful
uint32_t peaceful
Definition: player.h:146
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.c:942
liv::Str
int8_t Str
Definition: living.h:36
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:315
party_find
partylist * party_find(const char *partyname)
Definition: party.c:148
player_has_own_title
int player_has_own_title(const struct pl *pl)
Definition: player.c:247
pl::socket
socket_struct socket
Definition: player.h:107
pl::shoottype
rangetype shoottype
Definition: player.h:112
pl
Definition: player.h:105
pl::name_changed
uint32_t name_changed
Definition: player.h:145
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.c:1740
range_none
@ range_none
Definition: player.h:30
pl::mode
uint32_t mode
Definition: player.h:123
MIN
#define MIN(x, y)
Definition: compat.h:21
pl::ob
object * ob
Definition: player.h:176
NDI_ALL_DMS
#define NDI_ALL_DMS
Definition: newclient.h:264
bowtype_t
enum _bowtype bowtype_t
wrong_password
static void wrong_password(object *op)
Definition: login.c:487
pl::bowtype
bowtype_t bowtype
Definition: player.h:114
PROFILE_BEGIN
#define PROFILE_BEGIN(expr)
Definition: global.h:361
NDI_RED
#define NDI_RED
Definition: newclient.h:245
pl::partial_commands
uint32_t partial_commands
Definition: player.h:150
account_link
int account_link(const char *account_name, const char *player_name)
Definition: account.c:447
unapply_always
@ unapply_always
Definition: player.h:78
player_set_own_title
void player_set_own_title(struct pl *pl, const char *title)
Definition: player.c:272
LO_NEWFILE
#define LO_NEWFILE
Definition: loader.h:17
first_map_path
EXTERN char first_map_path[MAX_BUF]
Definition: global.h:141
npc_dialog.filename
filename
Definition: npc_dialog.py:99
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.c:1854
copy_file
static void copy_file(const char *filename, FILE *fpout)
Definition: login.c:466
pl::maplevel
char maplevel[MAX_BUF]
Definition: player.h:109
pl::gen_sp
int16_t gen_sp
Definition: player.h:127
hiscore_check
void hiscore_check(object *op, int quiet)
Definition: hiscore.c:346
make_path_to_file
void make_path_to_file(const char *filename)
Definition: porting.c:162
party_rejoin_always
@ party_rejoin_always
Definition: player.h:101
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:404
party_struct::partyname
char * partyname
Definition: party.h:14
settings
struct Settings settings
Definition: init.c:39
party_join
void party_join(object *op, partylist *party)
Definition: party.c:85
checksum
static unsigned checksum(const mtar_raw_header_t *rh)
Definition: microtar.c:49
Ns_Dead
@ Ns_Dead
Definition: newserver.h:67
pl::levsp
int8_t levsp[11]
Definition: player.h:186
PROFILE_END
#define PROFILE_END(var, expr)
Definition: global.h:366
socket_struct::account_chars
Account_Chars * account_chars
Definition: newserver.h:127
pl::savebed_map
char savebed_map[MAX_BUF]
Definition: player.h:110
pl::next
struct pl * next
Definition: player.h:106
EVENT_LOGIN
#define EVENT_LOGIN
Definition: events.h:43
link_player_skills
void link_player_skills(object *op)
Definition: player.c:287
final_free_player
void final_free_player(player *pl)
Definition: init.c:444
obj::name
sstring name
Definition: object.h:314
party_confirm_password
int party_confirm_password(const partylist *party, const char *password)
Definition: party.c:259
pl::state
uint8_t state
Definition: player.h:131
pl::digestion
int16_t digestion
Definition: player.h:125
playername_ok
int playername_ok(const char *cp)
Definition: player.c:254
pl::unarmed_skill
const char * unarmed_skill
Definition: player.h:220
of_close
int of_close(OutputFile *of)
Definition: output_file.c:61
account_get_account_for_char
const char * account_get_account_for_char(const char *charname)
Definition: account.c:589
remove_unpaid_objects
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.c:3182
pl::petmode
petmode_t petmode
Definition: player.h:115
petmode_t
enum _petmode petmode_t
save_player
int save_player(object *op, int flag)
Definition: login.c:230
liv::Cha
int8_t Cha
Definition: living.h:36
legal_range
int legal_range(object *op, int r)
Definition: c_range.c:247
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.c:687
i18n_get_language_code
sstring i18n_get_language_code(int language)
Definition: languages.c:108
socket_struct::host
char * host
Definition: newserver.h:100
tempnam_secure
FILE * tempnam_secure(const char *dir, const char *pfx, char **filename)
Definition: porting.c:69
socket_struct::account_name
char * account_name
Definition: newserver.h:126
check_name
int check_name(player *me, const char *name)
Definition: login.c:181
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:201
pl::no_shout
uint32_t no_shout
Definition: player.h:148
first_player
EXTERN player * first_player
Definition: global.h:115
obj::x
int16_t x
Definition: object.h:330
fix_object
void fix_object(object *op)
Definition: living.c:1126
pl::levgrace
int8_t levgrace[11]
Definition: player.h:187
party_set_password
void party_set_password(partylist *party, const char *password)
Definition: party.c:244
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
leave
void leave(player *pl, int draw_exit)
Definition: server.c:1302
MAX_NAME
#define MAX_NAME
Definition: define.h:41
disinfect.count
int count
Definition: disinfect.py:7
pl::gen_hp
int16_t gen_hp
Definition: player.h:126
rangetype
rangetype
Definition: player.h:28
liv::Con
int8_t Con
Definition: living.h:36
sproto.h
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
player_get_own_title
const char * player_get_own_title(const struct pl *pl)
Definition: player.c:260
is_dragon_pl
int is_dragon_pl(const object *op)
Definition: player.c:122
liv::Int
int8_t Int
Definition: living.h:36
pl::unapply
unapplymode unapply
Definition: player.h:121
party_form
partylist * party_form(object *op, const char *partyname)
Definition: party.c:40
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
pl::bed_x
int16_t bed_x
Definition: player.h:111
party_struct
Definition: party.h:10
key_inventory
@ key_inventory
Definition: player.h:66
Settings::reset_loc_time
int reset_loc_time
Definition: global.h:259
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:220
i18n_get_language_by_code
int i18n_get_language_by_code(const char *code)
Definition: languages.c:96
pl::listening
uint8_t listening
Definition: player.h:133
MAX_BUF
#define MAX_BUF
Definition: define.h:35
MSG_TYPE_ADMIN_LOADSAVE
#define MSG_TYPE_ADMIN_LOADSAVE
Definition: newclient.h:499
pl::search_str
char search_str[MAX_BUF]
Definition: player.h:210
pl::levhp
int8_t levhp[11]
Definition: player.h:185
remove_directory
void remove_directory(const char *path)
Definition: porting.c:115
Settings::playerdir
const char * playerdir
Definition: global.h:245
quest_first_player_save
void quest_first_player_save(player *pl)
Definition: quest.c:986
obj::y
int16_t y
Definition: object.h:330
pl::gen_grace
int16_t gen_grace
Definition: player.h:129
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
pl::bed_y
int16_t bed_y
Definition: player.h:111
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
Settings::emergency_mapname
char * emergency_mapname
Definition: global.h:294
llevInfo
@ llevInfo
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
pticks
uint32_t pticks
Definition: time.c:47
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
pl::language
int language
Definition: player.h:219
party_get_password
const char * party_get_password(const partylist *party)
Definition: party.c:232
liv::Dex
int8_t Dex
Definition: living.h:36
unapply_nochoice
@ unapply_nochoice
Definition: player.h:76
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
Definition: define.h:295
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
pl::password
char password[16]
Definition: player.h:192
liv::Wis
int8_t Wis
Definition: living.h:36
of_open
FILE * of_open(OutputFile *of, const char *fname)
Definition: output_file.c:30
give.op
op
Definition: give.py:33
NDI_ALL
#define NDI_ALL
Definition: newclient.h:263
pl::has_directory
uint32_t has_directory
Definition: player.h:149
autojail.value
value
Definition: autojail.py:6
MAX_PASSWORD_FAILURES
#define MAX_PASSWORD_FAILURES
Definition: newserver.h:84
define.h
pl::rejoin_party
party_rejoin_mode rejoin_party
Definition: player.h:209
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
Definition: define.h:277
verify_player
int verify_player(const char *name, char *password)
Definition: login.c:111
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
buf
StringBuffer * buf
Definition: readable.c:1610
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:248
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1330
delete_character
void delete_character(const char *name)
Definition: login.c:88
containers
@ containers
Definition: player.h:68
keyrings
@ keyrings
Definition: player.h:67
account_char_add
void account_char_add(Account_Chars *chars, player *pl)
Definition: account_char.c:225
MSG_TYPE_ADMIN_LOGIN
#define MSG_TYPE_ADMIN_LOGIN
Definition: newclient.h:500
SAVE_ERROR_OK
#define SAVE_ERROR_OK
Definition: map.h:144
loader.h
ST_GET_PARTY_PASSWORD
#define ST_GET_PARTY_PASSWORD
Definition: define.h:549
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
pl::ticks_played
uint32_t ticks_played
Definition: player.h:221
trying_emergency_save
EXTERN long trying_emergency_save
Definition: global.h:125
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.c:4439
emergency_save
void emergency_save(int flag)
Definition: login.c:41
check_login
void check_login(object *op, const char *password)
Definition: login.c:522
check_password
bool check_password(const char *typed, const char *crypted)
Definition: server.c:114
knowledge_send_known
void knowledge_send_known(player *pl)
Definition: knowledge.c:1400
Settings::search_items
uint8_t search_items
Definition: global.h:262
unapply_never
@ unapply_never
Definition: player.h:77
server.h
Settings::tmpdir
const char * tmpdir
Definition: global.h:250
confirm_password
void confirm_password(object *op)
Definition: player.c:998
pl::party
partylist * party
Definition: player.h:202
TRUE
#define TRUE
Definition: compat.h:11
pl::usekeys
usekeytype usekeys
Definition: player.h:120
party_rejoin_mode
party_rejoin_mode
Definition: player.h:98
account_char_save
void account_char_save(Account_Chars *chars)
Definition: account_char.c:179
SAVE_FLAG_SAVE_UNPAID
#define SAVE_FLAG_SAVE_UNPAID
Definition: map.h:111
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
kill_player
void kill_player(object *op, const object *killer)
Definition: player.c:3463
if
if(!(yy_init))
Definition: loader.c:2626
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:402
FORCE
@ FORCE
Definition: object.h:224
pl::title
char title[BIG_NAME]
Definition: player.h:183
liv::Pow
int8_t Pow
Definition: living.h:36
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:29
save_object
int save_object(FILE *fp, object *op, int flag)
Definition: object.c:5363
llevDebug
@ llevDebug
Definition: logger.h:13
curse_on_apply.me
me
Definition: curse_on_apply.py:3
pl::orig_stats
living orig_stats
Definition: player.h:166
give.name
name
Definition: give.py:27
quest_send_initial_states
void quest_send_initial_states(player *pl)
Definition: quest.c:928
has_been_loaded
mapstruct * has_been_loaded(const char *name)
Definition: map.c:78
OutputFile
Definition: output_file.h:41
get_name
void get_name(object *op)
Definition: player.c:873
knowledge_first_player_save
void knowledge_first_player_save(player *pl)
Definition: knowledge.c:1420
Settings::localdir
const char * localdir
Definition: global.h:244