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