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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines