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 |
} |