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-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 
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  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  */
272  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  /* Eneq(@csd.uu.se): If we have an open container hide it. */
295  if (op->container) {
296  container = op->container;
297  op->container = NULL;
298  }
299 
300  fprintf(fp, "password %s\n", pl->password);
301  if (settings.set_title == TRUE)
303  fprintf(fp, "title %s\n", player_get_own_title(pl));
304 
305  fprintf(fp, "gen_hp %d\n", pl->gen_hp);
306  fprintf(fp, "gen_sp %d\n", pl->gen_sp);
307  fprintf(fp, "gen_grace %d\n", pl->gen_grace);
308  fprintf(fp, "listening %d\n", pl->listening);
309  fprintf(fp, "shoottype %d\n", pl->shoottype);
310  fprintf(fp, "bowtype %d\n", pl->bowtype);
311  fprintf(fp, "petmode %d\n", pl->petmode);
312  fprintf(fp, "peaceful %d\n", pl->peaceful);
313  fprintf(fp, "no_shout %d\n", pl->no_shout);
314  fprintf(fp, "digestion %d\n", pl->digestion);
315  fprintf(fp, "pickup %u\n", pl->mode);
316  /*
317  * outputs_sync and outputs_count are now unused in favor of the facility
318  * being supported on the client instead of in the server, but for now,
319  * set sane values in case an older server is run on a new player file.
320  * Once the server is officially 2.x, this should likely be removed.
321  */
322  fprintf(fp, "outputs_sync %d\n", 16);
323  fprintf(fp, "outputs_count %d\n", 1);
324  /* Match the enumerations but in string form */
325  fprintf(fp, "usekeys %s\n", pl->usekeys == key_inventory ? "key_inventory" : (pl->usekeys == keyrings ? "keyrings" : "containers"));
326  /* Match the enumerations but in string form */
327  fprintf(fp, "unapply %s\n", pl->unapply == unapply_nochoice ? "unapply_nochoice" : (pl->unapply == unapply_never ? "unapply_never" : "unapply_always"));
328  if (pl->unarmed_skill) fprintf(fp, "unarmed_skill %s\n", pl->unarmed_skill);
329 
330 #ifdef BACKUP_SAVE_AT_HOME
331  if (op->map != NULL && flag == 0)
332 #else
333  if (op->map != NULL)
334 #endif
335  fprintf(fp, "map %s\n", op->map->path);
336  else
337  fprintf(fp, "map %s\n", settings.emergency_mapname);
338 
339  fprintf(fp, "savebed_map %s\n", pl->savebed_map);
340  fprintf(fp, "bed_x %d\nbed_y %d\n", pl->bed_x, pl->bed_y);
341  fprintf(fp, "Str %d\n", pl->orig_stats.Str);
342  fprintf(fp, "Dex %d\n", pl->orig_stats.Dex);
343  fprintf(fp, "Con %d\n", pl->orig_stats.Con);
344  fprintf(fp, "Int %d\n", pl->orig_stats.Int);
345  fprintf(fp, "Pow %d\n", pl->orig_stats.Pow);
346  fprintf(fp, "Wis %d\n", pl->orig_stats.Wis);
347  fprintf(fp, "Cha %d\n", pl->orig_stats.Cha);
348 
349  fprintf(fp, "lev_array %d\n", MIN(op->level, 10));
350  for (i = 1; i <= MIN(op->level, 10) && i <= 10; i++) {
351  fprintf(fp, "%d\n", pl->levhp[i]);
352  fprintf(fp, "%d\n", pl->levsp[i]);
353  fprintf(fp, "%d\n", pl->levgrace[i]);
354  }
355  fprintf(fp, "party_rejoin_mode %d\n", pl->rejoin_party);
356  if (pl->party != NULL) {
357  fprintf(fp, "party_rejoin_name %s\n", pl->party->partyname);
358  fprintf(fp, "party_rejoin_password %s\n", party_get_password(pl->party));
359  }
360  fprintf(fp, "language %s\n", i18n_get_language_code(pl->language));
361  fprintf(fp, "ticks_played %u\n", pl->ticks_played);
362  fprintf(fp, "endplst\n");
363 
366 #ifdef BACKUP_SAVE_AT_HOME
367  if (flag) {
368  backup_x = op->x;
369  backup_y = op->y;
370  op->x = -1;
371  op->y = -1;
372  }
373  /* Save objects, but not unpaid objects. Don't remove objects from
374  * inventory.
375  */
377  if (flag) {
378  op->x = backup_x;
379  op->y = backup_y;
380  }
381 #else
382  i = save_object(fp, op, SAVE_FLAG_SAVE_UNPAID|SAVE_FLAG_NO_REMOVE); /* don't check and don't remove */
383 #endif
384 
385  if (wiz)
386  SET_FLAG(op, FLAG_WIZ);
387 
388  if (fclose(fp) != 0 || i != SAVE_ERROR_OK) { /* make sure the write succeeded */
390  "Can't save character!");
391  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);
392  unlink(tmpfilename);
393  free(tmpfilename);
394  return 0;
395  }
396 
398 
399  if (!flag) {
400  // Clear last_skill_ob before removing inventory. This prevents us
401  // from accessing removed skill objects during cleanup.
402  for (int i = 0; i < MAX_SKILLS; i++) {
403  op->contr->last_skill_ob[i] = NULL;
404  }
405 
406  while (op->inv != NULL)
407  destroy_object(op->inv);
408 
409  /* destroying objects will most likely destroy the pointer
410  * in op->contr->ranges[], so clear the range to a safe value.
411  */
412  op->contr->shoottype = range_none;
413  }
414 
415  checksum = 0;
416  fp = of_open(&of, filename);
417  if (fp == NULL) {
419  "Can't open file for save.");
420  unlink(tmpfilename);
421  free(tmpfilename);
422  return 0;
423  }
424  fprintf(fp, "checksum %lx\n", checksum);
425  copy_file(tmpfilename, fp);
426  unlink(tmpfilename);
427  free(tmpfilename);
428  if (!of_close(&of)) {
430  "Can't close file for save.");
431  return 0;
432  }
433 
434  /* Eneq(@csd.uu.se): Reveal the container if we have one. */
435  if (flag && container != NULL)
436  op->container = container;
437 
438  if (!flag)
440 
441  if (chmod(filename, SAVE_MODE) != 0) {
442  LOG(llevError, "Could not set permissions on '%s'\n", filename);
443  }
444 
445  /* if this is the first player save, quest or knowledge states can be unsaved */
446  if (!op->contr->has_directory) {
447  op->contr->has_directory = 1;
449  quest_first_player_save(op->contr);
450  }
451 
452  return 1;
453 }
454 
463 static void copy_file(const char *filename, FILE *fpout) {
464  FILE *fp;
465  char buf[MAX_BUF];
466 
467  fp = fopen(filename, "r");
468  if (fp == NULL) {
469  LOG(llevError, "copy_file failed to open \"%s\", player file(s) may be corrupt.\n", filename);
470  return;
471  }
472  while (fgets(buf, MAX_BUF, fp) != NULL)
473  fputs(buf, fpout);
474  fclose(fp);
475 }
476 
484 static void wrong_password(object *op) {
486  "\nA character with this name already exists. "
487  "Please choose another name, or make sure you entered your "
488  "password correctly.\n");
489 
490  FREE_AND_COPY(op->name, "noname");
491  FREE_AND_COPY(op->name_pl, "noname");
492 
493  op->contr->socket.password_fails++;
494  if (op->contr->socket.password_fails >= MAX_PASSWORD_FAILURES) {
496  "You gave an incorrect password too many times, "
497  "you will now be dropped from the server.");
498 
499  LOG(llevInfo, "A player connecting from %s has been dropped for password failure\n",
500  op->contr->socket.host);
501 
502  op->contr->socket.status = Ns_Dead; /* the socket loop should handle the rest for us */
503  } else
504  get_name(op);
505 }
506 
519 void check_login(object *op, const char *password) {
520  FILE *fp;
521  char filename[MAX_BUF];
522  char buf[MAX_BUF], bufall[MAX_BUF];
523  int i, value;
524  uint32_t uvalue;
525  player *pl = op->contr, *pltmp;
526  int correct = 0;
527  time_t elapsed_save_time = 0;
528  struct stat statbuf;
529  char *party_name = NULL, party_password[9];
530 
531  strcpy(pl->maplevel, first_map_path);
532  party_password[0] = 0;
533 
534  /* Check if this matches a connected player, and if yes disconnect old / connect new. */
535  for (pltmp = first_player; pltmp != NULL; pltmp = pltmp->next) {
536  if (pltmp != pl && pltmp->ob->name != NULL && !strcmp(pltmp->ob->name, op->name)) {
537  if (!password || check_password(password, pltmp->password)) {
538  /* We could try and be more clever and re-assign the existing
539  * object to the new player, etc. However, I'm concerned that
540  * there may be a lot of other state that still needs to be sent
541  * in that case (we can't make any assumptions on what the
542  * client knows, as maybe the client crashed), so treating it
543  * as just a normal login is the safest and easiest thing to do.
544  */
545 
546  pltmp->socket.status = Ns_Dead;
547 
548  save_player(pltmp->ob, 0);
549  leave(pltmp, 1);
550  final_free_player(pltmp);
551  break;
552  }
553  if (password) {
555  return;
556  }
557  }
558  }
559 
560  snprintf(filename, sizeof(filename), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, op->name, op->name);
561 
562  /* If no file, must be a new player, so lets get confirmation of
563  * the password. Return control to the higher level dispatch,
564  * since the rest of this just deals with loading of the file.
565  */
566  fp = fopen(filename, "r");
567  if (fp == NULL) {
569  return;
570  }
571  if (fstat(fileno(fp), &statbuf)) {
572  LOG(llevError, "Unable to stat %s?\n", filename);
573  elapsed_save_time = 0;
574  } else {
575  elapsed_save_time = time(NULL)-statbuf.st_mtime;
576  if (elapsed_save_time < 0) {
577  LOG(llevError, "Player file %s was saved in the future? (%ld time)\n", filename, (long)elapsed_save_time);
578  elapsed_save_time = 0;
579  }
580  }
581 
582  if (fgets(bufall, MAX_BUF, fp) != NULL) {
583  if (!strncmp(bufall, "checksum ", 9)) {
584  if ( fgets(bufall, MAX_BUF, fp) == NULL ) {
585  bufall[0]=0; /* should never happen */
586  }
587  }
588  if (sscanf(bufall, "password %s\n", buf)) {
589  /* New password scheme: */
590  correct = password && check_password(password, buf);
591  if (!password) {
592  /* We want to preserve the password. Normally,
593  * pl->password is filled in when user enters
594  * data in the password prompt, but with new login,
595  * there is no password prompt.
596  */
597  strncpy(pl->password, buf, 15);
598  pl->password[15] = 0;
599  }
600  }
601  /* Old password mode removed - I have no idea what it
602  * was, and the current password mechanism has been used
603  * for at least several years.
604  */
605  }
606  if (!correct && password) {
608  fclose(fp);
609  return;
610  }
611 
612 #ifdef SAVE_INTERVAL
613  pl->last_save_time = time(NULL);
614 #endif /* SAVE_INTERVAL */
615  pl->party = NULL;
616  if (settings.search_items == TRUE)
617  pl->search_str[0] = '\0';
618  pl->name_changed = 1;
619  pl->orig_stats.Str = 0;
620  pl->orig_stats.Dex = 0;
621  pl->orig_stats.Con = 0;
622  pl->orig_stats.Int = 0;
623  pl->orig_stats.Pow = 0;
624  pl->orig_stats.Wis = 0;
625  pl->orig_stats.Cha = 0;
626  strcpy(pl->savebed_map, first_map_path);
627  pl->bed_x = 0,
628  pl->bed_y = 0;
629  pl->spellparam[0] = '\0';
630 
631  /* Loop through the file, loading the rest of the values */
632  while (fgets(bufall, MAX_BUF, fp) != NULL) {
633  char *val_string, *p;
634 
635  sscanf(bufall, "%s %d\n", buf, &value);
636 
637  val_string = bufall + strlen(buf) +1;
638  p = strchr(val_string, '\n');
639  if (p != NULL)
640  *p = '\0';
641 
642  /* uvalue is an unsigned value. Since at least a
643  * couple different things want an usigned value, cleaner
644  * to just do it once here vs everyplace it may be needed.
645  */
646 
647  uvalue = strtoul(val_string, (char **)NULL, 10);
648 
649  if (!strcmp(buf, "endplst"))
650  break;
651  if (!strcmp(buf, "title") && settings.set_title == TRUE)
652  player_set_own_title(pl, val_string);
653  else if (!strcmp(buf, "unarmed_skill"))
654  pl->unarmed_skill = add_string(val_string);
655  else if (!strcmp(buf, "explore"))
656  ; /* ignore: explore mode has been removed */
657  else if (!strcmp(buf, "gen_hp"))
658  pl->gen_hp = value;
659  else if (!strcmp(buf, "shoottype"))
661  else if (!strcmp(buf, "bowtype"))
663  else if (!strcmp(buf, "petmode"))
665  else if (!strcmp(buf, "gen_sp"))
666  pl->gen_sp = value;
667  else if (!strcmp(buf, "gen_grace"))
668  pl->gen_grace = value;
669  else if (!strcmp(buf, "listening"))
670  pl->listening = value;
671  else if (!strcmp(buf, "peaceful"))
672  pl->peaceful = value;
673  else if (!strcmp(buf, "no_shout"))
674  pl->no_shout = value;
675  else if (!strcmp(buf, "digestion"))
676  pl->digestion = value;
677  else if (!strcmp(buf, "pickup")) {
678  pl->mode = uvalue;
679  }
680  else if (!strcmp(buf, "map"))
681  strlcpy(pl->maplevel, val_string, sizeof(pl->maplevel));
682  else if (!strcmp(buf, "savebed_map"))
683  strlcpy(pl->savebed_map, val_string, sizeof(pl->savebed_map));
684  else if (!strcmp(buf, "bed_x"))
685  pl->bed_x = value;
686  else if (!strcmp(buf, "bed_y"))
687  pl->bed_y = value;
688  else if (!strcmp(buf, "Str"))
689  pl->orig_stats.Str = value;
690  else if (!strcmp(buf, "Dex"))
691  pl->orig_stats.Dex = value;
692  else if (!strcmp(buf, "Con"))
693  pl->orig_stats.Con = value;
694  else if (!strcmp(buf, "Int"))
695  pl->orig_stats.Int = value;
696  else if (!strcmp(buf, "Pow"))
697  pl->orig_stats.Pow = value;
698  else if (!strcmp(buf, "Wis"))
699  pl->orig_stats.Wis = value;
700  else if (!strcmp(buf, "Cha"))
701  pl->orig_stats.Cha = value;
702  else if (!strcmp(buf, "usekeys")) {
703  if (!strcmp(val_string, "key_inventory"))
705  else if (!strcmp(val_string, "keyrings"))
706  pl->usekeys = keyrings;
707  else if (!strcmp(val_string, "containers"))
708  pl->usekeys = containers;
709  else
710  LOG(llevDebug, "load_player: got unknown usekeys type: %s\n", val_string);
711  } else if (!strcmp(buf, "unapply")) {
712  if (!strcmp(val_string, "unapply_nochoice"))
714  else if (!strcmp(val_string, "unapply_never"))
716  else if (!strcmp(val_string, "unapply_always"))
718  else
719  LOG(llevDebug, "load_player: got unknown unapply type: %s\n", val_string);
720  } else if (!strcmp(buf, "lev_array")) {
721  for (i = 1; i <= value; i++) {
722  int j;
723  int count=0;
724 
725  count = fscanf(fp, "%d\n", &j);
726  if ( !count ) j=0; // sanity; should never happen
727  if (j < 3)
728  j = 3;
729  else if (j > 9)
730  j = 9;
731  pl->levhp[i] = j;
732  count = fscanf(fp, "%d\n", &j);
733  if ( !count ) j=0; // sanity; should never happen
734  if (j < 2)
735  j = 2;
736  else if (j > 6)
737  j = 6;
738  pl->levsp[i] = j;
739  count = fscanf(fp, "%d\n", &j);
740  if ( !count ) j=0; // sanity; should never happen
741  if (j < 1)
742  j = 1;
743  else if (j > 3)
744  j = 3;
745  pl->levgrace[i] = j;
746  }
747  } else if (!strcmp(buf, "party_rejoin_mode"))
749  else if (!strcmp(buf, "party_rejoin_name"))
750  party_name = strdup_local(val_string);
751  else if (!strcmp(buf, "party_rejoin_password")) {
752  strncpy(party_password, val_string, sizeof(party_password));
753  party_password[sizeof(party_password) - 1] = 0;
754  } else if (!strcmp(buf, "language")) {
755  pl->language = i18n_get_language_by_code(val_string);
756  }
757  else if (!strcmp(buf, "ticks_played")) {
758  pl->ticks_played = uvalue;
759  }
760  } /* End of loop loading the character file */
761 
762  /* on first login via account, this player does not exist anyplace -
763  * so don't remove them.
764  */
765  if (!QUERY_FLAG(op, FLAG_REMOVED))
766  object_remove(op);
767  op->speed = 0;
769  /*FIXME dangerous call, object_reset() should be used to init freshly allocated obj struct!*/
770  object_reset(op);
771  op->contr = pl;
772  pl->ob = op;
773  /* this loads the standard objects values. */
774  load_object(fp, op, LO_NEWFILE, 0);
775  fclose(fp);
776 
778 
779  LOG(llevInfo, "login: %s from %s\n", op->name, op->contr->socket.host);
780  strncpy(pl->title, op->arch->clone.name, sizeof(pl->title)-1);
781  pl->title[sizeof(pl->title)-1] = '\0';
782 
783  /* If the map where the person was last saved does not exist,
784  * restart them on their home-savebed. This is good for when
785  * maps change between versions
786  * First, we check for partial path, then check to see if the full
787  * path (for unique player maps)
788  */
789  if (has_been_loaded(pl->maplevel) == NULL
790  && check_path(pl->maplevel, 1) == -1
791  && check_path(pl->maplevel, 0) == -1) {
792  strcpy(pl->maplevel, pl->savebed_map);
793  op->x = pl->bed_x,
794  op->y = pl->bed_y;
795  /* if the map was a shop, the player can have unpaid items, remove them. */
796  remove_unpaid_objects(op, NULL, 1);
797  }
798 
799  /* If player saved beyond some time ago, and the feature is
800  * enabled, put the player back on his savebed map.
801  */
802  if ((settings.reset_loc_time > 0) && (elapsed_save_time > settings.reset_loc_time)) {
803  strcpy(pl->maplevel, pl->savebed_map);
804  op->x = pl->bed_x, op->y = pl->bed_y;
805  /* if the map was a shop, the player can have unpaid items, remove them. */
806  remove_unpaid_objects(op, NULL, 1);
807  }
808 
809  /* make sure he's a player--needed because of class change. */
810  op->type = PLAYER;
812 
813  pl->name_changed = 1;
815 #ifdef AUTOSAVE
816  pl->last_save_tick = pticks;
817 #endif
818  op->carrying = object_sum_weight(op);
819 
821 
822  if (!legal_range(op, op->contr->shoottype))
823  op->contr->shoottype = range_none;
824 
825  /* if it's a dragon player, set the correct title here */
826  if (is_dragon_pl(op) && op->inv != NULL) {
827  object *abil, *skin;
828 
829  abil = object_find_by_type_and_arch_name(op, FORCE, "dragon_ability_force");
830  skin = object_find_by_type_and_arch_name(op, FORCE, "dragon_skin_force");
831  set_dragon_name(op, abil, skin);
832  }
833 
835  "Welcome Back!");
838  "%s has entered the game.",
839  pl->ob->name);
841 
843  op->contr->socket.update_look = 1;
844  /* If the player should be dead, call kill_player for them
845  * Only check for hp - if player lacks food, let the normal
846  * logic for that to take place. If player is permanently
847  * dead, and not using permadeath mode, the kill_player will
848  * set the play_again flag, so return.
849  */
850  if (op->stats.hp < 0) {
852  "Your character was dead last time you played.");
853  kill_player(op, NULL);
854  if (pl->state != ST_PLAYING)
855  {
856  // Prevent memory leak from strdup-ed party_name.
857  if (party_name)
858  free(party_name);
859  return;
860  }
861  }
862 
863  /* Do this after checking for death - no reason sucking up bandwidth if
864  * the data isn't needed.
865  */
866  esrv_new_player(op->contr, op->weight+op->carrying);
867  /* Need to do these after esvr_new_player, as once the client
868  * sees that, it wipes any info it has about the player.
869  */
870  esrv_add_spells(op->contr, NULL);
871 
872  /* Need to call fix_object now - program modified so that it is not
873  * called during the load process (FLAG_NO_FIX_PLAYER set when
874  * saved)
875  * Moved ahead of the esrv functions, so proper weights will be
876  * sent to the client. Needs to be after esvr_add_spells, otherwise
877  * we'll try to update spells from fix_object.
878  */
879  fix_object(op);
880 
881  pl->has_directory = 1;
882 
887 
889 
890  /* can_use_shield is a new flag. However, the can_use.. seems to largely come
891  * from the class, and not race. I don't see any way to get the class information
892  * to then update this. I don't think this will actually break anything - anyone
893  * that can use armour should be able to use a shield. What this may 'break'
894  * are features new characters get, eg, if someone starts up with a Q, they
895  * should be able to use a shield. However, old Q's won't get that advantage.
896  */
899 
900  /* Rejoin party if needed. */
901  if (pl->rejoin_party != party_rejoin_no && party_name != NULL) {
902  partylist *party;
903 
904  party = party_find(party_name);
905  if (!party && pl->rejoin_party == party_rejoin_always) {
906  party = party_form(op, party_name);
907  if (party)
908  party_set_password(party, party_password);
909  }
910  if (party && !pl->party && party_confirm_password(party, party_password)) {
911  party_join(op, party);
912  }
913 
914  if (pl->party)
915  snprintf(buf, MAX_BUF, "Rejoined party %s.", party->partyname);
916  else
917  snprintf(buf, MAX_BUF, "Couldn't rejoin party %s: %s.", party_name, party ? "invalid password." : "no such party.");
919  buf);
920  }
921  free(party_name);
922 }
party_rejoin_no
@ party_rejoin_no
Definition: player.h:86
socket_struct::account_chars
Account_Char * account_chars
Definition: newserver.h:127
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:1806
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:561
account_char_add
Account_Char * account_char_add(Account_Char *chars, player *pl)
Definition: account_char.c:194
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:100
object_reset
void object_reset(object *op)
Definition: object.c:927
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:212
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:4285
load_object
int load_object(FILE *fp, object *op, int bufstate, int map_flags)
Definition: loader.c:5166
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:298
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
login_check_shutdown
void login_check_shutdown(object *const op)
Definition: server.c:1449
Settings::set_title
uint8_t set_title
Definition: global.h:261
destroy_object
void destroy_object(object *op)
Definition: login.c:209
pl::peaceful
uint32_t peaceful
Definition: player.h:133
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:312
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:250
pl::socket
socket_struct socket
Definition: player.h:94
pl::shoottype
rangetype shoottype
Definition: player.h:99
pl
Definition: player.h:92
pl::name_changed
uint32_t name_changed
Definition: player.h:132
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.c:1740
range_none
@ range_none
Definition: player.h:17
pl::mode
uint32_t mode
Definition: player.h:110
MIN
#define MIN(x, y)
Definition: compat.h:21
pl::ob
object * ob
Definition: player.h:162
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:484
pl::bowtype
bowtype_t bowtype
Definition: player.h:101
NDI_RED
#define NDI_RED
Definition: newclient.h:245
account_link
int account_link(const char *account_name, const char *player_name)
Definition: account.c:447
unapply_always
@ unapply_always
Definition: player.h:65
player_set_own_title
void player_set_own_title(struct pl *pl, const char *title)
Definition: player.c:275
LO_NEWFILE
#define LO_NEWFILE
Definition: loader.h:17
first_map_path
EXTERN char first_map_path[MAX_BUF]
Definition: global.h:143
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:463
pl::maplevel
char maplevel[MAX_BUF]
Definition: player.h:96
pl::gen_sp
int16_t gen_sp
Definition: player.h:114
hiscore_check
void hiscore_check(object *op, int quiet)
Definition: hiscore.c:348
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:88
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:172
pl::savebed_map
char savebed_map[MAX_BUF]
Definition: player.h:97
pl::next
struct pl * next
Definition: player.h:93
EVENT_LOGIN
#define EVENT_LOGIN
Definition: events.h:43
link_player_skills
void link_player_skills(object *op)
Definition: player.c:290
final_free_player
void final_free_player(player *pl)
Definition: init.c:444
obj::name
sstring name
Definition: object.h:312
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:118
pl::digestion
int16_t digestion
Definition: player.h:112
playername_ok
int playername_ok(const char *cp)
Definition: player.c:254
pl::unarmed_skill
const char * unarmed_skill
Definition: player.h:206
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:3171
pl::petmode
petmode_t petmode
Definition: player.h:102
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:264
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.c:676
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:202
pl::no_shout
uint32_t no_shout
Definition: player.h:135
first_player
EXTERN player * first_player
Definition: global.h:115
obj::x
int16_t x
Definition: object.h:328
fix_object
void fix_object(object *op)
Definition: living.c:1126
pl::levgrace
int8_t levgrace[11]
Definition: player.h:173
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:1275
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:113
rangetype
rangetype
Definition: player.h:15
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:263
is_dragon_pl
int is_dragon_pl(const object *op)
Definition: player.c:125
liv::Int
int8_t Int
Definition: living.h:36
pl::unapply
unapplymode unapply
Definition: player.h:108
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:98
party_struct
Definition: party.h:10
key_inventory
@ key_inventory
Definition: player.h:53
Settings::reset_loc_time
int reset_loc_time
Definition: global.h:260
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:120
account_char_save
void account_char_save(const char *account, Account_Char *chars)
Definition: account_char.c:146
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:196
pl::levhp
int8_t levhp[11]
Definition: player.h:171
remove_directory
void remove_directory(const char *path)
Definition: porting.c:115
Settings::playerdir
const char * playerdir
Definition: global.h:246
quest_first_player_save
void quest_first_player_save(player *pl)
Definition: quest.c:986
obj::y
int16_t y
Definition: object.h:328
pl::gen_grace
int16_t gen_grace
Definition: player.h:116
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
pl::bed_y
int16_t bed_y
Definition: player.h:98
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:295
llevInfo
@ llevInfo
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
pticks
uint32_t pticks
Definition: time.c:45
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
pl::language
int language
Definition: player.h:205
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:63
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:178
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:136
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:195
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:1606
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:248
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1317
delete_character
void delete_character(const char *name)
Definition: login.c:88
containers
@ containers
Definition: player.h:55
keyrings
@ keyrings
Definition: player.h:54
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:1533
pl::ticks_played
uint32_t ticks_played
Definition: player.h:207
trying_emergency_save
EXTERN long trying_emergency_save
Definition: global.h:127
player_set_state
void player_set_state(player *pl, uint8_t state)
Definition: player.c:4428
emergency_save
void emergency_save(int flag)
Definition: login.c:41
check_login
void check_login(object *op, const char *password)
Definition: login.c:519
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:1397
Settings::search_items
uint8_t search_items
Definition: global.h:263
unapply_never
@ unapply_never
Definition: player.h:64
server.h
Settings::tmpdir
const char * tmpdir
Definition: global.h:251
confirm_password
void confirm_password(object *op)
Definition: player.c:987
pl::party
partylist * party
Definition: player.h:188
TRUE
#define TRUE
Definition: compat.h:11
pl::usekeys
usekeytype usekeys
Definition: player.h:107
party_rejoin_mode
party_rejoin_mode
Definition: player.h:85
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:3452
if
if(!(yy_init))
Definition: loader.c:2589
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:169
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:27
save_object
int save_object(FILE *fp, object *op, int flag)
Definition: object.c:5347
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:152
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:88
OutputFile
Definition: output_file.h:41
get_name
void get_name(object *op)
Definition: player.c:862
knowledge_first_player_save
void knowledge_first_player_save(player *pl)
Definition: knowledge.c:1417
Settings::localdir
const char * localdir
Definition: global.h:245