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.2 by root, Fri Aug 25 13:24:50 2006 UTC vs.
Revision 1.35 by root, Mon Dec 25 17:11:17 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines