ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/login.C
(Generate patch)

Comparing deliantra/server/server/login.C (file contents):
Revision 1.7 by root, Wed Aug 30 06:06:27 2006 UTC vs.
Revision 1.31 by root, Sat Dec 23 03:38:43 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines