ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/login.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:14:32 2006 UTC (18 years, 3 months ago) by root
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15, UPSTREAM_2006_02_22, UPSTREAM_2006_02_03
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

# User Rev Content
1 root 1.1 /*
2     * static char *rcsid_login_c =
3     * "$Id: login.c,v 1.58 2006/01/30 17:00:34 cavesomething Exp $";
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     fprintf(fp,"password %s\n",pl->password);
284     if (settings.set_title == TRUE)
285     if(pl->own_title[0]!='\0')
286     fprintf(fp,"title %s\n",pl->own_title);
287    
288     fprintf(fp,"explore %d\n",pl->explore);
289     fprintf(fp,"gen_hp %d\n",pl->gen_hp);
290     fprintf(fp,"gen_sp %d\n",pl->gen_sp);
291     fprintf(fp,"gen_grace %d\n",pl->gen_grace);
292     fprintf(fp,"listening %d\n",pl->listening);
293     fprintf(fp,"shoottype %d\n",pl->shoottype);
294     fprintf(fp,"bowtype %d\n",pl->bowtype);
295     fprintf(fp,"petmode %d\n",pl->petmode);
296     fprintf(fp,"peaceful %d\n",pl->peaceful);
297     fprintf(fp,"no_shout %d\n",pl->no_shout);
298     fprintf(fp,"digestion %d\n",pl->digestion);
299     fprintf(fp,"pickup %d\n", pl->mode);
300     fprintf(fp,"outputs_sync %d\n", pl->outputs_sync);
301     fprintf(fp,"outputs_count %d\n", pl->outputs_count);
302     /* Match the enumerations but in string form */
303     fprintf(fp,"usekeys %s\n", pl->usekeys==key_inventory?"key_inventory":
304     (pl->usekeys==keyrings?"keyrings":"containers"));
305     /* Match the enumerations but in string form */
306     fprintf(fp,"unapply %s\n", pl->unapply==unapply_nochoice?"unapply_nochoice":
307     (pl->unapply==unapply_never?"unapply_never":"unapply_always"));
308    
309    
310    
311     #ifdef BACKUP_SAVE_AT_HOME
312     if (op->map!=NULL && flag==0)
313     #else
314     if (op->map!=NULL)
315     #endif
316     fprintf(fp,"map %s\n",op->map->path);
317     else
318     fprintf(fp,"map %s\n",settings.emergency_mapname);
319    
320     fprintf(fp,"savebed_map %s\n", pl->savebed_map);
321     fprintf(fp,"bed_x %d\nbed_y %d\n", pl->bed_x, pl->bed_y);
322     fprintf(fp,"weapon_sp %f\n",pl->weapon_sp);
323     fprintf(fp,"Str %d\n",pl->orig_stats.Str);
324     fprintf(fp,"Dex %d\n",pl->orig_stats.Dex);
325     fprintf(fp,"Con %d\n",pl->orig_stats.Con);
326     fprintf(fp,"Int %d\n",pl->orig_stats.Int);
327     fprintf(fp,"Pow %d\n",pl->orig_stats.Pow);
328     fprintf(fp,"Wis %d\n",pl->orig_stats.Wis);
329     fprintf(fp,"Cha %d\n",pl->orig_stats.Cha);
330    
331     fprintf(fp,"lev_array %d\n",op->level>10?10:op->level);
332     for(i=1;i<=pl->last_level&&i<=10;i++) {
333     fprintf(fp,"%d\n",pl->levhp[i]);
334     fprintf(fp,"%d\n",pl->levsp[i]);
335     fprintf(fp,"%d\n",pl->levgrace[i]);
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     if (fclose(fp) == EOF) { /* make sure the write succeeded */
367     new_draw_info(NDI_UNIQUE, 0,op, "Can't save character.");
368     unlink(tmpfilename);
369     free(tmpfilename);
370     return 0;
371     }
372     checksum = 0;
373     sprintf(backupfile, "%s.tmp", filename);
374     rename(filename, backupfile);
375     fp = fopen(filename,"w");
376     if(!fp) {
377     new_draw_info(NDI_UNIQUE, 0,op, "Can't open file for save.");
378     unlink(tmpfilename);
379     free(tmpfilename);
380     return 0;
381     }
382     fprintf(fp,"checksum %lx\n",checksum);
383     copy_file(tmpfilename, fp);
384     unlink(tmpfilename);
385     free(tmpfilename);
386     if (fclose(fp) == EOF) { /* got write error */
387     new_draw_info(NDI_UNIQUE, 0,op, "Can't close file for save.");
388     rename(backupfile, filename); /* Restore the original */
389     return 0;
390     }
391     else
392     unlink(backupfile);
393    
394     /* Eneq(@csd.uu.se): Reveal the container if we have one. */
395     if (flag&&container!=NULL)
396     op->container = container;
397    
398     if (wiz) SET_FLAG(op,FLAG_WIZ);
399     if(!flag)
400     esrv_send_inventory(op, op);
401    
402     chmod(filename,SAVE_MODE);
403     return 1;
404     }
405    
406     void copy_file(const char *filename, FILE *fpout) {
407     FILE *fp;
408     char buf[MAX_BUF];
409     if((fp = fopen(filename,"r")) == NULL)
410     return;
411     while(fgets(buf,MAX_BUF,fp)!=NULL)
412     fputs(buf,fpout);
413     fclose(fp);
414     }
415    
416    
417     void check_login(object *op) {
418     FILE *fp;
419     char filename[MAX_BUF];
420     char buf[MAX_BUF],bufall[MAX_BUF];
421     int i,value,comp;
422     long checksum = 0;
423     player *pl = op->contr;
424     int correct = 0;
425     time_t elapsed_save_time=0;
426     struct stat statbuf;
427    
428     strcpy (pl->maplevel,first_map_path);
429    
430     /* First, lets check for newest form of save */
431     sprintf(filename,"%s/%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name,op->name);
432     if (access(filename, F_OK)==-1) {
433     /* not there, Try the old style */
434    
435     sprintf(filename,"%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name);
436     /* Ok - old style exists. Lets make the new style directory */
437     if (access(filename, F_OK)==0) {
438     sprintf(buf,"%s/%s/%s",settings.localdir,settings.playerdir,op->name);
439     make_path_to_file(buf);
440     }
441     }
442    
443     /* If no file, must be a new player, so lets get confirmation of
444     * the password. Return control to the higher level dispatch,
445     * since the rest of this just deals with loading of the file.
446     */
447     if ((fp=open_and_uncompress(filename,1,&comp)) == NULL) {
448     confirm_password(op);
449     return;
450     }
451     if (fstat(fileno(fp), &statbuf)) {
452     LOG(llevError,"Unable to stat %s?\n", filename);
453     elapsed_save_time=0;
454     } else {
455     elapsed_save_time = time(NULL) - statbuf.st_mtime;
456     if (elapsed_save_time<0) {
457     LOG(llevError,"Player file %s was saved in the future? (%d time)\n", filename, elapsed_save_time);
458     elapsed_save_time=0;
459     }
460     }
461    
462     if(fgets(bufall,MAX_BUF,fp) != NULL) {
463     if(!strncmp(bufall,"checksum ",9)) {
464     checksum = strtol_local(bufall+9,(char **) NULL, 16);
465     (void) fgets(bufall,MAX_BUF,fp);
466     }
467     if(sscanf(bufall,"password %s\n",buf)) {
468     /* New password scheme: */
469     correct=check_password(pl->write_buf+1,buf);
470     }
471     /* Old password mode removed - I have no idea what it
472     * was, and the current password mechanism has been used
473     * for at least several years.
474     */
475     }
476     if (!correct) {
477     new_draw_info(NDI_UNIQUE, 0,op," ");
478     new_draw_info(NDI_UNIQUE, 0,op,"Wrong Password!");
479     new_draw_info(NDI_UNIQUE, 0,op," ");
480     FREE_AND_COPY(op->name, "noname");
481     FREE_AND_COPY(op->name_pl, "noname");
482     op->contr->socket.password_fails++;
483     if (op->contr->socket.password_fails >= MAX_PASSWORD_FAILURES) {
484     new_draw_info(NDI_UNIQUE, 0,op,
485     "You gave an incorrect password too many times, you will now be dropped from the server.");
486     LOG(llevInfo, "A player connecting from %s has been dropped for password failure\n",
487     op->contr->socket.host);
488     op->contr->socket.status = Ns_Dead; /* the socket loop should handle the rest for us */
489     }
490     else get_name(op);
491     return; /* Once again, rest of code just loads the char */
492     }
493    
494     #ifdef SAVE_INTERVAL
495     pl->last_save_time=time(NULL);
496     #endif /* SAVE_INTERVAL */
497     pl->party = NULL;
498     if (settings.search_items == TRUE)
499     pl->search_str[0]='\0';
500     pl->name_changed=1;
501     pl->orig_stats.Str=0;
502     pl->orig_stats.Dex=0;
503     pl->orig_stats.Con=0;
504     pl->orig_stats.Int=0;
505     pl->orig_stats.Pow=0;
506     pl->orig_stats.Wis=0;
507     pl->orig_stats.Cha=0;
508     strcpy(pl->savebed_map, first_map_path);
509     pl->bed_x=0, pl->bed_y=0;
510     pl->spellparam[0] = '\0';
511    
512     /* Loop through the file, loading the rest of the values */
513     while (fgets(bufall,MAX_BUF,fp)!=NULL) {
514     sscanf(bufall,"%s %d\n",buf,&value);
515     if (!strcmp(buf,"endplst"))
516     break;
517     else if (!strcmp(buf,"title") && settings.set_title == TRUE)
518     sscanf(bufall,"title %[^\n]",pl->own_title);
519     else if (!strcmp(buf,"explore"))
520     pl->explore = value;
521     else if (!strcmp(buf,"gen_hp"))
522     pl->gen_hp=value;
523     else if (!strcmp(buf,"shoottype"))
524     pl->shoottype=(rangetype)value;
525     else if (!strcmp(buf,"bowtype"))
526     pl->bowtype=(bowtype_t)value;
527     else if (!strcmp(buf,"petmode"))
528     pl->petmode=(petmode_t)value;
529     else if (!strcmp(buf,"gen_sp"))
530     pl->gen_sp=value;
531     else if (!strcmp(buf,"gen_grace"))
532     pl->gen_grace=value;
533     else if (!strcmp(buf,"listening"))
534     pl->listening=value;
535     else if (!strcmp(buf,"peaceful"))
536     pl->peaceful=value;
537     else if (!strcmp(buf,"no_shout"))
538     pl->no_shout=value;
539     else if (!strcmp(buf,"digestion"))
540     pl->digestion=value;
541     else if (!strcmp(buf,"pickup"))
542     pl->mode=value;
543     else if (!strcmp(buf,"outputs_sync"))
544     pl->outputs_sync = value;
545     else if (!strcmp(buf,"outputs_count"))
546     pl->outputs_count = value;
547     else if (!strcmp(buf,"map"))
548     sscanf(bufall,"map %s", pl->maplevel);
549     else if (!strcmp(buf,"savebed_map"))
550     sscanf(bufall,"savebed_map %s", pl->savebed_map);
551     else if (!strcmp(buf,"bed_x"))
552     pl->bed_x=value;
553     else if (!strcmp(buf,"bed_y"))
554     pl->bed_y=value;
555     else if (!strcmp(buf,"weapon_sp"))
556     sscanf(buf,"weapon_sp %f",&pl->weapon_sp);
557     else if (!strcmp(buf,"Str"))
558     pl->orig_stats.Str=value;
559     else if (!strcmp(buf,"Dex"))
560     pl->orig_stats.Dex=value;
561     else if (!strcmp(buf,"Con"))
562     pl->orig_stats.Con=value;
563     else if (!strcmp(buf,"Int"))
564     pl->orig_stats.Int=value;
565     else if (!strcmp(buf,"Pow"))
566     pl->orig_stats.Pow=value;
567     else if (!strcmp(buf,"Wis"))
568     pl->orig_stats.Wis=value;
569     else if (!strcmp(buf,"Cha"))
570     pl->orig_stats.Cha=value;
571     else if (!strcmp(buf,"usekeys")) {
572     if (!strcmp(bufall+8,"key_inventory\n"))
573     pl->usekeys=key_inventory;
574     else if (!strcmp(bufall+8,"keyrings\n"))
575     pl->usekeys=keyrings;
576     else if (!strcmp(bufall+8,"containers\n"))
577     pl->usekeys=containers;
578     else LOG(llevDebug,"load_player: got unknown usekeys type: %s\n", bufall+8);
579     }
580     else if (!strcmp(buf,"unapply")) {
581     if (!strcmp(bufall+8,"unapply_nochoice\n"))
582     pl->unapply=unapply_nochoice;
583     else if (!strcmp(bufall+8,"unapply_never\n"))
584     pl->unapply=unapply_never;
585     else if (!strcmp(bufall+8,"unapply_always\n"))
586     pl->unapply=unapply_always;
587     else LOG(llevDebug,"load_player: got unknown unapply type: %s\n", bufall+8);
588     }
589     else if (!strcmp(buf,"lev_array")){
590     for(i=1;i<=value;i++) {
591     int j;
592     fscanf(fp,"%d\n",&j);
593     pl->levhp[i]=j;
594     fscanf(fp,"%d\n",&j);
595     pl->levsp[i]=j;
596     fscanf(fp,"%d\n",&j);
597     pl->levgrace[i]=j;
598     }
599     /* spell_array code removed - don't know when that was last used.
600     * Even the load code below will someday be replaced by spells being
601     * objects.
602     */
603     } else if (!strcmp(buf,"known_spell")) {
604     #if 0
605     /* Logic is left here in case someone wants to try
606     * and write code to update to spell objects.
607     */
608     char *cp=strchr(bufall,'\n');
609     *cp='\0';
610     cp=strchr(bufall,' ');
611     cp++;
612     for(i=0;i<NROFREALSPELLS;i++)
613     if(!strcmp(spells[i].name,cp)) {
614     pl->known_spells[pl->nrofknownspells++]=i;
615     break;
616     }
617     if(i==NROFREALSPELLS)
618     LOG(llevDebug, "Error: unknown spell (%s)\n",cp);
619     #endif
620     }
621     } /* End of loop loading the character file */
622     leave_map(op);
623     op->speed=0;
624     update_ob_speed(op);
625     reset_object(op);
626     op->contr = pl;
627     pl->ob = op;
628     /* this loads the standard objects values. */
629     load_object(fp, op, LO_NEWFILE,0);
630     close_and_delete(fp, comp);
631    
632     CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER);
633    
634     strncpy(pl->title, op->arch->clone.name, sizeof(pl->title)-1);
635     pl->title[sizeof(pl->title)-1] = '\0';
636    
637     /* If the map where the person was last saved does not exist,
638     * restart them on their home-savebed. This is good for when
639     * maps change between versions
640     * First, we check for partial path, then check to see if the full
641     * path (for unique player maps)
642     */
643     if (check_path(pl->maplevel,1)==-1) {
644     if (check_path(pl->maplevel,0)==-1) {
645     strcpy(pl->maplevel, pl->savebed_map);
646     op->x = pl->bed_x, op->y = pl->bed_y;
647     }
648     }
649    
650     /* If player saved beyond some time ago, and the feature is
651     * enabled, put the player back on his savebed map.
652     */
653     if ((settings.reset_loc_time >0) && (elapsed_save_time > settings.reset_loc_time)) {
654     strcpy(pl->maplevel, pl->savebed_map);
655     op->x = pl->bed_x, op->y = pl->bed_y;
656     }
657    
658     /* make sure he's a player--needed because of class change. */
659     op->type = PLAYER;
660    
661     enter_exit(op,NULL);
662    
663     pl->name_changed=1;
664     pl->state = ST_PLAYING;
665     #ifdef AUTOSAVE
666     pl->last_save_tick = pticks;
667     #endif
668     op->carrying = sum_weight (op);
669     /* Need to call fix_player now - program modified so that it is not
670     * called during the load process (FLAG_NO_FIX_PLAYER set when
671     * saved)
672     * Moved ahead of the esrv functions, so proper weights will be
673     * sent to the client.
674     */
675     link_player_skills(op);
676    
677     if ( ! legal_range (op, op->contr->shoottype))
678     op->contr->shoottype = range_none;
679    
680     fix_player (op);
681    
682     /* if it's a dragon player, set the correct title here */
683     if (is_dragon_pl(op) && op->inv != NULL) {
684     object *tmp, *abil=NULL, *skin=NULL;
685     for (tmp=op->inv; tmp!=NULL; tmp=tmp->below) {
686     if (tmp->type == FORCE) {
687     if (strcmp(tmp->arch->name, "dragon_ability_force")==0)
688     abil = tmp;
689     else if (strcmp(tmp->arch->name, "dragon_skin_force")==0)
690     skin = tmp;
691     }
692     }
693     set_dragon_name(op, abil, skin);
694     }
695    
696     new_draw_info(NDI_UNIQUE, 0,op,"Welcome Back!");
697     new_draw_info_format(NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL,
698     "%s has entered the game.",pl->ob->name);
699    
700     /* Lauwenmark : Here we handle the LOGIN global event */
701     execute_global_event(EVENT_LOGIN, pl, pl->socket.host);
702     op->contr->socket.update_look=1;
703     /* If the player should be dead, call kill_player for them
704     * Only check for hp - if player lacks food, let the normal
705     * logic for that to take place. If player is permanently
706     * dead, and not using permadeath mode, the kill_player will
707     * set the play_again flag, so return.
708     */
709     if (op->stats.hp<0) {
710     new_draw_info(NDI_UNIQUE, 0,op,"Your character was dead last your played.");
711     kill_player(op);
712     if (pl->state != ST_PLAYING) return;
713     }
714     LOG(llevInfo,"LOGIN: Player named %s from ip %s\n", op->name,
715     op->contr->socket.host);
716    
717     /* Do this after checking for death - no reason sucking up bandwidth if
718     * the data isn't needed.
719     */
720     esrv_new_player(op->contr,op->weight+op->carrying);
721     esrv_send_inventory(op, op);
722     esrv_add_spells(op->contr, NULL);
723    
724     CLEAR_FLAG(op, FLAG_FRIENDLY);
725    
726     /* can_use_shield is a new flag. However, the can_use.. seems to largely come
727     * from the class, and not race. I don't see any way to get the class information
728     * to then update this. I don't think this will actually break anything - anyone
729     * that can use armour should be able to use a shield. What this may 'break'
730     * are features new characters get, eg, if someone starts up with a Q, they
731     * should be able to use a shield. However, old Q's won't get that advantage.
732     */
733     if (QUERY_FLAG(op, FLAG_USE_ARMOUR)) SET_FLAG(op, FLAG_USE_SHIELD);
734     return;
735     }