1 /* $Id$ */
2 /*
3  * Support for the "party" system.
4  */
5 
6 /* added this for consistency in some (unrelated) header-inclusion,
7    it IS a server file, isn't it? */
8 #define SERVER
9 
10 #include "angband.h"
11 #include "party.h"
12 
13 #ifdef TOMENET_WORLDS
14 #include "../world/world.h"
15 #endif
16 
17 
18 /*
19  * Give some exp-bonus to encourage partying (aka "C.Blue party bonus") [2]
20  * formula: (PARTY_XP_BOOST+1)/(PARTY_XP_BOOST + (# of applicable players))
21  */
22 #define PARTY_XP_BOOST	(cfg.party_xp_boost)
23 #define IDDC_PARTY_XP_BOOST	8
24 /* [7..10] 10-> 2:92%, 3:85%, 4:79%, 5:73%, 6:69%; 8-> 2:90%, 3:82%, 4:75%, 5:69%, 6:64%
25    8 is maybe best, assuming that of a larger group one or two will quickly die anyway xD */
26 
27 /* Keep these ANTI_MAXPLV_EXPLOIT..  defines consistent with cmd4.c:do_write_others_attributes()! */
28 /* prevent exploit strategies */
29 #define ANTI_MAXPLV_EXPLOIT	/* prevent exploiting by having a powerful char losing levels deliberately to get in range with lowbies to boost */
30 // #define ANTI_MAXPLV_EXPLOIT_SOFTLEV	/* be somewhat less strict (average between max_plv and current max_lev) */
31  #define ANTI_MAXPLV_EXPLOIT_SOFTEXP	/* be somewhat less strict (use reduced exp instead of preventing any exp) */
32 
33 /* Check for illegal party/guild name that could be abused to catch special chat commands */
34 //!(((N)[0] >= 'A' && (N)[0] <= 'Z') || ((N)[0] >= 'a' && (N)[0] <= 'z') || ((N)[0] >= '0' && (N)[0] <= '9'))
35 #define ILLEGAL_GROUP_NAME(N) \
36     ((N)[0] == 0 || (N)[0] == ' ' || \
37     streq(N, "Neutral") || \
38     streq(N, "!") || streq(N, "#") || streq(N, "%") || streq(N, "$") || streq(N, "-"))
39 
40 
41 #ifdef HAVE_CRYPT
42 #include <unistd.h>
43 #endif	// HAVE_CRYPT
44 
45 
46 static char *t_crypt(char *inbuf, cptr salt);
47 static void del_party(int id);
48 static u32b new_accid(void);
49 
50 /* The hash table itself */
51 hash_entry *hash_table[NUM_HASH_ENTRIES];
52 
53 
54 /* admin only - account edit function */
WriteAccount(struct account * r_acc,bool new)55 bool WriteAccount(struct account *r_acc, bool new) {
56 	FILE *fp;
57 	short found = 0;
58 	struct account c_acc;
59 	long delpos = -1L;
60 	char buf[1024];
61 	size_t retval;
62 
63 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
64 	fp = fopen(buf, "rb+");
65 
66 	if (!fp) {
67 		/* Attempt to create a new file */
68 		fp = fopen(buf, "wb+");
69 	}
70 
71 	if (!fp) {
72 		s_printf("Could not open tomenet.acc file! (errno = %d)\n", errno);
73 	} else {
74 		while (!feof(fp) && !found) {
75 			retval = fread(&c_acc, sizeof(struct account), 1, fp);
76 			if (retval == 0) break; /* EOF reached, nothing read into c_acc - mikaelh */
77 			if (c_acc.flags & ACC_DELD) {
78 				if (delpos == -1L) delpos = (ftell(fp) - sizeof(struct account));
79 				if (new) break;
80 				continue;
81 			}
82 			if (!strcmp(c_acc.name, r_acc->name)) found = 1;
83 		}
84 		if (found) {
85 			fseek(fp, -sizeof(struct account), SEEK_CUR);
86 			if (fwrite(r_acc, sizeof(struct account), 1, fp) < 1) {
87 				s_printf("Writing to account file failed: %s\n", feof(fp) ? "EOF" : strerror(ferror(fp)));
88 			}
89 		}
90 		if (new) {
91 			if (delpos != -1L) {
92 				fseek(fp, delpos, SEEK_SET);
93 			} else {
94 				fseek(fp, 0L, SEEK_END);
95 			}
96 			if (fwrite(r_acc, sizeof(struct account), 1, fp) < 1) {
97 				s_printf("Writing to account file failed: %s\n", feof(fp) ? "EOF" : strerror(ferror(fp)));
98 			}
99 			found = 1;
100 		}
101 	}
102 	memset(c_acc.pass, 0, sizeof(c_acc.pass));
103 	fclose(fp);
104 	return(found);
105 }
106 
107 /*
108  Get an existing account and set default valid flags on it
109  That will be SCORE on only (hack it for MULTI)
110  Modified to return TRUE on success and FALSE if account can't
111  be found - mikaelh
112  Makes the player valid now too - mikaelh
113  Modified to return 0 if not found, 1 if found but already 100% validated,
114  and -1 if found and there was still something invalid about it - C. Blue
115  */
validate(char * name)116 int validate(char *name) {
117 	struct account *c_acc;
118 	int i;
119 	bool effect = FALSE;
120 
121 	c_acc = GetAccount(name, NULL, TRUE);
122 	if (!c_acc) return(0);
123 
124 	if (c_acc->flags & ACC_TRIAL) {
125 		effect = TRUE;
126 		c_acc->flags &= ~(ACC_TRIAL | ACC_NOSCORE);
127 	}
128 	WriteAccount(c_acc, FALSE);
129 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
130 	for (i = 1; i <= NumPlayers; i++) {
131 		if (Players[i]->account == c_acc->id) {
132 			if (Players[i]->inval) effect = TRUE;
133 			Players[i]->inval = 0;
134 		}
135 	}
136 
137 	KILL(c_acc, struct account);
138 	if (effect) return(-1);
139 	return(1);
140 }
141 
142 /* invalidate - opposite to validate() */
invalidate(char * name,bool admin)143 int invalidate(char *name, bool admin) {
144 	struct account *c_acc;
145 	int i;
146 	bool effect = FALSE;
147 
148 	c_acc = GetAccount(name, NULL, TRUE);
149 	if (!c_acc) return(0);
150 
151 	if (!admin && (c_acc->flags & ACC_ADMIN)) {
152 		KILL(c_acc, struct account);
153 		return 2;
154 	}
155 
156 	if (!(c_acc->flags & ACC_TRIAL)) {
157 		effect = TRUE;
158 		c_acc->flags |= (ACC_TRIAL | ACC_NOSCORE);
159 	}
160 	WriteAccount(c_acc, FALSE);
161 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
162 	for (i = 1; i <= NumPlayers; i++) {
163 		if (Players[i]->account == c_acc->id) {
164 			if (!Players[i]->inval) effect = TRUE;
165 			Players[i]->inval = 1;
166 		}
167 	}
168 
169 	KILL(c_acc, struct account);
170 	if (effect) return(-1);
171 	return(1);
172 }
173 
makeadmin(char * name)174 int makeadmin(char *name) {
175 	struct account *c_acc;
176 	int i;
177 	c_acc = GetAccount(name, NULL, TRUE);
178 	if (!c_acc) return(FALSE);
179 	c_acc->flags &= ~(ACC_TRIAL);
180 	c_acc->flags |= (ACC_ADMIN | ACC_NOSCORE);
181 	WriteAccount(c_acc, FALSE);
182 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
183 	for (i = 1; i <= NumPlayers; i++) {
184 		if (Players[i]->account == c_acc->id) {
185 			Players[i]->inval = 0;
186 			if (!strcmp(name, Players[i]->name))
187 				Players[i]->admin_dm = 1;
188 			else
189 				Players[i]->admin_wiz = 1;
190 		}
191 	}
192 	KILL(c_acc, struct account);
193 	return(TRUE);
194 }
195 
196 /* set or clear account flags */
acc_set_flags(char * name,u32b flags,bool set)197 int acc_set_flags(char *name, u32b flags, bool set) {
198 	struct account *c_acc;
199 
200 	c_acc = GetAccount(name, NULL, TRUE);
201 	if (!c_acc) return(0);
202 
203 	if (set) c_acc->flags |= (flags);
204 	else c_acc->flags &= ~(flags);
205 
206 	WriteAccount(c_acc, FALSE);
207 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
208 
209 	KILL(c_acc, struct account);
210 	return(1);
211 }
212 
213 /* get account flags */
acc_get_flags(char * name)214 u32b acc_get_flags(char *name) {
215 	struct account *c_acc;
216 	u32b flags;
217 
218 	c_acc = GetAccount(name, NULL, FALSE);
219 	if (!c_acc) return(0);
220 
221 	flags = c_acc->flags;
222 	KILL(c_acc, struct account);
223 	return flags;
224 }
225 
226 /* set or clear account flags */
acc_set_flags_id(u32b id,u32b flags,bool set)227 int acc_set_flags_id(u32b id, u32b flags, bool set) {
228 	struct account *c_acc;
229 	char acc_name[MAX_CHARS];
230 
231 	acc_name[0] = 0;
232 	strcpy(acc_name, lookup_accountname(id));
233 
234 	if (acc_name[0] == 0) return(0);
235 	c_acc = GetAccount(acc_name, NULL, TRUE);
236 	if (!c_acc) return(0);
237 
238 	if (set) c_acc->flags |= (flags);
239 	else c_acc->flags &= ~(flags);
240 
241 	WriteAccount(c_acc, FALSE);
242 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
243 
244 	KILL(c_acc, struct account);
245 	return(1);
246 }
247 
248 /* set account guild info */
acc_set_guild(char * name,s32b id)249 int acc_set_guild(char *name, s32b id) {
250 	struct account *c_acc;
251 
252 	c_acc = GetAccount(name, NULL, TRUE);
253 	if (!c_acc) return(0);
254 
255 	c_acc->guild_id = id;
256 
257 	WriteAccount(c_acc, FALSE);
258 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
259 
260 	KILL(c_acc, struct account);
261 	return(1);
262 }
acc_set_guild_dna(char * name,u32b dna)263 int acc_set_guild_dna(char *name, u32b dna) {
264 	struct account *c_acc;
265 
266 	c_acc = GetAccount(name, NULL, TRUE);
267 	if (!c_acc) return(0);
268 
269 	c_acc->guild_dna = dna;
270 
271 	WriteAccount(c_acc, FALSE);
272 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
273 
274 	KILL(c_acc, struct account);
275 	return(1);
276 }
277 
278 /* get account guild info */
acc_get_guild(char * name)279 s32b acc_get_guild(char *name) {
280 	struct account *c_acc;
281 	s32b guild_id;
282 
283 	c_acc = GetAccount(name, NULL, FALSE);
284 	if (!c_acc) return(0);
285 
286 	guild_id = c_acc->guild_id;
287 	KILL(c_acc, struct account);
288 	return guild_id;
289 }
acc_get_guild_dna(char * name)290 u32b acc_get_guild_dna(char *name) {
291 	struct account *c_acc;
292 	u32b dna;
293 
294 	c_acc = GetAccount(name, NULL, FALSE);
295 	if (!c_acc) return(0);
296 
297 	dna = c_acc->guild_dna;
298 	KILL(c_acc, struct account);
299 	return dna;
300 }
301 
acc_set_deed_event(char * name,char deed_sval)302 int acc_set_deed_event(char *name, char deed_sval) {
303 	struct account *c_acc;
304 
305 	c_acc = GetAccount(name, NULL, TRUE);
306 	if (!c_acc) return(0);
307 
308 	c_acc->deed_event = deed_sval;
309 
310 	WriteAccount(c_acc, FALSE);
311 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
312 
313 	KILL(c_acc, struct account);
314 	return(1);
315 }
acc_get_deed_event(char * name)316 char acc_get_deed_event(char *name) {
317 	struct account *c_acc;
318 	char deed_sval;
319 
320 	c_acc = GetAccount(name, NULL, FALSE);
321 	if (!c_acc) return(0);
322 
323 	deed_sval = c_acc->deed_event;
324 	KILL(c_acc, struct account);
325 	return deed_sval;
326 }
acc_set_deed_achievement(char * name,char deed_sval)327 int acc_set_deed_achievement(char *name, char deed_sval) {
328 	struct account *c_acc;
329 
330 	c_acc = GetAccount(name, NULL, TRUE);
331 	if (!c_acc) return(0);
332 
333 	c_acc->deed_achievement = deed_sval;
334 
335 	WriteAccount(c_acc, FALSE);
336 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
337 
338 	KILL(c_acc, struct account);
339 	return(1);
340 }
acc_get_deed_achievement(char * name)341 char acc_get_deed_achievement(char *name) {
342 	struct account *c_acc;
343 	char deed_sval;
344 
345 	c_acc = GetAccount(name, NULL, FALSE);
346 	if (!c_acc) return(0);
347 
348 	deed_sval = c_acc->deed_achievement;
349 	KILL(c_acc, struct account);
350 	return deed_sval;
351 }
352 
353 /*
354  return player account information (by name)
355  */
356 //void accinfo(char *name){
357 //}
358 
359 /* most account type stuff was already in here.
360    a separate file should probably be made in
361    order to split party/guild from account
362    and database handling */
363 /* Note. Accounts will be deleted when empty
364    They will not be subject to their own 90
365    days timeout, but will be removed upon
366    the removal of the last character. */
GetAccount(cptr name,char * pass,bool leavepass)367 struct account *GetAccount(cptr name, char *pass, bool leavepass) {
368 	FILE *fp;
369 	char buf[1024];
370 	struct account *c_acc;
371 
372 	MAKE(c_acc, struct account);
373 	if (!c_acc) return(NULL);
374 
375 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
376 	fp = fopen(buf, "rb+");
377 	if (!fp) {
378 		if (errno == ENOENT) {	/* ONLY if non-existent */
379 			fp = fopen(buf, "wb+");
380 			if (!fp) {
381 				KILL(c_acc, struct account);
382 				return(NULL);
383 			}
384 			s_printf("Generated new account file\n");
385 		}
386 		else {
387 			KILL(c_acc, struct account);
388 			return(NULL);	/* failed */
389 		}
390 	}
391 	while (fread(c_acc, sizeof(struct account), 1, fp)) {
392 		if (c_acc->flags & ACC_DELD) continue;
393 		if (!strcmp(c_acc->name, name)) {
394 			int val;
395 			if (pass == NULL) {	/* direct name lookup */
396 				val = 0;
397 			} else {
398 				val = strcmp(c_acc->pass, t_crypt(pass, name));
399 
400 				/* Update the timestamp if the password is successfully verified - mikaelh */
401 				if (val == 0) {
402 					c_acc->acc_laston_real = c_acc->acc_laston = time(NULL);
403 					fseek(fp, -sizeof(struct account), SEEK_CUR);
404 					if (fwrite(c_acc, sizeof(struct account), 1, fp) < 1) {
405 						s_printf("Writing to account file failed: %s\n", feof(fp) ? "EOF" : strerror(ferror(fp)));
406 					}
407 				}
408 			}
409 			if (!leavepass || pass != NULL) {
410 				memset(c_acc->pass, 0, sizeof(c_acc->pass));
411 			}
412 			if (val != 0) {
413 				fclose(fp);
414 				KILL(c_acc, struct account);
415 				return(NULL);
416 			} else {
417 				fclose(fp);
418 				return(c_acc);
419 			}
420 		}
421 	}
422 	/* New accounts always have pass */
423 	if (!pass) {
424 		KILL(c_acc, struct account);
425 		fclose(fp);
426 		return(NULL);
427 	}
428 
429 	/* No account found. Create trial account */
430 	WIPE(c_acc, struct account);
431 	c_acc->id = new_accid();
432 	if (c_acc->id != 0L) {
433 		if (c_acc->id == 1)
434 			c_acc->flags = (ACC_ADMIN | ACC_NOSCORE);
435 		else
436 			c_acc->flags = (ACC_TRIAL | ACC_NOSCORE);
437 
438 		strncpy(c_acc->name, name, 29);
439 		c_acc->name[29] = '\0';
440 
441 		condense_name(buf, c_acc->name);
442 		strncpy(c_acc->name_normalised, buf, 29);
443 		c_acc->name_normalised[29] = '\0';
444 
445 		strcpy(c_acc->pass, t_crypt(pass, name));
446 		if (!(WriteAccount(c_acc, TRUE))) {
447 			KILL(c_acc, struct account);
448 			fclose(fp);
449 			return(NULL);
450 		}
451 	}
452 	memset(c_acc->pass, 0, sizeof(c_acc->pass));
453 	fclose(fp);
454 	if(c_acc->id) {
455 		return(c_acc);
456 	}
457 	KILL(c_acc, struct account);
458 	return(NULL);
459 }
460 
461 /* Return account structure of a specified account name */
Admin_GetAccount(cptr name)462 struct account *Admin_GetAccount(cptr name) {
463 	FILE *fp;
464 	char buf[1024];
465 	struct account *c_acc;
466 
467 	MAKE(c_acc, struct account);
468 	if (!c_acc) return(NULL);
469 
470 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
471 	fp = fopen(buf, "rb");
472 	if (!fp) {
473 		KILL(c_acc, struct account);
474 		return(NULL); /* cannot access account file */
475 	}
476 	while (fread(c_acc, sizeof(struct account), 1, fp)) {
477 		if (c_acc->flags & ACC_DELD) continue;
478 		if (!strcmp(c_acc->name, name)) {
479 			fclose(fp);
480 			return(c_acc);
481 		}
482 	}
483 	fclose(fp);
484 	KILL(c_acc, struct account);
485 	return(NULL);
486 }
487 
488 /* Check for an account of similar name to 'name'. If one is found, the name
489    will be forbiden to be used, except if 'accname' is identical to the found
490    account's name:
491    If checking for an account name, accname must be NULL.
492    If checking for a character name, accname must be set to its account holder.
493     - C. Blue */
494 /* Super-strict mode? Disallow (non-trivial) char/acc names that only have 1+
495    _letter_ inserted somewhere compared to existing account names */
496 #define STRICT_SIMILAR_NAMES
497 /* Only apply super-strict check above to account names being created,
498    let character names be created without this extra check. */
499 //#define SIMILAR_CHARNAMES_OK
lookup_similar_account(cptr name,cptr accname)500 bool lookup_similar_account(cptr name, cptr accname) {
501 	FILE *fp;
502 	char buf[1024], tmpname[ACCOUNTNAME_LEN > CHARACTERNAME_LEN ? ACCOUNTNAME_LEN : CHARACTERNAME_LEN];
503 	const char *ptr, *ptr2;
504 	struct account *c_acc;
505 	int diff, min;
506 
507 	MAKE(c_acc, struct account);
508 	/* ew, cannot reserve memory! we abuse the return value to cause an
509 	   'invalid account name' style error on purpose in this case, for paranoia */
510 	if (!c_acc) {
511 		s_printf("ERROR: COULDN'T ALLOCATE MEMORY IN lookup_similar_account()!\n");
512 		return TRUE;
513 	}
514 
515 	condense_name(tmpname, name);
516 
517 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
518 	fp = fopen(buf, "rb");
519 	if (!fp) {
520 		KILL(c_acc, struct account);
521 		s_printf("ERROR: COULDN'T ACCESS ACCOUNT FILE IN lookup_similar_account()!\n");
522 		return FALSE; /* cannot access account file */
523 	}
524 	while (fread(c_acc, sizeof(struct account), 1, fp)) {
525 		if (c_acc->flags & ACC_DELD) continue;
526 
527 		/* We may create character names similar to our own account name as we like */
528 		if (accname && !strcmp(c_acc->name, accname)) {
529 			continue;
530 		}
531 
532 #ifdef STRICT_SIMILAR_NAMES
533 		/* Super-strict mode? Disallow (non-trivial) names that only have 1+ letter inserted somewhere */
534 		if (
535  #ifdef SIMILAR_CHARNAMES_OK
536 		    /*only apply this check to account names being created, be lenient for character names */
537 		    !accname &&
538  #endif
539 		    strlen(name) >= 5 && strlen(c_acc->name) >= 5) { //non-trivial length
540 			/* don't exaggerate */
541 			if (strlen(name) > strlen(c_acc->name)) min = strlen(c_acc->name);
542 			else min = strlen(name);
543 
544 			/* '->' */
545 			diff = 0;
546 			ptr2 = name;
547 			for (ptr = c_acc->name; *ptr && *ptr2; ) {
548 				if (tolower(*ptr) != tolower(*ptr2)) diff++;
549 				else ptr++;
550 				ptr2++;
551 			}
552 			//all remaining characters that couldn't be matched are also "different"
553 			while (*ptr++) diff++;
554 			while (*ptr2++) diff++;
555 			//too little difference between account name and this character name? forbidden!
556 			if (diff <= (min - 5) / 2 + 1) {
557 				s_printf("lookup_similar_account (1): name '%s', aname '%s' (tmp '%s')\n", name, c_acc->name, tmpname);
558 				KILL(c_acc, struct account);
559 				return TRUE;
560 			}
561 
562 			/* '<-' */
563 			diff = 0;
564 			ptr2 = c_acc->name;
565 			for (ptr = name; *ptr && *ptr2; ) {
566 				if (tolower(*ptr) != tolower(*ptr2)) diff++;
567 				else ptr++;
568 				ptr2++;
569 			}
570 			//all remaining characters that couldn't be matched are also "different"
571 			while (*ptr++) diff++;
572 			while (*ptr2++) diff++;
573 			//too little difference between account name and this character name? forbidden!
574 			if (diff <= (min - 5) / 2 + 1) {
575 				s_printf("lookup_similar_account (2): name '%s', aname '%s' (tmp '%s')\n", name, c_acc->name, tmpname);
576 				KILL(c_acc, struct account);
577 				return TRUE;
578 			}
579 
580 			/* '='  -- note: weakness here is, the first 2 methods don't combine with this one ;).
581 			   So the checks could be tricked by combining one 'replaced char' with one 'too many char'
582 			   to circumvent the limitations for longer names that usually would require a 3+ difference.. =P */
583 			diff = 0;
584 			ptr2 = c_acc->name;
585 			for (ptr = name; *ptr && *ptr2; ) {
586 				if (tolower(*ptr) != tolower(*ptr2)) diff++;
587 				ptr++;
588 				ptr2++;
589 			}
590 			//all remaining characters that couldn't be matched are also "different"
591 			while (*ptr++) diff++;
592 			while (*ptr2++) diff++;
593 			//too little difference between account name and this character name? forbidden!
594 			if (diff <= (min - 5) / 2 + 1) {
595 				s_printf("lookup_similar_account (3): name '%s', aname '%s' (tmp '%s')\n", name, c_acc->name, tmpname);
596 				KILL(c_acc, struct account);
597 				return TRUE;
598 			}
599 		}
600 #endif
601 
602 		/* Differring normalised names? Skip. */
603 		if (strcmp(c_acc->name_normalised, tmpname)) continue;
604 
605 		/* We found same normalised names. Check! */
606 		fclose(fp);
607 
608 		/* Identical name (account vs character)? that's fine. */
609 		if (!strcmp(c_acc->name, name)) {
610 			KILL(c_acc, struct account);
611 			return FALSE;
612 		}
613 
614 		/* not identical but just too similar? forbidden! */
615 		s_printf("lookup_similar_account (4): name '%s', aname '%s' (tmp '%s')\n", name, c_acc->name, tmpname);
616 		KILL(c_acc, struct account);
617 		return TRUE;
618 	}
619 	fclose(fp);
620 
621 	/* no identical/similar account found, all green! */
622 	KILL(c_acc, struct account);
623 	return FALSE;
624 }
625 
626 /* Return account name of a specified PLAYER id */
lookup_accountname(int p_id)627 cptr lookup_accountname(int p_id) {
628 	FILE *fp;
629 	char buf[1024];
630 	static struct account c_acc;
631 	u32b acc_id = lookup_player_account(p_id);
632 
633 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
634 	fp = fopen(buf, "rb");
635 	if (!fp) return(NULL); /* cannot access account file */
636 	while (fread(&c_acc, sizeof(struct account), 1, fp)) {
637 		if (c_acc.flags & ACC_DELD) continue;
638 		if (c_acc.id == acc_id) {
639 			fclose(fp);
640 			memset(c_acc.pass, 0, sizeof(c_acc.pass));
641 			return(c_acc.name);
642 		}
643 	}
644 	memset(c_acc.pass, 0, sizeof(c_acc.pass));
645 	fclose(fp);
646 	return(NULL);
647 }
648 
649 /* Return account name of a specified account id.
650    Does not return NULL but "" if account doesn't exist! */
lookup_accountname2(u32b acc_id)651 cptr lookup_accountname2(u32b acc_id) {
652 	FILE *fp;
653 	char buf[1024];
654 	static struct account c_acc;
655 
656 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
657 	fp = fopen(buf, "rb");
658 	if (!fp) return(""); /* cannot access account file */
659 	while (fread(&c_acc, sizeof(struct account), 1, fp)) {
660 		if (c_acc.flags & ACC_DELD) continue;
661 		if (c_acc.id == acc_id) {
662 			fclose(fp);
663 			memset(c_acc.pass, 0, sizeof(c_acc.pass));
664 			return(c_acc.name);
665 		}
666 	}
667 	memset(c_acc.pass, 0, sizeof(c_acc.pass));
668 	fclose(fp);
669 	return("");
670 }
671 
672 /* our password encryptor */
t_crypt(char * inbuf,cptr salt)673 static char *t_crypt(char *inbuf, cptr salt) {
674 #ifdef HAVE_CRYPT
675 	static char out[64];
676  #if 1 /* fix for len-1 names */
677 	char setting[3];
678 	/* only 1 character long salt? expand to 2 chars length */
679 	if (!salt[1]) {
680 		setting[0] = '.';
681 		setting[1] = salt[0];
682 		setting[2] = 0;
683 		strcpy(out, (char*)crypt(inbuf, setting));
684 	} else
685  #endif
686  #if 1 /* SPACE _ ! - ' , and probably more as _2nd character_ cause crypt() to return a null pointer ('.' is ok) */
687 	if (!((salt[1] >= 'A' && salt[1] <= 'Z') ||
688 	    (salt[1] >= 'a' && salt[1] <= 'z') ||
689 	    (salt[1] >= '0' && salt[1] <= '9') ||
690 	    salt[1] == '.')) {
691 		char fixed_name[ACCOUNTNAME_LEN];
692 		strcpy(fixed_name, salt);
693 		fixed_name[1] = '.';
694 		strcpy(out, (char*)crypt(inbuf, fixed_name));
695 	} else
696  #endif
697 		strcpy(out, (char*)crypt(inbuf, salt));
698 	return(out);
699 #else
700 	return(inbuf);
701 #endif
702 }
703 
check_account(char * accname,char * c_name)704 int check_account(char *accname, char *c_name) {
705 	struct account *l_acc;
706 	u32b id, a_id;
707 	u32b flags;
708 	hash_entry *ptr;
709 	int i, success = 1;
710 #ifndef RPG_SERVER
711 	int ded_iddc, ded_pvp;
712 #endif
713 
714 	/* Make sure noone creates a character of the same name as another player's accountname!
715 	   This is important for new feat of messaging to an account instead of character name. - C. Blue */
716 	struct account *l2_acc;
717 	char c2_name[MAX_CHARS];
718 	strcpy(c2_name, c_name);
719 //	c2_name[0] = toupper(c2_name[0]);
720 	l_acc = GetAccount(accname, NULL, FALSE);
721 	l2_acc = GetAccount(c2_name, NULL, FALSE);
722 	if (l_acc && l2_acc && l_acc->id != l2_acc->id) {
723 		/* However, since ppl might have already created such characters, only apply this
724 		   rule for newly created characters, to avoid someone being unable to login on
725 		   an already existing character that unfortunately violates this rule :/ */
726 		int *id_list, chars;
727                 chars = player_id_list(&id_list, l_acc->id);
728 		for (i = 0; i < chars; i++)
729 			if (!strcmp(c_name, lookup_player_name(id_list[i]))) break;
730 		if (chars) C_KILL(id_list, chars, int);
731 		if (i == chars) {
732 			if (l_acc) KILL(l_acc, struct account);
733 			if (l2_acc) KILL(l2_acc, struct account);
734 			return 0; /* 'name already in use' */
735 		}
736 	} else if (!l_acc && l2_acc) {
737 		KILL(l2_acc, struct account);
738 		return 0; /* we don't even have an account yet? 'name already in use' for sure */
739 	}
740 	if (l_acc) KILL(l_acc, struct account);
741 	if (l2_acc) KILL(l2_acc, struct account);
742 
743 	if ((l_acc = GetAccount(accname, NULL, FALSE))) {
744 		int *id_list, chars;
745 #ifndef RPG_SERVER
746 		int max_cpa = MAX_CHARS_PER_ACCOUNT, max_cpa_plus = 0, plus_free = 0;
747 #endif
748                 chars = player_id_list(&id_list, l_acc->id);
749 #ifdef RPG_SERVER /* Allow only up to 1 character per account! */
750 		/* If this account DOES have characters, but the chosen character name is
751 		   NOT equal to the first character of this account, don't allow it!
752 		   (To restrict players to only 1 character per account! - C. Blue) */
753 		/* allow multiple chars for admins, even on RPG server */
754 		if ((chars > 0) && strcmp(c_name, lookup_player_name(id_list[0])) && !(l_acc->flags & ACC_ADMIN)) {
755 			C_KILL(id_list, chars, int);
756 			KILL(l_acc, struct account);
757 			return(-1);
758 		}
759 #else
760  #ifdef ALLOW_DED_IDDC_MODE
761 		max_cpa_plus += MAX_DED_IDDC_CHARS;
762 		plus_free += MAX_DED_IDDC_CHARS;
763  #endif
764  #ifdef ALLOW_DED_PVP_MODE
765 		max_cpa_plus += MAX_DED_PVP_CHARS;
766 		plus_free += MAX_DED_PVP_CHARS;
767  #endif
768 
769 		ded_iddc = 0;
770 		ded_pvp = 0;
771 		for (i = 0; i < chars; i++) {
772 			int m = lookup_player_mode(id_list[i]);
773 			if ((m & MODE_DED_IDDC) && ded_iddc < MAX_DED_IDDC_CHARS) {
774 				ded_iddc++;
775 				plus_free--;
776 			}
777 			if ((m & MODE_DED_PVP) && ded_pvp < MAX_DED_PVP_CHARS)  {
778 				ded_pvp++;
779 				plus_free--;
780 			}
781 			/* paranoia (server-client version/type mismatch might cause this in the future) */
782 			if (plus_free < 0) {
783 				s_printf("debug error: plus_free is %d\n", plus_free);
784 				plus_free = 0;
785 			}
786 		}
787 		//s_printf("plus_free=%d, ded_iddc=%d, ded_pvp=%d\n", plus_free, ded_iddc, ded_pvp);
788 		//s_printf("chars=%d, max_cpa=%d, max_cpa_plus=%d\n", chars, max_cpa, max_cpa_plus);
789 
790 		/* no more free chars */
791 		if (chars >= max_cpa + max_cpa_plus) {
792 			for (i = 0; i < chars; i++)
793 				if (!strcmp(c_name, lookup_player_name(id_list[i]))) break;
794 			/* We're out of free character slots: Char creation failed! */
795 			if (i == chars) {
796 				if (chars) C_KILL(id_list, chars, int);
797 				KILL(l_acc, struct account);
798 				return(-3);
799 			}
800 		/* only exclusive char slots left */
801 		} else if (chars >= max_cpa + max_cpa_plus - plus_free) {
802 			/* paranoia (maybe if slot # gets changed again in the future) */
803 			if (ded_iddc == MAX_DED_IDDC_CHARS && ded_pvp == MAX_DED_PVP_CHARS) {
804 				/* out of character slots */
805 				if (chars) C_KILL(id_list, chars, int);
806 				KILL(l_acc, struct account);
807 				return(-3);
808 			}
809 			if (ded_iddc == MAX_DED_IDDC_CHARS) success = -4; /* set char mode to MODE_DED_PVP */
810 			else if (ded_pvp == MAX_DED_PVP_CHARS) success = -5; /* set char mode to MODE_DED_IDDC */
811 			else success = -6; /* char mode can be either, make it depend on user choice */
812 		}
813 		/* at least one non-exclusive slot free */
814 		else {
815  #if 1 /* new: allow any dedicated mode character to be created in 'normal' slots! */
816 			success = -7;
817  #else
818 			if (ded_iddc < MAX_DED_IDDC_CHARS) {
819 				if (ded_pvp < MAX_DED_PVP_CHARS) success = -7; /* allow willing creation of any exlusive slot */
820 				else success = -8; /* allow willing creating of iddc-exclusive slot */
821 			} else if (ded_pvp < MAX_DED_PVP_CHARS) success = -9; /* allow willing creating of pvp-exclusive slot */
822  #endif
823 		}
824 #endif
825 		a_id = l_acc->id;
826 		flags = l_acc->flags;
827 
828 		if (chars) C_KILL(id_list, chars, int);
829 		KILL(l_acc, struct account);
830 
831 		id = lookup_player_id(c_name);
832 		ptr = lookup_player(id);
833 		/* Is the character either new, or is its ID belonging
834 		   to the same account as our account (ie it's us)? */
835 		if (!ptr || ptr->account == a_id) {
836 			/* Cannot create another character while being logged on, if not ACC_MULTI.
837 			   Allow to login with the same name to 'resume connection' though. */
838 			if (!(flags & ACC_MULTI)) {
839 				/* check for login-timing exploit */
840 				if (check_multi_exploit(accname, c_name)) return -2;
841 				/* check for normal ineligible multi-login attempts */
842 				for (i = 1; i <= NumPlayers; i++) {
843 					if (Players[i]->account == a_id && !(flags & ACC_MULTI) && strcmp(c_name, Players[i]->name))
844 						return(-2);
845 				}
846 			}
847 
848 			/* all green */
849 			return(success);
850 		}
851 	}
852 	/* "Name already in use by another player" (coming from 'else' branch above),
853 	   ie character isn't new and it belongs to a different account than ours. */
854 	return(0);
855 }
856 
GetAccountID(u32b id,bool leavepass)857 struct account *GetAccountID(u32b id, bool leavepass){
858 	FILE *fp;
859 	char buf[1024];
860 	struct account *c_acc;
861 
862 	/* we may want to store a local index for fast
863 	   id/name/filepos lookups in the future */
864 	MAKE(c_acc, struct account);
865 	if (!c_acc) return(NULL);
866 
867 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
868 	fp = fopen(buf, "rb");
869 	if (!fp) return(NULL);	/* failed */
870 	while (fread(c_acc, sizeof(struct account), 1, fp)) {
871 		if(id == c_acc->id && !(c_acc->flags & ACC_DELD)){
872 			if (!leavepass) memset(c_acc->pass, 0, sizeof(c_acc->pass));
873 			fclose(fp);
874 			return(c_acc);
875 		}
876 	}
877 	fclose(fp);
878 	KILL(c_acc, struct account);
879 	return(NULL);
880 }
881 
new_accid()882 static u32b new_accid() {
883 	u32b id;
884 	FILE *fp;
885 	char *t_map;
886 	char buf[1024];
887 	struct account t_acc;
888 	int num_entries = 0;
889 	id = account_id;
890 
891 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
892 	fp = fopen(buf, "rb");
893 	if (!fp) return(0L);
894 
895 	C_MAKE(t_map, MAX_ACCOUNTS / 8, char);
896 	while (fread(&t_acc, sizeof(struct account), 1, fp)) {
897 		if (t_acc.flags & ACC_DELD) continue;
898 		t_map[t_acc.id / 8] |= (1 << (t_acc.id % 8));
899 		num_entries++;
900 	}
901 
902 	fclose(fp);
903 
904 	/* HACK - Make account id 1 unavailable if the file is not empty.
905 	 * This prevents the next new player from becoming an admin if the
906 	 * first account is ever deleted.
907 	 *  - mikaelh
908 	 */
909 	if (num_entries) {
910 		t_map[0] |= (1 << 1);
911 	}
912 
913 	/* Make account id 0 unavailable just to be safe */
914 	t_map[0] |= (1 << 0);
915 
916 	/* Find the next free account ID */
917 	for (id = account_id; id < MAX_ACCOUNTS; id++){
918 		if(!(t_map[id / 8] & (1 << (id % 8)))) break;
919 	}
920 
921 	if (id == MAX_ACCOUNTS) {
922 		/* Wrap around */
923 		for (id = 1; id < account_id; id++) {
924 			if (!(t_map[id / 8] & (1 << (id % 8)))) break;
925 		}
926 
927 		/* Oops, no free account IDs */
928 		if (id == account_id) {
929 			s_printf("WARNING: No account ID numbers available!\n");
930 			id = 0;
931 		}
932 	}
933 
934 	C_KILL(t_map, MAX_ACCOUNTS / 8, char);
935 	account_id = id + 1;
936 
937 	return(id); /* temporary */
938 }
939 
940 /*
941  * Lookup a guild number by name.
942  */
guild_lookup(cptr name)943 int guild_lookup(cptr name) {
944 	int i;
945 
946 	/* Check each guild */
947 	for (i = 0; i < MAX_GUILDS; i++) { /* start from 0 or from 1? */
948 		/* Check name */
949 		if (streq(guilds[i].name, name)){
950 			return i;
951 		}
952 	}
953 
954 	/* No match */
955 	return -1;
956 }
957 
958 /*
959  * Lookup a party number by name.
960  */
party_lookup(cptr name)961 int party_lookup(cptr name) {
962 	int i;
963 
964 	/* Check each party */
965 	for (i = 1; i < MAX_PARTIES; i++) { /* was i = 0 but real parties start from i = 1 - mikaelh */
966 		/* Check name */
967 		if (streq(parties[i].name, name))
968 			return i;
969 	}
970 
971 	/* No match */
972 	return -1;
973 }
974 
975 
976 /*
977  * Check for the existence of a player in a party.
978  */
player_in_party(int party_id,int Ind)979 bool player_in_party(int party_id, int Ind) {
980 	player_type *p_ptr = Players[Ind];
981 
982 	/* Check - Fail on non party */
983 	if (party_id && p_ptr->party == party_id)
984 		return TRUE;
985 
986 	/* Not in the party */
987 	return FALSE;
988 }
989 
group_name_legal_characters(cptr name)990 static bool group_name_legal_characters(cptr name) {
991 	const char *ptr;
992 
993 	/* remove special chars that are used for parsing purpose */
994 	for (ptr = &name[strlen(name)]; ptr-- > name; )
995 		if (!((*ptr >= 'A' && *ptr <= 'Z') ||
996 		    (*ptr >= 'a' && *ptr <= 'z') ||
997 		    (*ptr >= '0' && *ptr <= '9') ||
998 		    strchr(" .,-'&_$%~#<>|", *ptr))) /* chars allowed for character name */
999 			return FALSE;
1000 	return TRUE;
1001 }
1002 
guild_name_legal(int Ind,char * name)1003 static bool guild_name_legal(int Ind, char *name) {
1004 	int index;
1005 	char *ptr, buf[NAME_LEN];
1006 	player_type *p_ptr = Players[Ind];
1007 	object_type forge, *o_ptr = &forge;
1008 
1009 	char buf2[NAME_LEN], *ptr2;
1010 	int diff, min;
1011 
1012 
1013 	if (strlen(name) >= NAME_LEN) {
1014 		msg_format(Ind, "\377yGuild name must not exceed %d characters!", NAME_LEN - 1);
1015 		return FALSE;
1016 	}
1017 
1018 	strncpy(buf, name, NAME_LEN);
1019 	buf[NAME_LEN - 1] = '\0';
1020 	/* remove spaces at the beginning */
1021 	for (ptr = buf; ptr < buf + strlen(buf); ) {
1022 		if (isspace(*ptr)) ptr++;
1023 		else break;
1024 	}
1025 	strcpy(buf, ptr);
1026 	/* remove spaces at the end */
1027 	for (ptr = buf + strlen(buf); ptr-- > buf; ) {
1028 		if (isspace(*ptr)) *ptr = '\0';
1029 		else break;
1030 	}
1031 	/* name consisted only of spaces? */
1032 	if (!buf[0]) {
1033 		msg_print(Ind, "\377ySorry, names must not just consist of spaces.");
1034 		return FALSE;
1035 	}
1036 	strcpy(name, buf);
1037 
1038 	/* Check for weird characters */
1039 	if (!group_name_legal_characters(name)) {
1040 		msg_print(Ind, "\377ySorry, that name contains illegal characters or symbols.");
1041 		return FALSE;
1042 	}
1043 
1044 	/* Prevent abuse */
1045 	if (ILLEGAL_GROUP_NAME(name)) {
1046 		msg_print(Ind, "\377yThat's not a legal guild name, please try again.");
1047 		return FALSE;
1048 	}
1049 
1050 	/* Check for already existing party by that name */
1051 	if (party_lookup(name) != -1) {
1052 		msg_print(Ind, "\377yThere's already a party using that name.");
1053 		return FALSE;
1054 	}
1055 
1056 	/* Check for already existing guild by that name */
1057 	if ((index = guild_lookup(name) != -1)) {
1058 		/* Admin can actually create a duplicate 'spare' key this way */
1059 		if (p_ptr->admin_dm) {
1060 			/* make the guild key */
1061 			invcopy(o_ptr, lookup_kind(TV_KEY, SV_GUILD_KEY));
1062 			o_ptr->number = 1;
1063 			o_ptr->pval = index;
1064 			o_ptr->level = 1;
1065 			o_ptr->owner = p_ptr->id;
1066 			o_ptr->mode = p_ptr->mode;
1067 			object_known(o_ptr);
1068 			object_aware(Ind, o_ptr);
1069 			(void)inven_carry(Ind, o_ptr);
1070 			msg_print(Ind, "Spare key created.");
1071 			return FALSE;
1072 		}
1073 		msg_print(Ind, "\377yA guild by that name already exists.");
1074 		return FALSE;
1075 	}
1076 
1077 	/* Check for already existing guild with too similar name */
1078 	condense_name(buf, name);
1079 	/* Check each guild */
1080 	for (index = 0; index < MAX_GUILDS; index++) {
1081 		/* for renaming a guild: skip similarity-check if it's our own guild! */
1082 		if (guilds[index].master == p_ptr->id) continue;
1083 
1084 		/* compare condensed names */
1085 		condense_name(buf2, guilds[index].name);
1086 		if (!strcmp(buf, buf2)) {
1087 			msg_print(Ind, "\377yA guild by a too similar name already exists.");
1088 			return FALSE;
1089 		}
1090 
1091 //#ifdef STRICT_SIMILAR_NAMES
1092 #if 1
1093 		/* Super-strict mode? Disallow (non-trivial) names that only have 1+ letter inserted somewhere */
1094 		if (
1095  #if 1
1096 		    TRUE &&
1097  #else
1098  //#ifdef SIMILAR_CHARNAMES_OK
1099 		    FALSE &&
1100  #endif
1101 		    strlen(buf) >= 5 && strlen(buf2) >= 5) { //non-trivial length
1102 			/* don't exaggerate */
1103 			if (strlen(buf) > strlen(buf2)) min = strlen(buf2);
1104 			else min = strlen(buf);
1105 
1106 			/* '->' */
1107 			diff = 0;
1108 			ptr2 = buf;
1109 			for (ptr = buf2; *ptr && *ptr2; ) {
1110 				if (tolower(*ptr) != tolower(*ptr2)) diff++;
1111 				else ptr++;
1112 				ptr2++;
1113 			}
1114 			//all remaining characters that couldn't be matched are also "different"
1115 			while (*ptr++) diff++;
1116 			while (*ptr2++) diff++;
1117 			//too little difference between account name and this character name? forbidden!
1118 			if (diff <= (min - 5) / 2 + 1) {
1119 				s_printf("similar guild? (1): ngname '%s', ogname '%s'\n", buf, buf2);
1120 				msg_print(Ind, "\377yA guild by a too similar name already exists.");
1121 				return FALSE;
1122 			}
1123 
1124 			/* '<-' */
1125 			diff = 0;
1126 			ptr2 = buf2;
1127 			for (ptr = buf; *ptr && *ptr2; ) {
1128 				if (tolower(*ptr) != tolower(*ptr2)) diff++;
1129 				else ptr++;
1130 				ptr2++;
1131 			}
1132 			//all remaining characters that couldn't be matched are also "different"
1133 			while (*ptr++) diff++;
1134 			while (*ptr2++) diff++;
1135 			//too little difference between account name and this character name? forbidden!
1136 			if (diff <= (min - 5) / 2 + 1) {
1137 				s_printf("similar guild? (2): ngname '%s', ogname '%s'\n", buf, buf2);
1138 				msg_print(Ind, "\377yA guild by a too similar name already exists.");
1139 				return FALSE;
1140 			}
1141 
1142 			/* '='  -- note: weakness here is, the first 2 methods don't combine with this one ;).
1143 			   So the checks could be tricked by combining one 'replaced char' with one 'too many char'
1144 			   to circumvent the limitations for longer names that usually would require a 3+ difference.. =P */
1145 			diff = 0;
1146 			ptr2 = buf2;
1147 			for (ptr = buf; *ptr && *ptr2; ) {
1148 				if (tolower(*ptr) != tolower(*ptr2)) diff++;
1149 				ptr++;
1150 				ptr2++;
1151 			}
1152 			//all remaining characters that couldn't be matched are also "different"
1153 			while (*ptr++) diff++;
1154 			while (*ptr2++) diff++;
1155 			//too little difference between account name and this character name? forbidden!
1156 			if (diff <= (min - 5) / 2 + 1) {
1157 				s_printf("similar guild? (3): ngname '%s', ogname '%s'\n", buf, buf2);
1158 				msg_print(Ind, "\377yA guild by a too similar name already exists.");
1159 				return FALSE;
1160 			}
1161 		}
1162 #endif
1163 	}
1164 
1165 	return TRUE;
1166 }
1167 
1168 /*
1169  * Create a new guild.
1170  */
guild_create(int Ind,cptr name)1171 int guild_create(int Ind, cptr name) {
1172 	player_type *p_ptr = Players[Ind];
1173 	int index = 0, i, j;
1174 	object_type forge, *o_ptr = &forge;
1175 	char temp[160];
1176 	struct account *acc;
1177 	int *id_list, ids;
1178 
1179 	strcpy(temp, name);
1180 	if (!guild_name_legal(Ind, temp)) return FALSE;
1181 
1182 	/* zonk */
1183 	if ((p_ptr->mode & MODE_PVP)) {
1184 		msg_print(Ind, "\377yPvP characters may not create a guild.");
1185 		return FALSE;
1186 	}
1187 
1188 	/* anti-cheeze: People could get an extra house on each character.
1189 	   So we allow only one guild master per player account to at least
1190 	   reduce the nonsense to 1 extra house per Account.. */
1191 	acc = GetAccount(p_ptr->accountname, NULL, FALSE);
1192 	/* paranoia */
1193 	if (!acc) {
1194 		/* uhh.. */
1195 		msg_print(Ind, "Sorry, guild creation has failed.");
1196 		return FALSE;
1197 	}
1198 	ids = player_id_list(&id_list, acc->id);
1199 	for (i = 0; i < ids; i++) {
1200 		if ((j = lookup_player_guild(id_list[i])) && /* one of his characters is in a guild.. */
1201 		    guilds[j].master == id_list[i]) { /* ..and he is actually the master of that guild? */
1202 			msg_print(Ind, "\377yOnly one character per account is allowed to be a guild master.");
1203 			return FALSE;
1204 		}
1205 	}
1206 	if (ids) C_KILL(id_list, ids, int);
1207 	KILL(acc, struct account);
1208 
1209 	/* Make sure this guy isn't in some other guild already */
1210 	if (p_ptr->guild != 0) {
1211 		msg_print(Ind, "\377yYou already belong to a guild!");
1212 		return FALSE;
1213 	}
1214 	if (p_ptr->lev < 30) {
1215 		msg_print(Ind, "\377yYou are not high enough level to start a guild.");
1216 		return FALSE;
1217 	}
1218 	/* This could probably be improved. */
1219 	if (p_ptr->au < GUILD_PRICE) {
1220 		if (GUILD_PRICE >= 1000000)
1221 			msg_format(Ind, "\377yYou need %d,000,000 gold pieces to start a guild.", GUILD_PRICE / 1000000);
1222 		else if (GUILD_PRICE >= 1000)
1223 			msg_format(Ind, "\377yYou need %d,000 gold pieces to start a guild.", GUILD_PRICE / 1000);
1224 		else
1225 			msg_format(Ind, "\377yYou need %d gold pieces to start a guild.", GUILD_PRICE);
1226 		return FALSE;
1227 	}
1228 
1229 	/* Find the "best" party index */
1230 	for (i = 1; i < MAX_GUILDS; i++) {
1231 		if (guilds[i].members == 0) {
1232 			index = i;
1233 			break;
1234 		}
1235 	}
1236 	/* Make sure we found an empty slot */
1237 	if (index == 0) {
1238 		/* Error */
1239 		msg_print(Ind, "\377yThere aren't enough guild slots!");
1240 		return FALSE;
1241 	}
1242 
1243 
1244 	/* Set guild identity */
1245 	guilds[index].dna = rand_int(0xFFFF) << 16;
1246 	guilds[index].dna += rand_int(0xFFFF);
1247 
1248 	/* Set guild name */
1249 	strcpy(guilds[index].name, temp);
1250 
1251 	/* Set guildmaster */
1252 	guilds[index].master = p_ptr->id;
1253 	guilds[index].cmode = p_ptr->mode;
1254 
1255 	/* Init guild hall, flags & level */
1256 	guilds[index].h_idx = 0;
1257 	guilds[index].flags = 0;
1258 	guilds[index].minlev = 0;
1259 
1260 	/* Add the owner as a member */
1261 	p_ptr->guild = index;
1262 	p_ptr->guild_dna = guilds[index].dna;
1263 	clockin(Ind, 3);
1264 	guilds[index].members = 1;
1265 
1266 	/* Set guild mode */
1267 	if ((p_ptr->mode & MODE_EVERLASTING))
1268 		guilds[index].flags |= GFLG_EVERLASTING;
1269 
1270 	Send_guild(Ind, FALSE, FALSE);
1271 	Send_guild_config(index);
1272 
1273 	/* broadcast the news */
1274 	snprintf(temp, 160, "\374\377yA new guild '\377%c%s\377y' has been created.", COLOUR_CHAT_GUILD, guilds[index].name);
1275 	msg_broadcast(0, temp);
1276 //	msg_print(Ind, "\374\377Gou can adjust guild options with the '/guild_cfg' command.");
1277 	s_printf("GUILD_CREATE: (by %s) '%s'\n", p_ptr->name, guilds[index].name);
1278 	l_printf("%s \\{yA new guild '%s' has been created\n", showdate(), guilds[index].name);
1279 
1280 	p_ptr->au -= GUILD_PRICE;
1281 	p_ptr->redraw |= PR_GOLD;
1282 
1283 	/* make the guild key */
1284 	invcopy(o_ptr, lookup_kind(TV_KEY, SV_GUILD_KEY));
1285 	o_ptr->number = 1;
1286 	o_ptr->pval = index;
1287 	o_ptr->level = 1;
1288 	o_ptr->owner = p_ptr->id;
1289 	o_ptr->mode = p_ptr->mode;
1290 	object_known(o_ptr);
1291 	object_aware(Ind, o_ptr);
1292 	(void)inven_carry(Ind, o_ptr);
1293 
1294 	/* Give the guildmaster some scrolls for a hall */
1295 #if 0	//scrolls are broken
1296 	invcopy(o_ptr, lookup_kind(TV_SCROLL, SV_SCROLL_HOUSE));
1297 	o_ptr->number = 6;
1298 	o_ptr->level = p_ptr->lev;
1299 	o_ptr->owner = p_ptr->id;
1300 	o_ptr->mode = p_ptr->mode;
1301 	o_ptr->discount = 50;
1302 	object_known(o_ptr);
1303 	object_aware(Ind, o_ptr);
1304 	(void)inven_carry(Ind, o_ptr);
1305 #endif
1306 
1307 	return(TRUE);
1308 }
1309 
1310 /*
1311  * New party check function - to be timed
1312  *
1313  */
party_check(int Ind)1314 void party_check(int Ind) {
1315 	int i, id;
1316 	for (i = 1; i < MAX_PARTIES; i++) {
1317 		if (parties[i].members != 0){
1318 			if (!(id = lookup_player_id(parties[i].owner))) {
1319 				msg_format(Ind, "Lost party %s (%s)", parties[i].name, parties[i].owner);
1320 				del_party(i);
1321 			} else {
1322 				if ((lookup_player_party(id) != i)) {
1323 					msg_format(Ind, "Disowned party %s (%s)", parties[i].name, parties[i].owner);
1324 					del_party(i);
1325 				}
1326 			}
1327 		}
1328 	}
1329 }
1330 
1331 /*
1332  * as with party checker, scan ALL player entries
1333  * if they are not linked to an existing account,
1334  * delete them.
1335  */
account_check(int Ind)1336 void account_check(int Ind) { /* Temporary Ind */
1337 	hash_entry *ptr;
1338 	int i, del;
1339 	struct account *c_acc;
1340 //	player_type *p_ptr = Players[Ind];
1341 
1342 	/* Search in each array slot */
1343 	for (i = 0; i < NUM_HASH_ENTRIES; i++) {
1344 		/* Acquire pointer to this chain */
1345 		ptr = hash_table[i];
1346 
1347 		/* Check all entries in this chain */
1348 		while (ptr) {
1349 			/* Check this name */
1350 			if (!(c_acc = GetAccountID(ptr->account, FALSE))) {
1351 				s_printf("Lost player: %s\n", ptr->name);
1352 				msg_format(Ind, "Lost player: %s", ptr->name);
1353 #if 0 /* del might not always be initialized! */
1354 				del = ptr->id;
1355 			} else KILL(c_acc, struct account);
1356 
1357 			/* Next entry in chain */
1358 			ptr = ptr->next;
1359 			delete_player_id(del);
1360 #else /* isn't it supposed to be this way instead?: */
1361 				del = ptr->id;
1362 				delete_player_id(del);
1363 			} else KILL(c_acc, struct account);
1364 
1365 			/* Next entry in chain */
1366 			ptr = ptr->next;
1367 #endif
1368 		}
1369 	}
1370 }
1371 
1372 /*
1373  * Create a new party, owned by "Ind", and called
1374  * "name".
1375  */
party_create(int Ind,cptr name)1376 int party_create(int Ind, cptr name) {
1377 	player_type *p_ptr = Players[Ind];
1378 	int index = 0, i, oldest = turn;
1379 
1380 	char *ptr, buf[NAME_LEN];
1381 	if (strlen(name) >= NAME_LEN) {
1382 		msg_format(Ind, "\377yParty name must not exceed %d characters!", NAME_LEN - 1);
1383 		return FALSE;
1384 	}
1385 	strncpy(buf, name, NAME_LEN);
1386 	buf[NAME_LEN - 1] = '\0';
1387 	/* remove spaces at the beginning */
1388 	for (ptr = buf; ptr < buf + strlen(buf); ) {
1389 		if (isspace(*ptr)) ptr++;
1390 		else break;
1391 	}
1392 	strcpy(buf, ptr);
1393 	/* remove spaces at the end */
1394 	for (ptr = buf + strlen(buf); ptr-- > buf; ) {
1395 		if (isspace(*ptr)) *ptr = '\0';
1396 		else break;
1397 	}
1398 	name = buf;
1399 
1400 	/* Check for weird characters */
1401 	if (!group_name_legal_characters(name)) {
1402 		msg_print(Ind, "\377ySorry, that name contains illegal characters or symbols.");
1403 		return FALSE;
1404 	}
1405 	/* Prevent abuse */
1406 	if (ILLEGAL_GROUP_NAME(name)) {
1407 		msg_print(Ind, "\377yThat's not a legal party name, please try again.");
1408 		return FALSE;
1409 	}
1410 
1411 	/* Check for already existing party by that name */
1412 	if (party_lookup(name) != -1) {
1413 		msg_print(Ind, "\377yA party by that name already exists.");
1414 		return FALSE;
1415 	}
1416 	/* Check for already existing guild by that name */
1417 	if (guild_lookup(name) != -1) {
1418 		msg_print(Ind, "\377yThere's already a guild using that name.");
1419 		return FALSE;
1420 	}
1421 
1422         /* If he's party owner, it's name change */
1423 	if (streq(parties[p_ptr->party].owner, p_ptr->name)) {
1424 		if (parties[p_ptr->party].mode != PA_NORMAL) {
1425 			msg_print(Ind, "\377yYour party is an Iron Team. Choose '2) Create an Iron Team' instead.");
1426 			return FALSE;
1427 		}
1428 
1429 		strcpy(parties[p_ptr->party].name, name);
1430 
1431 		/* Tell the party about its new name */
1432 		party_msg_format(p_ptr->party, "\377%cYour party is now called '%s'.", COLOUR_CHAT_GUILD, name);
1433 
1434 		Send_party(Ind, FALSE, FALSE);
1435 		return TRUE;
1436 	}
1437 
1438 	/* Make sure this guy isn't in some other party already */
1439 	if (p_ptr->party != 0) {
1440 		msg_print(Ind, "\377yYou already belong to a party!");
1441 		return FALSE;
1442 	}
1443 
1444 	/* Find the "best" party index */
1445 	for (i = 1; i < MAX_PARTIES; i++) {
1446 		/* Check deletion time of disbanded parties */
1447 		if (parties[i].members == 0 && parties[i].created < oldest) {
1448 			/* Track oldest */
1449 			oldest = parties[i].created;
1450 			index = i;
1451 		}
1452 	}
1453 
1454 	/* Make sure we found an empty slot */
1455 	if (index == 0 || oldest == turn) {
1456 		/* Error */
1457 		msg_print(Ind, "\377yThere aren't enough party slots!");
1458 		return FALSE;
1459 	}
1460 
1461 	/* Set party name */
1462 	strcpy(parties[index].name, name);
1463 
1464 	/* Set owner name */
1465 	strcpy(parties[index].owner, p_ptr->name);
1466 
1467 	/* Set mode to normal */
1468 	parties[index].mode = PA_NORMAL;
1469 	parties[index].cmode = p_ptr->mode;
1470 
1471 	/* Add the owner as a member */
1472 	p_ptr->party = index;
1473 	parties[index].members = 1;
1474 	clockin(Ind, 2);
1475 
1476 	/* Set the "creation time" */
1477 	parties[index].created = turn;
1478 
1479 	/* Resend party info */
1480 	Send_party(Ind, FALSE, FALSE);
1481 
1482 	/* Success */
1483 	return TRUE;
1484 }
1485 
party_create_ironteam(int Ind,cptr name)1486 int party_create_ironteam(int Ind, cptr name) {
1487 	player_type *p_ptr = Players[Ind];
1488 	int index = 0, i, oldest = turn;
1489 
1490 	char *ptr, buf[NAME_LEN];
1491 	strcpy(buf, name);
1492 	/* remove spaces at the beginning */
1493 	for (ptr = buf; ptr < buf + strlen(buf); ) {
1494 		if (isspace(*ptr)) ptr++;
1495 		else break;
1496 	}
1497 	strcpy(buf, ptr);
1498 	/* remove spaces at the end */
1499 	for (ptr = buf + strlen(buf); ptr-- > buf; ) {
1500 		if (isspace(*ptr)) *ptr = '\0';
1501 		else break;
1502 	}
1503 	name = buf;
1504 
1505 	/* Only newly created characters can create an iron team */
1506 	if (p_ptr->max_exp > 0 || p_ptr->max_plv > 1) {
1507 		msg_print(Ind, "\377yOnly newly created characters without experience can create an iron team.");
1508 		return FALSE;
1509 	}
1510 
1511 	/* Check for weird characters */
1512 	if (!group_name_legal_characters(name)) {
1513 		msg_print(Ind, "\377ySorry, that name contains illegal characters or symbols.");
1514 		return FALSE;
1515 	}
1516 	/* Prevent abuse */
1517 	if (ILLEGAL_GROUP_NAME(name)) {
1518 		msg_print(Ind, "\377yThat's not a legal party name, please try again.");
1519 		return FALSE;
1520 	}
1521 
1522 	/* Check for already existing party by that name */
1523 	if (party_lookup(name) != -1) {
1524 		msg_print(Ind, "\377yA party by that name already exists.");
1525 		return FALSE;
1526 	}
1527 
1528         /* If he's party owner, it's name change */
1529 	if (streq(parties[p_ptr->party].owner, p_ptr->name)) {
1530 		if (parties[p_ptr->party].mode != PA_IRONTEAM) {
1531 			msg_print(Ind, "\377yYour party isn't an Iron Team. Choose '1) Create a party' instead.");
1532 			return FALSE;
1533 		}
1534 
1535 		strcpy(parties[p_ptr->party].name, name);
1536 
1537 		/* Tell the party about its new name */
1538 		party_msg_format(p_ptr->party, "\377%cYour iron team is now called '%s'.", COLOUR_CHAT_GUILD, name);
1539 
1540 		Send_party(Ind, FALSE, FALSE);
1541 		return TRUE;
1542 	}
1543 
1544 	/* Make sure this guy isn't in some other party already */
1545 	if (p_ptr->party != 0) {
1546 		msg_print(Ind, "\377yYou already belong to a party!");
1547 		return FALSE;
1548 	}
1549 
1550 	/* Find the "best" party index */
1551 	for (i = 1; i < MAX_PARTIES; i++) {
1552 		/* Check deletion time of disbanded parties */
1553 		if (parties[i].members == 0 && parties[i].created < oldest) {
1554 			/* Track oldest */
1555 			oldest = parties[i].created;
1556 			index = i;
1557 		}
1558 	}
1559 
1560 	/* Make sure we found an empty slot */
1561 	if (index == 0 || oldest == turn) {
1562 		/* Error */
1563 		msg_print(Ind, "\377yThere aren't enough party slots!");
1564 		return FALSE;
1565 	}
1566 
1567 	/* Set party name */
1568 	strcpy(parties[index].name, name);
1569 
1570 	/* Set owner name */
1571 	strcpy(parties[index].owner, p_ptr->name);
1572 
1573 	/* Set mode to iron team */
1574 	parties[index].mode = PA_IRONTEAM;
1575 	parties[index].cmode = p_ptr->mode;
1576 
1577 	/* Initialize max exp */
1578 	parties[index].experience = 0;
1579 
1580 	/* Add the owner as a member */
1581 	p_ptr->party = index;
1582 	parties[index].members = 1;
1583 	clockin(Ind, 2);
1584 
1585 	/* Set the "creation time" */
1586 	parties[index].created = turn;
1587 
1588 	/* Resend party info */
1589 	Send_party(Ind, FALSE, FALSE);
1590 
1591 	/* Success */
1592 	return TRUE;
1593 }
1594 
1595 /*
1596  * Add player to a guild
1597  */
1598 /* Allow the guild master or an added to use any other character on their
1599    account too, as long as they are guild members, to add other players? */
1600 #define GUILD_ELIGIBLE_ACCOUNT_CAN_ADD
guild_add(int adder,cptr name)1601 int guild_add(int adder, cptr name) {
1602 	player_type *p_ptr;
1603 	player_type *q_ptr = Players[adder];
1604 	int guild_id = q_ptr->guild, Ind = 0, i;
1605 #ifdef GUILD_ELIGIBLE_ACCOUNT_CAN_ADD
1606 	int *id_list, ids;
1607 	struct account *acc;
1608 	bool far_success = FALSE;
1609 #endif
1610 
1611 	if (!guild_id) {
1612 		msg_print(adder, "\377yYou are not in a guild");
1613 		return(FALSE);
1614 	}
1615 
1616 	Ind = name_lookup_loose(adder, name, FALSE, TRUE);
1617 	if (Ind <= 0) return FALSE;
1618 	p_ptr = Players[Ind];
1619 
1620 	/* Leaderless guilds do not allow addition of new members */
1621 	if (!lookup_player_name(guilds[guild_id].master)) {
1622 		msg_print(adder, "\377yNo new members can be added while the guild is leaderless.");
1623 		return FALSE;
1624 	}
1625 
1626 	/* Everlasting and other chars cannot be in the same guild */
1627 	if (compat_pmode(adder, Ind, TRUE)) {
1628 		msg_format(adder, "\377yYou cannot add %s characters to this guild.", compat_pmode(adder, Ind, TRUE));
1629 		return FALSE;
1630 	}
1631 
1632 	/* Make sure this added person is neutral */
1633 	if (p_ptr->guild != 0) {
1634 		/* Message */
1635 		if (p_ptr->guild != guild_id) msg_print(adder, "\377yThat player is already in a guild.");
1636 		else msg_print(adder, "\377yThat player is already in your guild.");
1637 
1638 		/* Abort */
1639 		return FALSE;
1640 	}
1641 
1642 	if (p_ptr->lev < guilds[guild_id].minlev) {
1643 		msg_format(adder, "\377yThat player does not meet the minimum level requirements, %d, of the guild.", guilds[guild_id].minlev);
1644 		return FALSE;
1645 	}
1646 
1647 #ifdef GUILD_ELIGIBLE_ACCOUNT_CAN_ADD
1648 	/* check if he has a character in there already, to be eligible to self-add */
1649 	acc = GetAccount(q_ptr->accountname, NULL, FALSE);
1650 	/* paranoia */
1651 	if (!acc) {
1652 		/* uhh.. */
1653 		msg_print(Ind, "Sorry, self-adding has failed.");
1654 		return FALSE;
1655 	}
1656 	ids = player_id_list(&id_list, acc->id);
1657 	for (i = 0; i < ids; i++) {
1658                 if (lookup_player_guild(id_list[i]) != guild_id) continue;
1659 
1660 		if (id_list[i] != guilds[guild_id].master &&
1661 		    (!(guilds[guild_id].flags & GFLG_ALLOW_ADDERS) ||
1662 		    !(lookup_player_guildflags(id_list[i]) & PGF_ADDER)))
1663 			continue;
1664 
1665 		/* Log - security */
1666 		s_printf("GUILD_ADD_FAR: %s has been added to %s by %s.\n", p_ptr->name, guilds[guild_id].name, q_ptr->name);
1667 		far_success = TRUE;
1668 		break;
1669         }
1670         if (ids) C_KILL(id_list, ids, int);
1671         KILL(acc, struct account);
1672         /* failure? */
1673         if (!far_success)
1674 #endif
1675 
1676 	/* Make sure this isn't an impostor */
1677 	if (!((guilds[guild_id].flags & GFLG_ALLOW_ADDERS) && (q_ptr->guild_flags & PGF_ADDER))
1678 	    && guilds[guild_id].master != q_ptr->id
1679 	    && !is_admin(q_ptr)) {
1680 		msg_print(adder, "\377yYou cannot add new members.");
1681 		return FALSE;
1682 	}
1683 
1684 	/* Ignoring a player will prevent getting added to a party by him */
1685 	if (check_ignore(Ind, adder)) return FALSE;
1686 
1687 	/* Log - security */
1688 	if (!far_success) s_printf("GUILD_ADD: %s has been added to %s by %s.\n", p_ptr->name, guilds[guild_id].name, q_ptr->name);
1689 
1690 	/* Tell the guild about its new member */
1691 	guild_msg_format(guild_id, "\374\377y%s has been added to %s by %s.", p_ptr->name, guilds[guild_id].name, q_ptr->name);
1692 
1693 	/* One more player in this guild */
1694 	guilds[guild_id].members++;
1695 
1696 	/* Tell him about it */
1697 	msg_format(Ind, "\374\377yYou've been added to '%s' by %s.", guilds[guild_id].name, q_ptr->name);
1698 
1699 	/* Set his guild number */
1700 	p_ptr->guild = guild_id;
1701 	p_ptr->guild_dna = guilds[guild_id].dna;
1702 	clockin(Ind, 3);
1703 
1704 	/* Resend info */
1705 	Send_guild(Ind, FALSE, FALSE);
1706 
1707 	/* Display the guild note to him */
1708 	for (i = 0; i < MAX_GUILDNOTES; i++) {
1709 		if (!strcmp(guild_note_target[i], guilds[p_ptr->guild].name)) {
1710 			if (strcmp(guild_note[i], ""))
1711 				msg_format(Ind, "\374\377bGuild Note: %s", guild_note[i]);
1712 			break;
1713 		}
1714 	}
1715 
1716 	/* Re-check house permissions, to display doors in correct colour */
1717 	if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
1718 
1719 	/* Success */
1720 	return TRUE;
1721 }
guild_add_self(int Ind,cptr guild)1722 int guild_add_self(int Ind, cptr guild) {
1723 	player_type *p_ptr = Players[Ind];
1724 	int guild_id = guild_lookup(guild), i, *id_list, ids;
1725 	struct account *acc;
1726 	bool member = FALSE;
1727 
1728 	/* no guild name specified? */
1729 	if (!guild[0]) return FALSE;
1730 
1731 	if (guild_id == -1) {
1732 		msg_print(Ind, "That guild does not exist.");
1733 		return FALSE;
1734 	}
1735 
1736 	if (p_ptr->lev < guilds[guild_id].minlev) {
1737 		msg_format(Ind, "\377yYou do not meet the minimum level requirements, %d, of the guild.", guilds[guild_id].minlev);
1738 		return FALSE;
1739 	}
1740 
1741 	/* check if he has a character in there already, to be eligible to self-add */
1742 	acc = GetAccount(p_ptr->accountname, NULL, FALSE);
1743 	/* paranoia */
1744 	if (!acc) {
1745 		/* uhh.. */
1746 		msg_print(Ind, "Sorry, self-adding has failed.");
1747 		return FALSE;
1748 	}
1749 	ids = player_id_list(&id_list, acc->id);
1750 	for (i = 0; i < ids; i++) {
1751                 if (lookup_player_guild(id_list[i]) == guild_id) {
1752 			member = TRUE;
1753 
1754 			/* Everlasting and other chars cannot be in the same guild */
1755 			if (compat_mode(p_ptr->mode, lookup_player_mode(id_list[i]))) {
1756 				msg_format(Ind, "\377yYou cannot join %s guilds.", compat_mode(p_ptr->mode, lookup_player_mode(id_list[i])));
1757 				KILL(acc, struct account);
1758 				return FALSE;
1759 			}
1760 
1761 			/* player is guild master? -> ok */
1762 			if (id_list[i] == guilds[guild_id].master) {
1763 				/* Log - security */
1764 				s_printf("GUILD_ADD_SELF: (master) %s has been added to %s.\n", p_ptr->name, guilds[guild_id].name);
1765 
1766 				/* success */
1767 				break;
1768 			}
1769 			/* Make sure this isn't an impostor */
1770 			if (!(guilds[guild_id].flags & GFLG_ALLOW_ADDERS)) continue;
1771 			if (!(lookup_player_guildflags(id_list[i]) & PGF_ADDER)) continue;
1772 
1773 			/* Log - security */
1774 			s_printf("GUILD_ADD_SELF: (adder) %s has been added to %s.\n", p_ptr->name, guilds[guild_id].name);
1775 
1776 			/* success */
1777 			break;
1778                 }
1779         }
1780         if (ids) C_KILL(id_list, ids, int);
1781         KILL(acc, struct account);
1782         /* failure? */
1783         if (i == ids) {
1784 		if (!member) msg_print(Ind, "You do not have any character that is member of that guild.");
1785 		else msg_print(Ind, "You have no character in that guild that is allowed to add others.");
1786 		return FALSE;
1787         }
1788 
1789 	/* Tell the guild about its new member */
1790 	guild_msg_format(guild_id, "\374\377y%s has been added to %s.", p_ptr->name, guilds[guild_id].name);
1791 
1792 	/* One more player in this guild */
1793 	guilds[guild_id].members++;
1794 
1795 	/* Tell him about it */
1796 	msg_format(Ind, "\374\377yYou've been added to '%s'.", guilds[guild_id].name);
1797 
1798 	/* Set his guild number */
1799 	p_ptr->guild = guild_id;
1800 	p_ptr->guild_dna = guilds[guild_id].dna;
1801 	clockin(Ind, 3);
1802 
1803 	/* Resend info */
1804 	Send_guild(Ind, FALSE, FALSE);
1805 
1806 	/* Display the guild note to him */
1807 	for (i = 0; i < MAX_GUILDNOTES; i++) {
1808 		if (!strcmp(guild_note_target[i], guilds[p_ptr->guild].name)) {
1809 			if (strcmp(guild_note[i], ""))
1810 				msg_format(Ind, "\374\377bGuild Note: %s", guild_note[i]);
1811 			break;
1812 		}
1813 	}
1814 
1815 	/* Re-check house permissions, to display doors in correct colour */
1816 	if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
1817 
1818 	/* Success */
1819 	return TRUE;
1820 }
1821 
guild_auto_add(int Ind,int guild_id,char * message)1822 int guild_auto_add(int Ind, int guild_id, char *message) {
1823 	player_type *p_ptr = Players[Ind];
1824 	int i;
1825 
1826 	/* paranoia */
1827 	if (!guild_id) return FALSE;
1828 	if (p_ptr->guild) return FALSE;
1829 
1830 	if (!(guilds[guild_id].flags & GFLG_AUTO_READD)) return FALSE;
1831 
1832 	/* currently not eligible */
1833 	if (p_ptr->mode & MODE_PVP) return FALSE;
1834 
1835 	/* Everlasting and other chars cannot be in the same guild */
1836 	if (guilds[guild_id].flags & GFLG_EVERLASTING) {
1837 		if (!(p_ptr->mode & MODE_EVERLASTING)) return FALSE;
1838 	} else
1839 		if ((p_ptr->mode & MODE_EVERLASTING)) return FALSE;
1840 
1841 	/* Log - security */
1842 	s_printf("GUILD_ADD_AUTO: %s has been added to %s.\n", p_ptr->name, guilds[guild_id].name);
1843 
1844 	/* Tell the guild about its new member */
1845 	//sprintf(message, "\374\377y%s has been auto-added to %s.", p_ptr->name, guilds[guild_id].name);
1846 	//guild_msg_format(guild_id, "\374\377y%s has been auto-added to %s.", p_ptr->name, guilds[guild_id].name);
1847 	guild_msg_format(guild_id, "\374\377y%s has been added to %s.", p_ptr->name, guilds[guild_id].name);
1848 
1849 	/* One more player in this guild */
1850 	guilds[guild_id].members++;
1851 
1852 	/* Tell him about it */
1853 	msg_format(Ind, "\374\377yYou've been added to '%s'.", guilds[guild_id].name);
1854 
1855 	/* Set his guild number */
1856 	p_ptr->guild = guild_id;
1857 	p_ptr->guild_dna = guilds[guild_id].dna;
1858 	clockin(Ind, 3);
1859 
1860 	/* Resend info */
1861 	Send_guild(Ind, FALSE, FALSE);
1862 
1863 	/* Display the guild note to him */
1864 	for (i = 0; i < MAX_GUILDNOTES; i++) {
1865 		if (!strcmp(guild_note_target[i], guilds[p_ptr->guild].name)) {
1866 			if (strcmp(guild_note[i], ""))
1867 				msg_format(Ind, "\374\377bGuild Note: %s", guild_note[i]);
1868 			break;
1869 		}
1870 	}
1871 
1872 	/* Success */
1873 	return TRUE;
1874 }
1875 
1876 /*
1877  * Add a player to a party.
1878  */
party_add(int adder,cptr name)1879 int party_add(int adder, cptr name) {
1880 	player_type *p_ptr;
1881 	player_type *q_ptr = Players[adder];
1882 	int party_id = q_ptr->party, Ind = 0, i;
1883 
1884 	if (q_ptr->party == 0) {
1885 		msg_print(adder, "\377yYou don't belong to a party.");
1886 		return FALSE;
1887 	}
1888 
1889 	Ind = name_lookup_loose(adder, name, FALSE, TRUE);
1890 	if (Ind <= 0) return FALSE;
1891 
1892 	if (adder == Ind) {
1893 		msg_print(adder, "\377yYou cannot add yourself, you are already in the party.");
1894 		return FALSE;
1895 	}
1896 
1897 	/* Set pointer */
1898 	p_ptr = Players[Ind];
1899 
1900 #if 0 // It's really a prob that the owner can't add his own chars..so if0
1901 	/* Make sure this isn't an impostor */
1902 	if (!streq(parties[party_id].owner, q_ptr->name)) {
1903 		/* Message */
1904 		msg_print(adder, "\377yYou must be the owner to add someone.");
1905 
1906 		/* Abort */
1907 		return FALSE;
1908 	}
1909 #endif
1910 	/* Make sure this added person is neutral */
1911 	if (p_ptr->party != 0) {
1912 		/* Message */
1913 		if (p_ptr->party != party_id) msg_print(adder, "\377yThat player is already in a party.");
1914 		else msg_print(adder, "\377yThat player is already in your party.");
1915 
1916 		/* Abort */
1917 		return FALSE;
1918 	}
1919 
1920 	if (
1921 #ifdef ALLOW_NR_CROSS_PARTIES
1922 	    (!q_ptr->total_winner || !p_ptr->total_winner ||
1923 	    !at_netherrealm(&q_ptr->wpos) || !at_netherrealm(&p_ptr->wpos)) &&
1924 #endif
1925 #ifdef IRONDEEPDIVE_ALLOW_INCOMPAT
1926 	    (!in_irondeepdive(&q_ptr->wpos) || !in_irondeepdive(&p_ptr->wpos)) &&
1927 #endif
1928 	/* Everlasting and other chars cannot be in the same party */
1929 	    (compat_mode(parties[party_id].cmode, p_ptr->mode))) {
1930 		msg_format(adder, "\377yYou cannot form a party with %s characters.", compat_mode(parties[party_id].cmode, p_ptr->mode));
1931 		return FALSE;
1932 	}
1933 
1934 	/* Only newly created characters can join an iron team */
1935 	if ((parties[party_id].mode & PA_IRONTEAM) && (p_ptr->max_exp > 0 || p_ptr->max_plv > 1)) {
1936 		msg_print(adder, "\377yOnly newly created characters without experience can join an iron team.");
1937 		return FALSE;
1938 	}
1939 
1940 	/* Ignoring a player will prevent getting added to a party by him */
1941 	if (check_ignore(Ind, adder)) return FALSE;
1942 
1943 	/* Log - security */
1944 	s_printf("PARTY_ADD: %s has been added to %s by %s.\n", p_ptr->name, parties[party_id].name, q_ptr->name);
1945 
1946 	/* Tell the party about its new member */
1947 	party_msg_format(party_id, "\374\377y%s has been added to party %s by %s.", p_ptr->name, parties[party_id].name, q_ptr->name);
1948 
1949 	/* One more player in this party */
1950 	parties[party_id].members++;
1951 
1952 	/* Tell him about it */
1953 	if (parties[party_id].mode == PA_IRONTEAM)
1954 		msg_format(Ind, "\374\377yYou've been added to iron team '%s' by %s.", parties[party_id].name, q_ptr->name);
1955 	else
1956 		msg_format(Ind, "\374\377yYou've been added to party '%s' by %s.", parties[party_id].name, q_ptr->name);
1957 
1958 	/* Set his party number */
1959 	p_ptr->party = party_id;
1960 	clockin(Ind, 2);
1961 
1962 	/* Resend info */
1963 	Send_party(Ind, FALSE, FALSE);
1964 
1965 	/* Display the party note to him */
1966 	for (i = 0; i < MAX_PARTYNOTES; i++) {
1967 		if (!strcmp(party_note_target[i], parties[p_ptr->party].name)) {
1968 			if (strcmp(party_note[i], ""))
1969 				msg_format(Ind, "\374\377bParty Note: %s", party_note[i]);
1970 			break;
1971 		}
1972 	}
1973 
1974 	/* Re-check house permissions, to display doors in correct colour */
1975 	if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
1976 
1977 	/* Success */
1978 	return TRUE;
1979 }
party_add_self(int Ind,cptr party)1980 int party_add_self(int Ind, cptr party) {
1981 	player_type *p_ptr = Players[Ind];
1982 	int party_id = party_lookup(party), i, *id_list, ids;
1983 	struct account *acc;
1984 
1985 	if (party_id == -1) {
1986 		msg_print(Ind, "That party does not exist.");
1987 		return FALSE;
1988 	}
1989 
1990 	/* Everlasting and other chars cannot be in the same party */
1991 	if (compat_mode(p_ptr->mode, parties[party_id].cmode)) {
1992 		msg_format(Ind, "\377yYou cannot join %s parties.", compat_mode(p_ptr->mode, parties[party_id].cmode));
1993 		return FALSE;
1994 	}
1995 
1996 	/* Only newly created characters can join an iron team */
1997 	if ((parties[party_id].mode & PA_IRONTEAM) && (p_ptr->max_exp > 0 || p_ptr->max_plv > 1)) {
1998 		msg_print(Ind, "\377yOnly newly created characters without experience can join an iron team.");
1999 		return FALSE;
2000 	}
2001 
2002 	/* check if he has a character in there already, to be eligible to self-add */
2003 	acc = GetAccount(p_ptr->accountname, NULL, FALSE);
2004 	/* paranoia */
2005 	if (!acc) {
2006 		/* uhh.. */
2007 		msg_print(Ind, "Sorry, self-adding has failed.");
2008 		return FALSE;
2009 	}
2010 	ids = player_id_list(&id_list, acc->id);
2011 	for (i = 0; i < ids; i++) {
2012                 if (lookup_player_party(id_list[i]) == party_id) {
2013 			/* success */
2014 			break;
2015                 }
2016         }
2017         if (ids) C_KILL(id_list, ids, int);
2018 	KILL(acc, struct account);
2019         /* failure? */
2020         if (i == ids) {
2021 		msg_print(Ind, "You do not have any character that is member of that party.");
2022 		return FALSE;
2023         }
2024 
2025 	/* Log - security */
2026 	s_printf("PARTY_ADD_SELF: %s has been added to %s.\n", p_ptr->name, parties[party_id].name);
2027 
2028 	/* Tell the party about its new member */
2029 	party_msg_format(party_id, "\374\377y%s has been added to party %s.", p_ptr->name, parties[party_id].name);
2030 
2031 	/* One more player in this party */
2032 	parties[party_id].members++;
2033 
2034 	/* Tell him about it */
2035 	if (parties[party_id].mode == PA_IRONTEAM)
2036 		msg_format(Ind, "\374\377yYou've been added to iron team '%s'.", parties[party_id].name);
2037 	else
2038 		msg_format(Ind, "\374\377yYou've been added to party '%s'.", parties[party_id].name);
2039 
2040 	/* Set his party number */
2041 	p_ptr->party = party_id;
2042 	clockin(Ind, 2);
2043 
2044 	/* Resend info */
2045 	Send_party(Ind, FALSE, FALSE);
2046 
2047 	/* Display the party note to him */
2048 	for (i = 0; i < MAX_PARTYNOTES; i++) {
2049 		if (!strcmp(party_note_target[i], parties[p_ptr->party].name)) {
2050 			if (strcmp(party_note[i], ""))
2051 				msg_format(Ind, "\374\377bParty Note: %s", party_note[i]);
2052 			break;
2053 		}
2054 	}
2055 
2056 	/* Re-check house permissions, to display doors in correct colour */
2057 	if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
2058 
2059 	/* Success */
2060 	return TRUE;
2061 }
2062 
erase_guild_key(int id)2063 static void erase_guild_key(int id) {
2064 	int i, this_o_idx, next_o_idx;
2065 	monster_type *m_ptr;
2066 	object_type *o_ptr, *q_ptr;
2067 	char m_name[MNAME_LEN];
2068 
2069 #if 0 /* account-based */
2070 	int j;
2071         FILE *fp;
2072         char buf[1024];
2073         cptr cname;
2074         struct account c_acc;
2075 #else /* just hash-table (character) based */
2076 	int slot;
2077 	hash_entry *ptr;
2078 	player_type *p_ptr;
2079 #endif
2080 
2081 
2082 	/* objects on the floor/in monster inventories */
2083         for (i = 0; i < o_max; i++) {
2084                 o_ptr = &o_list[i];
2085                 /* Skip dead objects */
2086                 if (!o_ptr->k_idx) continue;
2087                 /* skip non-guild keys */
2088                 if (o_ptr->tval != TV_KEY || o_ptr->sval != SV_GUILD_KEY) continue;
2089 		/* Skip wrong guild keys */
2090 		if (o_ptr->pval != id) continue;
2091 
2092 		/* in monster inventory */
2093                 if (o_ptr->held_m_idx) {
2094 			m_ptr = &m_list[o_ptr->held_m_idx];
2095 			/* 1st object held is the key? */
2096 			if (m_ptr->hold_o_idx == i) {
2097 				m_ptr->hold_o_idx = o_ptr->next_o_idx;
2098 				monster_desc(0, m_name, o_ptr->held_m_idx, 0);
2099 				s_printf("GUILD_KEY_ERASE: monster inventory (%d, '%s', #1)\n", o_ptr->held_m_idx, m_name);
2100 				delete_object_idx(i, TRUE);
2101 				return;
2102 			} else {
2103 				i = 1;
2104 				q_ptr = &o_list[m_ptr->hold_o_idx];//compiler warning
2105 				for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) {
2106 					if (this_o_idx == i) {
2107 						q_ptr->next_o_idx = o_list[this_o_idx].next_o_idx;
2108 						monster_desc(0, m_name, o_ptr->held_m_idx, 0);
2109 						s_printf("GUILD_KEY_ERASE: monster inventory (%d, '%s', #%d)\n", o_ptr->held_m_idx, m_name, i);
2110 						delete_object_idx(this_o_idx, TRUE);
2111 						return;
2112 					}
2113 					q_ptr = &o_list[this_o_idx];
2114 					next_o_idx = q_ptr->next_o_idx;
2115 					i++;
2116 				}
2117 			}
2118                 }
2119 
2120 		s_printf("GUILD_KEY_ERASE: floor\n");
2121                 delete_object_idx(i, TRUE);
2122                 return;
2123         }
2124 
2125 	/* Players online */
2126 	for (this_o_idx = 1; this_o_idx <= NumPlayers; this_o_idx++) {
2127 	        p_ptr = Players[this_o_idx];
2128 		/* scan his inventory */
2129 		for (i = 0; i < INVEN_TOTAL; i++) {
2130 			o_ptr = &p_ptr->inventory[i];
2131 			if (!o_ptr->k_idx) continue;
2132 
2133 			if (o_ptr->tval == TV_KEY && o_ptr->sval == SV_GUILD_KEY && o_ptr->pval == id) {
2134 				s_printf("GUILD_KEY_ERASE: player '%s'\n", p_ptr->name);
2135 				inven_item_increase(this_o_idx, i, -1);
2136 				inven_item_describe(this_o_idx, i);
2137 				inven_item_optimize(this_o_idx, i);
2138 				return;
2139 			}
2140 		}
2141 	}
2142 
2143 #if 0 /* account-based */
2144 	/* objects in player inventories */
2145         path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
2146         fp = fopen(buf, "rb+");
2147         if (!fp) {
2148 		s_printf("GUILD_KEY_ERASE: failed to open tomenet.acc\n");
2149     		return;
2150         }
2151         while (fread(&c_acc, sizeof(struct account), 1, fp)) {
2152 		int *id_list, chars;
2153                 chars = player_id_list(&id_list, c_acc->id);
2154                 for (i = 0; i < chars; i++) {
2155 			cname = lookup_player_name(id_list[i]);
2156 			...//not implemented
2157                 }
2158                 if (chars) C_KILL(id_list, chars, int);
2159         }
2160 #else /* just hash-table (character) based */
2161 	/* hack */
2162 	NumPlayers++;
2163         MAKE(Players[NumPlayers], player_type);
2164         p_ptr = Players[NumPlayers];
2165         p_ptr->inventory = C_NEW(INVEN_TOTAL, object_type);
2166         for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
2167                 ptr = hash_table[slot];
2168                 while (ptr) {
2169 			/* clear his data (especially inventory) */
2170 			o_ptr = p_ptr->inventory;
2171 			WIPE(p_ptr, player_type);
2172 			p_ptr->inventory = o_ptr;
2173 			p_ptr->Ind = NumPlayers;
2174 			C_WIPE(p_ptr->inventory, INVEN_TOTAL, object_type);
2175 			/* set his supposed name */
2176 			strcpy(p_ptr->name, ptr->name);
2177 			/* generate savefile name */
2178 			process_player_name(NumPlayers, TRUE);
2179 			/* try to load him! */
2180 			if (!load_player(NumPlayers)) {
2181 				/* bad fail */
2182 				s_printf("GUILD_KEY_ERASE: load_player '%s' failed\n", p_ptr->name);
2183 				/* unhack */
2184 			        C_FREE(p_ptr->inventory, INVEN_TOTAL, object_type);
2185 			        KILL(p_ptr, player_type);
2186 				NumPlayers--;
2187 				return;
2188 			}
2189 			/* scan his inventory */
2190 			for (i = 0; i < INVEN_TOTAL; i++) {
2191 				o_ptr = &p_ptr->inventory[i];
2192 				if (!o_ptr->k_idx) continue;
2193 
2194 				if (o_ptr->tval == TV_KEY && o_ptr->sval == SV_GUILD_KEY && o_ptr->pval == id) {
2195 					s_printf("GUILD_KEY_ERASE: savegame '%s'\n", p_ptr->name);
2196 					o_ptr->tval = o_ptr->sval = o_ptr->k_idx = 0;
2197 					/* write savegame back */
2198 					save_player(NumPlayers);
2199 					/* unhack */
2200 				        C_FREE(p_ptr->inventory, INVEN_TOTAL, object_type);
2201 				        KILL(p_ptr, player_type);
2202 					NumPlayers--;
2203 					return;
2204 				}
2205 			}
2206 			/* advance to next character */
2207 			ptr = ptr->next;
2208 		}
2209 	}
2210 	/* unhack */
2211         C_FREE(p_ptr->inventory, INVEN_TOTAL, object_type);
2212         KILL(p_ptr, player_type);
2213 	NumPlayers--;
2214 #endif
2215 
2216 	/* hm, failed to locate the guild key. Maybe someone actually lost it. */
2217 	s_printf("GUILD_KEY_ERASE: not found\n");
2218 }
2219 
2220 /*
2221  * Remove a guild. What a sad day.
2222  *
2223  * In style of del_party.
2224  */
del_guild(int id)2225 void del_guild(int id) {
2226 	char temp[160];
2227 	int i;
2228 
2229 	/* Clear the guild hall */
2230 	kill_houses(id, OT_GUILD);
2231 
2232 	/* delete pending guild notes */
2233 	for (i = 0; i < MAX_GUILDNOTES; i++) {
2234 		if (!strcmp(guild_note_target[i], guilds[id].name)) {
2235 			strcpy(guild_note_target[i], "");
2236 			strcpy(guild_note[i], "");
2237 			break;
2238 		}
2239 	}
2240 
2241 	/* erase guild bbs */
2242 	for (i = 0; i < BBS_LINES; i++) strcpy(gbbs_line[id][i], "");
2243 
2244 	/* log! (to track auto-disbanding of leaderless guilds) */
2245 	s_printf("DEL_GUILD: '%s' (%d)\n", guilds[id].name, id);
2246 
2247 	/* Tell everyone */
2248 	snprintf(temp, 160, "\374\377yThe guild '\377%c%s\377y' no longer exists.", COLOUR_CHAT_GUILD, guilds[id].name);
2249 	msg_broadcast(0, temp);
2250 
2251 	/* Clear the basic info */
2252 	guilds[id].members = 0; /* it should be zero anyway */
2253 	strcpy(guilds[id].name,"");
2254 	for (i = 0; i < 5; i++) guilds[id].adder[i][0] = '\0'; /* they should be cleared anyway */
2255 	guilds[id].flags = GFLG_NONE;
2256 	guilds[id].minlev = 0;
2257 
2258 	/* erase guild hall */
2259 #if 0 /* not needed, since there can only be one guild hall */
2260 	kill_houses(id, OT_GUILD);
2261 #else
2262 	if (guilds[id].h_idx) {
2263 		struct dna_type *dna = houses[guilds[id].h_idx - 1].dna;
2264 		dna->owner = 0L;
2265 	        dna->creator = 0L;
2266 	        dna->a_flags = ACF_NONE;
2267 	        kill_house_contents(&houses[guilds[id].h_idx - 1]);
2268 
2269 		/* and in case it was suspended due to leaderlessness,
2270 		   so the next guild buying this house won't get a surprise.. */
2271 		houses[guilds[id].h_idx - 1].flags &= ~HF_GUILD_SUS;
2272 		fill_house(&houses[guilds[id].h_idx - 1], FILL_GUILD_SUS_UNDO, NULL);
2273 
2274 		guilds[id].h_idx = 0;//obsolete?
2275 	}
2276 #endif
2277 
2278 	/* Find and destroy the guild key! */
2279 	erase_guild_key(id);
2280 }
guild_timeout(int id)2281 void guild_timeout(int id) {
2282 	int i;
2283 	player_type *p_ptr;
2284 
2285 	for (i = 1; i <= NumPlayers; i++) {
2286 		p_ptr = Players[i];
2287 		if (p_ptr->guild && p_ptr->guild != id) continue;
2288 
2289 		p_ptr->guild = 0;
2290 		clockin(i, 3);
2291 
2292 		if (p_ptr->conn == NOT_CONNECTED) continue;
2293 
2294 		/* Re-check house permissions, to display doors in correct colour */
2295 		if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
2296 
2297 		msg_print(i, "\377oYour guild has been deleted from being leaderless for too long.");
2298 		Send_guild(i, TRUE, FALSE);
2299 	}
2300 
2301 	s_printf("GUILD_TIMEOUT: '%s' (%d)\n", guilds[id].name, id);
2302 	guilds[id].members = 0;
2303 	del_guild(id);
2304 }
2305 
2306 /*
2307  * Delete a party. Was in party remove.
2308  *
2309  * Design improvement
2310  */
del_party(int id)2311 static void del_party(int id){
2312 	int i;
2313 	bool sent = FALSE;
2314 	/* Remove the party altogether */
2315 	kill_houses(id, OT_PARTY);
2316 
2317 	/* delete pending party notes */
2318 	for (i = 0; i < MAX_PARTYNOTES; i++) {
2319 		if (!strcmp(party_note_target[i], parties[id].name)) {
2320 			strcpy(party_note_target[i], "");
2321 			strcpy(party_note[i], "");
2322 			break;
2323 		}
2324 	}
2325 
2326 	/* erase party bbs */
2327 	for (i = 0; i < BBS_LINES; i++) strcpy(pbbs_line[id][i], "");
2328 
2329 	/* Set the number of people in this party to zero */
2330 	parties[id].members = 0;
2331 
2332 	/* Remove everyone else */
2333 	for (i = 1; i <= NumPlayers; i++) {
2334 		/* Check if they are in here */
2335 		if (player_in_party(id, i)) {
2336 			if (!sent) { /* no need to spam this more than once */
2337 				Send_party(i, FALSE, TRUE);
2338 				sent = TRUE;
2339 			}
2340 			Players[i]->party = 0;
2341 			clockin(i, 2);
2342 
2343 			/* Re-check house permissions, to display doors in correct colour */
2344 			if (!Players[i]->wpos.wz) Players[i]->redraw |= PR_MAP;
2345 
2346 			if (parties[id].mode == PA_IRONTEAM)
2347 				msg_print(i, "\374\377yYour iron team has been disbanded.");
2348 			else
2349 				msg_print(i, "\374\377yYour party has been disbanded.");
2350 		}
2351 	}
2352 
2353 	/* Set the creation time to "disbanded time" */
2354 	parties[id].created = turn;
2355 
2356 	/* Empty the name */
2357 	strcpy(parties[id].name, "");
2358 }
2359 
2360 /*
2361  * Remove player from a guild
2362  */
guild_remove(int remover,cptr name)2363 int guild_remove(int remover, cptr name) {
2364 	player_type *p_ptr;
2365 	player_type *q_ptr = Players[remover];
2366 	int guild_id = q_ptr->guild, Ind = 0;
2367 
2368 	if (!guild_id) {
2369 		if (!is_admin(q_ptr)) {
2370 			msg_print(remover, "\377yYou are not in a guild");
2371 			return FALSE;
2372 		}
2373 	}
2374 
2375 	/* Make sure this is the owner */
2376 	if (guilds[guild_id].master != q_ptr->id && !is_admin(q_ptr)) {
2377 		/* Message */
2378 		msg_print(remover, "\377yYou must be the owner to delete someone.");
2379 
2380 		/* Abort */
2381 		return FALSE;
2382 	}
2383 
2384 	Ind = name_lookup_loose(remover, name, FALSE, TRUE);
2385 
2386 	if (Ind <= 0) return FALSE;
2387 
2388 	if (Ind == remover) {	/* remove oneself from guild - leave */
2389 		guild_leave(remover, TRUE);
2390 		return TRUE;
2391 	}
2392 
2393 	p_ptr = Players[Ind];
2394 
2395 	if (!guild_id && is_admin(q_ptr)) guild_id = p_ptr->guild;
2396 
2397 	/* Make sure they were in the guild to begin with */
2398 	if (guild_id != p_ptr->guild) {
2399 		/* Message */
2400 		msg_print(remover, "\377yYou can only delete guild members.");
2401 
2402 		/* Abort */
2403 		return FALSE;
2404 	}
2405 
2406 	/* Keep the guild, just lose a member */
2407 	else {
2408 		/* Lose a member */
2409 		guilds[guild_id].members--;
2410 
2411 		/* Messages */
2412 		msg_print(Ind, "\374\377yYou have been removed from the guild.");
2413 		if (!is_admin(p_ptr)) guild_msg_format(guild_id, "\374\377y%s has been removed from the guild.", p_ptr->name);
2414 
2415 		/* Last member deleted? */
2416 		if (guilds[guild_id].members == 0) {
2417 			Send_guild(Ind, TRUE, TRUE);
2418 			p_ptr->guild = 0;
2419 			clockin(Ind, 3);
2420 			del_guild(guild_id);
2421 
2422 			/* Re-check house permissions, to display doors in correct colour */
2423 			if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
2424 		} else {
2425 			Send_guild(Ind, TRUE, FALSE);
2426 			p_ptr->guild = 0;
2427 			clockin(Ind, 3);
2428 
2429 			/* Re-check house permissions, to display doors in correct colour */
2430 			if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
2431 		}
2432 	}
2433 
2434 	return TRUE;
2435 }
2436 
2437 /*
2438  * Remove a person from a party.
2439  *
2440  * Removing the party owner destroys the party. - Not always anymore:
2441  * On RPG server, removing the owner will just promote someone else to owner,
2442  * provided (s)he's logged on. Better for RPG diving partys - C. Blue
2443  */
party_remove(int remover,cptr name)2444 int party_remove(int remover, cptr name) {
2445 	player_type *p_ptr;
2446 	player_type *q_ptr = Players[remover];
2447 	int party_id = q_ptr->party, Ind = 0;
2448 	int i, j;
2449 
2450 	/* Make sure this is the owner */
2451 	if (!streq(parties[party_id].owner, q_ptr->name) && !is_admin(q_ptr)) {
2452 		msg_print(remover, "\377yYou must be the owner to delete someone.");
2453 
2454 		/* Abort */
2455 		return FALSE;
2456 	}
2457 
2458 	Ind = name_lookup_loose(remover, name, FALSE, TRUE);
2459 	if (Ind <= 0) return FALSE;
2460 	p_ptr = Players[Ind];
2461 
2462 	if((!party_id || !streq(parties[party_id].owner, q_ptr->name)) && is_admin(q_ptr))
2463 		party_id = p_ptr->party;
2464 
2465 	/* Make sure they were in the party to begin with */
2466 	if (!player_in_party(party_id, Ind)) {
2467 		msg_print(remover, "\377yYou can only delete party members.");
2468 
2469 		/* Abort */
2470 		return FALSE;
2471 	}
2472 
2473 	/* See if this is the owner we're deleting */
2474 	if (remover == Ind
2475 #ifndef RPG_SERVER
2476 	    && in_irondeepdive(&p_ptr->wpos)
2477 #endif
2478 	    ) {
2479 		/* Keep the party, just lose a member */
2480 		for (i = 1; i <= NumPlayers; i++) {
2481 			if (is_admin(Players[i])) continue;
2482 			if (Players[i]->party == q_ptr->party && i != Ind) {
2483 				strcpy(parties[party_id].owner, Players[i]->name);
2484 				msg_print(i, "\374\377yYou are now the party owner!");
2485 
2486 				for (j = 1; j <= NumPlayers; j++)
2487 					if (Players[j]->party == Players[i]->party && j != i)
2488 						msg_format(j, "\374\377y%s is now the party owner.", Players[i]->name);
2489 				break;
2490 			}
2491 		}
2492 		/* no other player online who is in the same party and could overtake leadership? Then erase party! */
2493 		if (i > NumPlayers) {
2494 			del_party(party_id);
2495 			return TRUE;
2496 		}
2497 	} else if (remover == Ind) {
2498 		del_party(party_id);
2499 		return TRUE;
2500 	}
2501 
2502 	/* Lose a member */
2503 	parties[party_id].members--;
2504 
2505 	/* Resend info */
2506 	Send_party(Ind, TRUE, FALSE);
2507 
2508 	/* Set his party number back to "neutral" */
2509 	p_ptr->party = 0;
2510 	clockin(Ind, 2);
2511 
2512 	/* Re-check house permissions, to display doors in correct colour */
2513 	if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
2514 
2515 	/* Messages */
2516 	if (parties[party_id].mode == PA_IRONTEAM) {
2517 		msg_print(Ind, "\374\377yYou have been removed from your iron team.");
2518 		if (!is_admin(p_ptr)) party_msg_format(party_id, "\374\377y%s has been removed from the iron team.", p_ptr->name);
2519 	} else {
2520 		msg_print(Ind, "\374\377yYou have been removed from your party.");
2521 		if (!is_admin(p_ptr)) party_msg_format(party_id, "\374\377y%s has been removed from the party.", p_ptr->name);
2522 	}
2523 
2524 	return TRUE;
2525 }
2526 
guild_leave(int Ind,bool voluntarily)2527 void guild_leave(int Ind, bool voluntarily) {
2528 	player_type *p_ptr = Players[Ind];
2529 	int guild_id = p_ptr->guild, i;
2530 
2531 	/* Make sure he belongs to a guild */
2532 	if (!guild_id) {
2533 		msg_print(Ind, "\377yYou don't belong to a guild.");
2534 		return;
2535 	}
2536 
2537 #ifdef GUILD_ADDERS_LIST
2538 	if ((p_ptr->guild_flags & PGF_ADDER))
2539 		for (i = 0; i < 5; i++) if (streq(guilds[p_ptr->guild].adder[i], p_ptr->name)) {
2540 			guilds[p_ptr->guild].adder[i][0] = '\0';
2541 			break;
2542 		}
2543 #endif
2544 
2545 	/* Lose a member */
2546 	guilds[guild_id].members--;
2547 
2548 	/* Inform people */
2549 	if (voluntarily) {
2550 		msg_print(Ind, "\374\377yYou have left your guild.");
2551 		if (!is_admin(p_ptr)) guild_msg_format(guild_id, "\374\377y%s has left the guild.", p_ptr->name);
2552 	} else {
2553 		msg_print(Ind, "\374\377yYou have been removed from your guild.");
2554 		if (!is_admin(p_ptr)) guild_msg_format(guild_id, "\374\377y%s has been removed from the guild.", p_ptr->name);
2555 	}
2556 
2557 	/* If he's the guildmaster, set master to zero */
2558 	if (p_ptr->id == guilds[guild_id].master) {
2559 		guild_msg(guild_id, "\374\377yThe guild is now leaderless!");
2560 		guilds[guild_id].master = 0;
2561 
2562 		/* set guild hall to 'suspended' */
2563 		if ((i = guilds[guild_id].h_idx)) {
2564 			houses[i - 1].flags |= HF_GUILD_SUS;
2565 			fill_house(&houses[i - 1], FILL_GUILD_SUS, NULL);
2566 		}
2567 	}
2568 
2569 	/* Resend info */
2570 	Send_guild(Ind, TRUE, FALSE);
2571 
2572 	/* Set him back to "neutral" */
2573 	p_ptr->guild = 0;
2574 	clockin(Ind, 3);
2575 
2576 	/* Re-check house permissions, to display doors in correct colour */
2577 	if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
2578 
2579 	/* Last member deleted? */
2580 	if (guilds[guild_id].members == 0)
2581 		del_guild(guild_id);
2582 }
2583 
2584 /*
2585  * A player wants to leave a party.
2586  */
party_leave(int Ind,bool voluntarily)2587 void party_leave(int Ind, bool voluntarily) {
2588 	player_type *p_ptr = Players[Ind];
2589 	int party_id = p_ptr->party;
2590 
2591 	/* Make sure he belongs to a party */
2592 	if (!party_id) {
2593 		msg_print(Ind, "\377yYou don't belong to a party.");
2594 		return;
2595 	}
2596 
2597 	/* If he's the owner, use the other function */
2598 	if (streq(p_ptr->name, parties[party_id].owner)) {
2599 		/* Call party_remove */
2600 		party_remove(Ind, p_ptr->name);
2601 		return;
2602 	}
2603 
2604 	/* Lose a member */
2605 	parties[party_id].members--;
2606 
2607 	/* Resend info */
2608 	Send_party(Ind, TRUE, FALSE);
2609 
2610 	/* Set him back to "neutral" */
2611 	p_ptr->party = 0;
2612 	clockin(Ind, 2);
2613 
2614 	/* Re-check house permissions, to display doors in correct colour */
2615 	if (!p_ptr->wpos.wz) p_ptr->redraw |= PR_MAP;
2616 
2617 	/* Inform people */
2618 	if (voluntarily) {
2619 		if (parties[party_id].mode == PA_IRONTEAM) {
2620 			msg_print(Ind, "\374\377yYou have left your iron team.");
2621 			if (!is_admin(p_ptr)) party_msg_format(party_id, "\374\377y%s has left the iron team.", p_ptr->name);
2622 		} else {
2623 			msg_print(Ind, "\374\377yYou have left your party.");
2624 			if (!is_admin(p_ptr)) party_msg_format(party_id, "\374\377y%s has left the party.", p_ptr->name);
2625 		}
2626 	} else {
2627 		if (parties[party_id].mode == PA_IRONTEAM) {
2628 			msg_print(Ind, "\374\377yYou have been removed from your iron team.");
2629 			if (!is_admin(p_ptr)) party_msg_format(party_id, "\374\377y%s has been removed from the iron team.", p_ptr->name);
2630 		} else {
2631 			msg_print(Ind, "\374\377yYou have been removed from your party.");
2632 			if (!is_admin(p_ptr)) party_msg_format(party_id, "\374\377y%s has been removed from the party.", p_ptr->name);
2633 		}
2634 	}
2635 }
2636 
guild_rename(int Ind,char * new_name)2637 bool guild_rename(int Ind, char *new_name) {
2638 	player_type *p_ptr = Players[Ind];
2639 	int i, gid = p_ptr->guild;
2640 
2641 	if (!gid) {
2642 		msg_print(Ind, "\377yYou are not in a guild");
2643 		return FALSE;
2644 	}
2645 
2646 	/* Leaderless guilds do not allow addition of new members */
2647 	if (p_ptr->id != guilds[gid].master) {
2648 		msg_print(Ind, "\377yOnly the guild master can rename a guild.");
2649 		return FALSE;
2650 	}
2651 
2652 	if (!strcmp(guilds[gid].name, new_name)) {
2653 		msg_print(Ind, "\377yNew guild name must be different from its current name.");
2654 		return FALSE;
2655 	}
2656 
2657 	if (!guild_name_legal(Ind, new_name)) return FALSE;
2658 
2659 	/* This could probably be improved. */
2660 	if (p_ptr->au < GUILD_PRICE) {
2661 		if (GUILD_PRICE >= 1000000 && ((int)(GUILD_PRICE / 1000000)) * 1000000 == GUILD_PRICE)
2662 			msg_format(Ind, "\377yYou need %d,000,000 gold pieces to rename a guild.", GUILD_PRICE / 1000000);
2663 		else if (GUILD_PRICE >= 1000 && ((int)(GUILD_PRICE / 1000)) * 1000 == GUILD_PRICE)
2664 			msg_format(Ind, "\377yYou need %d,000 gold pieces to rename a guild.", GUILD_PRICE / 1000);
2665 		else
2666 			msg_format(Ind, "\377yYou need %d gold pieces to rename a guild.", GUILD_PRICE);
2667 		return FALSE;
2668 	}
2669 
2670 
2671 	p_ptr->au -= GUILD_PRICE;
2672 	p_ptr->redraw |= PR_GOLD;
2673 
2674 	for (i = 0; i < MAX_GUILDNOTES; i++)
2675 		if (!strcmp(guild_note_target[i], guilds[gid].name))
2676 			strcpy(guild_note_target[i], new_name);
2677 
2678 	msg_broadcast_format(0, "\374\377yThe guild '\377%c%s\377y' changed name to '\377%c%s\377y'.",
2679 	    COLOUR_CHAT_GUILD, guilds[gid].name, COLOUR_CHAT_GUILD, new_name);
2680 
2681 	l_printf("%s \\{yThe guild '%s' changed name to '%s'\n",
2682 	    showdate(), guilds[gid].name, new_name);
2683 
2684 	strcpy(guilds[gid].name, new_name);
2685 	return TRUE;
2686 }
2687 
2688 /*
2689  * Send a message to everyone in a party.
2690  */
guild_msg(int guild_id,cptr msg)2691 void guild_msg(int guild_id, cptr msg) {
2692 	int i;
2693 
2694 	/* Check for this guy */
2695 	for (i = 1; i <= NumPlayers; i++) {
2696 		if (Players[i]->conn == NOT_CONNECTED)
2697 			continue;
2698 
2699 		/* Check this guy */
2700 		if (guild_id == Players[i]->guild)
2701 			msg_print(i, msg);
2702 	}
2703 }
2704 
2705 
2706 /*
2707  * Send a formatted message to a guild.
2708  */
guild_msg_format(int guild_id,cptr fmt,...)2709 void guild_msg_format(int guild_id, cptr fmt, ...) {
2710 	va_list vp;
2711 	char buf[1024];
2712 
2713 	/* Begin the Varargs Stuff */
2714 	va_start(vp, fmt);
2715 
2716 	/* Format the args, save the length */
2717 	(void)vstrnfmt(buf, 1024, fmt, vp);
2718 
2719 	/* End the Varargs Stuff */
2720 	va_end(vp);
2721 
2722 	/* Display */
2723 	guild_msg(guild_id, buf);
2724 }
2725 
2726 /*
2727  * Send a message to everyone in a party.
2728  */
party_msg(int party_id,cptr msg)2729 void party_msg(int party_id, cptr msg) {
2730 	int i;
2731 
2732 	/* Check for this guy */
2733 	for (i = 1; i <= NumPlayers; i++) {
2734 		if (Players[i]->conn == NOT_CONNECTED)
2735 			continue;
2736 
2737 		/* Check this guy */
2738 		if (player_in_party(party_id, i))
2739 			msg_print(i, msg);
2740 	}
2741 }
2742 
2743 /*
2744  * Send a formatted message to a party.
2745  */
party_msg_format(int party_id,cptr fmt,...)2746 void party_msg_format(int party_id, cptr fmt, ...) {
2747 	va_list vp;
2748 	char buf[1024];
2749 
2750 	/* Begin the Varargs Stuff */
2751 	va_start(vp, fmt);
2752 
2753 	/* Format the args, save the length */
2754 	(void)vstrnfmt(buf, 1024, fmt, vp);
2755 
2756 	/* End the Varargs Stuff */
2757 	va_end(vp);
2758 
2759 	/* Display */
2760 	party_msg(party_id, buf);
2761 }
2762 
2763 /*
2764  * Send a message to everyone in a party, considering ignorance.
2765  */
party_msg_ignoring(int sender,int party_id,cptr msg)2766 static void party_msg_ignoring(int sender, int party_id, cptr msg) {
2767 	int i;
2768 
2769 	/* Check for this guy */
2770 	for (i = 1; i <= NumPlayers; i++) {
2771 		if (Players[i]->conn == NOT_CONNECTED)
2772 			continue;
2773 
2774 		if (check_ignore(i, sender))
2775 			continue;
2776 
2777 		/* Check this guy */
2778 		if (player_in_party(party_id, i))
2779 			msg_print(i, msg);
2780 	}
2781 }
2782 
2783 /*
2784  * Send a formatted message to a party.
2785  */
party_msg_format_ignoring(int sender,int party_id,cptr fmt,...)2786 void party_msg_format_ignoring(int sender, int party_id, cptr fmt, ...) {
2787 	va_list vp;
2788 	char buf[1024];
2789 
2790 	/* Begin the Varargs Stuff */
2791 	va_start(vp, fmt);
2792 
2793 	/* Format the args, save the length */
2794 	(void)vstrnfmt(buf, 1024, fmt, vp);
2795 
2796 	/* End the Varargs Stuff */
2797 	va_end(vp);
2798 
2799 	/* Display */
2800 	party_msg_ignoring(sender, party_id, buf);
2801 }
2802 /*
2803  * Split some experience among party members.
2804  *
2805  * This should ONLY be used while killing monsters.  The amount
2806  * should be the monster base experience times the monster level.
2807  *
2808  * This algorithm may need some work....  However, it does have some nifty
2809  * features, such as:
2810  *
2811  * 1) A party with just one member functions identically as before.
2812  *
2813  * 2) A party with two equally-levelled members functions such that each
2814  * member gets half as much experience as he would have by killing the monster
2815  * by himself.
2816  *
2817  * 3) Higher-leveled members of a party get higher percentages of the
2818  * experience.
2819  */
2820 
2821  /* The XP distribution was too unfair for low level characters,
2822     it made partying a real pain. I am changing it so that if the players
2823     have a difference in level of less than 5 than there is no difference
2824     in XP distribution.
2825 
2826     I am also changing it so it divides by each players level, AFTER
2827     it has been given to them.
2828 
2829     UPDATE: it appears that it may be giving too much XP to the low lvl chars,
2830     but I have been too lazy to change it... however, this doesnt appear to be being
2831     abused much, and the new system is regardless much nicer than the old one.
2832 
2833     -APD-
2834     */
2835 
2836 /* This helper function checks if two players are allowed to share experience,
2837    based on a) level difference and b) royal status.
2838    Note a quirk here:
2839    Winners and non-winners don't share exp, but winners and once-winners do. */
players_in_level(int Ind,int Ind2)2840 static bool players_in_level(int Ind, int Ind2) {
2841 	player_type *p_ptr = Players[Ind], *p2_ptr = Players[Ind2];
2842 
2843 	/* Check for max allowed level difference.
2844 	   (p_ptr->lev would be more logical but harsh) */
2845 	if (p_ptr->total_winner && p2_ptr->total_winner) {
2846 	        if (ABS(p_ptr->max_lev - p2_ptr->max_lev) > MAX_KING_PARTY_LEVEL_DIFF) return FALSE;
2847 	        return TRUE;
2848 	}
2849 	if (ABS(p_ptr->max_lev - p2_ptr->max_lev) > MAX_PARTY_LEVEL_DIFF) return FALSE;
2850 
2851 	/* Winners and non-winners don't share experience!
2852 	   This is actually important because winners get special features
2853 	   such as super heavy armour and royal stances which are aimed at
2854 	   nether realm, and are not meant to influence pre-king gameplay. */
2855 	if ((p_ptr->total_winner && !(p2_ptr->total_winner || p2_ptr->once_winner)) ||
2856 	    (p2_ptr->total_winner && !(p_ptr->total_winner || p_ptr->once_winner)))
2857 		return FALSE;
2858 
2859 	return TRUE;
2860 }
2861 
2862 /* Note: 'amount' is actually multiplied by 100 for extra decimal digits if we're very low level (Training Tower exp'ing).
2863    The same is done to 'base_amount' so it's *100 too. */
2864 #define PERFORM_IRON_TEAM_CHECKS
party_gain_exp(int Ind,int party_id,s64b amount,s64b base_amount,int henc,int henc_top)2865 void party_gain_exp(int Ind, int party_id, s64b amount, s64b base_amount, int henc, int henc_top) {
2866 	player_type *p_ptr = Players[Ind], *q_ptr;
2867 	int PInd[NumPlayers], pi = 0, Ind2; /* local working copy of player indices, for efficiency hopefully */
2868 	int i, eff_henc, hlev = 0, htop = 0;
2869 #ifdef ANTI_MAXPLV_EXPLOIT
2870  #ifdef ANTI_MAXPLV_EXPLOIT_SOFTEXP
2871 	int diff;
2872  #endif
2873 #endif
2874 	struct worldpos *wpos = &p_ptr->wpos;
2875 	s64b new_exp, new_exp_frac, average_lev = 0, num_members = 0, new_amount, new_boosted_amount;
2876 	s64b modified_level;
2877 	int dlev = getlevel(wpos);
2878 	bool not_in_iddc = !in_irondeepdive(wpos);
2879 #ifdef PERFORM_IRON_TEAM_CHECKS
2880 	bool iron = (parties[party_id].mode == PA_IRONTEAM);
2881 	int iron_team_members_here = 0;//temporarily here
2882 #endif
2883 
2884 #ifdef ALLOW_NR_CROSS_PARTIES
2885 	/* quick and dirty anti-cheeze (for if NR surface already allows partying up) */
2886         if (at_netherrealm(wpos) && !wpos->wz) return;
2887 #endif
2888 
2889 	/* Calculate the average level and iron team presence */
2890 	for (i = 1; i <= NumPlayers; i++) {
2891 		q_ptr = Players[i];
2892 
2893 		if (q_ptr->conn == NOT_CONNECTED) continue;
2894 
2895 		/* Check for his existence in the party */
2896 		if (!(player_in_party(party_id, i) && (inarea(&q_ptr->wpos, wpos)))) continue;
2897 
2898 		/* Create map for efficiency */
2899 		PInd[pi] = i;
2900 		pi++;
2901 
2902 #ifdef PERFORM_IRON_TEAM_CHECKS
2903 		/* will be moved to gain_exp() if decrease of party.experience is implemented, nasty though.
2904 		until then, iron teams will just have to be re-formed as normal parties if a member falls
2905 		behind too much in terms of exp and hence blocks the whole team from gaining exp. */
2906 
2907 		/* Iron Teams only get exp if the whole team is on the same floor! */
2908 		if (iron &&
2909 		    /* note: this line means that iron teams must not add
2910 		       admins, or the members won't gain exp anymore */
2911 		    !is_admin(q_ptr))
2912 			iron_team_members_here++;
2913 #endif
2914 
2915 		/* For exp-splitting: Increase the "divisor" */
2916 		average_lev += q_ptr->lev;
2917 		num_members++;
2918 
2919 		/* Floor depth vs player level for efficient exp'ing always uses the highest-level team mate. */
2920 		if (q_ptr->lev > hlev) hlev = q_ptr->lev;
2921 
2922 		/* For keeping track of max-plv-exploits in case henc_strictness is actually disabled. */
2923 		if ((q_ptr->max_lev + q_ptr->max_plv) / 2 > htop) htop = (q_ptr->max_lev + q_ptr->max_plv) / 2;
2924 	}
2925 
2926 #ifdef PERFORM_IRON_TEAM_CHECKS
2927 	/* Iron team calc: nobody in an iron team can gain exp if not all members are present and in the same place! */
2928 	if (iron && iron_team_members_here != parties[party_id].members) return;
2929 #endif
2930 
2931 	/* Exp share calc: */
2932 	average_lev /= num_members;
2933 
2934 	/* Replace top max_plv value taken from any party member on the floor
2935 	   simply by the henc_top value, if we use the 'henc' feature: */
2936 	if (cfg.henc_strictness) htop = henc_top;
2937 	/* paranoia (m_ptr->henc shouldn't actually get set if
2938 	   henc_strictness is disabled, but better safe than sorry: */
2939 	else henc = 0;
2940 
2941 	/* Now, distribute the experience */
2942 	for (i = 0; i < pi; i++) {
2943 		Ind2 = PInd[i];
2944 		q_ptr = Players[Ind2];
2945 
2946 		/* players who exceed the restrictions to share exp with us don't get any,
2947 		   but still take share toll by increasing the divisor in the loop above. */
2948 		if (q_ptr->ghost || !players_in_level(Ind, Ind2)) continue;
2949 
2950 		/* HEnc-checks -
2951 		   in case henc_strictness is actually disabled, we abuse 'henc' here
2952 		   by calculating with max_plv values instead, using them as pseudo-henc values. */
2953 		if (!q_ptr->total_winner) {
2954 			eff_henc = henc; //(0 if henc_strictness is disabled)
2955 
2956 #ifdef ANTI_MAXPLV_EXPLOIT
2957 			/* Don't allow cheap support from super-high level characters whose max_plv
2958 			   is considerably higher than their normal level, resulting in them being
2959 			   way more powerful than usual (because they have more skill points allocated). */
2960 
2961 			/* Two cases:
2962 			   1) We're not the killer and the killer has too high max_plv/supp_top (= henc_top),
2963 			   2) We're the killer but we have too high supp_top
2964 			      (and optionally the monster maybe also has too high henc_top from the killer,
2965 			      but this can't be implemented easily because the henc_top might be ourself! oops!).
2966 			   However, the problem is that we might actually be a 10(40) char and someone else too;
2967 			   now we cannot distinguish anymore, and we should definitely get full exp when this
2968 			   team of two kills a monster, right?
2969 			   So there is probably no easy way except for disabling ANTI_MAXPLV_EXPLOIT completely :/. */
2970 
2971 			/* ..instead of the above stuff, here a new, simpler attempt:
2972 			   If there's anyone whose max_plv is > ours and exceeds the allowed level diff,
2973 			   henc penalty (AMES-LEV) or exp penalty (AMES-EXP) applies to us. */
2974  #ifdef ANTI_MAXPLV_EXPLOIT_SOFTLEV
2975 			 /* avg lev compariso, weighing a bit less than max_lev comparison */
2976 			if (htop - (q_ptr->max_lev + q_ptr->max_plv) / 2 > ((MAX_PARTY_LEVEL_DIFF + 1) * 3) / 2) continue; /* zonk, bam */
2977  #else
2978   #ifdef ANTI_MAXPLV_EXPLOIT_SOFTEXP
2979 			diff = htop - (q_ptr->max_lev + q_ptr->max_plv) / 2 - (MAX_PARTY_LEVEL_DIFF + 1);
2980 			if (diff > 0) new_amount = (new_amount * 4) / (4 + diff);
2981   #else
2982 			 /* avg lev comparison in the same way as max_lev comparison */
2983 			if (htop - (q_ptr->max_lev + q_ptr->max_plv) / 2 > MAX_PARTY_LEVEL_DIFF + 1) continue; /* zonk, bam */
2984   #endif
2985  #endif
2986 #endif
2987 
2988 			/* Don't allow cheap support from super-high level characters */
2989 			if (eff_henc - q_ptr->max_lev > MAX_PARTY_LEVEL_DIFF + 1) continue; /* zonk */
2990 		}
2991 
2992 		/* Calculate this guy's experience gain */
2993 		new_amount = amount;
2994 
2995 		/* dungeon floor specific reduction if player dives too shallow */
2996 		if (not_in_iddc) new_amount = det_exp_level(new_amount, hlev, dlev);
2997 
2998 		/* Never get too much exp off a monster
2999 		   due to high level difference,
3000 		   make exception for low exp boosts like "holy jackal" */
3001 		if ((new_amount > base_amount * 4 * q_ptr->lev) && (new_amount > 200 * q_ptr->lev))
3002 			new_amount = base_amount * 4 * q_ptr->lev; /* new_amount gets divided by q_ptr->lev later - mikaelh */
3003 
3004 		/* Especially high party xp boost in IDDC, or people might mostly prefer to solo to 2k */
3005 		if (!not_in_iddc)
3006 			new_boosted_amount = (new_amount * (IDDC_PARTY_XP_BOOST + 1)) / (num_members + IDDC_PARTY_XP_BOOST);
3007 		/* Some bonus is applied to encourage partying - Jir - */
3008 		else
3009 			new_boosted_amount = (new_amount * (PARTY_XP_BOOST + 1)) / (num_members + PARTY_XP_BOOST);
3010 
3011 		/* get less or more exp depending on if we're above or below the party average */
3012 		if (q_ptr->lev < average_lev) { // below average
3013 			if ((average_lev - q_ptr->lev) > 2)
3014 				modified_level = q_ptr->lev + 2;
3015 			else	modified_level = average_lev;
3016 		} else {
3017 			if ((q_ptr->lev - average_lev) > 2)
3018 				modified_level = q_ptr->lev - 2;
3019 			else	modified_level = average_lev;
3020 		}
3021 		new_amount = (new_boosted_amount * modified_level) / average_lev;
3022 
3023 		/* Calculate integer and fractional exp gain numbers */
3024 		new_exp = new_amount / q_ptr->lev / 100;
3025 		new_exp_frac = ((new_amount - new_exp * q_ptr->lev * 100)
3026 		    * 100L) / q_ptr->lev + q_ptr->exp_frac;
3027 
3028 		/* Keep track of experience */
3029 		if (new_exp_frac >= 10000L) {
3030 			new_exp++;
3031 			q_ptr->exp_frac = new_exp_frac - 10000L;
3032 		} else {
3033 			q_ptr->exp_frac = new_exp_frac;
3034 			q_ptr->redraw |= PR_EXP; //EXP_BAR_FINESCALE
3035 		}
3036 
3037 		/* Gain experience */
3038 		if (new_exp) gain_exp(Ind2, new_exp);
3039 		else if (!q_ptr->warning_fracexp && base_amount) {
3040 			msg_print(Ind2, "\374\377ySome monsters give less than 1 experience point, but you still gain a bit!");
3041 			s_printf("warning_fracexp: %s\n", q_ptr->name);
3042 			q_ptr->warning_fracexp = 1;
3043 		}
3044 	}
3045 }
3046 
3047 /*
3048  * Add a player to another player's list of hostilities.
3049  */
add_hostility(int Ind,cptr name,bool initiator)3050 bool add_hostility(int Ind, cptr name, bool initiator) {
3051 	player_type *p_ptr = Players[Ind], *q_ptr;
3052 	hostile_type *h_ptr;
3053 	int i;
3054 	bool bb = FALSE;
3055 
3056 #if 0 /* too risky? (exploitable) */
3057 	i = name_lookup_loose(Ind, name, TRUE, TRUE);
3058 #else
3059 	i = name_lookup(Ind, name, TRUE, TRUE);
3060 #endif
3061 
3062 	if (!i) {
3063 s_printf("ADD_HOSTILITY: not found.\n");
3064 		return FALSE;
3065 	}
3066 
3067 	/* Check for sillyness */
3068 	if (i == Ind) {
3069 		/* Message */
3070 		msg_print(Ind, "\377yYou cannot be hostile toward yourself.");
3071 		return FALSE;
3072 	}
3073 
3074 	/* If it's a blood bond, players may fight in safe zones and with party members np */
3075 	if (i > 0) bb = check_blood_bond(Ind, i);
3076 #ifdef NO_PK
3077 	if (i < 0 || !bb) return FALSE;
3078 #endif
3079 
3080 	/* log any attempts */
3081 	if (initiator) {
3082 		/* paranoia? shouldn't i always be > 0 here? */
3083 		if (i > 0) s_printf("HOSTILITY: %s attempts to declare war on %s.\n", p_ptr->name, Players[i]->name);
3084 		else s_printf("HOSTILITY: %s attempts to declare war (%d).\n", p_ptr->name, i);
3085 	}
3086 	/* prevent log spam from stormbringer */
3087 	else if (!istown(&p_ptr->wpos)) {
3088 		/* paranoia? shouldn't i always be > 0 here? */
3089 		if (i > 0) s_printf("HOSTILITY: %s attempts to declare war in return on %s.\n", p_ptr->name, Players[i]->name);
3090 		else s_printf("HOSTILITY: %s attempts to declare war in return (%d).\n", p_ptr->name, i);
3091 	}
3092 
3093 #ifndef KURZEL_PK
3094 	if (cfg.use_pk_rules == PK_RULES_DECLARE) {
3095 		if(!(p_ptr->pkill & PKILL_KILLER) && (p_ptr->pvpexception != 1)){
3096 			msg_print(Ind, "\377yYou may not be hostile to other players.");
3097 			return FALSE;
3098 		}
3099 	}
3100 #endif
3101 
3102 	if (cfg.use_pk_rules == PK_RULES_NEVER && (p_ptr->pvpexception != 1)) {
3103 		msg_print(Ind, "\377yYou may not be hostile to other players.");
3104 		return FALSE;
3105 	}
3106 
3107 	/* Non-validated players may not pkill */
3108 	if (p_ptr->inval) {
3109 		msg_print(Ind, "Your account needs to be validated in order to fight other players.");
3110 		return FALSE;
3111 	}
3112 
3113 #if 1
3114 	if (!bb && initiator && !istown(&p_ptr->wpos)) {
3115 		msg_print(Ind, "\377yYou need to be in town to declare war.");
3116 		return FALSE;
3117 	}
3118 #endif
3119 
3120 	if (p_ptr->pvpexception == 2) return FALSE;
3121 	if (p_ptr->pvpexception == 3) {
3122                 p_ptr->chp = -3;
3123                 strcpy(p_ptr->died_from, "adrenaline poisoning");
3124                 p_ptr->deathblow = 0;
3125 		p_ptr->energy = -666;
3126 //		p_ptr->death = TRUE;
3127                 player_death(Ind);
3128 		return FALSE;
3129 	}
3130 
3131 	if (i > 0) {
3132 		q_ptr = Players[i];
3133 
3134 		/* Make sure players aren't in the same party */
3135 		if (!bb && p_ptr->party && player_in_party(p_ptr->party, i)) {
3136 			msg_format(Ind, "\377y%^s is in your party!", q_ptr->name);
3137 			return FALSE;
3138 		}
3139 
3140 		/* Ensure we don't add the same player twice */
3141 		for (h_ptr = p_ptr->hostile; h_ptr; h_ptr = h_ptr->next) {
3142 			/* Check this ID */
3143 			if (h_ptr->id == q_ptr->id) {
3144 				msg_format(Ind, "\377yYou are already hostile toward %s.", q_ptr->name);
3145 				return FALSE;
3146 			}
3147 		}
3148 
3149 		/* Create a new hostility node */
3150 		MAKE(h_ptr, hostile_type);
3151 
3152 		/* Set ID in node */
3153 		h_ptr->id = q_ptr->id;
3154 
3155 		/* Put this node at the beginning of the list */
3156 		h_ptr->next = p_ptr->hostile;
3157 		p_ptr->hostile = h_ptr;
3158 
3159 #if 0
3160 		/* prevent anti-tele amulet instant recall into barrow-downs and crap */
3161 		if (p_ptr->word_recall) //&& istown(&p_ptr->wpos)
3162 			set_recall_timer(Ind, 0);
3163 #endif
3164 
3165 		/* Message */
3166 		if (bb) {
3167 			msg_format(Ind, "\377yYou are now hostile toward %s.", q_ptr->name);
3168 			msg_format(i, "\377y* Player %s declared war on you! *", p_ptr->name);
3169 		} else {
3170 			msg_format(Ind, "\374\377RYou are now hostile toward %s.", q_ptr->name);
3171 			msg_format(i, "\374\377R* Player %s declared war on you! *", p_ptr->name);
3172 		}
3173 
3174 		/* Success */
3175 		return TRUE;
3176 	} else {
3177 		/* Tweak - inverse i once more */
3178 		i = 0 - i;
3179 
3180 		/* Ensure we don't add the same party twice */
3181 		for (h_ptr = p_ptr->hostile; h_ptr; h_ptr = h_ptr->next) {
3182 			/* Check this ID */
3183 			if (h_ptr->id == 0 - i) {
3184 				msg_format(Ind, "\377yYou are already hostile toward party '%s'.", parties[i].name);
3185 				return FALSE;
3186 			}
3187 		}
3188 
3189 		/* Create a new hostility node */
3190 		MAKE(h_ptr, hostile_type);
3191 
3192 		/* Set ID in node */
3193 		h_ptr->id = 0 - i;
3194 
3195 		/* Put this node at the beginning of the list */
3196 		h_ptr->next = p_ptr->hostile;
3197 		p_ptr->hostile = h_ptr;
3198 
3199 #if 0
3200 		/* prevent anti-tele amulet instant recall into barrow-downs and crap */
3201 		if (p_ptr->word_recall) //&& istown(&p_ptr->wpos)
3202 			set_recall_timer(Ind, 0);
3203 #endif
3204 
3205 		/* Message */
3206 		msg_format(Ind, "\377RYou are now hostile toward party '%s'.", parties[i].name);
3207 		msg_broadcast_format(Ind, "\374\377R* %s declares war on party '%s'. *", p_ptr->name, parties[i].name);
3208 
3209 		/* Success */
3210 		return TRUE;
3211 	}
3212 }
3213 
3214 /*
3215  * Remove an entry from a player's list of hostilities
3216  */
remove_hostility(int Ind,cptr name)3217 bool remove_hostility(int Ind, cptr name) {
3218 	player_type *p_ptr = Players[Ind];
3219 	hostile_type *h_ptr, *i_ptr;
3220 	cptr p, q = NULL;
3221 	int i = name_lookup_loose(Ind, name, TRUE, TRUE);
3222 
3223 	if (!i) return FALSE;
3224 
3225 	/* Check for another silliness */
3226 	if (i == Ind) {
3227 		/* Message */
3228 		msg_print(Ind, "\377GYou are not hostile toward yourself.");
3229 
3230 		return FALSE;
3231 	}
3232 
3233 #ifdef NO_PK
3234 	/* If it's a blood bond, players may fight in safe zones and with party members np */
3235 	if (i < 0) return FALSE;
3236 	else if (!check_blood_bond(Ind, i)) return FALSE;
3237 #endif
3238 
3239 	/* Forge name */
3240 	if (i > 0) q = Players[i]->name;
3241 
3242 	/* Initialize lock-step */
3243 	i_ptr = NULL;
3244 
3245 	/* Search entries */
3246 	for (h_ptr = p_ptr->hostile; h_ptr; i_ptr = h_ptr, h_ptr = h_ptr->next) {
3247 		/* Lookup name of this entry */
3248 		if (h_ptr->id > 0) {
3249 			/* Efficiency */
3250 			if (i < 0) continue;
3251 
3252 			/* Look up name */
3253 			p = lookup_player_name(h_ptr->id);
3254 
3255 			/* Check player name */
3256 //			if (p && (streq(p, q) || streq(p, name)))
3257 			if (p && streq(p, q)) {
3258 				/* Delete this entry */
3259 				if (i_ptr) {
3260 					/* Skip over */
3261 					i_ptr->next = h_ptr->next;
3262 				} else {
3263 					/* Adjust beginning of list */
3264 					p_ptr->hostile = h_ptr->next;
3265 				}
3266 
3267 				/* Message */
3268 				msg_format(Ind, "\377GNo longer hostile toward %s.", p);
3269 				msg_format(i, "\374\377G%s is no longer hostile toward you.", p_ptr->name);
3270 
3271 				/* Delete node */
3272 				KILL(h_ptr, hostile_type);
3273 
3274 				/* Success */
3275 				return TRUE;
3276 			}
3277 		} else {
3278 			/* Efficiency */
3279 			if (i >= 0) continue;
3280 
3281 			/* Assume this is a party */
3282 //			if (streq(parties[0 - h_ptr->id].name, q))
3283 			if (i == h_ptr->id) {
3284 				/* Delete this entry */
3285 				if (i_ptr) {
3286 					/* Skip over */
3287 					i_ptr->next = h_ptr->next;
3288 				} else {
3289 					/* Adjust beginning of list */
3290 					p_ptr->hostile = h_ptr->next;
3291 				}
3292 
3293 				/* Message */
3294 				msg_format(Ind, "\377GNo longer hostile toward party '%s'.", parties[0 - i].name);
3295 				msg_broadcast_format(Ind, "\374\377G%s is no longer hostile toward party '%s'.", p_ptr->name, parties[0 - i].name);
3296 
3297 				/* Delete node */
3298 				KILL(h_ptr, hostile_type);
3299 
3300 				/* Success */
3301 				return TRUE;
3302 			}
3303 		}
3304 	}
3305 	return(FALSE);
3306 }
3307 
3308 /*
3309  * Check if one player is hostile toward the other
3310  */
check_hostile(int attacker,int target)3311 bool check_hostile(int attacker, int target) {
3312 	player_type *p_ptr = Players[attacker], *q_ptr = Players[target];
3313 	hostile_type *h_ptr;
3314 
3315 	/* Highlander Tournament is a fight to death */
3316 	if ((p_ptr->global_event_temp & PEVF_AUTOPVP_00) &&
3317 	    (q_ptr->global_event_temp & PEVF_AUTOPVP_00)) {
3318 		return(TRUE);
3319 	}
3320 
3321 	/* towns are safe-zones for ALL players - except for blood bond */
3322 	if ((istown(&q_ptr->wpos) || istown(&p_ptr->wpos)) &&
3323 	    (!check_blood_bond(attacker, target) ||
3324 	     p_ptr->afk || q_ptr->afk))
3325 		return(FALSE);
3326 	/* outside of towns, PvP-mode means auto-hostility! */
3327 	else if (((q_ptr->mode & MODE_PVP) && (p_ptr->mode & MODE_PVP))
3328 #ifdef KURZEL_PK
3329 	    || (((q_ptr->pkill & PKILL_SET) && (p_ptr->pkill & PKILL_SET)) && ((!p_ptr->party && !q_ptr->party) || !(q_ptr->party == p_ptr->party)))
3330 #endif
3331 	    )
3332 		return(TRUE);
3333 
3334 	/* Scan list */
3335 	for (h_ptr = p_ptr->hostile; h_ptr; h_ptr = h_ptr->next) {
3336 		/* Check ID */
3337 		if (h_ptr->id > 0) {
3338 			/* Identical ID's yield hostility */
3339 			if (h_ptr->id == q_ptr->id)
3340 				return TRUE;
3341 		} else {
3342 			/* Check if target belongs to hostile party */
3343 			if (q_ptr->party == 0 - h_ptr->id)
3344 				return TRUE;
3345 		}
3346 	}
3347 
3348 	/* Not hostile */
3349 	return FALSE;
3350 }
3351 
3352 
3353 /*
3354  * Add/remove a player to/from another player's list of ignorance.
3355  * These functions should be common with hostilityes in the future. -Jir-
3356  */
add_ignore(int Ind,cptr name)3357 bool add_ignore(int Ind, cptr name) {
3358 	player_type *p_ptr = Players[Ind], *q_ptr;
3359 	hostile_type *h_ptr, *i_ptr;
3360 	int i;
3361 	int snum = 0;
3362 	cptr p, q = NULL;
3363 	char search[80], *pname;
3364 
3365 	/* Check for silliness */
3366 	if (!name) {
3367 		msg_print(Ind, "Usage: /ignore foobar");
3368 
3369 		return FALSE;
3370 	}
3371 
3372 #ifdef TOMENET_WORLDS
3373 	if ((pname = strchr(name, '@'))){
3374 		struct remote_ignore *curr, *prev = NULL;
3375 		struct rplist *w_player;
3376 		strncpy(search, name, pname - name);
3377 		search[pname - name] = '\0';
3378 		snum = atoi(pname + 1);
3379 		w_player = world_find_player(search, snum);
3380 		if (!w_player) {
3381 			msg_format(Ind, "Could not find %s in the world", search);
3382 			return(FALSE);
3383 		}
3384 		curr = p_ptr->w_ignore;
3385 		while (curr) {
3386 			if (curr->serverid == w_player->server && curr->id == w_player->id) break;
3387 			prev = curr;
3388 			curr = curr->next;
3389 		}
3390 		if (!curr) {
3391 			msg_format(Ind, "Ignoring %s across the world", w_player->name);
3392 			curr = NEW(struct remote_ignore);
3393 			curr->serverid = w_player->server;
3394 			curr->id = w_player->id;
3395 			curr->next = NULL;
3396 			if (prev)
3397 				prev->next = curr;
3398 			else
3399 				p_ptr->w_ignore = curr;
3400 		}
3401 		else {
3402 			msg_format(Ind, "Hearing %s from across the world", search);
3403 			if (!prev)
3404 				p_ptr->w_ignore = curr->next;
3405 			else
3406 				prev->next = curr->next;
3407 			FREE(curr, struct remote_ignore);
3408 		}
3409 		return(TRUE);
3410 	}
3411 #endif
3412 
3413 	i = name_lookup_loose(Ind, name, TRUE, TRUE);
3414 	if (!i) return FALSE;
3415 
3416 	/* Check for another silliness */
3417 	if (i == Ind) {
3418 		/* Message */
3419 		msg_print(Ind, "You cannot ignore yourself.");
3420 
3421 		return FALSE;
3422 	}
3423 
3424 	/* Forge name */
3425 	if (i > 0) {
3426 		q = Players[i]->name;
3427 	}
3428 
3429 	/* Initialize lock-step */
3430 	i_ptr = NULL;
3431 
3432 	/* Toggle ignorance if already on the list */
3433 	for (h_ptr = p_ptr->ignore; h_ptr; i_ptr = h_ptr, h_ptr = h_ptr->next) {
3434 		/* Lookup name of this entry */
3435 		if (h_ptr->id > 0) {
3436 			/* Efficiency */
3437 			if (i < 0) continue;
3438 
3439 			/* Look up name */
3440 			p = lookup_player_name(h_ptr->id);
3441 
3442 			/* Check player name */
3443 			if (p && streq(p, q)) {
3444 				/* Delete this entry */
3445 				if (i_ptr) {
3446 					/* Skip over */
3447 					i_ptr->next = h_ptr->next;
3448 				} else {
3449 					/* Adjust beginning of list */
3450 					p_ptr->ignore = h_ptr->next;
3451 				}
3452 
3453 				/* Message */
3454 				msg_format(Ind, "Now listening to %s again.", p);
3455 
3456 				/* Delete node */
3457 				KILL(h_ptr, hostile_type);
3458 
3459 				/* Success */
3460 				return TRUE;
3461 			}
3462 		} else {
3463 			/* Efficiency */
3464 			if (i > 0) continue;
3465 
3466 			/* Assume this is a party */
3467 //			if (streq(parties[0 - h_ptr->id].name, q))
3468 			if (i == h_ptr->id) {
3469 				/* Delete this entry */
3470 				if (i_ptr) {
3471 					/* Skip over */
3472 					i_ptr->next = h_ptr->next;
3473 				} else {
3474 					/* Adjust beginning of list */
3475 					p_ptr->ignore = h_ptr->next;
3476 				}
3477 
3478 				/* Message */
3479 				msg_format(Ind, "Now listening to party '%s' again.", parties[0 - i].name);
3480 
3481 				/* Delete node */
3482 				KILL(h_ptr, hostile_type);
3483 
3484 				/* Success */
3485 				return TRUE;
3486 			}
3487 		}
3488 	}
3489 
3490 	if (i > 0) {
3491 		q_ptr = Players[i];
3492 
3493 		/* Create a new hostility node */
3494 		MAKE(h_ptr, hostile_type);
3495 
3496 		/* Set ID in node */
3497 		h_ptr->id = q_ptr->id;
3498 
3499 		/* Put this node at the beginning of the list */
3500 		h_ptr->next = p_ptr->ignore;
3501 		p_ptr->ignore = h_ptr;
3502 
3503 		/* Message */
3504 		msg_format(Ind, "You aren't hearing %s any more.", q_ptr->name);
3505 
3506 		/* Success */
3507 		return TRUE;
3508 	} else {
3509 		/* Tweak - inverse i once more */
3510 		i = 0 - i;
3511 
3512 		/* Create a new hostility node */
3513 		MAKE(h_ptr, hostile_type);
3514 
3515 		/* Set ID in node */
3516 		h_ptr->id = 0 - i;
3517 
3518 		/* Put this node at the beginning of the list */
3519 		h_ptr->next = p_ptr->ignore;
3520 		p_ptr->ignore = h_ptr;
3521 
3522 		/* Message */
3523 		msg_format(Ind, "You aren't hearing party '%s' any more.", parties[i].name);
3524 
3525 		/* Success */
3526 		return TRUE;
3527 	}
3528 }
3529 
3530 /*
3531  * Check if one player is ignoring the other
3532  */
check_ignore(int attacker,int target)3533 bool check_ignore(int attacker, int target) {
3534 	player_type *p_ptr = Players[attacker];
3535 	hostile_type *h_ptr;
3536 
3537 	/* Scan list */
3538 	for (h_ptr = p_ptr->ignore; h_ptr; h_ptr = h_ptr->next) {
3539 		/* Check ID */
3540 		if (h_ptr->id > 0) {
3541 			/* Identical ID's yield hostility */
3542 			if (h_ptr->id == Players[target]->id)
3543 				return TRUE;
3544 		} else {
3545 			/* Check if target belongs to hostile party */
3546 			if (Players[target]->party == 0 - h_ptr->id)
3547 				return TRUE;
3548 		}
3549 	}
3550 
3551 	/* Not hostile */
3552 	return FALSE;
3553 }
3554 
3555 /*
3556  * The following is a simple hash table, which is used for mapping a player's
3557  * ID number to his name.  Only players that are still alive are stored in
3558  * the table, thus the mapping from a 32-bit integer is very sparse.  Also,
3559  * duplicate ID numbers are prohibitied.
3560  *
3561  * The hash function is going to be h(x) = x % n, where n is the length of
3562  * the table.  For efficiency reasons, n will be a power of 2, thus the
3563  * hash function can be a bitwise "and" and get the relevant bits off the end.
3564  *
3565  * No "probing" is done; if any two ID's map to the same hash slot, they will
3566  * be chained in a linked list.  This will most likely be a very rare thing,
3567  * however.
3568  */
3569 
3570 
3571 /*
3572  * Return the slot in which an ID should be stored.
3573  */
hash_slot(int id)3574 static int hash_slot(int id) {
3575 	/* Be very efficient */
3576 	return (id & (NUM_HASH_ENTRIES - 1));
3577 }
3578 
3579 
3580 /*
3581  * Lookup a player record ID.  Will return NULL on failure.
3582  */
lookup_player(int id)3583 hash_entry *lookup_player(int id) {
3584 	int slot;
3585 	hash_entry *ptr;
3586 
3587 	/* Get the slot */
3588 	slot = hash_slot(id);
3589 
3590 	/* Acquire the pointer to the first element in the chain */
3591 	ptr = hash_table[slot];
3592 
3593 	/* Search the chain, looking for the correct ID */
3594 	while (ptr) {
3595 		/* Check this entry */
3596 		if (ptr->id == id)
3597 			return ptr;
3598 
3599 		/* Next entry in chain */
3600 		ptr = ptr->next;
3601 	}
3602 
3603 	/* Not found */
3604 	return NULL;
3605 }
3606 
3607 
3608 /*
3609  * Get the player's highest level.
3610  */
lookup_player_level(int id)3611 byte lookup_player_level(int id) {
3612 	hash_entry *ptr;
3613 
3614 	if ((ptr = lookup_player(id)))
3615 		return ptr->level;
3616 
3617 	/* Not found */
3618 	return -1L;
3619 }
3620 
lookup_player_admin(int id)3621 byte lookup_player_admin(int id) {
3622 	hash_entry *ptr;
3623 
3624 	if ((ptr = lookup_player(id)))
3625 		return (ptr->admin ? 1 : 0);
3626 
3627 	/* Not found */
3628 	return -1L;
3629 }
3630 
lookup_player_type(int id)3631 u16b lookup_player_type(int id) {
3632 	hash_entry *ptr;
3633 
3634 	if ((ptr = lookup_player(id)))
3635 		return(ptr->race | (ptr->class <<8 ));
3636 
3637 	/* Not found */
3638 	return -1L;
3639 }
3640 
3641 /*
3642  * Get the player's current party.
3643  */
lookup_player_party(int id)3644 s32b lookup_player_party(int id) {
3645 	hash_entry *ptr;
3646 
3647 	if ((ptr = lookup_player(id)))
3648 		return ptr->party;
3649 
3650 	/* Not found */
3651 	return -1L;
3652 }
3653 
lookup_player_guild(int id)3654 s32b lookup_player_guild(int id) {
3655 	hash_entry *ptr;
3656 
3657 	if ((ptr = lookup_player(id)))
3658 		return ptr->guild;
3659 
3660 	/* Not found */
3661 	return -1L;
3662 }
3663 
lookup_player_guildflags(int id)3664 u32b lookup_player_guildflags(int id) {
3665 	hash_entry *ptr;
3666 
3667 	if ((ptr = lookup_player(id)))
3668 		return ptr->guild_flags;
3669 
3670 	/* Not found */
3671 	return -1L;
3672 }
3673 
3674 /*
3675  * Get the timestamp for the last time player was on.
3676  */
lookup_player_laston(int id)3677 time_t lookup_player_laston(int id) {
3678 	hash_entry *ptr;
3679 
3680 	if ((ptr = lookup_player(id)))
3681 		return ptr->laston;
3682 
3683 	/* Not found */
3684 	return -1L;
3685 }
3686 
3687 /*
3688  * Lookup a player name by ID.  Will return NULL if the name doesn't exist.
3689  */
lookup_player_name(int id)3690 cptr lookup_player_name(int id) {
3691 	hash_entry *ptr;
3692 
3693 	if ((ptr = lookup_player(id)))
3694 		return ptr->name;
3695 
3696 	/* Not found */
3697 	return NULL;
3698 }
3699 
3700 /*
3701  * Get the player's character mode (needed for account overview screen only).
3702  */
lookup_player_mode(int id)3703 byte lookup_player_mode(int id) {
3704 	hash_entry *ptr;
3705 
3706 	if ((ptr = lookup_player(id)))
3707 		return ptr->mode;
3708 
3709 	/* Not found */
3710 	return -1L;
3711 }
3712 
3713 /*
3714  * Get the player's current location in the world.
3715  */
lookup_player_wpos(int id)3716 struct worldpos lookup_player_wpos(int id) {
3717 	hash_entry *ptr;
3718 	struct worldpos wpos = {-1, -1, 0};
3719 
3720 	if ((ptr = lookup_player(id)))
3721 		return ptr->wpos;
3722 
3723 	/* Not found */
3724 	return wpos;
3725 }
3726 
3727 #ifdef AUCTION_SYSTEM
3728 /*
3729  * Get the amount of gold the player has.
3730  */
lookup_player_au(int id)3731 s32b lookup_player_au(int id) {
3732 	hash_entry *ptr;
3733 
3734 	if ((ptr = lookup_player(id)))
3735 		return ptr->au;
3736 
3737 	/* Not found */
3738 	return -1L;
3739 }
3740 
3741 /*
3742  * Get the player's bank balance.
3743  */
lookup_player_balance(int id)3744 s32b lookup_player_balance(int id) {
3745 	hash_entry *ptr;
3746 
3747 	if ((ptr = lookup_player(id)))
3748 		return ptr->balance;
3749 
3750 	/* Not found */
3751 	return -1L;
3752 }
3753 #endif
3754 
3755 /*
3756  * Lookup a player's ID by name.  Return 0 if not found.
3757  */
lookup_player_id(cptr name)3758 int lookup_player_id(cptr name)
3759 {
3760 	hash_entry *ptr;
3761 	int i;
3762 
3763 	/* Search in each array slot */
3764 	for (i = 0; i < NUM_HASH_ENTRIES; i++)
3765 	{
3766 		/* Acquire pointer to this chain */
3767 		ptr = hash_table[i];
3768 
3769 		/* Check all entries in this chain */
3770 		while (ptr)
3771 		{
3772 			/* Check this name */
3773 			if (!strcmp(ptr->name, name))
3774 				return ptr->id;
3775 
3776 			/* Next entry in chain */
3777 			ptr = ptr->next;
3778 		}
3779 	}
3780 
3781 	/* Not found */
3782 	return 0;
3783 }
3784 
fix_player_case(char * name)3785 bool fix_player_case(char *name) {
3786 	hash_entry *ptr;
3787 	int i;
3788 
3789 	/* Search in each array slot */
3790 	for (i = 0; i < NUM_HASH_ENTRIES; i++) {
3791 		/* Acquire pointer to this chain */
3792 		ptr = hash_table[i];
3793 
3794 		/* Check all entries in this chain */
3795 		while (ptr) {
3796 			/* Check this name */
3797 			if (!strcasecmp(ptr->name, name)) {
3798 				/* Overwrite it with currently used capitalization */
3799 				if (strcmp(ptr->name, name)) {
3800 					strcpy(name, ptr->name);
3801 					return TRUE;
3802 				}
3803 				return FALSE;
3804 			}
3805 
3806 			/* Next entry in chain */
3807 			ptr = ptr->next;
3808 		}
3809 	}
3810 
3811 	/* Not found */
3812 	return FALSE;
3813 }
3814 
3815 /* Messed up version of lookup_player_id for house ownership changes
3816    that involve messed up characters (in terms of their ID, for example
3817    if they were copied / restored instead of cleanly created..) mea culpa! */
lookup_player_id_messy(cptr name)3818 int lookup_player_id_messy(cptr name)
3819 {
3820 	hash_entry *ptr;
3821 	int i, tmp_id = 0;
3822 
3823 	/* Search in each array slot */
3824 	for (i = 0; i < NUM_HASH_ENTRIES; i++)
3825 	{
3826 		/* Acquire pointer to this chain */
3827 		ptr = hash_table[i];
3828 
3829 		/* Check all entries in this chain */
3830 		while (ptr)
3831 		{
3832 			/* Check this name
3833 			   The ' && (ptr->id > 0)' part is only needed for the hack below this while loop - C. Blue */
3834 			if (!strcmp(ptr->name, name) && (ptr->id > 0)) {
3835 				tmp_id = ptr->id;
3836 				break;
3837 			}
3838 
3839 			/* Next entry in chain */
3840 			ptr = ptr->next;
3841 		}
3842 		if (tmp_id) break;
3843 	}
3844 
3845 	/* In case of messed up IDs (due to restoring erased chars, etc)
3846 	   perform a double check on all players who are currently on: - C. Blue
3847 	   (on a clean server *cough* this shouldn't be needed I think) */
3848 	for (i = 1; i <= NumPlayers; i++)
3849 		if (!strcmp(Players[i]->name, name)) {
3850 			if (tmp_id && (tmp_id != Players[i]->id)) /* mess-up detected */
3851 				s_printf("$ID-WARNING$ Player %s has hash id %d but character id %d.\n", Players[i]->name, tmp_id, Players[i]->id);
3852 			/* have character-id override the hash id.. sigh */
3853 			if (Players[i]->id > 0) return (Players[i]->id);
3854 			/* the > 0 check is paranoia.. */
3855 			break;
3856 		}
3857 
3858 	if (tmp_id) return (tmp_id);
3859 
3860 	/* Not found */
3861 	return 0;
3862 }
3863 
lookup_player_account(int id)3864 u32b lookup_player_account(int id) {
3865 	hash_entry *ptr;
3866 	if ((ptr = lookup_player(id)))
3867 		return ptr->account;
3868 
3869 	/* Not found */
3870 	return -1L;
3871 }
3872 
stat_player(char * name,bool on)3873 void stat_player(char *name, bool on) {
3874 	int id;
3875 	int slot;
3876 	hash_entry *ptr;
3877 
3878 	id = lookup_player_id(name);
3879 	if (id) {
3880 		slot = hash_slot(id);
3881 		ptr = hash_table[slot];
3882 		while (ptr) {
3883 			if (ptr->id == id) {
3884 				ptr->laston = on ? 0L : time(&ptr->laston);
3885 			}
3886 			ptr = ptr->next;
3887 		}
3888 	}
3889 }
3890 
3891 /* Timestamp an existing player */
clockin(int Ind,int type)3892 void clockin(int Ind, int type) {
3893 	int slot;
3894 	hash_entry *ptr;
3895 	player_type *p_ptr = Players[Ind];
3896 	slot = hash_slot(p_ptr->id);
3897 	ptr = hash_table[slot];
3898 	while (ptr) {
3899 		if (ptr->id == p_ptr->id) {
3900 			switch (type) {
3901 			case 0:
3902 				if (ptr->laston) ptr->laston = time(&ptr->laston);
3903 				break;
3904 			case 1:
3905 /*				if(p_ptr->lev>ptr->level)  -- changed it to != -- C. Blue */
3906 				if (p_ptr->lev != ptr->level)
3907 					ptr->level = p_ptr->lev;
3908 				break;
3909 			case 2:
3910 				ptr->party = p_ptr->party;
3911 				break;
3912 			case 3:
3913 				ptr->guild = p_ptr->guild;
3914 				ptr->guild_flags = p_ptr->guild_flags;
3915 				break;
3916 			case 4:
3917 				ptr->xorder = p_ptr->xorder_id;
3918 				break;
3919 #ifdef AUCTION_SYSTEM
3920 			case 5:
3921 				ptr->au = p_ptr->au;
3922 				ptr->balance = p_ptr->balance;
3923 				break;
3924 #endif
3925 			case 6:
3926 				ptr->admin = p_ptr->admin_dm ? 1 : (p_ptr->admin_wiz ? 2 : 0);
3927 				break;
3928 			case 7:
3929 				ptr->wpos = p_ptr->wpos;
3930 				break;
3931 			}
3932 			break;
3933 		}
3934 		ptr = ptr->next;
3935 	}
3936 }
3937 
3938 /* dish out a valid new player ID */
newid()3939 int newid() {
3940 	int id;
3941 	int slot;
3942 	hash_entry *ptr;
3943 
3944 /* there should be no need to do player_id > MAX_ID check
3945    as it should cycle just fine */
3946 
3947 	for (id = player_id; id <= MAX_ID; id++) {
3948 		slot = hash_slot(id);
3949 		ptr = hash_table[slot];
3950 
3951 		while (ptr) {
3952 			if (ptr->id == id) break;
3953 			ptr = ptr->next;
3954 		}
3955 		if (ptr) continue;	/* its on a valid one */
3956 		player_id = id + 1;	/* new cycle counter */
3957 		return(id);
3958 	}
3959 	for (id = 1; id < player_id; id++) {
3960 		slot = hash_slot(id);
3961 		ptr = hash_table[slot];
3962 
3963 		while (ptr) {
3964 			if (ptr->id == id) break;
3965 			ptr = ptr->next;
3966 		}
3967 		if(ptr) continue;	/* its on a valid one */
3968 		player_id = id + 1;	/* new cycle counter */
3969 		return(id);
3970 	}
3971 	return(0);	/* no user IDs available - not likely */
3972 }
3973 
sf_delete(const char * name)3974 void sf_delete(const char *name) {
3975 	int i, k = 0;
3976 	char temp[128],fname[MAX_PATH_LENGTH];
3977 	/* Extract "useful" letters */
3978 	for (i = 0; name[i]; i++) {
3979 		char c = name[i];
3980 
3981 		/* Accept some letters */
3982 		if (isalpha(c) || isdigit(c)) temp[k++] = c;
3983 
3984 		/* Convert space, dot, and underscore to underscore */
3985 		else if (strchr(SF_BAD_CHARS, c)) temp[k++] = '_';
3986 	}
3987 	temp[k] = '\0';
3988 	path_build(fname, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, temp);
3989 	unlink(fname);
3990 }
3991 
3992 /* For marking accounts active */
3993 static bool *account_active = NULL;
3994 
3995 /*
3996  *  Called once every 24 hours. Deletes unused IDs.
3997  */
scan_players()3998 void scan_players() {
3999 	int slot, amt = 0;
4000 	int i, j;
4001 	hash_entry *ptr, *pptr = NULL;
4002 	time_t now;
4003 	object_type *o_ptr;
4004 
4005 #if 0 /* Low-performance version */
4006 	struct account *c_acc = NULL;
4007 #endif
4008 
4009 #ifdef PLAYERS_NEVER_EXPIRE
4010 	s_printf("(scan_players() disabled due to PLAYERS_NEVER_EXPIRE (DEF).)\n");
4011 	return;
4012 #else
4013 	if (cfg.players_never_expire) s_printf("(scan_players() disabled due to PLAYERS_NEVER_EXPIRE (cfg).)\n");
4014 	return;
4015 #endif
4016 
4017 	/* Allocate an array for marking accounts as active */
4018 	C_MAKE(account_active, MAX_ACCOUNTS / 8, bool);
4019 
4020 	now = time(&now);
4021 
4022 	s_printf("Starting player inactivity check..\n");
4023 	for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4024 		pptr = NULL;
4025 		ptr = hash_table[slot];
4026 		while (ptr) {
4027 			if (ptr->laston && (now - ptr->laston > 3600 * 24 * CHARACTER_EXPIRY_DAYS)) {/*15552000; 7776000 = 90 days at 60fps*/
4028 				hash_entry *dptr;
4029 				cptr acc;
4030 
4031 				acc = lookup_accountname(ptr->id);
4032 				if (!acc) acc = "(no account)";
4033 				s_printf("  Removing player: %s (%s)\n", ptr->name, acc);
4034 
4035 				if (ptr->level >= 50 && ptr->admin == 0) l_printf("%s \\{D%s, level %d, was erased by timeout\n", showdate(), ptr->name, ptr->level);
4036 
4037 				for (i = 1; i < MAX_PARTIES; i++) { /* was i = 0 but real parties start from i = 1 - mikaelh */
4038 					if (streq(parties[i].owner, ptr->name)) {
4039 						s_printf("  Disbanding party: %s\n",parties[i].name);
4040 						del_party(i);
4041 						/* remove pending notes to his party -C. Blue */
4042 						for (j = 0; j < MAX_PARTYNOTES; j++) {
4043 							if (!strcmp(party_note_target[j], parties[i].name)) {
4044 								strcpy(party_note_target[j], "");
4045 								strcpy(party_note[j], "");
4046 							}
4047 						}
4048 						break;
4049 					}
4050 				}
4051 				kill_houses(ptr->id, OT_PLAYER);
4052 				rem_xorder(ptr->xorder);
4053 				/* Added this one.. should work well? */
4054 				kill_objs(ptr->id);
4055 
4056 #ifdef AUCTION_SYSTEM
4057 				auction_player_death(ptr->id);
4058 #endif
4059 
4060 				/* Wipe Artifacts (s)he had  -C. Blue */
4061 				for (i = 0; i < o_max; i++) {
4062 					o_ptr = &o_list[i];
4063 			                if (true_artifact_p(o_ptr) && (o_ptr->owner == ptr->id))
4064 						delete_object_idx(i, TRUE);
4065 				}
4066 
4067 				amt++;
4068 				sf_delete(ptr->name);	/* a sad day ;( */
4069 				if (!pptr) hash_table[slot] = ptr->next;
4070 				else pptr->next = ptr->next;
4071 				/* Free the memory in the player name */
4072 				free((char *)(ptr->name));
4073 
4074 				dptr = ptr;	/* safe storage */
4075 				ptr = ptr->next;	/* advance */
4076 
4077 				/* Free the memory for this struct */
4078 				KILL(dptr, hash_entry);
4079 				continue;
4080 			} else {
4081 #if 0 /* Low-performance version */
4082 				/* if a character didn't timeout, timestamp his
4083 				   account here, to help the account-expiry routines,
4084 				   keeping the account 'active' - see scan_accounts() - C. Blue */
4085 				c_acc = GetAccountID(ptr->account, TRUE);
4086 				/* avoid tagging multi-char accounts again for each char - once is sufficient */
4087 				if (c_acc) {
4088 					if (c_acc->acc_laston != now) {
4089 						c_acc->acc_laston = now;
4090 						WriteAccount(c_acc, FALSE);
4091 					}
4092 					KILL(c_acc, struct account);
4093 				}
4094 #else
4095 				/* If a character didn't timeout, mark his
4096 				   account as active here */
4097 				account_active[ptr->account / 8] |= 1 << (ptr->account % 8);
4098 #endif
4099 			}
4100 
4101 			/* proceed to next entry of this hash slot */
4102 			pptr = ptr;
4103 			ptr = ptr->next;
4104 		}
4105 	}
4106 
4107 	s_printf("  %d players expired.\n", amt);
4108 	s_printf("Finished player inactivity check.\n");
4109 }
4110 /*
4111  *  Called once every 24 hours. Deletes unused Account IDs.
4112  *  It's called straight after scan_players, usually.
4113  *  Unused means that there aren't any characters on it,
4114  *  and it's not been used to log in with for a certain amount of time. - C. Blue
4115  */
scan_accounts()4116 void scan_accounts() {
4117 	int total = 0, nondel = 0, active = 0, expired = 0, fixed = 0;
4118 	bool modified;
4119 	FILE *fp;
4120 	char buf[1024];
4121 	struct account c_acc;
4122 	time_t now;
4123 
4124 #ifdef PLAYERS_NEVER_EXPIRE
4125 	s_printf("(scan_accounts() disabled due to PLAYERS_NEVER_EXPIRE.)\n");
4126 	return;
4127 #else
4128 	if (cfg.players_never_expire) s_printf("(scan_accounts() disabled due to PLAYERS_NEVER_EXPIRE (cfg).)\n");
4129 	return;
4130 #endif
4131 
4132 	now = time(NULL);
4133 
4134 	if (!account_active) {
4135 		s_printf("scan_players() must be called before scan_accounts() is called!\n");
4136 		return;
4137 	}
4138 
4139 	s_printf("Starting account inactivity check..\n");
4140 
4141 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
4142 	fp = fopen(buf, "rb+");
4143 	if (!fp) return;
4144 
4145 	while (fread(&c_acc, sizeof(struct account), 1, fp)) {
4146 		modified = FALSE;
4147 
4148 		/* Count all accounts in the file */
4149 		total++;
4150 
4151 		if (c_acc.flags & ACC_DELD) continue;
4152 
4153 		/* Count non-deleted accounts */
4154 		nondel++;
4155 
4156 		if (c_acc.flags & ACC_ADMIN) {
4157 			/* Admin accounts always count as active */
4158 			active++;
4159 			continue;
4160 		}
4161 
4162 //		if (!c_acc.acc_laston) continue; /* not using this 'hack' for staticing here */
4163 
4164 		/* fix old accounts that don't have a timestamp yet */
4165 		if (!c_acc.acc_laston) {
4166 			c_acc.acc_laston = c_acc.acc_laston_real = now; /* set new timestamp */
4167 			fixed++;
4168 			modified = TRUE;
4169 		}
4170 
4171 		/* Check for bad account id */
4172 		else if (c_acc.id >= MAX_ACCOUNTS) {
4173 			/* Log it */
4174 			s_printf("  Bad account ID: %d\n", c_acc.id);
4175 
4176 			/* Fix the id */
4177 			c_acc.id = MAX_ACCOUNTS - 1;
4178 
4179 			/* Mark as deleted */
4180 			c_acc.flags |= ACC_DELD;
4181 
4182 			modified = TRUE;
4183 		}
4184 
4185 		/* Was the account marked as active? */
4186 		else if (account_active[c_acc.id / 8] & (1 << (c_acc.id % 8))) {
4187 			c_acc.acc_laston = now;
4188 
4189 			/* Count active accounts */
4190 			active++;
4191 
4192 			modified = TRUE;
4193 		}
4194 
4195 #if 1
4196 		/* test for expiry -> delete */
4197 		else if (now - c_acc.acc_laston >= 3600 * 24 * ACCOUNT_EXPIRY_DAYS) {
4198 			c_acc.flags |= ACC_DELD;
4199 
4200 			/* Count expired accounts */
4201 			expired++;
4202 
4203 			s_printf("  Account '%s' expired.\n", c_acc.name);
4204 			modified = TRUE;
4205 		}
4206 #endif
4207 
4208 //		if (modified) WriteAccount(&c_acc, FALSE);
4209 		if (modified) {
4210 			fseek(fp, -sizeof(struct account), SEEK_CUR);
4211 			if (fwrite(&c_acc, sizeof(struct account), 1, fp) < 1) {
4212 				s_printf("Writing to account file failed: %s\n", feof(fp) ? "EOF" : strerror(ferror(fp)));
4213 			}
4214 
4215 			/* HACK - Prevent reading past the end of the file on Windows - mikaelh */
4216 			fseek(fp, 0, SEEK_CUR);
4217 		}
4218 	}
4219 
4220 	if (fixed) s_printf("  %d accounts have been fixed.\n", fixed);
4221 	s_printf("  %d accounts in total, %d non-deleted, %d active.\n", total, nondel, active);
4222 	s_printf("  %d accounts have expired.\n", expired);
4223 
4224 	memset(c_acc.pass, 0, sizeof(c_acc.pass));
4225 	fclose(fp);
4226 	s_printf("Finished account inactivity check.\n");
4227 
4228 	C_KILL(account_active, MAX_ACCOUNTS / 8, bool);
4229 }
4230 
4231 /* Rename a player's char savegame as well as the name inside.
4232    Not sure if this function is 100% ok to use, regarding treatment of hash table. */
rename_character(char * pnames)4233 void rename_character(char *pnames){
4234 	int slot, pos, i, Ind;
4235 	hash_entry *ptr;
4236 	char pname[40], nname[40];
4237 	player_type *p_ptr;
4238 
4239 	Ind = ++NumPlayers;
4240 
4241         /* Allocate memory for him */
4242         MAKE(Players[Ind], player_type);
4243         C_MAKE(Players[Ind]->inventory, INVEN_TOTAL, object_type);
4244 	p_ptr = Players[Ind];
4245 
4246 	/* extract old+new name from 'pnames' */
4247 	if (!(strchr(pnames, ':'))) return;
4248 	pos = strchr(pnames, ':') - pnames;
4249 	strncpy(pname, pnames, pos);
4250 	pname[pos] = 0;
4251 	strcpy(nname, pnames + pos + 1);
4252 	s_printf("Renaming player: %s to %s\n", pname, nname);
4253 
4254 	/* scan hash entries */
4255 	for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4256 		ptr = hash_table[slot];
4257 		while (ptr) {
4258 			if (strcmp(ptr->name, pname)) {
4259 				ptr = ptr->next;
4260 				continue;
4261 			}
4262 
4263 			/* load him */
4264 			strcpy(p_ptr->name, pname);
4265 			process_player_name(Ind, TRUE);
4266 			if (!load_player(Ind)) {
4267 				/* bad fail */
4268 				s_printf("rename_character: load_player '%s' failed\n", pname);
4269 			        C_KILL(Players[Ind]->inventory, INVEN_TOTAL, object_type);
4270 			        KILL(Players[Ind], player_type);
4271 				NumPlayers--;
4272 				return;
4273 			}
4274 
4275 			/* change his name */
4276 			strcpy(p_ptr->name, nname);
4277 			if (!process_player_name(Ind, TRUE)) {
4278 				/* done (failure) */
4279 				s_printf("rename_character: bad new name '%s'\n", nname);
4280 			        C_KILL(Players[Ind]->inventory, INVEN_TOTAL, object_type);
4281 			        KILL(Players[Ind], player_type);
4282 				NumPlayers--;
4283 				return;
4284 			}
4285 			/* change his name in hash table */
4286 			strcpy((char *) ptr->name, p_ptr->name);
4287 			/* save him */
4288 			save_player(Ind);
4289 			/* delete old savefile) */
4290 			sf_delete(pname);
4291 
4292 			/* change his name as party owner */
4293 			for (i = 1; i < MAX_PARTIES; i++) { /* was i = 0 but real parties start from i = 1 - mikaelh */
4294 				if (streq(parties[i].owner, ptr->name)) {
4295 					s_printf("Renaming owner of party: %s\n",parties[i].name);
4296 					strcpy(parties[i].owner, nname);
4297 					break;
4298 				}
4299 			}
4300 
4301 			/* (guilds only use numerical ID, not names) */
4302 
4303 			/* done (success) */
4304 			s_printf("rename_character: success '%s' -> '%s'\n", pname, nname);
4305 		        C_KILL(Players[Ind]->inventory, INVEN_TOTAL, object_type);
4306 		        KILL(Players[Ind], player_type);
4307 			NumPlayers--;
4308 
4309 			/* update live player */
4310 			for (i = 1; i <= NumPlayers; i++) {
4311 				p_ptr = Players[i];
4312 				if (strcmp(p_ptr->name, pname)) continue;
4313 
4314 				strcpy(p_ptr->name, nname);
4315 				if (!process_player_name(i, TRUE)) {
4316 					/* done (failure) -- paranoia, shouldn't happen (caught above already!) */
4317 					s_printf("rename_character: *LIVE* bad new name '%s'\n", nname);
4318 					Destroy_connection(i, "Name changed. Please log in again.");
4319 					/* delete old savefile) */
4320 					sf_delete(pname);
4321 					return;
4322 				}
4323 				Send_char_info(i, p_ptr->prace, p_ptr->pclass, p_ptr->ptrait, p_ptr->male, p_ptr->mode, p_ptr->name);
4324 				return;
4325 			}
4326 			return;
4327 		}
4328 	}
4329 
4330 	/* free temporary player */
4331 	s_printf("rename_character: name not found\n");
4332         C_KILL(Players[Ind]->inventory, INVEN_TOTAL, object_type);
4333         KILL(Players[Ind], player_type);
4334 	NumPlayers--;
4335 }
4336 
4337 /*
4338  *  Erase a player by charfile-name - C. Blue
4339  */
erase_player_name(char * pname)4340 void erase_player_name(char *pname){
4341 	int slot;
4342 	hash_entry *ptr, *pptr = NULL;
4343 	object_type *o_ptr;
4344 
4345 	for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4346 		pptr = NULL;
4347 		ptr = hash_table[slot];
4348 		while (ptr) {
4349 			if (!strcmp(ptr->name, pname)) {
4350 				int i,j;
4351 				hash_entry *dptr;
4352 				cptr acc;
4353 
4354 				acc = lookup_accountname(ptr->id);
4355 				if (!acc) acc = "(no account)";
4356 				s_printf("Removing player: %s (%s)\n", ptr->name, acc);
4357 
4358 				for (i = 1; i < MAX_PARTIES; i++) { /* was i = 0 but real parties start from i = 1 - mikaelh */
4359 					if (streq(parties[i].owner, ptr->name)) {
4360 						s_printf("Disbanding party: %s\n",parties[i].name);
4361 						del_party(i);
4362 	        				/* remove pending notes to his party -C. Blue */
4363 					        for (j = 0; j < MAX_PARTYNOTES; j++) {
4364 					                if (!strcmp(party_note_target[j], parties[i].name)) {
4365 			                		        strcpy(party_note_target[j], "");
4366 					                        strcpy(party_note[j], "");
4367 					                }
4368 					        }
4369 						break;
4370 					}
4371 				}
4372 				kill_houses(ptr->id, OT_PLAYER);
4373 				rem_xorder(ptr->xorder);
4374 				/* Added this one.. should work well? */
4375 				kill_objs(ptr->id);
4376 
4377 #ifdef AUCTION_SYSTEM
4378 				auction_player_death(ptr->id);
4379 #endif
4380 
4381 				/* Wipe Artifacts (s)he had  -C. Blue */
4382 				for (i = 0; i < o_max; i++) {
4383 					o_ptr = &o_list[i];
4384 					if (true_artifact_p(o_ptr) && (o_ptr->owner == ptr->id))
4385 						delete_object_idx(i, TRUE);
4386 				}
4387 
4388 				sf_delete(ptr->name);	/* a sad day ;( */
4389 				if (!pptr)
4390 					hash_table[slot] = ptr->next;
4391 				else
4392 					pptr->next = ptr->next;
4393 				/* Free the memory in the player name */
4394 				free((char *)(ptr->name));
4395 
4396 				dptr = ptr;	/* safe storage */
4397 				ptr = ptr->next;	/* advance */
4398 
4399 				/* Free the memory for this struct */
4400 				KILL(dptr, hash_entry);
4401 
4402 				continue;
4403 			}
4404 			pptr = ptr;
4405 			ptr = ptr->next;
4406 		}
4407 	}
4408 }
4409 
4410 /*
4411  * List of players about to expire - mikaelh
4412  */
checkexpiry(int Ind,int days)4413 void checkexpiry(int Ind, int days)
4414 {
4415 	int slot, expire;
4416 	hash_entry *ptr;
4417 	time_t now;
4418 	now = time(NULL);
4419 	msg_format(Ind, "\377oPlayers that are about to expire in %d days:", days);
4420 	for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4421 		ptr = hash_table[slot];
4422 		while (ptr) {
4423 			expire = CHARACTER_EXPIRY_DAYS * 86400 - now + ptr->laston;
4424 			if (ptr->laston && expire < days * 86400) {
4425 				if (expire < 86400) {
4426 					msg_format(Ind, "\377rPlayer %s (accid %d) will expire in less than a day!", ptr->name, ptr->account);
4427 				}
4428 				else if (expire < 7 * 86400) {
4429 					msg_format(Ind, "\377yPlayer %s (accid %d) will expire in %d days!", ptr->name, ptr->account, (expire / 86400));
4430 				}
4431 				else {
4432 					msg_format(Ind, "\377gPlayer %s (accid %d) will expire in %d days.", ptr->name, ptr->account, (expire / 86400));
4433 				}
4434 			}
4435 			ptr = ptr->next;
4436 		}
4437 	}
4438 }
4439 
4440 /*
4441  * Warn the player if other characters on his/her account will expire soon
4442  *  - mikaelh
4443  */
account_checkexpiry(int Ind)4444 void account_checkexpiry(int Ind) {
4445 	player_type *p_ptr = Players[Ind];
4446 	int slot, expire;
4447 	hash_entry *ptr;
4448 	time_t now;
4449 
4450 #ifdef PLAYERS_NEVER_EXPIRE
4451 	return;
4452 #else
4453 	if (cfg.players_never_expire) return;
4454 #endif
4455 	now = time(NULL);
4456 
4457 	for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4458 		ptr = hash_table[slot];
4459 		while (ptr) {
4460 			if (p_ptr->id != ptr->id && p_ptr->account == ptr->account && ptr->laston) {
4461 				expire = CHARACTER_EXPIRY_DAYS * 86400 - now + ptr->laston;
4462 
4463 				if (expire < 86400) {
4464 					msg_format(Ind, "\374\377yYour character %s will be removed \377rvery soon\377y!", ptr->name, expire / 86400);
4465 				} else if (expire < 60 * 86400) {
4466 					msg_format(Ind, "\374\377yYour character %s will be removed in %d days.", ptr->name, expire / 86400);
4467 				}
4468 			}
4469 			ptr = ptr->next;
4470 		}
4471 	}
4472 }
4473 
4474 /*
4475  * Add a name to the hash table.
4476  */
add_player_name(cptr name,int id,u32b account,byte race,byte class,byte mode,byte level,u16b party,byte guild,u32b guild_flags,u16b xorder,time_t laston,byte admin,struct worldpos wpos)4477 void add_player_name(cptr name, int id, u32b account, byte race, byte class, byte mode, byte level, u16b party, byte guild, u32b guild_flags, u16b xorder, time_t laston, byte admin, struct worldpos wpos) {
4478 	int slot;
4479 	hash_entry *ptr;
4480 
4481 	/* Set the entry's id */
4482 
4483 	/* Get the destination slot */
4484 	slot = hash_slot(id);
4485 
4486 	/* Create a new hash entry struct */
4487 	MAKE(ptr, hash_entry);
4488 
4489 	/* Make a copy of the player name in the entry */
4490 	ptr->name = strdup(name);
4491 	ptr->accountname = strdup(lookup_accountname2(account));
4492 	ptr->laston = laston;
4493 	ptr->id = id;
4494 	ptr->account = account;
4495 	ptr->level = level;
4496 	ptr->party = party;
4497 	ptr->guild = guild;
4498 	ptr->guild_flags = guild_flags;
4499 	ptr->xorder = xorder;
4500 	ptr->race = race;
4501 	ptr->class = class;
4502 	ptr->mode = mode;
4503 	ptr->admin = admin;
4504 	ptr->wpos.wx = wpos.wx;
4505 	ptr->wpos.wy = wpos.wy;
4506 	ptr->wpos.wz = wpos.wz;
4507 
4508 	/* Add the rest of the chain to this entry */
4509 	ptr->next = hash_table[slot];
4510 
4511 	/* Put this entry in the table */
4512 	hash_table[slot] = ptr;
4513 }
4514 
4515 /*
4516  * Verify a player's data against the hash table. - C. Blue
4517  */
verify_player(cptr name,int id,u32b account,byte race,byte class,byte mode,byte level,u16b party,byte guild,u32b guild_flags,u16b quest,time_t laston,byte admin,struct worldpos wpos)4518 void verify_player(cptr name, int id, u32b account, byte race, byte class, byte mode, byte level, u16b party, byte guild, u32b guild_flags, u16b quest, time_t laston, byte admin, struct worldpos wpos) {
4519 	hash_entry *ptr = lookup_player(id);
4520 
4521 	/* For savegame conversion 4.2.0 -> 4.2.2: */
4522 	if (ptr->mode != mode) {
4523 		s_printf("hash_entry: fixing mode of %s.\n", ptr->name);
4524 		ptr->mode = mode;
4525 	}
4526 	/* For savegame conversion 4.3.4 -> 4.3.5: */
4527 	if (ptr->class != class) {
4528 		s_printf("hash_entry: fixing class of %s.\n", ptr->name);
4529 		ptr->class = class;
4530 	}
4531 	if (ptr->guild != guild) {
4532 		s_printf("hash_entry: fixing guild of %s.\n", ptr->name);
4533 		ptr->guild = guild;
4534 	}
4535 	if (ptr->guild_flags != guild_flags) {
4536 		s_printf("hash_entry: fixing guild_flags of %s.\n", ptr->name);
4537 		ptr->guild_flags = guild_flags;
4538 	}
4539 	if (ptr->admin != admin) {
4540 		s_printf("hash_entry: fixing admin state of %s.\n", ptr->name);
4541 		ptr->admin = admin;
4542 	}
4543 	/* added in 4.5.7.1 */
4544 	if (ptr->wpos.wx != wpos.wx || ptr->wpos.wy != wpos.wy || ptr->wpos.wz != wpos.wz) {
4545 		s_printf("hash_entry: fixing wpos of %s.\n", ptr->name);
4546 		ptr->wpos.wx = wpos.wx;
4547 		ptr->wpos.wy = wpos.wy;
4548 		ptr->wpos.wz = wpos.wz;
4549 	}
4550 	/* --actually not needed-- */
4551 	if (!ptr->accountname) {
4552 		s_printf("hash_entry: fixing accountname of %s.\n", ptr->name);
4553 		ptr->accountname = strdup(lookup_accountname2(account));
4554 	}
4555 }
4556 
4557 /*
4558  * Delete an entry from the table, by ID.
4559  */
delete_player_id(int id)4560 void delete_player_id(int id) {
4561 	int slot;
4562 	hash_entry *ptr, *old_ptr;
4563 
4564 	/* Get the destination slot */
4565 	slot = hash_slot(id);
4566 
4567 	/* Acquire the pointer to the entry chain */
4568 	ptr = hash_table[slot];
4569 
4570 	/* Keep a pointer one step behind this one */
4571 	old_ptr = NULL;
4572 
4573 	/* Attempt to find the ID to delete */
4574 	while (ptr) {
4575 		/* Check this one */
4576 		if (ptr->id == id) {
4577 			/* Delete this one from the table */
4578 			if (old_ptr == NULL)
4579 				hash_table[slot] = ptr->next;
4580 			else old_ptr->next = ptr->next;
4581 
4582 			/* Free the memory in the player name */
4583 			free((char *)(ptr->name));
4584 
4585 			/* Free the memory for this struct */
4586 			KILL(ptr, hash_entry);
4587 
4588 			/* Done */
4589 			return;
4590 		}
4591 
4592 		/* Remember this entry */
4593 		old_ptr = ptr;
4594 
4595 		/* Advance to next entry in the chain */
4596 		ptr = ptr->next;
4597 	}
4598 
4599 	/* Not found */
4600 	return;
4601 }
4602 
4603 /*
4604  * Delete a player by name.
4605  *
4606  * This is useful for fault tolerance, as it is possible to have
4607  * two entries for one player name, if the server crashes hideously
4608  * or the machine has a power outage or something.
4609  */
delete_player_name(cptr name)4610 void delete_player_name(cptr name) {
4611 	int id;
4612 
4613 	/* Delete every occurence of this name */
4614 	while ((id = lookup_player_id(name))) {
4615 		/* Delete this one */
4616 		delete_player_id(id);
4617 	}
4618 }
4619 
4620 /*
4621  * Return a list of the player ID's stored in the table.
4622  */
player_id_list(int ** list,u32b account)4623 int player_id_list(int **list, u32b account) {
4624 	int i, j, len = 0, k = 0, tmp;
4625 	hash_entry *ptr;
4626 	int *llist;
4627 	int max_cpa = MAX_CHARS_PER_ACCOUNT;
4628 #ifdef ALLOW_DED_IDDC_MODE
4629 	max_cpa += MAX_DED_IDDC_CHARS;
4630 #endif
4631 #ifdef ALLOW_DED_PVP_MODE
4632 	max_cpa += MAX_DED_PVP_CHARS;
4633 #endif
4634 
4635 	/* Count up the number of valid entries */
4636 	for (i = 0; i < NUM_HASH_ENTRIES; i++) {
4637 		/* Acquire this chain */
4638 		ptr = hash_table[i];
4639 
4640 		/* Check this chain */
4641 		while (ptr) {
4642 			/* One more entry */
4643 			if(!account || ptr->account == account)
4644 				len++;
4645 
4646 			/* Next entry in chain */
4647 			ptr = ptr->next;
4648 		}
4649 	}
4650 	if (!len) return(0);
4651 
4652 	/* Allocate memory for the list */
4653 	C_MAKE((*list), len, int);
4654 
4655 	/* Direct pointer to the list */
4656 	llist = *list;
4657 
4658 	/* Look again, this time storing ID's */
4659 	for (i = 0; i < NUM_HASH_ENTRIES; i++) {
4660 		/* Acquire this chain */
4661 		ptr = hash_table[i];
4662 
4663 		/* Check this chain */
4664 		while (ptr) {
4665 			/* Store this ID */
4666 			if (!account || ptr->account == account) {
4667 				llist[k++] = ptr->id;
4668 
4669 				/* Insertion sort for account specific lists */
4670 				if (account) {
4671 					j = k - 1;
4672 					while (j > 0 && llist[j - 1] > llist[j]) {
4673 						tmp = llist[j - 1];
4674 						llist[j - 1] = llist[j];
4675 						llist[j] = tmp;
4676 						j--;
4677 					}
4678 				}
4679 			}
4680 
4681 			/* Next entry in chain */
4682 			ptr = ptr->next;
4683 		}
4684 	}
4685 
4686 	/* Limit number of characters per account - C. Blue */
4687 	/* This screwed up saving players in save.c, check that account is not 0 - mikaelh */
4688 	if (len > max_cpa && account) len = max_cpa;
4689 
4690 	return len;
4691 }
4692 
4693 /*
4694  * Set/reset 'pk' mode, which allows a player to kill the others
4695  *
4696  * These functions should be common with hostilityes in the future. -Jir-
4697  */
set_pkill(int Ind,int delay)4698 void set_pkill(int Ind, int delay) {
4699 	player_type *p_ptr = Players[Ind];
4700 	//bool admin = is_admin(p_ptr);
4701 
4702 	if (cfg.use_pk_rules != PK_RULES_DECLARE) {
4703 		msg_print(Ind, "\377o/pkill is not available on this server. Be pacifist.");
4704 		p_ptr->tim_pkill = 0;
4705 		p_ptr->pkill = 0;
4706 		return;
4707 	}
4708 #ifdef KURZEL_PK
4709 	else {
4710 		if (is_admin(p_ptr)) {
4711 			p_ptr->pkill ^= PKILL_SET; //Flag TOGGLE
4712 			if (p_ptr->pkill & PKILL_SET) msg_print(Ind, "\377RYou may now kill (and be killed by) other PK enabled players.");
4713 			else msg_print(Ind, "\377RPK Mode toggled OFF. (Admin ONLY)");
4714 		} else {
4715 			if (!(p_ptr->pkill & PKILL_SET)) {
4716 				p_ptr->pkill |= PKILL_SET; //Flag ON
4717 				msg_print(Ind, "\377RYou may now kill (and be killed by) other PK enabled players.");
4718 			} else {
4719 				msg_print(Ind, "\377RThere is no going back! (Party members are pacifist, however.)");
4720 			}
4721 		}
4722 		return;
4723 	}
4724 #endif
4725 
4726 //	p_ptr->tim_pkill= admin ? 10 : 200;	/* so many turns */
4727 	p_ptr->tim_pkill= delay;
4728 	p_ptr->pkill ^= PKILL_SET; /* Toggle value */
4729 	if (p_ptr->pkill & PKILL_SET) {
4730 		msg_print(Ind, "\377rYou wish to kill other players");
4731 		p_ptr->pkill |= PKILL_KILLABLE;
4732 	} else {
4733 		hostile_type *t_host;
4734 		msg_print(Ind, "\377gYou do not wish to kill other players");
4735 		p_ptr->pkill &= ~PKILL_KILLER;
4736 		/* Remove all hostilities */
4737 		while (p_ptr->hostile) {
4738 			t_host = p_ptr->hostile;
4739 			p_ptr->hostile = t_host->next;
4740 			KILL(t_host, hostile_type);
4741 		}
4742 	}
4743 }
4744 
4745 #if 0	// under construction
4746 /*
4747  * Set/reset 'pilot' mode, which allows a player to follow another player
4748  * for comfort in party diving.
4749  *
4750  * These functions should be common with hostilityes in the future. -Jir-
4751  */
4752 bool pilot_set(int Ind, cptr name)
4753 {
4754 	player_type *p_ptr = Players[Ind], *q_ptr;
4755 	hostile_type *h_ptr, *i_ptr;
4756 	int i;
4757 	cptr p,q;
4758 
4759 	/* Check for silliness */
4760 	if (!name) {
4761 		msg_print(Ind, "Usage: /pilot foobar");
4762 		return FALSE;
4763 	}
4764 
4765 	i = name_lookup_loose(Ind, name, TRUE, TRUE);
4766 
4767 	if (!i) {
4768 		return FALSE;
4769 	}
4770 
4771 	/* Check for another silliness */
4772 	if (i == Ind) {
4773 		/* Message */
4774 		msg_print(Ind, "You cannot follow yourself.");
4775 
4776 		return FALSE;
4777 	}
4778 
4779 	/* Forge name */
4780 	if (i > 0) {
4781 		q = Players[i]->name;
4782 	}
4783 
4784 
4785 	if (i > 0) {
4786 		q_ptr = Players[i];
4787 
4788 		/* Create a new hostility node */
4789 		MAKE(h_ptr, hostile_type);
4790 
4791 		/* Set ID in node */
4792 		h_ptr->id = q_ptr->id;
4793 
4794 		/* Put this node at the beginning of the list */
4795 		h_ptr->next = p_ptr->ignore;
4796 		p_ptr->ignore = h_ptr;
4797 
4798 		/* Message */
4799 		msg_format(Ind, "You aren't hearing %s any more.", q_ptr->name);
4800 
4801 		/* Success */
4802 		return TRUE;
4803 	} else {
4804 		/* Tweak - inverse i once more */
4805 		i = 0 - i;
4806 
4807 		/* Create a new hostility node */
4808 		MAKE(h_ptr, hostile_type);
4809 
4810 		/* Set ID in node */
4811 		h_ptr->id = 0 - i;
4812 
4813 		/* Put this node at the beginning of the list */
4814 		h_ptr->next = p_ptr->ignore;
4815 		p_ptr->ignore = h_ptr;
4816 
4817 		/* Message */
4818 		msg_format(Ind, "You aren't hearing party '%s' any more.", parties[i].name);
4819 
4820 		/* Success */
4821 		return TRUE;
4822 	}
4823 }
4824 #endif	// 0
4825 
strip_true_arts_from_hashed_players()4826 void strip_true_arts_from_hashed_players(){
4827         int slot, i, j = 0;
4828         hash_entry *ptr;
4829         object_type *o_ptr;
4830 
4831         s_printf("Starting player true artifact stripping\n");
4832         for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4833 		j++;
4834 //		if (j > 5) break;/*only check for 5 players right now */
4835 
4836 		ptr = hash_table[slot];
4837 		if (!ptr) continue;
4838 		s_printf("Stripping player: %s\n", ptr->name);
4839 		/* Wipe Artifacts (s)he had  -C. Blue */
4840 		for (i = 0; i < o_max; i++) {
4841 			o_ptr = &o_list[i];
4842 			if (true_artifact_p(o_ptr) &&
4843 			    (o_ptr->owner == ptr->id) && // <- why?
4844 			    !winner_artifact_p(o_ptr))
4845 #if 1 /* set 0 to not change cur_num */
4846 				delete_object_idx(i, TRUE);
4847 #else
4848 				excise_object_idx(o_idx);
4849 				WIPE(o_ptr, object_type);
4850 #endif
4851 	        }
4852 	}
4853         s_printf("Finished true artifact stripping for %d players.\n", j);
4854 }
4855 
account_change_password(int Ind,char * old_pass,char * new_pass)4856 void account_change_password(int Ind, char *old_pass, char *new_pass) {
4857 	player_type *p_ptr = Players[Ind];
4858 	struct account *c_acc;
4859 
4860 	c_acc = GetAccount(p_ptr->accountname, old_pass, FALSE);
4861 
4862 	if (!c_acc) {
4863 		msg_print(Ind, "Wrong password!");
4864 		return;
4865 	}
4866 
4867 	/* Change password */
4868 	strcpy(c_acc->pass, t_crypt(new_pass, c_acc->name));
4869 
4870 	if (!(WriteAccount(c_acc, FALSE))) {
4871 		KILL(c_acc, struct account);
4872 		msg_print(Ind, "Failed to write to account file!");
4873 		return;
4874 	}
4875 
4876 	s_printf("Changed password for account %s.\n", c_acc->name);
4877 	msg_print(Ind, "Password changed.");
4878 
4879 	KILL(c_acc, struct account);
4880 }
4881 
lookup_player_ind(u32b id)4882 int lookup_player_ind(u32b id) {
4883 	int n;
4884 	for (n = 1; n <= NumPlayers; n++)
4885 		if (Players[n]->id == id) return n;
4886 	return 0;
4887 }
4888 
backup_acclists(void)4889 void backup_acclists(void) {
4890 	FILE *fp;
4891 	char buf[MAX_PATH_LENGTH], buf2[MAX_PATH_LENGTH];
4892 	hash_entry *ptr;
4893 	int del, i;
4894 	struct account *c_acc;
4895 
4896 	s_printf("Backing up all accounts...\n");
4897 	/* create folder lib/save/estate if not existing */
4898 	path_build(buf2, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "estate");
4899 	path_build(buf, MAX_PATH_LENGTH, buf2, "_accounts_");
4900 	if ((fp = fopen(buf, "wb")) == NULL) {
4901 		s_printf("  error: cannot open file '%s'.\nfailed.\n", buf);
4902 		return;
4903 	}
4904 	/* begin with a version tag */
4905 	fprintf(fp, "%s\n", "v1");
4906 
4907 	/* Search in each array slot */
4908 	for (i = 0; i < NUM_HASH_ENTRIES; i++) {
4909 		/* Acquire pointer to this chain */
4910 		ptr = hash_table[i];
4911 
4912 		/* Check all entries in this chain */
4913 		while (ptr) {
4914 			/* Check this name */
4915 			if ((c_acc = GetAccountID(ptr->account, FALSE))) {
4916 				/* back him up */
4917 				fprintf(fp, "%d\n", (int)strlen(ptr->name));
4918 				(void)fwrite(ptr->name, sizeof(char), strlen(ptr->name), fp);
4919 #if 0
4920 				(void)fprintf(fp, "%lu%d%u%c%hu%c%hd%c%c%c",
4921 				    ptr->laston, ptr->id, ptr->account,
4922     				    ptr->level, ptr->party, ptr->guild,
4923 				    ptr->xorder, ptr->race, ptr->class, ptr->mode);
4924  #ifdef AUCTION_SYSTEM
4925 				fprintf(fp, "%d%d", ptr->au, ptr->balance);
4926  #endif
4927 #else
4928 				(void)fwrite(ptr, sizeof(hash_entry), 1, fp);
4929 #endif
4930 
4931 				/* cleanup (?) */
4932 				KILL(c_acc, struct account);
4933 			} else {
4934 				s_printf("Lost player: %s\n", ptr->name);
4935 #if 0 /* del might not always be initialized! */
4936 				del = ptr->id;
4937 			}
4938 
4939 			/* Next entry in chain */
4940 			ptr = ptr->next;
4941 			delete_player_id(del);
4942 #else /* isn't it supposed to be this way instead?: */
4943 				del = ptr->id;
4944 				delete_player_id(del);
4945 			}
4946 
4947 			/* Next entry in chain */
4948 			ptr = ptr->next;
4949 #endif
4950 		}
4951 	}
4952 
4953 	s_printf("done.\n");
4954 	fclose(fp);
4955 }
4956 
restore_acclists(void)4957 void restore_acclists(void) {
4958 	FILE *fp;
4959 	char buf[MAX_PATH_LENGTH], buf2[MAX_PATH_LENGTH], tmp[MAX_CHARS];
4960 	char name_forge[MAX_CHARS];
4961 	hash_entry forge, *ptr = &forge;
4962 	forge.name = name_forge;
4963 	int name_len, r;
4964 
4965 	s_printf("Restoring accounts...\n");
4966 
4967 	path_build(buf2, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "estate");
4968 	path_build(buf, MAX_PATH_LENGTH, buf2, "_accounts_");
4969 	if ((fp = fopen(buf, "rb")) == NULL) {
4970 		s_printf("  error: cannot open file '%s'.\nfailed.\n", buf);
4971 		return;
4972 	}
4973 	/* begin with a version tag */
4974 	r = fscanf(fp, "%s\n", tmp);
4975 	if (r == EOF || r == 0) {
4976 		s_printf("  error: failed to read version tag.\n");
4977 		fclose(fp);
4978 		return;
4979 	}
4980 
4981 	while (!feof(fp)) {
4982 		r = fscanf(fp, "%d\n", &name_len);
4983 		if (r == EOF || r == 0) break;
4984 		r = fread(name_forge, sizeof(char), name_len, fp);
4985 		if (r == 0) break;
4986 		name_forge[name_len] = '\0';
4987 #if 0
4988 		r = fscanf(fp, "%lu%d%u%c%hu%c%hd%c%c%c",
4989 		    &ptr->laston, &ptr->id, &ptr->account,
4990 		    &ptr->level, &ptr->party, &ptr->guild,
4991 		    &ptr->xorder, &ptr->race, &ptr->class, &ptr->mode);
4992 		if (r == EOF || r == 0) break;
4993  #ifdef AUCTION_SYSTEM
4994 		r = fscanf(fp, "%d%d", &ptr->au, &ptr->balance);
4995 		if (r == EOF || r == 0) break;
4996  #endif
4997 #else
4998 		r = fread(ptr, sizeof(hash_entry), 1, fp);
4999 		if (r == 0) break;
5000 		ptr->name = NULL;//just to be clean
5001 #endif
5002 
5003 		//s_printf(" '%s', id %d, acc %d, lev %d, race %d, class %d, mode %d.\n", ptr->name, ptr->id, ptr->account, ptr->level, ptr->race, ptr->class, ptr->mode);
5004 
5005 		if (!lookup_player_name(ptr->id)) { /* paranoia: if the 'server' file was just deleted then there can be no names */
5006 			time_t ttime;
5007 			//s_printf("  adding: '%s' (id %d, acc %d)\n", ptr->name, ptr->id, ptr->account);
5008 			/* Add backed-up entry again */
5009 			add_player_name(name_forge, ptr->id, ptr->account, ptr->race, ptr->class, ptr->mode, 1, 0, 0, 0, 0, time(&ttime), ptr->admin, ptr->wpos);
5010 		} else s_printf("  already exists: '%s' (id %d, acc %d)\n", name_forge, ptr->id, ptr->account);
5011 	}
5012 
5013 	s_printf("done.\n");
5014 	fclose(fp);
5015 }
5016 
5017 /* search for any members of a guild, and set guild's mode to that first member found's mode */
fix_lost_guild_mode(int g_id)5018 void fix_lost_guild_mode(int g_id) {
5019         int slot;
5020         hash_entry *ptr;
5021         for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
5022                 ptr = hash_table[slot];
5023                 while (ptr) {
5024                         if (ptr->guild && ptr->guild == g_id) {
5025                                 guilds[g_id].cmode = ptr->mode;
5026                                 s_printf("Guild '%s' (%d): Mode has been fixed to %d.\n", guilds[g_id].name, g_id, guilds[g_id].cmode);
5027 				return;
5028                         }
5029                         ptr = ptr->next;
5030                 }
5031 
5032         }
5033         /* paranoia: something went really wrong, such as savefile rollback or divine intervention */
5034         if (slot == NUM_HASH_ENTRIES) {
5035 		guilds[g_id].members = 0;
5036 		s_printf("Guild '%s' (%d): Has been erased!\n", guilds[g_id].name, g_id);
5037         }
5038 }
5039