1 | |
|
|
2 | /* |
|
|
3 | * static char *rcsid_login_c = |
|
|
4 | * "$Id: login.C,v 1.16 2006/09/10 16:56:22 root Exp $"; |
|
|
5 | */ |
|
|
6 | |
|
|
7 | /* |
1 | /* |
8 | CrossFire, A Multiplayer game for X-windows |
2 | CrossFire, A Multiplayer game for X-windows |
9 | |
3 | |
10 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
4 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
11 | Copyright (C) 1992 Frank Tore Johansen |
5 | Copyright (C) 1992 Frank Tore Johansen |
… | |
… | |
22 | |
16 | |
23 | You should have received a copy of the GNU General Public License |
17 | You should have received a copy of the GNU General Public License |
24 | along with this program; if not, write to the Free Software |
18 | along with this program; if not, write to the Free Software |
25 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | |
20 | |
27 | The authors can be reached via e-mail at crossfire-devel@real-time.com |
21 | The authors can be reached via e-mail at <crossfire@schmorp.de> |
28 | */ |
22 | */ |
29 | |
23 | |
30 | #include <global.h> |
24 | #include <global.h> |
31 | #ifndef __CEXTRACT__ |
|
|
32 | # include <sproto.h> |
25 | #include <sproto.h> |
33 | #endif |
|
|
34 | #include <spells.h> |
26 | #include <spells.h> |
35 | #include <loader.h> |
27 | #include <loader.h> |
36 | #include <define.h> |
28 | #include <define.h> |
37 | |
29 | |
38 | extern void sub_weight (object *, signed long); |
30 | extern void sub_weight (object *, signed long); |
… | |
… | |
45 | void |
37 | void |
46 | emergency_save (int flag) |
38 | emergency_save (int flag) |
47 | { |
39 | { |
48 | player *pl; |
40 | player *pl; |
49 | |
41 | |
50 | #ifndef NO_EMERGENCY_SAVE |
|
|
51 | trying_emergency_save = 1; |
42 | trying_emergency_save = 1; |
52 | if (editor) |
43 | |
53 | return; |
|
|
54 | LOG (llevError, "Emergency save: "); |
44 | LOG (llevError, "Emergency save: "); |
55 | for (pl = first_player; pl != NULL; pl = pl->next) |
45 | for (pl = first_player; pl; pl = pl->next) |
56 | { |
46 | { |
57 | if (!pl->ob) |
47 | if (!pl->ob) |
58 | { |
48 | { |
59 | LOG (llevError, "No name, ignoring this.\n"); |
49 | LOG (llevError, "No name, ignoring this.\n"); |
60 | continue; |
50 | continue; |
61 | } |
51 | } |
|
|
52 | |
62 | LOG (llevError, "%s ", pl->ob->name); |
53 | LOG (llevError, "%s ", &pl->ob->name); |
63 | new_draw_info (NDI_UNIQUE, 0, pl->ob, "Emergency save..."); |
54 | new_draw_info (NDI_UNIQUE, 0, pl->ob, "Emergency save..."); |
64 | |
55 | |
65 | /* If we are not exiting the game (ie, this is sort of a backup save), then |
56 | /* 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 |
57 | * 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 |
58 | * options to have backup saves be done at the starting village |
68 | */ |
59 | */ |
69 | if (!flag) |
60 | if (!flag) |
70 | { |
61 | { |
71 | strcpy (pl->maplevel, first_map_path); |
62 | strcpy (pl->maplevel, first_map_path); |
72 | if (pl->ob->map != NULL) |
63 | |
73 | pl->ob->map = NULL; |
64 | pl->ob->map = 0; |
74 | pl->ob->x = -1; |
65 | pl->ob->x = -1; |
75 | pl->ob->y = -1; |
66 | pl->ob->y = -1; |
76 | } |
67 | } |
77 | if (!save_player (pl->ob, flag)) |
68 | |
78 | { |
69 | pl->save (1); |
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 | } |
70 | } |
|
|
71 | |
84 | LOG (llevError, "\n"); |
72 | 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 | } |
73 | } |
99 | |
74 | |
100 | /* Delete character with name. if new is set, also delete the new |
75 | /* Delete character with name. if new is set, also delete the new |
101 | * style directory, otherwise, just delete the old style playfile |
76 | * style directory, otherwise, just delete the old style playfile |
102 | * (needed for transition) |
77 | * (needed for transition) |
… | |
… | |
105 | delete_character (const char *name, int newchar) |
80 | delete_character (const char *name, int newchar) |
106 | { |
81 | { |
107 | char buf[MAX_BUF]; |
82 | char buf[MAX_BUF]; |
108 | |
83 | |
109 | sprintf (buf, "%s/%s/%s.pl", settings.localdir, settings.playerdir, name); |
84 | sprintf (buf, "%s/%s/%s.pl", settings.localdir, settings.playerdir, name); |
|
|
85 | |
110 | if (unlink (buf) == -1) |
86 | if (unlink (buf) == -1) |
111 | LOG (llevDebug, "Cannot delete character file %s: %s\n", buf, strerror (errno)); |
87 | LOG (llevDebug, "Cannot delete character file %s: %s\n", buf, strerror (errno)); |
|
|
88 | |
112 | if (newchar) |
89 | if (newchar) |
113 | { |
90 | { |
114 | sprintf (buf, "%s/%s/%s", settings.localdir, settings.playerdir, name); |
91 | sprintf (buf, "%s/%s/%s", settings.localdir, settings.playerdir, name); |
115 | /* this effectively does an rm -rf on the directory */ |
92 | /* this effectively does an rm -rf on the directory */ |
116 | remove_directory (buf); |
93 | remove_directory (buf); |
117 | } |
94 | } |
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 | } |
95 | } |
216 | |
96 | |
217 | int |
97 | int |
218 | create_savedir_if_needed (char *savedir) |
98 | create_savedir_if_needed (char *savedir) |
219 | { |
99 | { |
… | |
… | |
233 | LOG (llevError, "Unable to create player savedir %s: %s\n", savedir, strerror (errno)); |
113 | LOG (llevError, "Unable to create player savedir %s: %s\n", savedir, strerror (errno)); |
234 | return 0; |
114 | return 0; |
235 | } |
115 | } |
236 | free (buf); |
116 | free (buf); |
237 | } |
117 | } |
|
|
118 | |
238 | return 1; |
119 | return 1; |
239 | } |
120 | } |
240 | |
121 | |
|
|
122 | /* |
|
|
123 | * If final is set, it a clean/final save, not a backup, ie dont remove objects from inventory |
|
|
124 | */ |
241 | void |
125 | void |
242 | destroy_object (object *op) |
126 | player::save (bool final) |
243 | { |
127 | { |
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; |
128 | object *tmp, *container = 0; |
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 | |
129 | |
287 | /* Sanity check - some stuff changes this when player is exiting */ |
130 | /* Sanity check - some stuff changes this when player is exiting */ |
288 | if (op->type != PLAYER) |
131 | if (ob->type != PLAYER || !enable_save || !ns) |
289 | return 0; |
132 | return; |
290 | |
133 | |
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); |
134 | INVOKE_PLAYER (SAVE, ob->contr); |
298 | |
|
|
299 | if (flag == 0) |
|
|
300 | terminate_all_pets (op); |
|
|
301 | |
135 | |
302 | object_freezer freezer; |
136 | object_freezer freezer; |
303 | |
137 | |
|
|
138 | int wiz = ob->flags [FLAG_WIZ]; |
|
|
139 | |
304 | /* Eneq(@csd.uu.se): If we have an open container hide it. */ |
140 | /* Eneq(@csd.uu.se): If we have an open container hide it. */ |
305 | if (op->container) |
|
|
306 | { |
|
|
307 | container = op->container; |
141 | container = ob->container; |
308 | op->container = NULL; |
142 | ob->container = 0; |
309 | } |
|
|
310 | |
143 | |
311 | fprintf (freezer, "password %s\n", pl->password); |
144 | fprintf (freezer, "password %s\n", password); |
312 | |
145 | |
313 | if (settings.set_title == TRUE) |
|
|
314 | if (pl->own_title[0] != '\0') |
146 | if (own_title[0] != '\0') |
315 | fprintf (freezer, "title %s\n", pl->own_title); |
147 | fprintf (freezer, "title %s\n", own_title); |
316 | |
148 | |
317 | fprintf (freezer, "explore %d\n", pl->explore); |
149 | fprintf (freezer, "explore %d\n", explore); |
318 | fprintf (freezer, "gen_hp %d\n", pl->gen_hp); |
150 | fprintf (freezer, "gen_hp %d\n", gen_hp); |
319 | fprintf (freezer, "gen_sp %d\n", pl->gen_sp); |
151 | fprintf (freezer, "gen_sp %d\n", gen_sp); |
320 | fprintf (freezer, "gen_grace %d\n", pl->gen_grace); |
152 | fprintf (freezer, "gen_grace %d\n", gen_grace); |
321 | fprintf (freezer, "listening %d\n", pl->listening); |
153 | fprintf (freezer, "listening %d\n", listening); |
322 | fprintf (freezer, "shoottype %d\n", pl->shoottype); |
154 | fprintf (freezer, "shoottype %d\n", shoottype); |
323 | fprintf (freezer, "bowtype %d\n", pl->bowtype); |
155 | fprintf (freezer, "bowtype %d\n", bowtype); |
324 | fprintf (freezer, "petmode %d\n", pl->petmode); |
156 | fprintf (freezer, "petmode %d\n", petmode); |
325 | fprintf (freezer, "peaceful %d\n", pl->peaceful); |
157 | fprintf (freezer, "peaceful %d\n", peaceful); |
326 | fprintf (freezer, "no_shout %d\n", pl->no_shout); |
|
|
327 | fprintf (freezer, "digestion %d\n", pl->digestion); |
158 | fprintf (freezer, "digestion %d\n", digestion); |
328 | fprintf (freezer, "pickup %d\n", pl->mode); |
159 | fprintf (freezer, "pickup %d\n", mode); |
329 | fprintf (freezer, "outputs_sync %d\n", pl->outputs_sync); |
160 | fprintf (freezer, "outputs_sync %d\n", outputs_sync); |
330 | fprintf (freezer, "outputs_count %d\n", pl->outputs_count); |
161 | fprintf (freezer, "outputs_count %d\n", outputs_count); |
331 | /* Match the enumerations but in string form */ |
162 | /* Match the enumerations but in string form */ |
332 | fprintf (freezer, "usekeys %s\n", pl->usekeys == key_inventory ? "key_inventory" : (pl->usekeys == keyrings ? "keyrings" : "containers")); |
163 | fprintf (freezer, "usekeys %s\n", usekeys == key_inventory ? "key_inventory" : (usekeys == keyrings ? "keyrings" : "containers")); |
333 | /* Match the enumerations but in string form */ |
164 | /* Match the enumerations but in string form */ |
334 | fprintf (freezer, "unapply %s\n", pl->unapply == unapply_nochoice ? "unapply_nochoice" : |
165 | fprintf (freezer, "unapply %s\n", unapply == unapply_nochoice ? "unapply_nochoice" : |
335 | (pl->unapply == unapply_never ? "unapply_never" : "unapply_always")); |
166 | (unapply == unapply_never ? "unapply_never" : "unapply_always")); |
336 | |
167 | |
337 | #ifdef BACKUP_SAVE_AT_HOME |
168 | if (ob->map) |
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); |
169 | fprintf (freezer, "map %s\n", ob->map->path); |
343 | else |
170 | else |
344 | fprintf (freezer, "map %s\n", settings.emergency_mapname); |
171 | fprintf (freezer, "map %s\n", settings.emergency_mapname); |
345 | |
172 | |
346 | fprintf (freezer, "savebed_map %s\n", pl->savebed_map); |
173 | fprintf (freezer, "savebed_map %s\n", savebed_map); |
347 | fprintf (freezer, "bed_x %d\nbed_y %d\n", pl->bed_x, pl->bed_y); |
174 | fprintf (freezer, "bed_x %d\nbed_y %d\n", bed_x, bed_y); |
348 | fprintf (freezer, "weapon_sp %f\n", pl->weapon_sp); |
175 | fprintf (freezer, "weapon_sp %f\n", weapon_sp); |
349 | fprintf (freezer, "Str %d\n", pl->orig_stats.Str); |
176 | fprintf (freezer, "Str %d\n", orig_stats.Str); |
350 | fprintf (freezer, "Dex %d\n", pl->orig_stats.Dex); |
177 | fprintf (freezer, "Dex %d\n", orig_stats.Dex); |
351 | fprintf (freezer, "Con %d\n", pl->orig_stats.Con); |
178 | fprintf (freezer, "Con %d\n", orig_stats.Con); |
352 | fprintf (freezer, "Int %d\n", pl->orig_stats.Int); |
179 | fprintf (freezer, "Int %d\n", orig_stats.Int); |
353 | fprintf (freezer, "Pow %d\n", pl->orig_stats.Pow); |
180 | fprintf (freezer, "Pow %d\n", orig_stats.Pow); |
354 | fprintf (freezer, "Wis %d\n", pl->orig_stats.Wis); |
181 | fprintf (freezer, "Wis %d\n", orig_stats.Wis); |
355 | fprintf (freezer, "Cha %d\n", pl->orig_stats.Cha); |
182 | fprintf (freezer, "Cha %d\n", orig_stats.Cha); |
356 | |
183 | |
357 | fprintf (freezer, "lev_array %d\n", op->level > 10 ? 10 : op->level); |
184 | fprintf (freezer, "lev_array %d\n", ob->level > 10 ? 10 : ob->level); |
|
|
185 | |
358 | for (i = 1; i <= pl->last_level && i <= 10; i++) |
186 | for (int i = 1; i <= last_level && i <= 10; i++) |
359 | { |
187 | { |
360 | fprintf (freezer, "%d\n", pl->levhp[i]); |
188 | fprintf (freezer, "%d\n", levhp[i]); |
361 | fprintf (freezer, "%d\n", pl->levsp[i]); |
189 | fprintf (freezer, "%d\n", levsp[i]); |
362 | fprintf (freezer, "%d\n", pl->levgrace[i]); |
190 | fprintf (freezer, "%d\n", levgrace[i]); |
363 | } |
191 | } |
364 | |
192 | |
365 | freezer.put (op->contr); |
193 | freezer.put (ob->contr); |
366 | |
194 | |
367 | fprintf (freezer, "endplst\n"); |
195 | fprintf (freezer, "endplst\n"); |
368 | |
196 | |
369 | SET_FLAG (op, FLAG_NO_FIX_PLAYER); |
197 | SET_FLAG (ob, FLAG_NO_FIX_PLAYER); |
370 | CLEAR_FLAG (op, FLAG_WIZ); |
198 | CLEAR_FLAG (ob, 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 */ |
199 | save_object (freezer, ob, 3); /* don't check and don't remove */ |
390 | #endif |
|
|
391 | |
200 | |
392 | char filename[MAX_BUF]; |
201 | char filename[MAX_BUF]; |
393 | |
202 | |
394 | sprintf (filename, "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, &op->name, &op->name); |
203 | sprintf (filename, "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, &ob->name, &ob->name); |
395 | make_path_to_file (filename); |
204 | make_path_to_file (filename); |
396 | freezer.save (filename); |
205 | freezer.save (filename); |
397 | |
206 | |
398 | CLEAR_FLAG (op, FLAG_NO_FIX_PLAYER); |
207 | CLEAR_FLAG (ob, FLAG_NO_FIX_PLAYER); |
399 | |
|
|
400 | if (!flag) |
|
|
401 | while ((tmp = op->inv)) |
|
|
402 | destroy_object (tmp); |
|
|
403 | |
208 | |
404 | /* Eneq(@csd.uu.se): Reveal the container if we have one. */ |
209 | /* Eneq(@csd.uu.se): Reveal the container if we have one. */ |
405 | if (flag && container != NULL) |
|
|
406 | op->container = container; |
210 | ob->container = container; |
407 | |
211 | |
408 | if (wiz) |
212 | ob->flags [FLAG_WIZ] = wiz; |
409 | SET_FLAG (op, FLAG_WIZ); |
|
|
410 | |
213 | |
411 | if (!flag) |
214 | enable_save = !final; |
412 | esrv_send_inventory (op, op); |
|
|
413 | |
|
|
414 | return 1; |
|
|
415 | } |
215 | } |
416 | |
216 | |
417 | void |
217 | player * |
418 | check_login (object *op) |
218 | player::load (const char *path) |
419 | { |
219 | { |
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); |
220 | object_thawer thawer (path); |
430 | |
221 | |
431 | /* If no file, must be a new player, so lets get confirmation of |
222 | /* If no file, must be a new player, so lets get confirmation of |
432 | * the password. Return control to the higher level dispatch, |
223 | * the password. Return control to the higher level dispatch, |
433 | * since the rest of this just deals with loading of the file. |
224 | * since the rest of this just deals with loading of the file. |
434 | */ |
225 | */ |
435 | if (!thawer) |
226 | if (!thawer) |
436 | { |
|
|
437 | confirm_password (op); |
|
|
438 | return; |
227 | return 0; |
439 | } |
|
|
440 | |
228 | |
441 | if (fgets (bufall, MAX_BUF, thawer) != NULL) |
229 | player *pl = new player; |
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 | |
230 | |
450 | if (!correct) |
231 | char buf[MAX_BUF], bufall[MAX_BUF]; |
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 | |
232 | |
468 | #ifdef SAVE_INTERVAL |
233 | pl->set_object (object::create ()); |
469 | pl->last_save_time = time (NULL); |
234 | pl->last_save_time = time (0); |
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; |
235 | pl->name_changed = 1; |
475 | pl->orig_stats.Str = 0; |
236 | |
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); |
237 | assign (pl->savebed_map, first_map_path); |
483 | pl->bed_x = 0, pl->bed_y = 0; |
|
|
484 | pl->spellparam[0] = '\0'; |
|
|
485 | |
238 | |
486 | /* Loop through the file, loading the rest of the values */ |
239 | /* Loop through the file, loading the rest of the values */ |
487 | while (fgets (bufall, MAX_BUF, thawer) != NULL) |
240 | while (fgets (bufall, MAX_BUF, thawer)) |
488 | { |
241 | { |
|
|
242 | int value; |
489 | sscanf (bufall, "%s %d\n", buf, &value); |
243 | sscanf (bufall, "%s %d\n", buf, &value); |
|
|
244 | |
490 | if (!strcmp (buf, "endplst")) |
245 | if (!strcmp (buf, "endplst")) |
491 | break; |
246 | break; |
492 | else if (!strcmp (buf, "oid")) |
247 | else if (!strcmp (buf, "oid")) |
493 | thawer.get (pl, value); |
248 | thawer.get (pl, value); |
494 | else if (!strcmp (buf, "title") && settings.set_title == TRUE) |
249 | else if (!strcmp (buf, "password")) |
|
|
250 | sscanf (bufall, "password %[^\n]", pl->password); |
|
|
251 | else if (!strcmp (buf, "title")) |
495 | sscanf (bufall, "title %[^\n]", pl->own_title); |
252 | sscanf (bufall, "title %[^\n]", pl->own_title); |
496 | else if (!strcmp (buf, "explore")) |
253 | else if (!strcmp (buf, "explore")) |
497 | pl->explore = value; |
254 | pl->explore = value; |
498 | else if (!strcmp (buf, "gen_hp")) |
255 | else if (!strcmp (buf, "gen_hp")) |
499 | pl->gen_hp = value; |
256 | pl->gen_hp = value; |
… | |
… | |
509 | pl->gen_grace = value; |
266 | pl->gen_grace = value; |
510 | else if (!strcmp (buf, "listening")) |
267 | else if (!strcmp (buf, "listening")) |
511 | pl->listening = value; |
268 | pl->listening = value; |
512 | else if (!strcmp (buf, "peaceful")) |
269 | else if (!strcmp (buf, "peaceful")) |
513 | pl->peaceful = value; |
270 | pl->peaceful = value; |
514 | else if (!strcmp (buf, "no_shout")) |
|
|
515 | pl->no_shout = value; |
|
|
516 | else if (!strcmp (buf, "digestion")) |
271 | else if (!strcmp (buf, "digestion")) |
517 | pl->digestion = value; |
272 | pl->digestion = value; |
518 | else if (!strcmp (buf, "pickup")) |
273 | else if (!strcmp (buf, "pickup")) |
519 | pl->mode = value; |
274 | pl->mode = value; |
520 | else if (!strcmp (buf, "outputs_sync")) |
275 | else if (!strcmp (buf, "outputs_sync")) |
… | |
… | |
567 | else |
322 | else |
568 | LOG (llevDebug, "load_player: got unknown unapply type: %s\n", bufall + 8); |
323 | LOG (llevDebug, "load_player: got unknown unapply type: %s\n", bufall + 8); |
569 | } |
324 | } |
570 | else if (!strcmp (buf, "lev_array")) |
325 | else if (!strcmp (buf, "lev_array")) |
571 | { |
326 | { |
572 | for (i = 1; i <= value; i++) |
327 | for (int i = 1; i <= value; i++) |
573 | { |
328 | { |
574 | char line[128]; |
329 | char line[128]; |
575 | |
330 | |
576 | fgets (line, 128, thawer); |
331 | fgets (line, 128, thawer); |
577 | pl->levhp[i] = atoi (line); |
332 | pl->levhp[i] = atoi (line); |
… | |
… | |
583 | /* spell_array code removed - don't know when that was last used. |
338 | /* 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 |
339 | * Even the load code below will someday be replaced by spells being |
585 | * objects. |
340 | * objects. |
586 | */ |
341 | */ |
587 | } |
342 | } |
588 | else if (!strcmp (buf, "known_spell")) |
343 | else |
589 | { |
344 | LOG (llevDebug, "unparseable line in player file %s: %s\n", path, bufall); |
590 | #if 0 |
345 | } |
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 | |
346 | |
619 | /* this loads the standard objects values. */ |
347 | /* this loads the standard objects values. */ |
620 | load_object (thawer, op, 0); |
348 | load_object (thawer, pl->ob, 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 | |
349 | |
627 | /* If the map where the person was last saved does not exist, |
350 | /* If the map where the person was last saved does not exist, |
628 | * restart them on their home-savebed. This is good for when |
351 | * restart them on their home-savebed. This is good for when |
629 | * maps change between versions |
352 | * maps change between versions |
630 | * First, we check for partial path, then check to see if the full |
353 | * First, we check for partial path, then check to see if the full |
631 | * path (for unique player maps) |
354 | * path (for unique player maps) |
632 | */ |
355 | */ |
|
|
356 | if (!has_been_loaded (pl->maplevel) |
633 | if (check_path (pl->maplevel, 1) == -1) |
357 | && check_path (pl->maplevel, 1) == -1 |
634 | { |
|
|
635 | if (check_path (pl->maplevel, 0) == -1) |
358 | && check_path (pl->maplevel, 0) == -1) |
636 | { |
359 | { |
637 | strcpy (pl->maplevel, pl->savebed_map); |
360 | strcpy (pl->maplevel, pl->savebed_map); |
638 | op->x = pl->bed_x, op->y = pl->bed_y; |
361 | pl->ob->x = pl->bed_x, pl->ob->y = pl->bed_y; |
639 | } |
|
|
640 | } |
362 | } |
641 | |
363 | |
642 | /* make sure he's a player--needed because of class change. */ |
364 | /* 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; |
365 | pl->name_changed = 1; |
648 | pl->state = ST_PLAYING; |
|
|
649 | #ifdef AUTOSAVE |
|
|
650 | pl->last_save_tick = pticks; |
366 | 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 | |
367 | |
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)); |
368 | INVOKE_PLAYER (LOAD, pl, ARG_STRING (path)); |
688 | INVOKE_PLAYER (LOGIN, pl); |
|
|
689 | |
369 | |
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; |
370 | return pl; |
725 | } |
371 | } |
|
|
372 | |