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.14 by root, Sat Sep 9 21:48:29 2006 UTC vs.
Revision 1.15 by root, Sun Sep 10 15:59:27 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines