ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/login.C
(Generate patch)

Comparing deliantra/server/server/login.C (file contents):
Revision 1.5 by root, Mon Aug 28 14:05:24 2006 UTC vs.
Revision 1.36 by root, Sat Dec 30 10:16:11 2006 UTC

1/*
2 * static char *rcsid_login_c =
3 * "$Id: login.C,v 1.5 2006/08/28 14:05:24 root Exp $";
4 */
5
6/* 1/*
7 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
8 3
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
21 16
22 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 20
26 The authors can be reached via e-mail at crossfire-devel@real-time.com 21 The authors can be reached via e-mail at <crossfire@schmorp.de>
27*/ 22*/
28 23
29#include <global.h> 24#include <global.h>
30#ifndef __CEXTRACT__
31#include <sproto.h> 25#include <sproto.h>
32#endif
33#include <spells.h> 26#include <spells.h>
34#include <loader.h> 27#include <loader.h>
35#include <define.h> 28#include <define.h>
36 29
37extern void sub_weight (object *, signed long); 30extern void sub_weight (object *, signed long);
38extern void add_weight (object *, signed long); 31extern void add_weight (object *, signed long);
39extern long pticks; 32extern long pticks;
40
41/* If flag is non zero, it means that we want to try and save everyone, but
42 * keep the game running. Thus, we don't want to free any information.
43 */
44void emergency_save(int flag) {
45 player *pl;
46#ifndef NO_EMERGENCY_SAVE
47 trying_emergency_save = 1;
48 if(editor)
49 return;
50 LOG(llevError,"Emergency save: ");
51 for(pl=first_player;pl!=NULL;pl=pl->next) {
52 if(!pl->ob) {
53 LOG(llevError, "No name, ignoring this.\n");
54 continue;
55 }
56 LOG(llevError,"%s ",pl->ob->name);
57 new_draw_info(NDI_UNIQUE, 0,pl->ob,"Emergency save...");
58
59/* If we are not exiting the game (ie, this is sort of a backup save), then
60 * don't change the location back to the village. Note that there are other
61 * options to have backup saves be done at the starting village
62 */
63 if (!flag) {
64 strcpy(pl->maplevel, first_map_path);
65 if(pl->ob->map!=NULL)
66 pl->ob->map = NULL;
67 pl->ob->x = -1;
68 pl->ob->y = -1;
69 }
70 if(!save_player(pl->ob,flag)) {
71 LOG(llevError, "(failed) ");
72 new_draw_info(NDI_UNIQUE, 0,pl->ob,"Emergency save failed, checking score...");
73 }
74 check_score(pl->ob);
75 }
76 LOG(llevError,"\n");
77#else
78 LOG(llevInfo,"Emergency saves disabled, no save attempted\n");
79#endif
80 /* If the game is exiting, remove the player locks */
81 if (!flag) {
82 for(pl=first_player;pl!=NULL;pl=pl->next) {
83 if(pl->ob) {
84 }
85 }
86 }
87}
88 33
89/* Delete character with name. if new is set, also delete the new 34/* Delete character with name. if new is set, also delete the new
90 * style directory, otherwise, just delete the old style playfile 35 * style directory, otherwise, just delete the old style playfile
91 * (needed for transition) 36 * (needed for transition)
92 */ 37 */
38void
93void delete_character(const char *name, int newchar) { 39delete_character (const char *name, int newchar)
40{
94 char buf[MAX_BUF]; 41 char buf[MAX_BUF];
95 42
96 sprintf(buf,"%s/%s/%s.pl",settings.localdir,settings.playerdir,name); 43 sprintf (buf, "%s/%s/%s.pl", settings.localdir, settings.playerdir, name);
44
97 if(unlink(buf)== -1) 45 if (unlink (buf) == -1)
98 LOG(llevDebug, "Cannot delete character file %s: %s\n", buf, strerror_local(errno)); 46 LOG (llevDebug, "Cannot delete character file %s: %s\n", buf, strerror (errno));
47
99 if (newchar) { 48 if (newchar)
49 {
100 sprintf(buf,"%s/%s/%s",settings.localdir,settings.playerdir,name); 50 sprintf (buf, "%s/%s/%s", settings.localdir, settings.playerdir, name);
101 /* this effectively does an rm -rf on the directory */ 51 /* this effectively does an rm -rf on the directory */
102 remove_directory(buf); 52 remove_directory (buf);
103 } 53 }
104} 54}
105 55
106/* This verify that a character of name exits, and that it matches 56int
107 * password. It return 0 if there is match, 1 if no such player,
108 * 2 if incorrect password.
109 */
110
111int verify_player(const char *name, char *password)
112{
113 char buf[MAX_BUF];
114 int comp;
115 FILE *fp;
116
117 if (strpbrk(name, "/.\\") != NULL) {
118 LOG(llevError, "Username contains illegal characters: %s\n", name);
119 return 1;
120 }
121
122 snprintf(buf, sizeof(buf), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, name, name);
123 if (strlen(buf) >= sizeof(buf)-1) {
124 LOG(llevError, "Username too long: %s\n", name);
125 return 1;
126 }
127
128 if ((fp=open_and_uncompress(buf,0,&comp))==NULL) return 1;
129
130 /* Read in the file until we find the password line. Our logic could
131 * be a bit better on cleaning up the password from the file, but since
132 * it is written by the program, I think it is fair to assume that the
133 * syntax should be pretty standard.
134 */
135 while (fgets(buf, MAX_BUF-1, fp) != NULL) {
136 if (!strncmp(buf,"password ",9)) {
137 buf[strlen(buf)-1]=0; /* remove newline */
138 if (check_password(password, buf+9)) {
139 close_and_delete(fp, comp);
140 return 0;
141 }
142 else {
143 close_and_delete(fp, comp);
144 return 2;
145 }
146 }
147 }
148 LOG(llevDebug,"Could not find a password line in player %s\n", name);
149 close_and_delete(fp, comp);
150 return 1;
151}
152
153/* Checks to see if anyone else by 'name' is currently playing.
154 * If we find that file or another character of some name is already in the
155 * game, we don't let this person join (we should really let the new player
156 * enter the password, and if correct, disconnect that socket and attach it to
157 * the players current session.
158 * If no one by that name is currently playing, we then make sure the name
159 * doesn't include any bogus characters.
160 * We return 0 if the name is in use/bad, 1 if it is OK to use this name.
161 */
162
163int check_name(player *me,const char *name) {
164 player *pl;
165
166 for(pl=first_player;pl!=NULL;pl=pl->next)
167 if(pl!=me&&pl->ob->name!=NULL&&!strcmp(pl->ob->name,name)) {
168 new_draw_info(NDI_UNIQUE, 0,me->ob,"That name is already in use.");
169 return 0;
170 }
171
172 if (*name=='\0') {
173 new_draw_info(NDI_UNIQUE, 0,me->ob,"Null names are not allowed.");
174 return 0;
175 }
176
177 if(!playername_ok(name)) {
178 new_draw_info(NDI_UNIQUE, 0,me->ob,"That name contains illegal characters.");
179 return 0;
180 }
181 if (strlen(name) >= MAX_NAME) {
182 new_draw_info(NDI_UNIQUE, 0,me->ob,"That name is too long.");
183 return 0;
184 }
185
186 return 1;
187}
188
189int create_savedir_if_needed(char *savedir) 57create_savedir_if_needed (char *savedir)
190{ 58{
191 struct stat *buf; 59 struct stat *buf;
192 60
193 if ((buf = (struct stat *) malloc(sizeof(struct stat))) == NULL) { 61 if ((buf = (struct stat *) malloc (sizeof (struct stat))) == NULL)
62 {
194 LOG(llevError, "Unable to save playerfile... out of memory.\n"); 63 LOG (llevError, "Unable to save playerfile... out of memory.\n");
195 return 0;
196 } else {
197 stat(savedir, buf);
198 if (!S_ISDIR(buf->st_mode))
199 if (mkdir(savedir, SAVE_DIR_MODE))
200 {
201 LOG(llevError, "Unable to create player savedir %s: %s\n", savedir, strerror_local(errno));
202 return 0;
203 }
204 free(buf);
205 }
206 return 1;
207}
208
209void destroy_object (object *op)
210{
211 object *tmp;
212 while ((tmp = op->inv))
213 destroy_object (tmp);
214
215 if (!QUERY_FLAG(op, FLAG_REMOVED))
216 remove_ob(op);
217 free_object(op);
218}
219
220/*
221 * If flag is set, it's only backup, ie dont remove objects from inventory
222 * If BACKUP_SAVE_AT_HOME is set, and the flag is set, then the player
223 * will be saved at the emergency save location.
224 * Returns non zero if successful.
225 */
226
227int save_player(object *op, int flag) {
228 char filename[MAX_BUF];
229 object *tmp, *container=NULL;
230 player *pl = op->contr;
231 int i,wiz=QUERY_FLAG(op,FLAG_WIZ);
232 long checksum;
233#ifdef BACKUP_SAVE_AT_HOME
234 sint16 backup_x, backup_y;
235#endif
236
237 if (!op->stats.exp) return 0; /* no experience, no save */
238
239 flag&=1;
240
241 if(!pl->name_changed||(!flag&&!op->stats.exp)) {
242 if(!flag) {
243 new_draw_info(NDI_UNIQUE, 0,op,"Your game is not valid,");
244 new_draw_info(NDI_UNIQUE, 0,op,"Game not saved.");
245 }
246 return 0;
247 }
248
249 /* Sanity check - some stuff changes this when player is exiting */
250 if (op->type != PLAYER) return 0;
251
252 /* Prevent accidental saves if connection is reset after player has
253 * mostly exited.
254 */
255 if (pl->state != ST_PLAYING && pl->state != ST_GET_PARTY_PASSWORD)
256 return 0;
257
258 INVOKE_PLAYER (SAVE, op->contr, ARG_STRING (filename));
259
260 if (flag == 0)
261 terminate_all_pets(op);
262
263 sprintf(filename,"%s/%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name,op->name);
264 make_path_to_file(filename);
265
266 object_freezer fp (filename);
267
268 if (!fp)
269 {
270 new_draw_info(NDI_UNIQUE, 0,op, "Can't open file for save.");
271 return 0; 64 return 0;
272 } 65 }
273
274/* Eneq(@csd.uu.se): If we have an open container hide it. */
275 if (op->container)
276 {
277 container = op->container;
278 op->container = NULL;
279 }
280
281 fprintf(fp,"password %s\n",pl->password);
282
283 if (settings.set_title == TRUE)
284 if(pl->own_title[0]!='\0')
285 fprintf(fp,"title %s\n",pl->own_title);
286
287 fprintf(fp,"explore %d\n",pl->explore);
288 fprintf(fp,"gen_hp %d\n",pl->gen_hp);
289 fprintf(fp,"gen_sp %d\n",pl->gen_sp);
290 fprintf(fp,"gen_grace %d\n",pl->gen_grace);
291 fprintf(fp,"listening %d\n",pl->listening);
292 fprintf(fp,"shoottype %d\n",pl->shoottype);
293 fprintf(fp,"bowtype %d\n",pl->bowtype);
294 fprintf(fp,"petmode %d\n",pl->petmode);
295 fprintf(fp,"peaceful %d\n",pl->peaceful);
296 fprintf(fp,"no_shout %d\n",pl->no_shout);
297 fprintf(fp,"digestion %d\n",pl->digestion);
298 fprintf(fp,"pickup %d\n", pl->mode);
299 fprintf(fp,"outputs_sync %d\n", pl->outputs_sync);
300 fprintf(fp,"outputs_count %d\n", pl->outputs_count);
301 /* Match the enumerations but in string form */
302 fprintf(fp,"usekeys %s\n", pl->usekeys==key_inventory?"key_inventory":
303 (pl->usekeys==keyrings?"keyrings":"containers"));
304 /* Match the enumerations but in string form */
305 fprintf(fp,"unapply %s\n", pl->unapply==unapply_nochoice?"unapply_nochoice":
306 (pl->unapply==unapply_never?"unapply_never":"unapply_always"));
307
308#ifdef BACKUP_SAVE_AT_HOME
309 if (op->map!=NULL && flag==0)
310#else
311 if (op->map!=NULL)
312#endif
313 fprintf(fp,"map %s\n",op->map->path);
314 else 66 else
315 fprintf(fp,"map %s\n",settings.emergency_mapname); 67 {
316 68 stat (savedir, buf);
317 fprintf(fp,"savebed_map %s\n", pl->savebed_map); 69 if (!S_ISDIR (buf->st_mode))
318 fprintf(fp,"bed_x %d\nbed_y %d\n", pl->bed_x, pl->bed_y); 70 if (mkdir (savedir, SAVE_DIR_MODE))
319 fprintf(fp,"weapon_sp %f\n",pl->weapon_sp); 71 {
320 fprintf(fp,"Str %d\n",pl->orig_stats.Str); 72 LOG (llevError, "Unable to create player savedir %s: %s\n", savedir, strerror (errno));
321 fprintf(fp,"Dex %d\n",pl->orig_stats.Dex); 73 return 0;
322 fprintf(fp,"Con %d\n",pl->orig_stats.Con); 74 }
323 fprintf(fp,"Int %d\n",pl->orig_stats.Int); 75 free (buf);
324 fprintf(fp,"Pow %d\n",pl->orig_stats.Pow);
325 fprintf(fp,"Wis %d\n",pl->orig_stats.Wis);
326 fprintf(fp,"Cha %d\n",pl->orig_stats.Cha);
327
328 fprintf(fp,"lev_array %d\n",op->level>10?10:op->level);
329 for(i=1;i<=pl->last_level&&i<=10;i++) {
330 fprintf(fp,"%d\n",pl->levhp[i]);
331 fprintf(fp,"%d\n",pl->levsp[i]);
332 fprintf(fp,"%d\n",pl->levgrace[i]);
333 } 76 }
334
335 fp.put (op->contr);
336
337 fprintf(fp,"endplst\n");
338
339 SET_FLAG(op, FLAG_NO_FIX_PLAYER);
340 CLEAR_FLAG(op, FLAG_WIZ);
341#ifdef BACKUP_SAVE_AT_HOME
342 if (flag) {
343 backup_x = op->x;
344 backup_y = op->y;
345 op->x = -1;
346 op->y = -1;
347 }
348 /* Save objects, but not unpaid objects. Don't remove objects from
349 * inventory.
350 */
351 save_object(fp, op, 2);
352 if (flag) {
353 op->x = backup_x;
354 op->y = backup_y;
355 }
356#else
357 save_object(fp, op, 3); /* don't check and don't remove */
358#endif
359
360 CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER);
361
362 if(!flag)
363 while ((tmp = op->inv))
364 destroy_object (tmp);
365
366 /* Eneq(@csd.uu.se): Reveal the container if we have one. */
367 if (flag&&container!=NULL)
368 op->container = container;
369
370 if (wiz) SET_FLAG(op,FLAG_WIZ);
371
372 if(!flag)
373 esrv_send_inventory(op, op);
374 77
375 return 1; 78 return 1;
376} 79}
377 80
378void check_login(object *op) { 81/*
379 FILE *fp; 82 * If final is set, it a clean/final save, not a backup, ie dont remove objects from inventory
380 char filename[MAX_BUF];
381 char buf[MAX_BUF],bufall[MAX_BUF];
382 int i,value,comp;
383 long checksum = 0;
384 player *pl = op->contr;
385 int correct = 0;
386 time_t elapsed_save_time=0;
387 struct stat statbuf;
388
389 strcpy (pl->maplevel,first_map_path);
390
391 sprintf(filename,"%s/%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name,op->name);
392
393 /* If no file, must be a new player, so lets get confirmation of
394 * the password. Return control to the higher level dispatch,
395 * since the rest of this just deals with loading of the file.
396 */
397 if ((fp=open_and_uncompress(filename,1,&comp)) == NULL) {
398 confirm_password(op);
399 return;
400 }
401 if (fstat(fileno(fp), &statbuf)) {
402 LOG(llevError,"Unable to stat %s?\n", filename);
403 elapsed_save_time=0;
404 } else {
405 elapsed_save_time = time(NULL) - statbuf.st_mtime;
406 if (elapsed_save_time<0) {
407 LOG(llevError,"Player file %s was saved in the future? (%d time)\n", filename, elapsed_save_time);
408 elapsed_save_time=0;
409 }
410 }
411
412 object_thawer thawer (fp, filename);
413
414 if(fgets(bufall,MAX_BUF,fp) != NULL) {
415 if(!strncmp(bufall,"checksum ",9)) {
416 checksum = strtol(bufall+9,(char **) NULL, 16);
417 (void) fgets(bufall,MAX_BUF,fp);
418 }
419 if(sscanf(bufall,"password %s\n",buf)) {
420 /* New password scheme: */
421 correct=check_password(pl->write_buf+1,buf);
422 }
423 /* Old password mode removed - I have no idea what it
424 * was, and the current password mechanism has been used
425 * for at least several years.
426 */ 83 */
427 } 84void
428 if (!correct) { 85player::save (bool final)
429 new_draw_info(NDI_UNIQUE, 0,op," "); 86{
430 new_draw_info(NDI_UNIQUE, 0,op,"Wrong Password!"); 87 object *tmp, *container = 0;
431 new_draw_info(NDI_UNIQUE, 0,op," ");
432 FREE_AND_COPY(op->name, "noname");
433 FREE_AND_COPY(op->name_pl, "noname");
434 op->contr->socket.password_fails++;
435 if (op->contr->socket.password_fails >= MAX_PASSWORD_FAILURES) {
436 new_draw_info(NDI_UNIQUE, 0,op,
437 "You gave an incorrect password too many times, you will now be dropped from the server.");
438 LOG(llevInfo, "A player connecting from %s has been dropped for password failure\n",
439 op->contr->socket.host);
440 op->contr->socket.status = Ns_Dead; /* the socket loop should handle the rest for us */
441 }
442 else get_name(op);
443 return; /* Once again, rest of code just loads the char */
444 }
445 88
446#ifdef SAVE_INTERVAL 89 /* Sanity check - some stuff changes this when player is exiting */
447 pl->last_save_time=time(NULL); 90 if (ob->type != PLAYER || !enable_save || !ns)
448#endif /* SAVE_INTERVAL */
449 pl->party = NULL;
450 if (settings.search_items == TRUE)
451 pl->search_str[0]='\0';
452 pl->name_changed=1;
453 pl->orig_stats.Str=0;
454 pl->orig_stats.Dex=0;
455 pl->orig_stats.Con=0;
456 pl->orig_stats.Int=0;
457 pl->orig_stats.Pow=0;
458 pl->orig_stats.Wis=0;
459 pl->orig_stats.Cha=0;
460 strcpy(pl->savebed_map, first_map_path);
461 pl->bed_x=0, pl->bed_y=0;
462 pl->spellparam[0] = '\0';
463
464 /* Loop through the file, loading the rest of the values */
465 while (fgets(bufall,MAX_BUF,fp)!=NULL) {
466 sscanf(bufall,"%s %d\n",buf,&value);
467 if (!strcmp(buf,"endplst"))
468 break;
469 else if (!strcmp(buf,"oid"))
470 thawer.get (pl, value);
471 else if (!strcmp(buf,"title") && settings.set_title == TRUE)
472 sscanf(bufall,"title %[^\n]",pl->own_title);
473 else if (!strcmp(buf,"explore"))
474 pl->explore = value;
475 else if (!strcmp(buf,"gen_hp"))
476 pl->gen_hp=value;
477 else if (!strcmp(buf,"shoottype"))
478 pl->shoottype=(rangetype)value;
479 else if (!strcmp(buf,"bowtype"))
480 pl->bowtype=(bowtype_t)value;
481 else if (!strcmp(buf,"petmode"))
482 pl->petmode=(petmode_t)value;
483 else if (!strcmp(buf,"gen_sp"))
484 pl->gen_sp=value;
485 else if (!strcmp(buf,"gen_grace"))
486 pl->gen_grace=value;
487 else if (!strcmp(buf,"listening"))
488 pl->listening=value;
489 else if (!strcmp(buf,"peaceful"))
490 pl->peaceful=value;
491 else if (!strcmp(buf,"no_shout"))
492 pl->no_shout=value;
493 else if (!strcmp(buf,"digestion"))
494 pl->digestion=value;
495 else if (!strcmp(buf,"pickup"))
496 pl->mode=value;
497 else if (!strcmp(buf,"outputs_sync"))
498 pl->outputs_sync = value;
499 else if (!strcmp(buf,"outputs_count"))
500 pl->outputs_count = value;
501 else if (!strcmp(buf,"map"))
502 sscanf(bufall,"map %s", pl->maplevel);
503 else if (!strcmp(buf,"savebed_map"))
504 sscanf(bufall,"savebed_map %s", pl->savebed_map);
505 else if (!strcmp(buf,"bed_x"))
506 pl->bed_x=value;
507 else if (!strcmp(buf,"bed_y"))
508 pl->bed_y=value;
509 else if (!strcmp(buf,"weapon_sp"))
510 sscanf(buf,"weapon_sp %f",&pl->weapon_sp);
511 else if (!strcmp(buf,"Str"))
512 pl->orig_stats.Str=value;
513 else if (!strcmp(buf,"Dex"))
514 pl->orig_stats.Dex=value;
515 else if (!strcmp(buf,"Con"))
516 pl->orig_stats.Con=value;
517 else if (!strcmp(buf,"Int"))
518 pl->orig_stats.Int=value;
519 else if (!strcmp(buf,"Pow"))
520 pl->orig_stats.Pow=value;
521 else if (!strcmp(buf,"Wis"))
522 pl->orig_stats.Wis=value;
523 else if (!strcmp(buf,"Cha"))
524 pl->orig_stats.Cha=value;
525 else if (!strcmp(buf,"usekeys")) {
526 if (!strcmp(bufall+8,"key_inventory\n"))
527 pl->usekeys=key_inventory;
528 else if (!strcmp(bufall+8,"keyrings\n"))
529 pl->usekeys=keyrings;
530 else if (!strcmp(bufall+8,"containers\n"))
531 pl->usekeys=containers;
532 else LOG(llevDebug,"load_player: got unknown usekeys type: %s\n", bufall+8);
533 }
534 else if (!strcmp(buf,"unapply")) {
535 if (!strcmp(bufall+8,"unapply_nochoice\n"))
536 pl->unapply=unapply_nochoice;
537 else if (!strcmp(bufall+8,"unapply_never\n"))
538 pl->unapply=unapply_never;
539 else if (!strcmp(bufall+8,"unapply_always\n"))
540 pl->unapply=unapply_always;
541 else LOG(llevDebug,"load_player: got unknown unapply type: %s\n", bufall+8);
542 }
543 else if (!strcmp(buf,"lev_array")){
544 for(i=1;i<=value;i++) {
545 int j;
546 fscanf(fp,"%d\n",&j);
547 pl->levhp[i]=j;
548 fscanf(fp,"%d\n",&j);
549 pl->levsp[i]=j;
550 fscanf(fp,"%d\n",&j);
551 pl->levgrace[i]=j;
552 }
553 /* spell_array code removed - don't know when that was last used.
554 * Even the load code below will someday be replaced by spells being
555 * objects.
556 */
557 } else if (!strcmp(buf,"known_spell")) {
558#if 0
559 /* Logic is left here in case someone wants to try
560 * and write code to update to spell objects.
561 */
562 char *cp=strchr(bufall,'\n');
563 *cp='\0';
564 cp=strchr(bufall,' ');
565 cp++;
566 for(i=0;i<NROFREALSPELLS;i++)
567 if(!strcmp(spells[i].name,cp)) {
568 pl->known_spells[pl->nrofknownspells++]=i;
569 break;
570 }
571 if(i==NROFREALSPELLS)
572 LOG(llevDebug, "Error: unknown spell (%s)\n",cp);
573#endif
574 }
575 } /* End of loop loading the character file */
576 leave_map(op);
577 op->speed=0;
578 update_ob_speed(op);
579 reset_object(op);
580 op->contr = pl;
581 pl->ob = op;
582
583 /* this loads the standard objects values. */
584 load_object(thawer, op, LO_NEWFILE,0);
585 close_and_delete(fp, comp);
586
587 CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER);
588
589 strncpy(pl->title, op->arch->clone.name, sizeof(pl->title)-1);
590 pl->title[sizeof(pl->title)-1] = '\0';
591
592 /* If the map where the person was last saved does not exist,
593 * restart them on their home-savebed. This is good for when
594 * maps change between versions
595 * First, we check for partial path, then check to see if the full
596 * path (for unique player maps)
597 */
598 if (check_path(pl->maplevel,1)==-1) {
599 if (check_path(pl->maplevel,0)==-1) {
600 strcpy(pl->maplevel, pl->savebed_map);
601 op->x = pl->bed_x, op->y = pl->bed_y;
602 }
603 }
604
605 /* If player saved beyond some time ago, and the feature is
606 * enabled, put the player back on his savebed map.
607 */
608 if ((settings.reset_loc_time >0) && (elapsed_save_time > settings.reset_loc_time)) {
609 strcpy(pl->maplevel, pl->savebed_map);
610 op->x = pl->bed_x, op->y = pl->bed_y;
611 }
612
613 /* make sure he's a player--needed because of class change. */
614 op->type = PLAYER;
615
616 enter_exit(op,NULL);
617
618 pl->name_changed=1;
619 pl->state = ST_PLAYING;
620#ifdef AUTOSAVE
621 pl->last_save_tick = pticks;
622#endif
623 op->carrying = sum_weight (op);
624 /* Need to call fix_player now - program modified so that it is not
625 * called during the load process (FLAG_NO_FIX_PLAYER set when
626 * saved)
627 * Moved ahead of the esrv functions, so proper weights will be
628 * sent to the client.
629 */
630 link_player_skills(op);
631
632 if ( ! legal_range (op, op->contr->shoottype))
633 op->contr->shoottype = range_none;
634
635 fix_player (op);
636
637 /* if it's a dragon player, set the correct title here */
638 if (is_dragon_pl(op) && op->inv != NULL) {
639 object *tmp, *abil=NULL, *skin=NULL;
640 for (tmp=op->inv; tmp!=NULL; tmp=tmp->below) {
641 if (tmp->type == FORCE) {
642 if (strcmp(tmp->arch->name, "dragon_ability_force")==0)
643 abil = tmp;
644 else if (strcmp(tmp->arch->name, "dragon_skin_force")==0)
645 skin = tmp;
646 }
647 }
648 set_dragon_name(op, abil, skin);
649 }
650
651 new_draw_info(NDI_UNIQUE, 0,op,"Welcome Back!");
652 new_draw_info_format(NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL,
653 "%s has entered the game.",pl->ob->name);
654
655 INVOKE_PLAYER (LOAD, pl, ARG_STRING (filename));
656 INVOKE_PLAYER (LOGIN, pl);
657
658 op->contr->socket.update_look=1;
659 /* If the player should be dead, call kill_player for them
660 * Only check for hp - if player lacks food, let the normal
661 * logic for that to take place. If player is permanently
662 * dead, and not using permadeath mode, the kill_player will
663 * set the play_again flag, so return.
664 */
665 if (op->stats.hp<0) {
666 new_draw_info(NDI_UNIQUE, 0,op,"Your character was dead last your played.");
667 kill_player(op);
668 if (pl->state != ST_PLAYING) return;
669 }
670 LOG(llevInfo,"LOGIN: Player named %s from ip %s\n", op->name,
671 op->contr->socket.host);
672
673 /* Do this after checking for death - no reason sucking up bandwidth if
674 * the data isn't needed.
675 */
676 esrv_new_player(op->contr,op->weight+op->carrying);
677 esrv_send_inventory(op, op);
678 esrv_add_spells(op->contr, NULL);
679
680 CLEAR_FLAG(op, FLAG_FRIENDLY);
681
682 /* can_use_shield is a new flag. However, the can_use.. seems to largely come
683 * from the class, and not race. I don't see any way to get the class information
684 * to then update this. I don't think this will actually break anything - anyone
685 * that can use armour should be able to use a shield. What this may 'break'
686 * are features new characters get, eg, if someone starts up with a Q, they
687 * should be able to use a shield. However, old Q's won't get that advantage.
688 */
689 if (QUERY_FLAG(op, FLAG_USE_ARMOUR)) SET_FLAG(op, FLAG_USE_SHIELD);
690 return; 91 return;
92
93 INVOKE_PLAYER (SAVE, ob->contr);
94
95 object_freezer freezer;
96
97 int wiz = ob->flag [FLAG_WIZ];
98
99 /* Eneq(@csd.uu.se): If we have an open container hide it. */
100 container = ob->container;
101 ob->container = 0;
102
103 fprintf (freezer, "password %s\n", password);
104
105 if (own_title[0] != '\0')
106 fprintf (freezer, "title %s\n", own_title);
107
108 fprintf (freezer, "explore %d\n", explore);
109 fprintf (freezer, "gen_hp %d\n", gen_hp);
110 fprintf (freezer, "gen_sp %d\n", gen_sp);
111 fprintf (freezer, "gen_grace %d\n", gen_grace);
112 fprintf (freezer, "listening %d\n", listening);
113 fprintf (freezer, "shoottype %d\n", shoottype);
114 fprintf (freezer, "bowtype %d\n", bowtype);
115 fprintf (freezer, "petmode %d\n", petmode);
116 fprintf (freezer, "peaceful %d\n", peaceful);
117 fprintf (freezer, "digestion %d\n", digestion);
118 fprintf (freezer, "pickup %d\n", mode);
119 fprintf (freezer, "outputs_sync %d\n", outputs_sync);
120 fprintf (freezer, "outputs_count %d\n", outputs_count);
121 /* Match the enumerations but in string form */
122 fprintf (freezer, "usekeys %s\n", usekeys == key_inventory ? "key_inventory" : (usekeys == keyrings ? "keyrings" : "containers"));
123 /* Match the enumerations but in string form */
124 fprintf (freezer, "unapply %s\n", unapply == unapply_nochoice ? "unapply_nochoice" :
125 (unapply == unapply_never ? "unapply_never" : "unapply_always"));
126
127 if (ob->map)
128 fprintf (freezer, "map %s\n", &ob->map->path);
129
130 fprintf (freezer, "savebed_map %s\n", savebed_map);
131 fprintf (freezer, "bed_x %d\nbed_y %d\n", bed_x, bed_y);
132 fprintf (freezer, "weapon_sp %f\n", weapon_sp);
133 fprintf (freezer, "Str %d\n", orig_stats.Str);
134 fprintf (freezer, "Dex %d\n", orig_stats.Dex);
135 fprintf (freezer, "Con %d\n", orig_stats.Con);
136 fprintf (freezer, "Int %d\n", orig_stats.Int);
137 fprintf (freezer, "Pow %d\n", orig_stats.Pow);
138 fprintf (freezer, "Wis %d\n", orig_stats.Wis);
139 fprintf (freezer, "Cha %d\n", orig_stats.Cha);
140
141 fprintf (freezer, "lev_array %d\n", ob->level > 10 ? 10 : ob->level);
142
143 for (int i = 1; i <= last_level && i <= 10; i++)
144 {
145 fprintf (freezer, "%d\n", levhp[i]);
146 fprintf (freezer, "%d\n", levsp[i]);
147 fprintf (freezer, "%d\n", levgrace[i]);
148 }
149
150 freezer.put (ob->contr);
151
152 fprintf (freezer, "endplst\n");
153
154 SET_FLAG (ob, FLAG_NO_FIX_PLAYER);
155 CLEAR_FLAG (ob, FLAG_WIZ);
156 save_object (freezer, ob, 1); /* don't check and don't remove */
157
158 char filename[MAX_BUF];
159
160 sprintf (filename, "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, &ob->name, &ob->name);
161 make_path_to_file (filename);
162 freezer.save (filename);
163
164 CLEAR_FLAG (ob, FLAG_NO_FIX_PLAYER);
165
166 /* Eneq(@csd.uu.se): Reveal the container if we have one. */
167 ob->container = container;
168
169 ob->flag [FLAG_WIZ] = wiz;
170
171 enable_save = !final;
691} 172}
173
174player *
175player::load (const char *path)
176{
177 object_thawer thawer (path);
178
179 /* If no file, must be a new player, so lets get confirmation of
180 * the password. Return control to the higher level dispatch,
181 * since the rest of this just deals with loading of the file.
182 */
183 if (!thawer)
184 return 0;
185
186 player *pl = new player;
187
188 char buf[MAX_BUF], bufall[MAX_BUF];
189
190 pl->set_object (object::create ());
191 pl->last_save_time = time (0);
192
193 assign (pl->savebed_map, first_map_path);
194
195 /* Loop through the file, loading the rest of the values */
196 while (fgets (bufall, MAX_BUF, thawer))
197 {
198 int value;
199 sscanf (bufall, "%s %d\n", buf, &value);
200
201 if (!strcmp (buf, "endplst"))
202 break;
203 else if (!strcmp (buf, "oid"))
204 thawer.get (pl, value);
205 else if (!strcmp (buf, "password"))
206 sscanf (bufall, "password %[^\n]", pl->password);
207 else if (!strcmp (buf, "title"))
208 sscanf (bufall, "title %[^\n]", pl->own_title);
209 else if (!strcmp (buf, "explore"))
210 pl->explore = value;
211 else if (!strcmp (buf, "gen_hp"))
212 pl->gen_hp = value;
213 else if (!strcmp (buf, "shoottype"))
214 pl->shoottype = (rangetype) value;
215 else if (!strcmp (buf, "bowtype"))
216 pl->bowtype = (bowtype_t) value;
217 else if (!strcmp (buf, "petmode"))
218 pl->petmode = (petmode_t) value;
219 else if (!strcmp (buf, "gen_sp"))
220 pl->gen_sp = value;
221 else if (!strcmp (buf, "gen_grace"))
222 pl->gen_grace = value;
223 else if (!strcmp (buf, "listening"))
224 pl->listening = value;
225 else if (!strcmp (buf, "peaceful"))
226 pl->peaceful = value;
227 else if (!strcmp (buf, "digestion"))
228 pl->digestion = value;
229 else if (!strcmp (buf, "pickup"))
230 pl->mode = value;
231 else if (!strcmp (buf, "outputs_sync"))
232 pl->outputs_sync = value;
233 else if (!strcmp (buf, "outputs_count"))
234 pl->outputs_count = value;
235 else if (!strcmp (buf, "map"))
236 sscanf (bufall, "map %s", pl->maplevel);
237 else if (!strcmp (buf, "savebed_map"))
238 sscanf (bufall, "savebed_map %s", pl->savebed_map);
239 else if (!strcmp (buf, "bed_x"))
240 pl->bed_x = value;
241 else if (!strcmp (buf, "bed_y"))
242 pl->bed_y = value;
243 else if (!strcmp (buf, "weapon_sp"))
244 sscanf (buf, "weapon_sp %f", &pl->weapon_sp);
245 else if (!strcmp (buf, "Str"))
246 pl->orig_stats.Str = value;
247 else if (!strcmp (buf, "Dex"))
248 pl->orig_stats.Dex = value;
249 else if (!strcmp (buf, "Con"))
250 pl->orig_stats.Con = value;
251 else if (!strcmp (buf, "Int"))
252 pl->orig_stats.Int = value;
253 else if (!strcmp (buf, "Pow"))
254 pl->orig_stats.Pow = value;
255 else if (!strcmp (buf, "Wis"))
256 pl->orig_stats.Wis = value;
257 else if (!strcmp (buf, "Cha"))
258 pl->orig_stats.Cha = value;
259 else if (!strcmp (buf, "usekeys"))
260 {
261 if (!strcmp (bufall + 8, "key_inventory\n"))
262 pl->usekeys = key_inventory;
263 else if (!strcmp (bufall + 8, "keyrings\n"))
264 pl->usekeys = keyrings;
265 else if (!strcmp (bufall + 8, "containers\n"))
266 pl->usekeys = containers;
267 else
268 LOG (llevDebug, "load_player: got unknown usekeys type: %s\n", bufall + 8);
269 }
270 else if (!strcmp (buf, "unapply"))
271 {
272 if (!strcmp (bufall + 8, "unapply_nochoice\n"))
273 pl->unapply = unapply_nochoice;
274 else if (!strcmp (bufall + 8, "unapply_never\n"))
275 pl->unapply = unapply_never;
276 else if (!strcmp (bufall + 8, "unapply_always\n"))
277 pl->unapply = unapply_always;
278 else
279 LOG (llevDebug, "load_player: got unknown unapply type: %s\n", bufall + 8);
280 }
281 else if (!strcmp (buf, "lev_array"))
282 {
283 for (int i = 1; i <= value; i++)
284 {
285 char line[128];
286
287 fgets (line, 128, thawer);
288 pl->levhp[i] = atoi (line);
289 fgets (line, 128, thawer);
290 pl->levsp[i] = atoi (line);
291 fgets (line, 128, thawer);
292 pl->levgrace[i] = atoi (line);
293 }
294 /* spell_array code removed - don't know when that was last used.
295 * Even the load code below will someday be replaced by spells being
296 * objects.
297 */
298 }
299 else
300 LOG (llevDebug, "unparseable line in player file %s: %s\n", path, bufall);
301 }
302
303 /* this loads the standard objects values. */
304 load_object (thawer, pl->ob, 0);
305
306 pl->last_save_tick = pticks;
307
308 INVOKE_PLAYER (LOAD, pl, ARG_STRING (path));
309
310 return pl;
311}
312

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines