ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/login.c
Revision: 1.4
Committed: Sun Aug 13 17:16:04 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +0 -0 lines
State: FILE REMOVED
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# Content
1 /*
2 * static char *rcsid_login_c =
3 * "$Id$";
4 */
5
6 /*
7 CrossFire, A Multiplayer game for X-windows
8
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28
29 #include <global.h>
30 #ifndef __CEXTRACT__
31 #include <sproto.h>
32 #endif
33 #include <spells.h>
34 #include <loader.h>
35 #include <define.h>
36
37 extern void sub_weight (object *, signed long);
38 extern void add_weight (object *, signed long);
39 extern 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 */
44 void 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
89 /* Delete character with name. if new is set, also delete the new
90 * style directory, otherwise, just delete the old style playfile
91 * (needed for transition)
92 */
93 void delete_character(const char *name, int new) {
94 char buf[MAX_BUF];
95
96 sprintf(buf,"%s/%s/%s.pl",settings.localdir,settings.playerdir,name);
97 if(unlink(buf)== -1)
98 LOG(llevDebug, "Cannot delete character file %s: %s\n", buf, strerror_local(errno));
99 if (new) {
100 sprintf(buf,"%s/%s/%s",settings.localdir,settings.playerdir,name);
101 /* this effectively does an rm -rf on the directory */
102 remove_directory(buf);
103 }
104 }
105
106 /* This verify that a character of name exits, and that it matches
107 * password. It return 0 if there is match, 1 if no such player,
108 * 2 if incorrect password.
109 */
110
111 int 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
163 int 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
189 int create_savedir_if_needed(char *savedir)
190 {
191 struct stat *buf;
192
193 if ((buf = (struct stat *) malloc(sizeof(struct stat))) == NULL) {
194 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
209 void 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
227 int save_player(object *op, int flag) {
228 FILE *fp;
229 char filename[MAX_BUF], *tmpfilename,backupfile[MAX_BUF];
230 object *tmp, *container=NULL;
231 player *pl = op->contr;
232 int i,wiz=QUERY_FLAG(op,FLAG_WIZ);
233 long checksum;
234 #ifdef BACKUP_SAVE_AT_HOME
235 sint16 backup_x, backup_y;
236 #endif
237
238 if (!op->stats.exp) return 0; /* no experience, no save */
239
240 flag&=1;
241
242 if(!pl->name_changed||(!flag&&!op->stats.exp)) {
243 if(!flag) {
244 new_draw_info(NDI_UNIQUE, 0,op,"Your game is not valid,");
245 new_draw_info(NDI_UNIQUE, 0,op,"Game not saved.");
246 }
247 return 0;
248 }
249
250 /* Sanity check - some stuff changes this when player is exiting */
251 if (op->type != PLAYER) return 0;
252
253 /* Prevent accidental saves if connection is reset after player has
254 * mostly exited.
255 */
256 if (pl->state != ST_PLAYING && pl->state != ST_GET_PARTY_PASSWORD)
257 return 0;
258
259 if (flag == 0)
260 terminate_all_pets(op);
261
262 /* Delete old style file */
263 sprintf(filename,"%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name);
264 unlink(filename);
265
266 sprintf(filename,"%s/%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name,op->name);
267 make_path_to_file(filename);
268 tmpfilename = tempnam_local(settings.tmpdir,NULL);
269 fp=fopen(tmpfilename, "w");
270 if(!fp) {
271 new_draw_info(NDI_UNIQUE, 0,op, "Can't open file for save.");
272 LOG(llevDebug,"Can't open file for save (%s).\n",tmpfilename);
273 free(tmpfilename);
274 return 0;
275 }
276
277 /* Eneq(@csd.uu.se): If we have an open container hide it. */
278 if (op->container) {
279 container=op->container;
280 op->container=NULL;
281 }
282
283 execute_global_event (EVENT_PLAYER_SAVE, op, filename);
284
285 fprintf(fp,"password %s\n",pl->password);
286 if (settings.set_title == TRUE)
287 if(pl->own_title[0]!='\0')
288 fprintf(fp,"title %s\n",pl->own_title);
289
290 fprintf(fp,"explore %d\n",pl->explore);
291 fprintf(fp,"gen_hp %d\n",pl->gen_hp);
292 fprintf(fp,"gen_sp %d\n",pl->gen_sp);
293 fprintf(fp,"gen_grace %d\n",pl->gen_grace);
294 fprintf(fp,"listening %d\n",pl->listening);
295 fprintf(fp,"shoottype %d\n",pl->shoottype);
296 fprintf(fp,"bowtype %d\n",pl->bowtype);
297 fprintf(fp,"petmode %d\n",pl->petmode);
298 fprintf(fp,"peaceful %d\n",pl->peaceful);
299 fprintf(fp,"no_shout %d\n",pl->no_shout);
300 fprintf(fp,"digestion %d\n",pl->digestion);
301 fprintf(fp,"pickup %d\n", pl->mode);
302 fprintf(fp,"outputs_sync %d\n", pl->outputs_sync);
303 fprintf(fp,"outputs_count %d\n", pl->outputs_count);
304 /* Match the enumerations but in string form */
305 fprintf(fp,"usekeys %s\n", pl->usekeys==key_inventory?"key_inventory":
306 (pl->usekeys==keyrings?"keyrings":"containers"));
307 /* Match the enumerations but in string form */
308 fprintf(fp,"unapply %s\n", pl->unapply==unapply_nochoice?"unapply_nochoice":
309 (pl->unapply==unapply_never?"unapply_never":"unapply_always"));
310
311
312
313 #ifdef BACKUP_SAVE_AT_HOME
314 if (op->map!=NULL && flag==0)
315 #else
316 if (op->map!=NULL)
317 #endif
318 fprintf(fp,"map %s\n",op->map->path);
319 else
320 fprintf(fp,"map %s\n",settings.emergency_mapname);
321
322 fprintf(fp,"savebed_map %s\n", pl->savebed_map);
323 fprintf(fp,"bed_x %d\nbed_y %d\n", pl->bed_x, pl->bed_y);
324 fprintf(fp,"weapon_sp %f\n",pl->weapon_sp);
325 fprintf(fp,"Str %d\n",pl->orig_stats.Str);
326 fprintf(fp,"Dex %d\n",pl->orig_stats.Dex);
327 fprintf(fp,"Con %d\n",pl->orig_stats.Con);
328 fprintf(fp,"Int %d\n",pl->orig_stats.Int);
329 fprintf(fp,"Pow %d\n",pl->orig_stats.Pow);
330 fprintf(fp,"Wis %d\n",pl->orig_stats.Wis);
331 fprintf(fp,"Cha %d\n",pl->orig_stats.Cha);
332
333 fprintf(fp,"lev_array %d\n",op->level>10?10:op->level);
334 for(i=1;i<=pl->last_level&&i<=10;i++) {
335 fprintf(fp,"%d\n",pl->levhp[i]);
336 fprintf(fp,"%d\n",pl->levsp[i]);
337 fprintf(fp,"%d\n",pl->levgrace[i]);
338 }
339 fprintf(fp,"endplst\n");
340
341 SET_FLAG(op, FLAG_NO_FIX_PLAYER);
342 CLEAR_FLAG(op, FLAG_WIZ);
343 #ifdef BACKUP_SAVE_AT_HOME
344 if (flag) {
345 backup_x = op->x;
346 backup_y = op->y;
347 op->x = -1;
348 op->y = -1;
349 }
350 /* Save objects, but not unpaid objects. Don't remove objects from
351 * inventory.
352 */
353 save_object(fp, op, 2);
354 if (flag) {
355 op->x = backup_x;
356 op->y = backup_y;
357 }
358 #else
359 save_object(fp, op, 3); /* don't check and don't remove */
360 #endif
361
362 CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER);
363
364 if(!flag)
365 while ((tmp = op->inv))
366 destroy_object (tmp);
367
368 if (fclose(fp) == EOF) { /* make sure the write succeeded */
369 new_draw_info(NDI_UNIQUE, 0,op, "Can't save character.");
370 unlink(tmpfilename);
371 free(tmpfilename);
372 return 0;
373 }
374
375 checksum = 0;
376 sprintf(backupfile, "%s.tmp", filename);
377 rename(filename, backupfile);
378 fp = fopen(filename,"w");
379 if(!fp) {
380 new_draw_info(NDI_UNIQUE, 0,op, "Can't open file for save.");
381 unlink(tmpfilename);
382 free(tmpfilename);
383 return 0;
384 }
385 fprintf(fp,"checksum %lx\n",checksum);
386 copy_file(tmpfilename, fp);
387 unlink(tmpfilename);
388 free(tmpfilename);
389 if (fclose(fp) == EOF) { /* got write error */
390 new_draw_info(NDI_UNIQUE, 0,op, "Can't close file for save.");
391 rename(backupfile, filename); /* Restore the original */
392 return 0;
393 }
394 else
395 unlink(backupfile);
396
397 /* Eneq(@csd.uu.se): Reveal the container if we have one. */
398 if (flag&&container!=NULL)
399 op->container = container;
400
401 if (wiz) SET_FLAG(op,FLAG_WIZ);
402 if(!flag)
403 esrv_send_inventory(op, op);
404
405 chmod(filename,SAVE_MODE);
406
407 return 1;
408 }
409
410 void copy_file(const char *filename, FILE *fpout) {
411 FILE *fp;
412 char buf[MAX_BUF];
413 if((fp = fopen(filename,"r")) == NULL)
414 return;
415 while(fgets(buf,MAX_BUF,fp)!=NULL)
416 fputs(buf,fpout);
417 fclose(fp);
418 }
419
420
421 void check_login(object *op) {
422 FILE *fp;
423 char filename[MAX_BUF];
424 char buf[MAX_BUF],bufall[MAX_BUF];
425 int i,value,comp;
426 long checksum = 0;
427 player *pl = op->contr;
428 int correct = 0;
429 time_t elapsed_save_time=0;
430 struct stat statbuf;
431
432 strcpy (pl->maplevel,first_map_path);
433
434 /* First, lets check for newest form of save */
435 sprintf(filename,"%s/%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name,op->name);
436 if (access(filename, F_OK)==-1) {
437 /* not there, Try the old style */
438
439 sprintf(filename,"%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name);
440 /* Ok - old style exists. Lets make the new style directory */
441 if (access(filename, F_OK)==0) {
442 sprintf(buf,"%s/%s/%s",settings.localdir,settings.playerdir,op->name);
443 make_path_to_file(buf);
444 }
445 }
446
447 /* If no file, must be a new player, so lets get confirmation of
448 * the password. Return control to the higher level dispatch,
449 * since the rest of this just deals with loading of the file.
450 */
451 if ((fp=open_and_uncompress(filename,1,&comp)) == NULL) {
452 confirm_password(op);
453 return;
454 }
455 if (fstat(fileno(fp), &statbuf)) {
456 LOG(llevError,"Unable to stat %s?\n", filename);
457 elapsed_save_time=0;
458 } else {
459 elapsed_save_time = time(NULL) - statbuf.st_mtime;
460 if (elapsed_save_time<0) {
461 LOG(llevError,"Player file %s was saved in the future? (%d time)\n", filename, elapsed_save_time);
462 elapsed_save_time=0;
463 }
464 }
465
466 if(fgets(bufall,MAX_BUF,fp) != NULL) {
467 if(!strncmp(bufall,"checksum ",9)) {
468 checksum = strtol_local(bufall+9,(char **) NULL, 16);
469 (void) fgets(bufall,MAX_BUF,fp);
470 }
471 if(sscanf(bufall,"password %s\n",buf)) {
472 /* New password scheme: */
473 correct=check_password(pl->write_buf+1,buf);
474 }
475 /* Old password mode removed - I have no idea what it
476 * was, and the current password mechanism has been used
477 * for at least several years.
478 */
479 }
480 if (!correct) {
481 new_draw_info(NDI_UNIQUE, 0,op," ");
482 new_draw_info(NDI_UNIQUE, 0,op,"Wrong Password!");
483 new_draw_info(NDI_UNIQUE, 0,op," ");
484 FREE_AND_COPY(op->name, "noname");
485 FREE_AND_COPY(op->name_pl, "noname");
486 op->contr->socket.password_fails++;
487 if (op->contr->socket.password_fails >= MAX_PASSWORD_FAILURES) {
488 new_draw_info(NDI_UNIQUE, 0,op,
489 "You gave an incorrect password too many times, you will now be dropped from the server.");
490 LOG(llevInfo, "A player connecting from %s has been dropped for password failure\n",
491 op->contr->socket.host);
492 op->contr->socket.status = Ns_Dead; /* the socket loop should handle the rest for us */
493 }
494 else get_name(op);
495 return; /* Once again, rest of code just loads the char */
496 }
497
498 #ifdef SAVE_INTERVAL
499 pl->last_save_time=time(NULL);
500 #endif /* SAVE_INTERVAL */
501 pl->party = NULL;
502 if (settings.search_items == TRUE)
503 pl->search_str[0]='\0';
504 pl->name_changed=1;
505 pl->orig_stats.Str=0;
506 pl->orig_stats.Dex=0;
507 pl->orig_stats.Con=0;
508 pl->orig_stats.Int=0;
509 pl->orig_stats.Pow=0;
510 pl->orig_stats.Wis=0;
511 pl->orig_stats.Cha=0;
512 strcpy(pl->savebed_map, first_map_path);
513 pl->bed_x=0, pl->bed_y=0;
514 pl->spellparam[0] = '\0';
515
516 /* Loop through the file, loading the rest of the values */
517 while (fgets(bufall,MAX_BUF,fp)!=NULL) {
518 sscanf(bufall,"%s %d\n",buf,&value);
519 if (!strcmp(buf,"endplst"))
520 break;
521 else if (!strcmp(buf,"title") && settings.set_title == TRUE)
522 sscanf(bufall,"title %[^\n]",pl->own_title);
523 else if (!strcmp(buf,"explore"))
524 pl->explore = value;
525 else if (!strcmp(buf,"gen_hp"))
526 pl->gen_hp=value;
527 else if (!strcmp(buf,"shoottype"))
528 pl->shoottype=(rangetype)value;
529 else if (!strcmp(buf,"bowtype"))
530 pl->bowtype=(bowtype_t)value;
531 else if (!strcmp(buf,"petmode"))
532 pl->petmode=(petmode_t)value;
533 else if (!strcmp(buf,"gen_sp"))
534 pl->gen_sp=value;
535 else if (!strcmp(buf,"gen_grace"))
536 pl->gen_grace=value;
537 else if (!strcmp(buf,"listening"))
538 pl->listening=value;
539 else if (!strcmp(buf,"peaceful"))
540 pl->peaceful=value;
541 else if (!strcmp(buf,"no_shout"))
542 pl->no_shout=value;
543 else if (!strcmp(buf,"digestion"))
544 pl->digestion=value;
545 else if (!strcmp(buf,"pickup"))
546 pl->mode=value;
547 else if (!strcmp(buf,"outputs_sync"))
548 pl->outputs_sync = value;
549 else if (!strcmp(buf,"outputs_count"))
550 pl->outputs_count = value;
551 else if (!strcmp(buf,"map"))
552 sscanf(bufall,"map %s", pl->maplevel);
553 else if (!strcmp(buf,"savebed_map"))
554 sscanf(bufall,"savebed_map %s", pl->savebed_map);
555 else if (!strcmp(buf,"bed_x"))
556 pl->bed_x=value;
557 else if (!strcmp(buf,"bed_y"))
558 pl->bed_y=value;
559 else if (!strcmp(buf,"weapon_sp"))
560 sscanf(buf,"weapon_sp %f",&pl->weapon_sp);
561 else if (!strcmp(buf,"Str"))
562 pl->orig_stats.Str=value;
563 else if (!strcmp(buf,"Dex"))
564 pl->orig_stats.Dex=value;
565 else if (!strcmp(buf,"Con"))
566 pl->orig_stats.Con=value;
567 else if (!strcmp(buf,"Int"))
568 pl->orig_stats.Int=value;
569 else if (!strcmp(buf,"Pow"))
570 pl->orig_stats.Pow=value;
571 else if (!strcmp(buf,"Wis"))
572 pl->orig_stats.Wis=value;
573 else if (!strcmp(buf,"Cha"))
574 pl->orig_stats.Cha=value;
575 else if (!strcmp(buf,"usekeys")) {
576 if (!strcmp(bufall+8,"key_inventory\n"))
577 pl->usekeys=key_inventory;
578 else if (!strcmp(bufall+8,"keyrings\n"))
579 pl->usekeys=keyrings;
580 else if (!strcmp(bufall+8,"containers\n"))
581 pl->usekeys=containers;
582 else LOG(llevDebug,"load_player: got unknown usekeys type: %s\n", bufall+8);
583 }
584 else if (!strcmp(buf,"unapply")) {
585 if (!strcmp(bufall+8,"unapply_nochoice\n"))
586 pl->unapply=unapply_nochoice;
587 else if (!strcmp(bufall+8,"unapply_never\n"))
588 pl->unapply=unapply_never;
589 else if (!strcmp(bufall+8,"unapply_always\n"))
590 pl->unapply=unapply_always;
591 else LOG(llevDebug,"load_player: got unknown unapply type: %s\n", bufall+8);
592 }
593 else if (!strcmp(buf,"lev_array")){
594 for(i=1;i<=value;i++) {
595 int j;
596 fscanf(fp,"%d\n",&j);
597 pl->levhp[i]=j;
598 fscanf(fp,"%d\n",&j);
599 pl->levsp[i]=j;
600 fscanf(fp,"%d\n",&j);
601 pl->levgrace[i]=j;
602 }
603 /* spell_array code removed - don't know when that was last used.
604 * Even the load code below will someday be replaced by spells being
605 * objects.
606 */
607 } else if (!strcmp(buf,"known_spell")) {
608 #if 0
609 /* Logic is left here in case someone wants to try
610 * and write code to update to spell objects.
611 */
612 char *cp=strchr(bufall,'\n');
613 *cp='\0';
614 cp=strchr(bufall,' ');
615 cp++;
616 for(i=0;i<NROFREALSPELLS;i++)
617 if(!strcmp(spells[i].name,cp)) {
618 pl->known_spells[pl->nrofknownspells++]=i;
619 break;
620 }
621 if(i==NROFREALSPELLS)
622 LOG(llevDebug, "Error: unknown spell (%s)\n",cp);
623 #endif
624 }
625 } /* End of loop loading the character file */
626 leave_map(op);
627 op->speed=0;
628 update_ob_speed(op);
629 reset_object(op);
630 op->contr = pl;
631 pl->ob = op;
632 /* this loads the standard objects values. */
633 load_object(fp, op, LO_NEWFILE,0);
634 close_and_delete(fp, comp);
635
636 CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER);
637
638 strncpy(pl->title, op->arch->clone.name, sizeof(pl->title)-1);
639 pl->title[sizeof(pl->title)-1] = '\0';
640
641 /* If the map where the person was last saved does not exist,
642 * restart them on their home-savebed. This is good for when
643 * maps change between versions
644 * First, we check for partial path, then check to see if the full
645 * path (for unique player maps)
646 */
647 if (check_path(pl->maplevel,1)==-1) {
648 if (check_path(pl->maplevel,0)==-1) {
649 strcpy(pl->maplevel, pl->savebed_map);
650 op->x = pl->bed_x, op->y = pl->bed_y;
651 }
652 }
653
654 /* If player saved beyond some time ago, and the feature is
655 * enabled, put the player back on his savebed map.
656 */
657 if ((settings.reset_loc_time >0) && (elapsed_save_time > settings.reset_loc_time)) {
658 strcpy(pl->maplevel, pl->savebed_map);
659 op->x = pl->bed_x, op->y = pl->bed_y;
660 }
661
662 /* make sure he's a player--needed because of class change. */
663 op->type = PLAYER;
664
665 enter_exit(op,NULL);
666
667 pl->name_changed=1;
668 pl->state = ST_PLAYING;
669 #ifdef AUTOSAVE
670 pl->last_save_tick = pticks;
671 #endif
672 op->carrying = sum_weight (op);
673 /* Need to call fix_player now - program modified so that it is not
674 * called during the load process (FLAG_NO_FIX_PLAYER set when
675 * saved)
676 * Moved ahead of the esrv functions, so proper weights will be
677 * sent to the client.
678 */
679 link_player_skills(op);
680
681 if ( ! legal_range (op, op->contr->shoottype))
682 op->contr->shoottype = range_none;
683
684 fix_player (op);
685
686 /* if it's a dragon player, set the correct title here */
687 if (is_dragon_pl(op) && op->inv != NULL) {
688 object *tmp, *abil=NULL, *skin=NULL;
689 for (tmp=op->inv; tmp!=NULL; tmp=tmp->below) {
690 if (tmp->type == FORCE) {
691 if (strcmp(tmp->arch->name, "dragon_ability_force")==0)
692 abil = tmp;
693 else if (strcmp(tmp->arch->name, "dragon_skin_force")==0)
694 skin = tmp;
695 }
696 }
697 set_dragon_name(op, abil, skin);
698 }
699
700 new_draw_info(NDI_UNIQUE, 0,op,"Welcome Back!");
701 new_draw_info_format(NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL,
702 "%s has entered the game.",pl->ob->name);
703
704 execute_global_event (EVENT_PLAYER_LOAD, op, filename);
705
706 /* Lauwenmark : Here we handle the LOGIN global event */
707 execute_global_event(EVENT_LOGIN, pl, pl->socket.host);
708 op->contr->socket.update_look=1;
709 /* If the player should be dead, call kill_player for them
710 * Only check for hp - if player lacks food, let the normal
711 * logic for that to take place. If player is permanently
712 * dead, and not using permadeath mode, the kill_player will
713 * set the play_again flag, so return.
714 */
715 if (op->stats.hp<0) {
716 new_draw_info(NDI_UNIQUE, 0,op,"Your character was dead last your played.");
717 kill_player(op);
718 if (pl->state != ST_PLAYING) return;
719 }
720 LOG(llevInfo,"LOGIN: Player named %s from ip %s\n", op->name,
721 op->contr->socket.host);
722
723 /* Do this after checking for death - no reason sucking up bandwidth if
724 * the data isn't needed.
725 */
726 esrv_new_player(op->contr,op->weight+op->carrying);
727 esrv_send_inventory(op, op);
728 esrv_add_spells(op->contr, NULL);
729
730 CLEAR_FLAG(op, FLAG_FRIENDLY);
731
732 /* can_use_shield is a new flag. However, the can_use.. seems to largely come
733 * from the class, and not race. I don't see any way to get the class information
734 * to then update this. I don't think this will actually break anything - anyone
735 * that can use armour should be able to use a shield. What this may 'break'
736 * are features new characters get, eg, if someone starts up with a Q, they
737 * should be able to use a shield. However, old Q's won't get that advantage.
738 */
739 if (QUERY_FLAG(op, FLAG_USE_ARMOUR)) SET_FLAG(op, FLAG_USE_SHIELD);
740 return;
741 }