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.11 by root, Sun Sep 3 22:45:57 2006 UTC vs.
Revision 1.17 by root, Tue Sep 12 19:20:08 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines