Crossfire Server, Trunk
login.cpp
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  player *pl = op->contr;
235  int i, wiz = QUERY_FLAG(op, FLAG_WIZ);
236  long checksum;
237 #ifdef BACKUP_SAVE_AT_HOME
238  int16_t backup_x, backup_y;
239 #endif
240 
241  PROFILE_BEGIN();
242  if (!op->stats.exp)
243  return 0; /* no experience, no save */
244 
245  flag &= 1;
246 
247  if (!pl->name_changed) {
248  if (!flag) {
250  "Your game is not valid, game not saved.");
251  }
252  return 0;
253  }
254 
255  /* Sanity check - some stuff changes this when player is exiting */
256  if (op->type != PLAYER)
257  return 0;
258 
259  /* Prevent accidental saves if connection is reset after player has
260  * mostly exited.
261  */
263  return 0;
264 
265  if (flag == 0)
267 
268  /* Update information on this character. Only do it if it is eligible for
269  * for saving.
270  */
271  if (pl->socket->account_name) {
274  /* Add this character to the account. This really only comes up
275  * for new characters, at which time we want to wait until save -
276  * otherwise there is a good chance that character will be
277  * terminated.
278  */
281  }
282 
283 
284  snprintf(filename, sizeof(filename), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, op->name, op->name);
286  fp = tempnam_secure(settings.tmpdir, NULL, &tmpfilename);
287  if (!fp) {
289  "Can't get secure temporary file for save.");
290  LOG(llevDebug, "Can't get secure temporary file for save.\n");
291  return 0;
292  }
293 
294  fprintf(fp, "password %s\n", pl->password);
295  if (settings.set_title == TRUE)
297  fprintf(fp, "title %s\n", player_get_own_title(pl));
298 
299  fprintf(fp, "gen_hp %d\n", pl->gen_hp);
300  fprintf(fp, "gen_sp %d\n", pl->gen_sp);
301  fprintf(fp, "gen_grace %d\n", pl->gen_grace);
302  fprintf(fp, "listening %d\n", pl->listening);
303  fprintf(fp, "shoottype %d\n", pl->shoottype);
304  fprintf(fp, "bowtype %d\n", pl->bowtype);
305  fprintf(fp, "petmode %d\n", pl->petmode);
306  fprintf(fp, "peaceful %d\n", pl->peaceful);
307  fprintf(fp, "no_shout %d\n", pl->no_shout);
308  fprintf(fp, "digestion %d\n", pl->digestion);
309  fprintf(fp, "pickup %u\n", pl->mode);
310  fprintf(fp, "partial_commands %u\n", pl->partial_commands);
311  /*
312  * outputs_sync and outputs_count are now unused in favor of the facility
313  * being supported on the client instead of in the server, but for now,
314  * set sane values in case an older server is run on a new player file.
315  * Once the server is officially 2.x, this should likely be removed.
316  */
317  fprintf(fp, "outputs_sync %d\n", 16);
318  fprintf(fp, "outputs_count %d\n", 1);
319  /* Match the enumerations but in string form */
320  fprintf(fp, "usekeys %s\n", pl->usekeys == key_inventory ? "key_inventory" : (pl->usekeys == keyrings ? "keyrings" : "containers"));
321  /* Match the enumerations but in string form */
322  fprintf(fp, "unapply %s\n", pl->unapply == unapply_nochoice ? "unapply_nochoice" : (pl->unapply == unapply_never ? "unapply_never" : "unapply_always"));
323  if (pl->unarmed_skill) fprintf(fp, "unarmed_skill %s\n", pl->unarmed_skill);
324 
325 #ifdef BACKUP_SAVE_AT_HOME
326  if (op->map != NULL && flag == 0)
327 #else
328  if (op->map != NULL)
329 #endif
330  fprintf(fp, "map %s\n", op->map->path);
331  else
332  fprintf(fp, "map %s\n", settings.emergency_mapname);
333 
334  fprintf(fp, "savebed_map %s\n", pl->savebed_map);
335  fprintf(fp, "bed_x %d\nbed_y %d\n", pl->bed_x, pl->bed_y);
336  fprintf(fp, "Str %d\n", pl->orig_stats.Str);
337  fprintf(fp, "Dex %d\n", pl->orig_stats.Dex);
338  fprintf(fp, "Con %d\n", pl->orig_stats.Con);
339  fprintf(fp, "Int %d\n", pl->orig_stats.Int);
340  fprintf(fp, "Pow %d\n", pl->orig_stats.Pow);
341  fprintf(fp, "Wis %d\n", pl->orig_stats.Wis);
342  fprintf(fp, "Cha %d\n", pl->orig_stats.Cha);
343 
344  fprintf(fp, "lev_array %d\n", MIN(op->level, 10));
345  for (i = 1; i <= MIN(op->level, 10) && i <= 10; i++) {
346  fprintf(fp, "%d\n", pl->levhp[i]);
347  fprintf(fp, "%d\n", pl->levsp[i]);
348  fprintf(fp, "%d\n", pl->levgrace[i]);
349  }
350  fprintf(fp, "party_rejoin_mode %d\n", pl->rejoin_party);
351  if (pl->party != NULL) {
352  fprintf(fp, "party_rejoin_name %s\n", pl->party->partyname);
353  fprintf(fp, "party_rejoin_password %s\n", party_get_password(pl->party));
354  }
355  fprintf(fp, "language %s\n", i18n_get_language_code(pl->language));
356  fprintf(fp, "ticks_played %u\n", pl->ticks_played);
357  fprintf(fp, "endplst\n");
358 
361 #ifdef BACKUP_SAVE_AT_HOME
362  if (flag) {
363  backup_x = op->x;
364  backup_y = op->y;
365  op->x = -1;
366  op->y = -1;
367  }
368  /* Save objects, but not unpaid objects. Don't remove objects from
369  * inventory.
370  */
372  if (flag) {
373  op->x = backup_x;
374  op->y = backup_y;
375  }
376 #else
377  i = save_object(fp, op, SAVE_FLAG_SAVE_UNPAID|SAVE_FLAG_NO_REMOVE); /* don't check and don't remove */
378 #endif
379 
380  if (wiz)
381  SET_FLAG(op, FLAG_WIZ);
382 
383  if (fclose(fp) != 0 || i != SAVE_ERROR_OK) { /* make sure the write succeeded */
385  "Can't save character!");
386  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);
387  unlink(tmpfilename);
388  free(tmpfilename);
389  return 0;
390  }
391 
393 
394  if (!flag) {
395  // Clear last_skill_ob before removing inventory. This prevents us
396  // from accessing removed skill objects during cleanup.
397  for (int i = 0; i < MAX_SKILLS; i++) {
398  op->contr->last_skill_ob[i] = NULL;
399  }
400 
401  while (op->inv != NULL)
402  destroy_object(op->inv);
403 
404  /* destroying objects will most likely destroy the pointer
405  * in op->contr->ranges[], so clear the range to a safe value.
406  */
407  op->contr->shoottype = range_none;
408  }
409 
410  checksum = 0;
411  fp = of_open(&of, filename);
412  if (fp == NULL) {
414  "Can't open file for save.");
415  unlink(tmpfilename);
416  free(tmpfilename);
417  return 0;
418  }
419  fprintf(fp, "checksum %lx\n", checksum);
420  copy_file(tmpfilename, fp);
421  unlink(tmpfilename);
422  free(tmpfilename);
423  if (!of_close(&of)) {
425  "Can't close file for save.");
426  return 0;
427  }
428 
429  if (!flag)
431 
432  if (chmod(filename, SAVE_MODE) != 0) {
433  LOG(llevError, "Could not set permissions on '%s'\n", filename);
434  }
435 
436  /* if this is the first player save, quest or knowledge states can be unsaved */
437  if (!op->contr->has_directory) {
438  op->contr->has_directory = 1;
440  quest_first_player_save(op->contr);
441  }
442 
443  PROFILE_END(diff, LOG(llevDebug, "Saved player %s (%ld ms)\n", op->name, diff/1000));
444  return 1;
445 }
446 
455 static void copy_file(const char *filename, FILE *fpout) {
456  FILE *fp;
457  char buf[MAX_BUF];
458 
459  fp = fopen(filename, "r");
460  if (fp == NULL) {
461  LOG(llevError, "copy_file failed to open \"%s\", player file(s) may be corrupt.\n", filename);
462  return;
463  }
464  while (fgets(buf, MAX_BUF, fp) != NULL)
465  fputs(buf, fpout);
466  fclose(fp);
467 }
468 
476 static void wrong_password(object *op) {
478  "\nA character with this name already exists. "
479  "Please choose another name, or make sure you entered your "
480  "password correctly.\n");
481 
482  FREE_AND_COPY(op->name, "noname");
483  FREE_AND_COPY(op->name_pl, "noname");
484 
485  op->contr->socket->password_fails++;
486  if (op->contr->socket->password_fails >= MAX_PASSWORD_FAILURES) {
488  "You gave an incorrect password too many times, "
489  "you will now be dropped from the server.");
490 
491  LOG(llevInfo, "A player connecting from %s has been dropped for password failure\n",
492  op->contr->socket->host);
493 
494  op->contr->socket->status = Ns_Dead; /* the socket loop should handle the rest for us */
495  } else
496  get_name(op);
497 }
498 
511 void check_login(object *op, const char *password) {
512  FILE *fp;
513  char filename[MAX_BUF];
514  char buf[MAX_BUF], bufall[MAX_BUF];
515  int i, value;
516  uint32_t uvalue;
517  player *pl = op->contr, *pltmp;
518  int correct = 0;
519  time_t elapsed_save_time = 0;
520  struct stat statbuf;
521  char *party_name = NULL, party_password[9];
522 
523  strcpy(pl->maplevel, first_map_path);
524  party_password[0] = 0;
525 
526  /* Check if this matches a connected player, and if yes disconnect old / connect new. */
527  for (pltmp = first_player; pltmp != NULL; pltmp = pltmp->next) {
528  if (pltmp != pl && pltmp->ob->name != NULL && !strcmp(pltmp->ob->name, op->name)) {
529  if (!password || check_password(password, pltmp->password)) {
530  /* We could try and be more clever and re-assign the existing
531  * object to the new player, etc. However, I'm concerned that
532  * there may be a lot of other state that still needs to be sent
533  * in that case (we can't make any assumptions on what the
534  * client knows, as maybe the client crashed), so treating it
535  * as just a normal login is the safest and easiest thing to do.
536  */
537 
538  pltmp->socket->status = Ns_Dead;
539 
540  save_player(pltmp->ob, 0);
541  leave(pltmp, 1);
542  final_free_player(pltmp);
543  break;
544  }
545  if (password) {
547  return;
548  }
549  }
550  }
551 
552  snprintf(filename, sizeof(filename), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, op->name, op->name);
553 
554  /* If no file, must be a new player, so lets get confirmation of
555  * the password. Return control to the higher level dispatch,
556  * since the rest of this just deals with loading of the file.
557  */
558  fp = fopen(filename, "r");
559  if (fp == NULL) {
561  return;
562  }
563  if (fstat(fileno(fp), &statbuf)) {
564  LOG(llevError, "Unable to stat %s?\n", filename);
565  elapsed_save_time = 0;
566  } else {
567  elapsed_save_time = time(NULL)-statbuf.st_mtime;
568  if (elapsed_save_time < 0) {
569  LOG(llevError, "Player file %s was saved in the future? (%ld time)\n", filename, (long)elapsed_save_time);
570  elapsed_save_time = 0;
571  }
572  }
573 
574  if (fgets(bufall, MAX_BUF, fp) != NULL) {
575  if (!strncmp(bufall, "checksum ", 9)) {
576  if ( fgets(bufall, MAX_BUF, fp) == NULL ) {
577  bufall[0]=0; /* should never happen */
578  }
579  }
580  if (sscanf(bufall, "password %s\n", buf)) {
581  /* New password scheme: */
582  correct = password && check_password(password, buf);
583  if (!password) {
584  /* We want to preserve the password. Normally,
585  * pl->password is filled in when user enters
586  * data in the password prompt, but with new login,
587  * there is no password prompt.
588  */
589  strncpy(pl->password, buf, 15);
590  pl->password[15] = 0;
591  }
592  }
593  /* Old password mode removed - I have no idea what it
594  * was, and the current password mechanism has been used
595  * for at least several years.
596  */
597  }
598  if (!correct && password) {
600  fclose(fp);
601  return;
602  }
603 
604 #ifdef SAVE_INTERVAL
605  pl->last_save_time = time(NULL);
606 #endif /* SAVE_INTERVAL */
607  pl->party = NULL;
608  if (settings.search_items == TRUE)
609  pl->search_str[0] = '\0';
610  pl->name_changed = 1;
611  pl->orig_stats.Str = 0;
612  pl->orig_stats.Dex = 0;
613  pl->orig_stats.Con = 0;
614  pl->orig_stats.Int = 0;
615  pl->orig_stats.Pow = 0;
616  pl->orig_stats.Wis = 0;
617  pl->orig_stats.Cha = 0;
618  strcpy(pl->savebed_map, first_map_path);
619  pl->bed_x = 0,
620  pl->bed_y = 0;
621  pl->spellparam[0] = '\0';
622 
623  /* Loop through the file, loading the rest of the values */
624  while (fgets(bufall, MAX_BUF, fp) != NULL) {
625  char *val_string, *p;
626 
627  sscanf(bufall, "%s %d\n", buf, &value);
628 
629  val_string = bufall + strlen(buf) +1;
630  p = strchr(val_string, '\n');
631  if (p != NULL)
632  *p = '\0';
633 
634  /* uvalue is an unsigned value. Since at least a
635  * couple different things want an usigned value, cleaner
636  * to just do it once here vs everyplace it may be needed.
637  */
638 
639  uvalue = strtoul(val_string, (char **)NULL, 10);
640 
641  if (!strcmp(buf, "endplst"))
642  break;
643  if (!strcmp(buf, "title") && settings.set_title == TRUE)
644  player_set_own_title(pl, val_string);
645  else if (!strcmp(buf, "unarmed_skill"))
646  pl->unarmed_skill = add_string(val_string);
647  else if (!strcmp(buf, "explore"))
648  ; /* ignore: explore mode has been removed */
649  else if (!strcmp(buf, "gen_hp"))
650  pl->gen_hp = value;
651  else if (!strcmp(buf, "shoottype"))
653  else if (!strcmp(buf, "bowtype"))
655  else if (!strcmp(buf, "petmode"))
657  else if (!strcmp(buf, "gen_sp"))
658  pl->gen_sp = value;
659  else if (!strcmp(buf, "gen_grace"))
660  pl->gen_grace = value;
661  else if (!strcmp(buf, "listening"))
662  pl->listening = value;
663  else if (!strcmp(buf, "peaceful"))
664  pl->peaceful = value;
665  else if (!strcmp(buf, "no_shout"))
666  pl->no_shout = value;
667  else if (!strcmp(buf, "digestion"))
668  pl->digestion = value;
669  else if (!strcmp(buf, "pickup")) {
670  pl->mode = uvalue;
671  } else if (!strcmp(buf, "partial_commands")) {
672  pl->partial_commands = uvalue;
673  }
674  else if (!strcmp(buf, "map"))
675  strlcpy(pl->maplevel, val_string, sizeof(pl->maplevel));
676  else if (!strcmp(buf, "savebed_map"))
677  strlcpy(pl->savebed_map, val_string, sizeof(pl->savebed_map));
678  else if (!strcmp(buf, "bed_x"))
679  pl->bed_x = value;
680  else if (!strcmp(buf, "bed_y"))
681  pl->bed_y = value;
682  else if (!strcmp(buf, "Str"))
683  pl->orig_stats.Str = value;
684  else if (!strcmp(buf, "Dex"))
685  pl->orig_stats.Dex = value;
686  else if (!strcmp(buf, "Con"))
687  pl->orig_stats.Con = value;
688  else if (!strcmp(buf, "Int"))
689  pl->orig_stats.Int = value;
690  else if (!strcmp(buf, "Pow"))
691  pl->orig_stats.Pow = value;
692  else if (!strcmp(buf, "Wis"))
693  pl->orig_stats.Wis = value;
694  else if (!strcmp(buf, "Cha"))
695  pl->orig_stats.Cha = value;
696  else if (!strcmp(buf, "usekeys")) {
697  if (!strcmp(val_string, "key_inventory"))
699  else if (!strcmp(val_string, "keyrings"))
700  pl->usekeys = keyrings;
701  else if (!strcmp(val_string, "containers"))
702  pl->usekeys = containers;
703  else
704  LOG(llevDebug, "load_player: got unknown usekeys type: %s\n", val_string);
705  } else if (!strcmp(buf, "unapply")) {
706  if (!strcmp(val_string, "unapply_nochoice"))
708  else if (!strcmp(val_string, "unapply_never"))
710  else if (!strcmp(val_string, "unapply_always"))
712  else
713  LOG(llevDebug, "load_player: got unknown unapply type: %s\n", val_string);
714  } else if (!strcmp(buf, "lev_array")) {
715  for (i = 1; i <= value; i++) {
716  int j;
717  int count=0;
718 
719  count = fscanf(fp, "%d\n", &j);
720  if ( !count ) j=0; // sanity; should never happen
721  if (j < 3)
722  j = 3;
723  else if (j > 9)
724  j = 9;
725  pl->levhp[i] = j;
726  count = fscanf(fp, "%d\n", &j);
727  if ( !count ) j=0; // sanity; should never happen
728  if (j < 2)
729  j = 2;
730  else if (j > 6)
731  j = 6;
732  pl->levsp[i] = j;
733  count = fscanf(fp, "%d\n", &j);
734  if ( !count ) j=0; // sanity; should never happen
735  if (j < 1)
736  j = 1;
737  else if (j > 3)
738  j = 3;
739  pl->levgrace[i] = j;
740  }
741  } else if (!strcmp(buf, "party_rejoin_mode"))
743  else if (!strcmp(buf, "party_rejoin_name"))
744  party_name = strdup_local(val_string);
745  else if (!strcmp(buf, "party_rejoin_password")) {
746  strncpy(party_password, val_string, sizeof(party_password));
747  party_password[sizeof(party_password) - 1] = 0;
748  } else if (!strcmp(buf, "language")) {
749  pl->language = i18n_get_language_by_code(val_string);
750  }
751  else if (!strcmp(buf, "ticks_played")) {
752  pl->ticks_played = uvalue;
753  }
754  } /* End of loop loading the character file */
755 
756  /* on first login via account, this player does not exist anyplace -
757  * so don't remove them.
758  */
759  if (!QUERY_FLAG(op, FLAG_REMOVED))
760  object_remove(op);
761  op->speed = 0;
763  /*FIXME dangerous call, object_reset() should be used to init freshly allocated obj struct!*/
764  object_reset(op);
765  op->contr = pl;
766  pl->ob = op;
767  /* this loads the standard objects values. */
768  PROFILE_BEGIN();
769  load_object(fp, op, LO_NEWFILE, 0, false);
770  PROFILE_END(diff, LOG(llevDebug, "Loaded player file for %s (%ld ms)\n", op->name, diff/1000));
771  fclose(fp);
772 
774 
775  LOG(llevInfo, "login: %s from %s\n", op->name, op->contr->socket->host);
776  strncpy(pl->title, op->arch->clone.name, sizeof(pl->title)-1);
777  pl->title[sizeof(pl->title)-1] = '\0';
778 
779  /* If the map where the person was last saved does not exist,
780  * restart them on their home-savebed. This is good for when
781  * maps change between versions
782  * First, we check for partial path, then check to see if the full
783  * path (for unique player maps)
784  */
785  if (has_been_loaded(pl->maplevel) == NULL
786  && check_path(pl->maplevel, 1) == -1
787  && check_path(pl->maplevel, 0) == -1) {
788  strcpy(pl->maplevel, pl->savebed_map);
789  op->x = pl->bed_x,
790  op->y = pl->bed_y;
791  /* if the map was a shop, the player can have unpaid items, remove them. */
792  remove_unpaid_objects(op, NULL, 1);
793  }
794 
795  /* If player saved beyond some time ago, and the feature is
796  * enabled, put the player back on his savebed map.
797  */
798  if ((settings.reset_loc_time > 0) && (elapsed_save_time > settings.reset_loc_time)) {
799  strcpy(pl->maplevel, pl->savebed_map);
800  op->x = pl->bed_x, op->y = pl->bed_y;
801  /* if the map was a shop, the player can have unpaid items, remove them. */
802  remove_unpaid_objects(op, NULL, 1);
803  }
804 
805  /* make sure he's a player--needed because of class change. */
806  op->type = PLAYER;
808 
809  pl->name_changed = 1;
811 #ifdef AUTOSAVE
812  pl->last_save_tick = pticks;
813 #endif
814  op->carrying = object_sum_weight(op);
815 
817 
818  if (!legal_range(op, op->contr->shoottype))
819  op->contr->shoottype = range_none;
820 
821  /* if it's a dragon player, set the correct title here */
822  if (is_dragon_pl(op) && op->inv != NULL) {
823  object *abil, *skin;
824 
825  abil = object_find_by_type_and_arch_name(op, FORCE, "dragon_ability_force");
826  skin = object_find_by_type_and_arch_name(op, FORCE, "dragon_skin_force");
827  set_dragon_name(op, abil, skin);
828  }
829 
831  "Welcome Back!");
834  "%s has entered the game.",
835  pl->ob->name);
837 
839  op->contr->socket->update_look = 1;
840  /* If the player should be dead, call kill_player for them
841  * Only check for hp - if player lacks food, let the normal
842  * logic for that to take place. If player is permanently
843  * dead, and not using permadeath mode, the kill_player will
844  * set the play_again flag, so return.
845  */
846  if (op->stats.hp < 0) {
848  "Your character was dead last time you played.");
849  kill_player(op, NULL);
850  if (pl->state != ST_PLAYING)
851  {
852  // Prevent memory leak from strdup-ed party_name.
853  if (party_name)
854  free(party_name);
855  return;
856  }
857  }
858 
859  /* Do this after checking for death - no reason sucking up bandwidth if
860  * the data isn't needed.
861  */
862  esrv_new_player(op->contr, op->weight+op->carrying);
863  /* Need to do these after esvr_new_player, as once the client
864  * sees that, it wipes any info it has about the player.
865  */
866  esrv_add_spells(op->contr, NULL);
867 
868  /* Need to call fix_object now - program modified so that it is not
869  * called during the load process (FLAG_NO_FIX_PLAYER set when
870  * saved)
871  * Moved ahead of the esrv functions, so proper weights will be
872  * sent to the client. Needs to be after esvr_add_spells, otherwise
873  * we'll try to update spells from fix_object.
874  */
875  fix_object(op);
876 
877  pl->has_directory = 1;
878 
883 
885 
886  /* can_use_shield is a new flag. However, the can_use.. seems to largely come
887  * from the class, and not race. I don't see any way to get the class information
888  * to then update this. I don't think this will actually break anything - anyone
889  * that can use armour should be able to use a shield. What this may 'break'
890  * are features new characters get, eg, if someone starts up with a Q, they
891  * should be able to use a shield. However, old Q's won't get that advantage.
892  */
895 
896  /* Rejoin party if needed. */
897  if (pl->rejoin_party != party_rejoin_no && party_name != NULL) {
898  partylist *party;
899 
900  party = party_find(party_name);
901  if (!party && pl->rejoin_party == party_rejoin_always) {
902  party = party_form(op, party_name);
903  if (party)
904  party_set_password(party, party_password);
905  }
906  if (party && !pl->party && party_confirm_password(party, party_password)) {
907  party_join(op, party);
908  }
909 
910  if (pl->party)
911  snprintf(buf, MAX_BUF, "Rejoined party %s.", party->partyname);
912  else
913  snprintf(buf, MAX_BUF, "Couldn't rejoin party %s: %s.", party_name, party ? "invalid password." : "no such party.");
915  buf);
916  }
917  free(party_name);
918 }
party_rejoin_no
@ party_rejoin_no
Definition: player.h:99
PLAYER
@ PLAYER
Definition: object.h:110
output_file.h
global.h
first_player
player * first_player
Definition: init.cpp:106
settings
struct Settings settings
Definition: init.cpp:139
SAVE_MODE
#define SAVE_MODE
Definition: config.h:555
pets_terminate_all
void pets_terminate_all(object *owner)
Definition: pets.cpp:225
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:530
llevError
@ llevError
Definition: logger.h:11
pl::spellparam
char spellparam[MAX_BUF]
Definition: player.h:113
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:496
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
of_close
int of_close(OutputFile *of)
Definition: output_file.cpp:61
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
player_has_own_title
int player_has_own_title(const struct pl *pl)
Definition: player.cpp:247
of_open
FILE * of_open(OutputFile *of, const char *fname)
Definition: output_file.cpp:30
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:303
first_map_path
char first_map_path[MAX_BUF]
Definition: init.cpp:120
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
login_check_shutdown
void login_check_shutdown(object *const op)
Definition: server.cpp:1487
Settings::set_title
uint8_t set_title
Definition: global.h:265
pl::peaceful
uint32_t peaceful
Definition: player.h:146
has_been_loaded
mapstruct * has_been_loaded(const char *name)
Definition: map.cpp:78
esrv_new_player
void esrv_new_player(player *pl, uint32_t weight)
Definition: request.cpp:943
liv::Str
int8_t Str
Definition: living.h:36
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.cpp:316
party_find
partylist * party_find(const char *partyname)
Definition: party.cpp:148
pl::shoottype
rangetype shoottype
Definition: player.h:112
pl
Definition: player.h:105
pl::name_changed
uint32_t name_changed
Definition: player.h:145
copy_file
static void copy_file(const char *filename, FILE *fpout)
Definition: login.cpp:455
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.cpp:1741
range_none
@ range_none
Definition: player.h:30
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
pl::mode
uint32_t mode
Definition: player.h:123
checksum
static unsigned checksum(const mtar_raw_header_t *rh)
Definition: microtar.cpp:49
MIN
#define MIN(x, y)
Definition: compat.h:21
object_reset
void object_reset(object *op)
Definition: object.cpp:934
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
pl::bowtype
bowtype_t bowtype
Definition: player.h:114
fix_object
void fix_object(object *op)
Definition: living.cpp:1125
PROFILE_BEGIN
#define PROFILE_BEGIN(expr)
Definition: global.h:366
NDI_RED
#define NDI_RED
Definition: newclient.h:245
pl::partial_commands
uint32_t partial_commands
Definition: player.h:150
player_set_own_title
void player_set_own_title(struct pl *pl, const char *title)
Definition: player.cpp:272
save_player
int save_player(object *op, int flag)
Definition: login.cpp:230
account_link
int account_link(const char *account_name, const char *player_name)
Definition: account.cpp:461
unapply_always
@ unapply_always
Definition: player.h:78
LO_NEWFILE
#define LO_NEWFILE
Definition: loader.h:17
i18n_get_language_code
sstring i18n_get_language_code(int language)
Definition: languages.cpp:108
npc_dialog.filename
filename
Definition: npc_dialog.py:99
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.cpp:1855
pl::maplevel
char maplevel[MAX_BUF]
Definition: player.h:109
pl::gen_sp
int16_t gen_sp
Definition: player.h:127
pticks
uint32_t pticks
Definition: time.cpp:47
buf
StringBuffer * buf
Definition: readable.cpp:1611
hiscore_check
void hiscore_check(object *op, int quiet)
Definition: hiscore.cpp:348
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
player_get_own_title
const char * player_get_own_title(const struct pl *pl)
Definition: player.cpp:260
party_join
void party_join(object *op, partylist *party)
Definition: party.cpp:85
Ns_Dead
@ Ns_Dead
Definition: newserver.h:67
pl::levsp
int8_t levsp[11]
Definition: player.h:186
remove_directory
void remove_directory(const char *path)
Definition: porting.cpp:117
PROFILE_END
#define PROFILE_END(var, expr)
Definition: global.h:371
socket_struct::account_chars
Account_Chars * account_chars
Definition: newserver.h:127
pl::savebed_map
char savebed_map[MAX_BUF]
Definition: player.h:110
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
pl::next
struct pl * next
Definition: player.h:106
EVENT_LOGIN
#define EVENT_LOGIN
Definition: events.h:44
final_free_player
void final_free_player(player *pl)
Definition: init.cpp:455
obj::name
sstring name
Definition: object.h:317
party_confirm_password
int party_confirm_password(const partylist *party, const char *password)
Definition: party.cpp: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.cpp:255
pl::unarmed_skill
const char * unarmed_skill
Definition: player.h:220
account_get_account_for_char
const char * account_get_account_for_char(const char *charname)
Definition: account.cpp:603
remove_unpaid_objects
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.cpp:3175
pl::petmode
petmode_t petmode
Definition: player.h:115
petmode_t
enum _petmode petmode_t
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
liv::Cha
int8_t Cha
Definition: living.h:36
wrong_password
static void wrong_password(object *op)
Definition: login.cpp:476
legal_range
int legal_range(object *op, int r)
Definition: c_range.cpp:247
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.cpp:687
trying_emergency_save
long trying_emergency_save
Definition: init.cpp:111
verify_player
int verify_player(const char *name, char *password)
Definition: login.cpp:111
socket_struct::host
char * host
Definition: newserver.h:100
delete_character
void delete_character(const char *name)
Definition: login.cpp:88
socket_struct::account_name
char * account_name
Definition: newserver.h:126
object_update_speed
void object_update_speed(object *op)
Definition: object.cpp:1349
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
pl::no_shout
uint32_t no_shout
Definition: player.h:148
obj::x
int16_t x
Definition: object.h:333
pl::levgrace
int8_t levgrace[11]
Definition: player.h:187
party_set_password
void party_set_password(partylist *party, const char *password)
Definition: party.cpp:244
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
leave
void leave(player *pl, int draw_exit)
Definition: server.cpp:1302
i18n_get_language_by_code
int i18n_get_language_by_code(const char *code)
Definition: languages.cpp:96
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
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.cpp: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:264
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
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
pl::search_str
char search_str[MAX_BUF]
Definition: player.h:210
pl::levhp
int8_t levhp[11]
Definition: player.h:185
Settings::playerdir
const char * playerdir
Definition: global.h:250
quest_first_player_save
void quest_first_player_save(player *pl)
Definition: quest.cpp:986
obj::y
int16_t y
Definition: object.h:333
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:299
llevInfo
@ llevInfo
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
destroy_object
void destroy_object(object *op)
Definition: login.cpp:209
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.cpp:232
is_dragon_pl
int is_dragon_pl(const object *op)
Definition: player.cpp:122
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
pl::password
char password[16]
Definition: player.h:192
liv::Wis
int8_t Wis
Definition: living.h:36
check_name
int check_name(player *me, const char *name)
Definition: login.cpp:181
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
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
tempnam_secure
FILE * tempnam_secure(const char *dir, const char *pfx, char **filename)
Definition: porting.cpp:71
check_login
void check_login(object *op, const char *password)
Definition: login.cpp:511
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:248
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.cpp:4270
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.cpp:229
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.cpp:308
pl::ticks_played
uint32_t ticks_played
Definition: player.h:221
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.cpp:4432
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.cpp:568
check_password
bool check_password(const char *typed, const char *crypted)
Definition: server.cpp:114
make_path_to_file
void make_path_to_file(const char *filename)
Definition: porting.cpp:164
emergency_save
void emergency_save(int flag)
Definition: login.cpp:41
knowledge_send_known
void knowledge_send_known(player *pl)
Definition: knowledge.cpp:1400
Settings::search_items
uint8_t search_items
Definition: global.h:267
unapply_never
@ unapply_never
Definition: player.h:77
server.h
Settings::tmpdir
const char * tmpdir
Definition: global.h:255
confirm_password
void confirm_password(object *op)
Definition: player.cpp:986
pl::party
partylist * party
Definition: player.h:202
TRUE
#define TRUE
Definition: compat.h:11
pl::usekeys
usekeytype usekeys
Definition: player.h:120
link_player_skills
void link_player_skills(object *op)
Definition: player.cpp:287
set_dragon_name
void set_dragon_name(object *pl, const object *abil, const object *skin)
Definition: living.cpp:1677
party_rejoin_mode
party_rejoin_mode
Definition: player.h:98
account_char_save
void account_char_save(Account_Chars *chars)
Definition: account_char.cpp:179
SAVE_FLAG_SAVE_UNPAID
#define SAVE_FLAG_SAVE_UNPAID
Definition: map.h:111
save_object
int save_object(FILE *fp, object *op, int flag)
Definition: object.cpp:5383
pl::socket
socket_struct * socket
Definition: player.h:107
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
kill_player
void kill_player(object *op, const object *killer)
Definition: player.cpp:3456
if
if(!(yy_init))
Definition: loader.c:2626
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:402
FORCE
@ FORCE
Definition: object.h:227
check_path
int check_path(const char *name, int prepend_dir)
Definition: map.cpp:202
pl::title
char title[BIG_NAME]
Definition: player.h:183
liv::Pow
int8_t Pow
Definition: living.h:36
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:27
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.cpp:928
OutputFile
Definition: output_file.h:41
get_name
void get_name(object *op)
Definition: player.cpp:861
knowledge_first_player_save
void knowledge_first_player_save(player *pl)
Definition: knowledge.cpp:1420
Settings::localdir
const char * localdir
Definition: global.h:249