1 /*
2 * Slash commands..
3 * It was getting too ugly, and
4 * util.c was getting big
5 *
6 * old (working) code is at bottom of file
7 *
8 * design subject to change (suggestions welcome)
9 *
10 * - evileye
11 */
12
13 /* #define NOTYET *//* only for testing and working atm */
14
15 /* added this for consistency in some (unrelated) header-inclusion,
16 it IS a server file, isn't it? */
17 #define SERVER
18 #include "angband.h"
19
20 /* how many chars someone may enter (formerly used for /bbs, was an ugly hack) */
21 #define MAX_SLASH_LINE_LEN MSG_LEN
22
23 #ifdef BACKTRACE_NOTHINGS
24 #include <execinfo.h>
25 #endif
26
27 static void do_slash_brief_help(int Ind);
28 char pet_creation(int Ind);
29 //static int lInd = 0;
30 #ifdef NOTYET /* new idea */
31
32 struct scmd{
33 char *cmd;
34 unsigned short admin; /* bool require admin or not */
35 short minargs, maxargs; /* MIN/MAX number of args
36 * both 0 for a line content, -1 for any */
37 void (*func)(int, void*); /* point either to char * or args (NULL terminated char**) */
38 char *errorhlp; /* if its bad, tell them this */
39 };
40
41 /* the function declarations */
42 void sc_shutdown(int Ind, void *value);
43 void sc_report(int Ind, void *string);
44 void sc_wish(int Ind, void *argp);
45 void sc_shout(int Ind, void *string);
46
47 /* the commands structure */
48 struct scmd scmd[] = {
49 { "shutdown", 1, 0, 1, sc_shutdown , NULL },
50
51 { "bug", 0, 0, 0, sc_report, "\377oUsage: /rfe (message)" },
52 { "rfe", 0, 0, 0, sc_report, "\377oUsage: /rfe (message)" },
53 { "cookie", 0, 0, 0, sc_report, "\377oUsage: /rfe (message)" },
54 { "ignore", 0, 1, 1, add_ignore, "\377oUsage: /ignore (user)" },
55 { "shout", 0, 0, 1, sc_shout, NULL },
56
57 { "wish", 1, 3, 5, sc_wish, "\377oUsage: /wish (tval) (sval) (pval) [discount] [name]" },
58 { NULL, 0, 0, 0, NULL, NULL }
59 };
60
61 /*
62 * updated slash command parser - evileye
63 *
64 */
do_slash_cmd(int Ind,char * message)65 void do_slash_cmd(int Ind, char *message){
66 int i, j;
67 player_type *p_ptr;
68
69 p_ptr = Players[Ind];
70 if (!p_ptr) return;
71
72 /* check for idiots */
73 if (!message[1]) return;
74
75 for (i = 0; scmd[i].cmd; i++) {
76 if (!strncmp(scmd[i].cmd, &message[1], strlen(scmd[i].cmd))) {
77 if (scmd[i].admin && !is_admin(p_ptr)) break;
78
79 if (scmd[i].minargs == -1) {
80 /* no string required */
81 scmd[i].func(Ind, NULL);
82 return;
83 }
84
85 for (j = strlen(scmd[i].cmd) + 1; message[j]; j++) {
86 if (message[j] != ' ') {
87 break;
88 }
89 }
90 if (!message[j] && scmd[i].minargs) {
91 if (scmd[i].errorhlp) msg_print(Ind, scmd[i].errorhlp);
92 return;
93 }
94
95 if (!scmd[i].minargs && !scmd[i].maxargs) {
96 /* a line arg */
97 scmd[i].func(Ind, &message[strlen(scmd[i].cmd) + 1]);
98 } else {
99 char **args;
100 char *cp = &message[strlen(scmd[i].cmd) + 1];
101
102 /* allocate args array */
103 args = (char**)malloc(sizeof(char*) * (scmd[i].maxargs + 1));
104 if (args == (char**)NULL) {
105 /* unlikely - best to check */
106 msg_print(Ind, "\377uError. Please try later.");
107 return;
108 }
109
110 /* simple tokenize into args */
111 j = 0;
112 while (j <= scmd[i].maxargs) {
113 while (*cp == ' ') {
114 *cp = '\0';
115 cp++;
116 }
117 if (*cp == '\0') break;
118 args[j++] = cp;
119
120 while (*cp != ' ') cp++;
121 if (*cp == '\0') break;
122 }
123
124 if (j < scmd[i].minargs || j > scmd[i].maxargs) {
125 if (scmd[i].errorhlp) msg_print(Ind, scmd[i].errorhlp);
126 return;
127 }
128
129 args[j] = NULL;
130 if (scmd[i].maxargs == 1) scmd[i].func(Ind, args[0]);
131 else scmd[i].func(Ind, args);
132 }
133 return;
134 }
135 }
136 do_slash_brief_help(Ind);
137 }
138
sc_shout(int Ind,void * string)139 void sc_shout(int Ind, void *string) {
140 player_type *p_ptr = Players[Ind];
141
142 aggravate_monsters(Ind, -1);
143 if (string)
144 msg_format_near(Ind, "\377%c%^s shouts:%s", COLOUR_CHAT, p_ptr->name, (char*)string);
145 else
146 msg_format_near(Ind, "\377%cYou hear %s shout!", COLOUR_CHAT, p_ptr->name);
147 msg_format(Ind, "\377%cYou shout %s", COLOUR_CHAT, (char*)string);
148 }
149
sc_shutdown(int Ind,void * value)150 void sc_shutdown(int Ind, void *value) {
151 bool kick = (cfg.runlevel == 1024);
152 int val;
153
154 if ((char*)value)
155 val = atoi((char*)value);
156 else
157 val = (cfg.runlevel < 6 || kick) ? 6 : 5;
158
159 set_runlevel(val);
160
161 msg_format(Ind, "Runlevel set to %d", cfg.runlevel);
162
163 /* Hack -- character edit mode */
164 if (val == 1024 || kick) {
165 int i;
166 if (val == 1024) msg_print(Ind, "\377rEntering edit mode!");
167 else msg_print(Ind, "\377rLeaving edit mode!");
168
169 for (i = NumPlayers; i > 0; i--) {
170 /* Check connection first */
171 if (Players[i]->conn == NOT_CONNECTED)
172 continue;
173
174 /* Check for death */
175 if (!is_admin(Players[i]))
176 Destroy_connection(Players[i]->conn, "Server maintenance");
177 }
178 }
179 time(&cfg.closetime);
180 }
181
sc_wish(int Ind,void * argp)182 void sc_wish(int Ind, void *argp){
183 char **args = (args);
184 #if 0
185 object_type forge;
186 object_type *o_ptr = &forge;
187
188 if (tk < 1 || !k) {
189 msg_print(Ind, "\377oUsage: /wish (tval) (sval) (pval) [discount] [name] or /wish (o_idx)");
190 return;
191 }
192
193 invcopy(o_ptr, tk > 1 ? lookup_kind(k, atoi(token[2])) : k);
194
195 /* Wish arts out! */
196 if (tk > 4) {
197 int nom = atoi(token[5]);
198 o_ptr->number = 1;
199
200 if (nom > 0) o_ptr->name1 = nom;
201 else {
202 /* It's ego or randarts */
203 if (nom) {
204 o_ptr->name2 = 0 - nom;
205 if (tk > 4) o_ptr->name2b = 0 - atoi(token[5]);
206 }
207 else o_ptr->name1 = ART_RANDART;
208
209 /* Piece together a 32-bit random seed */
210 o_ptr->name3 = rand_int(0xFFFF) << 16;
211 o_ptr->name3 += rand_int(0xFFFF);
212 }
213 } else {
214 o_ptr->number = o_ptr->weight > 100 ? 2 : 99;
215 }
216
217 apply_magic(&p_ptr->wpos, o_ptr, -1, TRUE, TRUE, TRUE, FALSE, make_resf(p_ptr));
218 if (tk > 3) {
219 o_ptr->discount = atoi(token[4]);
220 } else {
221 o_ptr->discount = 100;
222 }
223 object_known(o_ptr);
224 o_ptr->owner = 0;
225 if (tk > 2)
226 o_ptr->pval = atoi(token[3]);
227 //o_ptr->owner = p_ptr->id;
228 o_ptr->level = 1;
229 (void)inven_carry(Ind, o_ptr);
230 #endif
231 }
232
233
sc_report(int Ind,void * string)234 void sc_report(int Ind, void *string){
235 player_type *p_ptr = Players[Ind];
236
237 rfe_printf("[%s]%s\n", p_ptr->name, (char*)string);
238 msg_print(Ind, "\377GThank you for sending us a message!");
239 }
240
241 #else
242
243 /*
244 * Litterally. - Jir -
245 */
246
find_inscription(s16b quark,char * what)247 static char *find_inscription(s16b quark, char *what)
248 {
249 const char *ax = quark_str(quark);
250 if( ax == NULL || !what) { return FALSE; };
251
252 return (strstr(ax, what));
253 }
254
do_cmd_refresh(int Ind)255 static void do_cmd_refresh(int Ind)
256 {
257 player_type *p_ptr = Players[Ind];
258 object_type *o_ptr;
259 int k;
260
261 /* Hack -- fix the inventory count */
262 p_ptr->inven_cnt = 0;
263 for (k = 0; k < INVEN_PACK; k++)
264 {
265 o_ptr = &p_ptr->inventory[k];
266
267 /* Skip empty items */
268 if (!o_ptr->k_idx || !o_ptr->tval) {
269 /* hack - make sure the item is really erased - had some bugs there
270 since some code parts use k_idx, and some tval, to kill/test items - C. Blue */
271 invwipe(o_ptr);
272 continue;
273 }
274
275 p_ptr->inven_cnt++;
276 }
277
278 /* Clear the target */
279 p_ptr->target_who = 0;
280
281 /* Update his view, light, bonuses, and torch radius */
282 p_ptr->update |= (PU_VIEW | PU_LITE | PU_BONUS | PU_TORCH |
283 PU_DISTANCE | PU_SKILL_MOD);
284
285 /* Recalculate mana */
286 p_ptr->update |= (PU_MANA | PU_HP | PU_SANITY);
287
288 /* Redraw */
289 p_ptr->redraw |= PR_MAP | PR_EXTRA | PR_HISTORY | PR_VARIOUS | PR_STATE;
290 p_ptr->redraw |= (PR_HP | PR_GOLD | PR_BASIC | PR_PLUSSES);
291
292 /* Notice */
293 p_ptr->notice |= (PN_COMBINE | PN_REORDER);
294
295 /* Window stuff */
296 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
297
298 return;
299 }
300
301 /*
302 * Slash commands - huge hack function for command expansion.
303 *
304 * TODO: introduce sl_info.txt, like:
305 * N:/lua:1
306 * F:ADMIN
307 * D:/lua (LUA script command)
308 */
309
do_slash_cmd(int Ind,char * message)310 void do_slash_cmd(int Ind, char *message) {
311 int i = 0, j = 0, h = 0;
312 int k = 0, tk = 0;
313 player_type *p_ptr = Players[Ind];
314 char *colon, *token[9], message2[MAX_SLASH_LINE_LEN], message3[MAX_SLASH_LINE_LEN];
315 char message4[MAX_SLASH_LINE_LEN];
316
317 worldpos wp;
318 #ifndef TEST_SERVER
319 bool admin = is_admin(p_ptr);
320 #else
321 bool admin = TRUE;
322 #endif
323
324 /* prevent overflow - bad hack for now (needed as you can now enter lines MUCH longer than 140 chars) */
325 message[MAX_SLASH_LINE_LEN - 1] = 0;
326
327 strcpy(message2, message);
328 wpcopy(&wp, &p_ptr->wpos);
329
330 /* message3 contains all tokens but not the command: */
331 strcpy(message3, "");
332 for (i = 0; i < (int)strlen(message); i++)
333 if (message[i] == ' ') {
334 strcpy(message3, message + i + 1);
335 break;
336 }
337
338 /* Look for a player's name followed by a colon */
339 colon = strchr(message, ' ');
340
341 /* hack -- non-token ones first */
342 if ((prefix(message, "/script") ||
343 // prefix(message, "/scr") || used for /scream now
344 prefix(message, "/ ") || // use with care!
345 prefix(message, "//") || // use with care!
346 prefix(message, "/lua")) && admin)
347 {
348 if (colon) {
349 master_script_exec(Ind, colon);
350 } else {
351 msg_print(Ind, "\377oUsage: /lua (LUA script command)");
352 }
353 return;
354 }
355 else if ((prefix(message, "/rfe")) ||
356 prefix(message, "/cookie"))
357 {
358 if (colon) {
359 rfe_printf("RFE [%s]%s\n", p_ptr->accountname, colon);
360 msg_print(Ind, "\377GThank you for sending us a message!");
361 } else {
362 msg_print(Ind, "\377oUsage: /rfe <message>");
363 }
364 return;
365 }
366 else if (prefix(message, "/bug")) {
367 if (colon) {
368 rfe_printf("BUG [%s]%s\n", p_ptr->accountname, colon);
369 msg_print(Ind, "\377GThank you for sending us a message!");
370 } else {
371 msg_print(Ind, "\377oUsage: /bug <message>");
372 }
373 return;
374 }
375 /* Oops conflict; took 'never duplicate' principal */
376 else if (prefix(message, "/cough"))
377 // /count || prefix(message, "/cou"))
378 {
379 break_cloaking(Ind, 4);
380 msg_format_near(Ind, "\377%c%^s coughs noisily.", COLOUR_CHAT, p_ptr->name);
381 msg_format(Ind, "\377%cYou cough noisily..", COLOUR_CHAT);
382 wakeup_monsters_somewhat(Ind, -1);
383 return;
384 }
385 else if (prefix(message, "/shout") ||
386 prefix(message, "/sho"))
387 {
388 break_cloaking(Ind, 4);
389 if (colon++) {
390 censor_message = TRUE;
391 censor_length = strlen(colon);
392 msg_format_near(Ind, "\377%c%^s shouts: %s", COLOUR_CHAT, p_ptr->name, colon);
393 msg_format(Ind, "\377%cYou shout: %s", COLOUR_CHAT, colon);
394 censor_message = FALSE;
395 handle_punish(Ind, censor_punish);
396 } else {
397 msg_format_near(Ind, "\377%cYou hear %s shout!", COLOUR_CHAT, p_ptr->name);
398 msg_format(Ind, "\377%cYou shout!", COLOUR_CHAT);
399 }
400 wakeup_monsters(Ind, -1);
401 return;
402 }
403 else if (prefix(message, "/scream") ||
404 prefix(message, "/scr"))
405 {
406 break_cloaking(Ind, 6);
407 if (colon++) {
408 censor_message = TRUE;
409 censor_length = strlen(colon);
410 msg_format_near(Ind, "\377%c%^s screams: %s", COLOUR_CHAT, p_ptr->name, colon);
411 msg_format(Ind, "\377%cYou scream: %s", COLOUR_CHAT, colon);
412 censor_message = FALSE;
413 handle_punish(Ind, censor_punish);
414 } else {
415 msg_format_near(Ind, "\377%cYou hear %s scream!", COLOUR_CHAT, p_ptr->name);
416 msg_format(Ind, "\377%cYou scream!", COLOUR_CHAT);
417 }
418 aggravate_monsters(Ind, -1);
419 return;
420 }
421 /* RPG-style talking to people who are nearby, instead of global chat. - C. Blue */
422 else if (prefix(message, "/say"))
423 {
424 if (colon++) {
425 censor_message = TRUE;
426 censor_length = strlen(colon);
427 msg_format_near(Ind, "\377%c%^s says: %s", COLOUR_CHAT, p_ptr->name, colon);
428 msg_format(Ind, "\377%cYou say: %s", COLOUR_CHAT, colon);
429 censor_message = FALSE;
430 handle_punish(Ind, censor_punish);
431 } else {
432 msg_format_near(Ind, "\377%c%s clears %s throat.", COLOUR_CHAT, p_ptr->name, p_ptr->male ? "his" : "her");
433 msg_format(Ind, "\377%cYou clear your throat.", COLOUR_CHAT);
434 }
435 return;
436 // :) break_cloaking(Ind, 3);
437 }
438 else if (prefix(message, "/whisper"))
439 {
440 if (colon++) {
441 censor_message = TRUE;
442 censor_length = strlen(colon);
443 msg_format_verynear(Ind, "\377%c%^s whispers: %s", COLOUR_CHAT, p_ptr->name, colon);
444 msg_format(Ind, "\377%cYou whisper: %s", COLOUR_CHAT, colon);
445 censor_message = FALSE;
446 handle_punish(Ind, censor_punish);
447 } else {
448 msg_print(Ind, "What do you want to whisper?");
449 }
450 return;
451 // :) break_cloaking(Ind, 3);
452 }
453 else if (prefix(message, "/self")) /* A local version of '/me', relating to it like '/say' to global chat */
454 {
455 if (colon++) {
456 censor_message = TRUE;
457 censor_length = strlen(colon);
458 msg_format_near(Ind, "\377%c%^s %s", COLOUR_CHAT, p_ptr->name, colon);
459 msg_format(Ind, "\377%c%s %s", COLOUR_CHAT, p_ptr->name, colon);
460 censor_message = FALSE;
461 handle_punish(Ind, censor_punish);
462 } else {
463 msg_print(Ind, "What do you want to do?");
464 }
465 return;
466 // :) break_cloaking(Ind, 3);
467 }
468
469 else
470 {
471 /* cut tokens off (thx Asclep(DEG)) */
472 if ((token[0] = strtok(message," "))) {
473 // s_printf("%d : %s", tk, token[0]);
474 for (i = 1 ;i < 9; i++) {
475 token[i] = strtok(NULL," ");
476 if (token[i] == NULL)
477 break;
478 tk = i;
479 }
480 }
481
482 /* Default to no search string */
483 // strcpy(search, "");
484
485 /* Form a search string if we found a colon */
486 if (tk) k = atoi(token[1]);
487
488 /* User commands */
489 if (prefix(message, "/ignore") ||
490 prefix(message, "/ig"))
491 {
492 add_ignore(Ind, token[1]);
493 return;
494 }
495 if (prefix(message, "/ignchat") ||
496 prefix(message, "/ic"))
497 {
498 if (p_ptr->ignoring_chat) {
499 p_ptr->ignoring_chat = FALSE;
500 msg_print(Ind, "\377yYou're no longer ignoring normal chat messages.");
501 } else {
502 p_ptr->ignoring_chat = TRUE;
503 msg_print(Ind, "\377yYou're now ignoring normal chat messages.");
504 msg_print(Ind, "\377yYou will only receive private and party messages.");
505 }
506 return;
507 }
508 else if (prefix(message, "/afk"))
509 {
510 if (strlen(message2 + 4) > 0)
511 toggle_afk(Ind, message2 + 5);
512 else
513 toggle_afk(Ind, "");
514 return;
515 }
516
517 else if (prefix(message, "/page"))
518 {
519 int p;
520 //spam? s_printf("(%s) SLASH_PAGE: %s:%s.\n", showtime(), p_ptr->name, message3);
521 if(!tk) {
522 msg_print(Ind, "\377oUsage: /page <playername>");
523 msg_print(Ind, "\377oAllows you to send a 'beep' sound to someone who is currently afk.");
524 return;
525 }
526 p = name_lookup_loose(Ind, message3, FALSE, TRUE);
527 if (!p || (Players[Ind]->admin_dm && cfg.secret_dungeon_master && !is_admin(Players[Ind]))) {
528 msg_format(Ind, "\377yPlayer %s not online.", message3);
529 return;
530 }
531 #if 0 /* no real need to restrict this */
532 if (!Players[p]->afk) {
533 msg_format(Ind, "\377yPlayer %s is not afk.", message3);
534 return;
535 }
536 #endif
537 #if 0 /* no need to tell him, same as for chat messages.. */
538 if (check_ignore(p, Ind)) {
539 msg_print(Ind, "\377yThat player is currently ignoring you.");
540 return;
541 }
542 #endif
543 if (Players[p]->paging) {
544 /* already paging, I hope this can prevent floods too - mikaelh */
545 return;
546 }
547
548 msg_format(Ind, "\376\377yPaged %s.", Players[p]->name);
549 if (!check_ignore(p, Ind)) {
550 Players[p]->paging = 3; /* Play 3 beeps quickly */
551 msg_format(p, "\376\377y%s is paging you.", Players[Ind]->name);
552 }
553 return;
554 }
555
556 /* Semi-auto item destroyer */
557 else if ((prefix(message, "/dispose")) ||
558 prefix(message, "/dis"))
559 {
560 object_type *o_ptr;
561 u32b f1, f2, f3, f4, f5, f6, esp;
562 bool nontag = FALSE, baseonly = FALSE;
563
564 //if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
565 if (p_ptr->energy < 0) return;
566 disturb(Ind, 1, 0);
567
568 /* only tagged ones? */
569 if (tk > 0) {
570 char *parm = token[1];
571 bool floor = FALSE;
572
573 if (*parm == 'f') {
574 floor = TRUE;
575 parm++;
576 }
577
578 if (*parm == 'a') {
579 nontag = TRUE;
580 } else if (*parm == 'b') {
581 nontag = baseonly = TRUE;
582 } else if (!floor || *parm) {
583 msg_print(Ind, "\377oUsage: /dis [f][a|b]");
584 msg_print(Ind, "\377oExample: /dis fb");
585 return;
586 }
587
588 if (floor) { /* Lerg's patch/idea, "/dis f" command */
589 struct worldpos *wpos = &p_ptr->wpos;
590 cave_type *c_ptr;
591 cave_type **zcave;
592
593 /* get our grid */
594 if (!(zcave = getcave(wpos))) return;
595 c_ptr = &zcave[p_ptr->py][p_ptr->px];
596 if (!c_ptr->o_idx) {
597 msg_print(Ind, "There is no item on the floor here.");
598 return;
599 }
600
601 /* Get the object */
602 o_ptr = &o_list[c_ptr->o_idx];
603 if (!o_ptr->k_idx) return;
604
605 /* keep inscribed items? */
606 if (!nontag && o_ptr->note) return;
607
608 /* destroy base items (non-egos)? */
609 if (baseonly && object_known_p(Ind, o_ptr) &&
610 (o_ptr->name1 || o_ptr->name2 || o_ptr->name2b ||
611 /* let exploding ammo count as ego.. pft */
612 (is_ammo(o_ptr->tval) && o_ptr->pval))
613 && !cursed_p(o_ptr))
614 return;
615
616 do_cmd_destroy(Ind, -c_ptr->o_idx, o_ptr->number);
617 whats_under_your_feet(Ind);
618 return;
619 }
620 }
621
622 for (i = 0; i < INVEN_PACK; i++) {
623 bool resist = FALSE;
624 o_ptr = &(p_ptr->inventory[i]);
625 if (!o_ptr->tval) break;
626
627 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
628
629 #if 1 /* check for: tag _equals_ pseudo id tag */
630 /* skip items inscribed with more than a single non-greatpseudo-ID tag */
631 if (o_ptr->note &&
632 strcmp(quark_str(o_ptr->note), "terrible") &&
633 strcmp(quark_str(o_ptr->note), "cursed") &&
634 strcmp(quark_str(o_ptr->note), "uncursed") &&
635 strcmp(quark_str(o_ptr->note), "broken") &&
636 strcmp(quark_str(o_ptr->note), "average") &&
637 strcmp(quark_str(o_ptr->note), "good") &&
638 // strcmp(quark_str(o_ptr->note), "excellent"))
639 strcmp(quark_str(o_ptr->note), "worthless"))
640 continue;
641 #else /* check for: tag _contains_ pseudo id tag */
642 if (o_ptr->note &&
643 !strstr(quark_str(o_ptr->note), "terrible") &&
644 !strstr(quark_str(o_ptr->note), "cursed") &&
645 !strstr(quark_str(o_ptr->note), "uncursed") &&
646 !strstr(quark_str(o_ptr->note), "broken") &&
647 !strstr(quark_str(o_ptr->note), "average") &&
648 !strstr(quark_str(o_ptr->note), "good") &&
649 // !strstr(quark_str(o_ptr->note), "excellent"))
650 !strstr(quark_str(o_ptr->note), "worthless"))
651 continue;
652
653 /* skip items that are tagged as unkillable */
654 if (check_guard_inscription(o_ptr->note, 'k')) continue;
655 /* skip items that seem to be tagged as being in use */
656 if (strchr(quark_str(o_ptr->note), '@')) continue;
657 #endif
658
659 /* destroy base items (non-egos)? */
660 if (baseonly && object_known_p(Ind, o_ptr) &&
661 (o_ptr->name1 || o_ptr->name2 || o_ptr->name2b ||
662 /* let exploding ammo count as ego.. pft */
663 (is_ammo(o_ptr->tval) && o_ptr->pval))
664 && !cursed_p(o_ptr))
665 continue;
666
667 /* destroy non-inscribed items too? */
668 if (!nontag && !o_ptr->note &&
669 /* Handle {cursed} */
670 !(cursed_p(o_ptr) &&
671 (object_known_p(Ind, o_ptr) ||
672 (o_ptr->ident & ID_SENSE))))
673 continue;
674
675 /* Player might wish to identify it first */
676 if (k_info[o_ptr->k_idx].has_flavor &&
677 !p_ptr->obj_aware[o_ptr->k_idx])
678 continue;
679
680 /* Hrm, this cannot be destroyed */
681 if (((f4 & TR4_CURSE_NO_DROP) && cursed_p(o_ptr)) ||
682 like_artifact_p(o_ptr))
683 resist = TRUE;
684 #if 0 /* too easy! */
685 /* Hack -- filter by value */
686 if (k && (!object_known_p(Ind, o_ptr) ||
687 object_value_real(Ind, o_ptr) > k))
688 continue;
689 #endif
690
691 /* Avoid being somewhat spammy, since arts can't be destroyed */
692 if (like_artifact_p(o_ptr)) continue;
693
694 /* guild keys cannot be destroyed */
695 if (o_ptr->tval == TV_KEY) continue;
696
697 do_cmd_destroy(Ind, i, o_ptr->number);
698 if (!resist) i--;
699
700 /* Hack - Don't take a turn here */
701 p_ptr->energy += level_speed(&p_ptr->wpos);
702 }
703 /* Take total of one turn */
704 p_ptr->energy -= level_speed(&p_ptr->wpos);
705 return;
706 }
707
708 /* add inscription to everything */
709 else if (prefix(message, "/tag") ||
710 prefix(message, "/t ") || (prefix(message, "/t") && !message[2]))
711 {
712 object_type *o_ptr;
713
714 if (tk && (token[1][0] != '*')) {
715 h = (token[1][0]) - 'a';
716 j = h;
717 if (h < 0 || h >= INVEN_PACK || token[1][1]) {
718 msg_print(Ind, "\377oUsage: /tag [a..w|* [<inscription>]]");
719 return;
720 }
721 } else {
722 h = 0;
723 j = INVEN_PACK - 1;
724 }
725
726 for(i = h; i <= j; i++) {
727 o_ptr = &(p_ptr->inventory[i]);
728 if (!o_ptr->tval) break;
729
730 /* skip inscribed items, except if we designated one item in particular (j==h) */
731 if (o_ptr->note &&
732 strcmp(quark_str(o_ptr->note), "terrible") &&
733 strcmp(quark_str(o_ptr->note), "cursed") &&
734 strcmp(quark_str(o_ptr->note), "uncursed") &&
735 strcmp(quark_str(o_ptr->note), "broken") &&
736 strcmp(quark_str(o_ptr->note), "average") &&
737 strcmp(quark_str(o_ptr->note), "good") &&
738 strcmp(quark_str(o_ptr->note), "worthless")) {
739 if (j != h) continue; /* skip inscribed items when mass-tagging */
740 else o_ptr->note = 0; /* hack to overwrite its inscription */
741 }
742
743 if (!o_ptr->note)
744 o_ptr->note = quark_add(tk < 2 ? "!k" : token[2]);
745 else
746 o_ptr->note = quark_add(tk < 2 ?
747 format("%s-!k", quark_str(o_ptr->note)) :
748 format("%s-%s", quark_str(o_ptr->note), token[2]));
749 }
750 /* Window stuff */
751 p_ptr->window |= (PW_INVEN | PW_EQUIP);
752
753 return;
754 }
755 /* remove specific inscription.
756 If '*' is given, all pseudo-id tags are removed,
757 if no parameter is given, '!k' is the default. */
758 else if (prefix(message, "/untag") ||
759 prefix(message, "/ut"))
760 {
761 object_type *o_ptr;
762 // cptr ax = token[1] ? token[1] : "!k";
763 cptr ax = tk ? message3 : "!k";
764 char note2[80], noteid[10];
765 bool remove_all = !strcmp(ax, "*");
766 bool remove_pseudo = !strcmp(ax, "p");
767 bool remove_unique = !strcmp(ax, "u");
768
769 for (i = 0; i < (remove_pseudo || remove_unique ? INVEN_TOTAL : INVEN_PACK); i++) {
770 o_ptr = &(p_ptr->inventory[i]);
771
772 /* Skip empty slots */
773 if (!o_ptr->tval) continue;
774
775 /* skip uninscribed items */
776 if (!o_ptr->note) continue;
777
778 /* remove all inscriptions? */
779 if (remove_all) {
780 o_ptr->note = 0;
781 o_ptr->note_utag = 0;
782 continue;
783 }
784
785 if (remove_unique && o_ptr->note_utag) {
786 j = strlen(quark_str(o_ptr->note)) - o_ptr->note_utag;
787 if (j >= 0) { /* bugfix hack */
788 //s_printf("j: %d, strlen: %d, note_utag: %d, i: %d.\n", j, strlen(quark_str(o_ptr->note)), o_ptr->note_utag, i);
789 strncpy(note2, quark_str(o_ptr->note), j);
790 if (j > 0 && note2[j - 1] == '-') j--; /* absorb '-' orphaned spacers */
791 note2[j] = 0; /* terminate string */
792 o_ptr->note_utag = 0;
793 if (note2[0]) o_ptr->note = quark_add(note2);
794 else o_ptr->note = 0;
795 } else o_ptr->note_utag = 0; //paranoia?
796 continue;
797 }
798
799 /* just remove pseudo-id tags? */
800 if (remove_pseudo) {
801 /* prevent 'empty' inscriptions from being erased by this */
802 if ((quark_str(o_ptr->note))[0] == '\0') continue;
803
804 note_crop_pseudoid(note2, noteid, quark_str(o_ptr->note));
805 if (!note2[0]) {
806 o_ptr->note = 0;
807 o_ptr->note_utag = 0; //paranoia
808 } else {
809 o_ptr->note = quark_add(note2);
810 }
811 continue;
812 }
813
814 /* ignore pseudo-id inscriptions */
815 note_crop_pseudoid(note2, noteid, quark_str(o_ptr->note));
816
817 /* skip non-matching tags */
818 if (strcmp(note2, ax)) continue;
819
820 if (!noteid[0]) {
821 /* tag removed, no more inscription */
822 o_ptr->note = 0;
823 o_ptr->note_utag = 0; //in case tag == unique name
824 } else {
825 /* tag removed, keeping pseudo-id inscription */
826 o_ptr->note = quark_add(noteid);
827 o_ptr->note_utag = 0; //in case tag == unique name
828 }
829 }
830
831 /* Combine the pack */
832 p_ptr->notice |= (PN_COMBINE);
833
834 /* Window stuff */
835 p_ptr->window |= (PW_INVEN | PW_EQUIP);
836
837 return;
838 }
839 #if 0 /* new '/cast' version below this one - C. Blue */
840 /* '/cast' code is written by Asclep(DEG). thx! */
841 else if (prefix(message, "/cast"))
842 {
843 msg_print(Ind, "\377oSorry, /cast is not available for the time being.");
844 #if 0 // TODO: make that work without dependance on CLASS_
845 int book, whichplayer, whichspell;
846 bool ami = FALSE;
847 #if 0
848 token[0] = strtok(message," ");
849 if (token[0] == NULL)
850 {
851 msg_print(Ind, "\377oUsage: /cast (Book) (Spell) [Playername]");
852 return;
853 }
854
855 for (i = 1; i < 50; i++)
856 {
857 token[i] = strtok(NULL, " ");
858 if (token[i] == NULL)
859 break;
860 }
861 #endif
862
863 /* at least 2 arguments required */
864 if (tk < 2)
865 {
866 msg_print(Ind, "\377oUsage: /cast (Book) (Spell) [Player name]");
867 return;
868 }
869
870 if (*token[1] >= '1' && *token[1] <= '9')
871 {
872 object_type *o_ptr;
873 char c[4] = "@";
874 bool found = FALSE;
875
876 c[1] = ((p_ptr->pclass == CLASS_PRIEST) ||
877 (p_ptr->pclass == CLASS_PALADIN)? 'p':'m');
878 if (p_ptr->pclass == CLASS_WARRIOR) c[1] = 'n';
879 c[2] = *token[1];
880 c[3] = '\0';
881
882 for(i = 0; i < INVEN_PACK; i++)
883 {
884 o_ptr = &(p_ptr->inventory[i]);
885 if (!o_ptr->tval) break;
886
887 if (find_inscription(o_ptr->note, c))
888 {
889 book = i;
890 found = TRUE;
891 break;
892 }
893 }
894
895 if (!found)
896 {
897 msg_format(Ind, "\377oInscription {%s} not found.", c);
898 return;
899 }
900 // book = atoi(token[1])-1;
901 }
902 else
903 {
904 *token[1] &= ~(0x20);
905 if (*token[1] >= 'A' && *token[1] <= 'W')
906 book = (int)(*token[1] - 'A');
907 else {
908 msg_print(Ind,"\377oBook variable was out of range (a-i) or (1-9)");
909 return;
910 }
911 }
912
913 if(*token[2] >= '1' && *token[2] <= '9')
914 {
915 // whichspell = atoi(token[2]+'A'-1);
916 whichspell = atoi(token[2]) - 1;
917 }
918 else if(*token[2] >= 'a' && *token[2] <= 'i')
919 {
920 whichspell = (int)(*token[2] - 'a');
921 }
922 /* if Capital letter, it's for friends */
923 else if(*token[2] >= 'A' && *token[2] <= 'I')
924 {
925 whichspell = (int)(*token[2] - 'A');
926 // *token[2] &= 0xdf;
927 // whichspell = *token[2]-1;
928 ami = TRUE;
929 }
930 else
931 {
932 msg_print(Ind,"\377oSpell out of range [A-I].");
933 return;
934 }
935
936 if (token[3])
937 {
938 if (!(whichplayer = name_lookup_loose(Ind, token[3], TRUE, FALSE)))
939 return;
940
941 if (whichplayer == Ind) {
942 msg_print(Ind,"You feel lonely.");
943 /* Ignore "unreasonable" players */
944 } else if (!target_able(Ind, 0 - whichplayer)) {
945 msg_print(Ind,"\377oThat player is out of your sight.");
946 return;
947 } else {
948 // msg_format(Ind,"Book = %d, Spell = %d, PlayerName = %s, PlayerID = %d",book,whichspell,token[3],whichplayer);
949 target_set_friendly(Ind,5,whichplayer);
950 whichspell += 64;
951 }
952 } else if (ami) {
953 target_set_friendly(Ind, 5);
954 whichspell += 64;
955 } else {
956 target_set(Ind, 5);
957 }
958
959 switch (p_ptr->pclass)
960 {
961 }
962
963 // msg_format(Ind,"Book = %d, Spell = %d, PlayerName = %s, PlayerID = %d",book,whichspell,token[3],whichplayer);
964 #endif
965 return;
966 }
967 #endif
968 #if 0
969 /* cast a spell by name, instead of book/position */
970 else if (prefix(message, "/cast"))
971 {
972 for (i = 0; i < 100; i++) {
973 if (!strncmp(p_ptr->spell_name[i], message3, strlen(message3))) {
974 cast_school_spell(Ind, p_ptr->spell_book[i], p_ptr->spell_pos[i], dir, item, aux);
975 break;
976 }
977 }
978 return;
979 }
980 #endif
981 /* Take everything off */
982 else if ((prefix(message, "/bed")) ||
983 prefix(message, "/naked"))
984 {
985 byte start = INVEN_WIELD, end = INVEN_TOTAL;
986 object_type *o_ptr;
987
988 if (!tk)
989 {
990 start = INVEN_BODY;
991 end = INVEN_FEET + 1;
992 }
993
994 disturb(Ind, 1, 0);
995
996 // for (i=INVEN_WIELD;i<INVEN_TOTAL;i++)
997 for (i = start; i < end; i++)
998 {
999 o_ptr = &(p_ptr->inventory[i]);
1000 if (!o_ptr->tval) continue;
1001
1002 /* skip inscribed items */
1003 /* skip non-matching tags */
1004 if ((check_guard_inscription(o_ptr->note, 't')) ||
1005 (check_guard_inscription(o_ptr->note, 'T')) ||
1006 (cursed_p(o_ptr))) continue;
1007
1008 inven_takeoff(Ind, i, 255, FALSE);
1009 p_ptr->energy -= level_speed(&p_ptr->wpos) / 2;
1010 }
1011 return;
1012 }
1013
1014 /* Try to wield everything */
1015 else if ((prefix(message, "/dress")) ||
1016 (prefix(message, "/dr") && !prefix(message, "/draw"))) {
1017 object_type *o_ptr;
1018 bool gauche = FALSE;
1019
1020 /* Paralyzed? */
1021 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1022
1023 disturb(Ind, 1, 0);
1024
1025 for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) {
1026 if (!item_tester_hook_wear(Ind, i)) continue;
1027
1028 o_ptr = &(p_ptr->inventory[i]);
1029 if (o_ptr->tval) continue;
1030
1031 for(j = 0; j < INVEN_PACK; j++) {
1032 o_ptr = &(p_ptr->inventory[j]);
1033 if (!o_ptr->k_idx) break;
1034
1035 /* Limit to items with specified strings, if any */
1036 if (tk) {
1037 if (!o_ptr->note || !strstr(quark_str(o_ptr->note), token[1]))
1038 continue;
1039 } else {
1040 /* skip unsuitable inscriptions */
1041 if (o_ptr->note &&
1042 (!strcmp(quark_str(o_ptr->note), "cursed") ||
1043 !strcmp(quark_str(o_ptr->note), "terrible") ||
1044 !strcmp(quark_str(o_ptr->note), "broken") ||
1045 !strcmp(quark_str(o_ptr->note), "worthless") ||
1046 check_guard_inscription(o_ptr->note, 'w')))
1047 continue;
1048
1049 if (!object_known_p(Ind, o_ptr)) continue;
1050 if (cursed_p(o_ptr)) continue;
1051 }
1052
1053 /* legal item? */
1054 if (wield_slot(Ind, o_ptr) != i) continue;
1055
1056 do_cmd_wield(Ind, j, 0x0);
1057
1058 /* MEGAHACK -- tweak to handle rings right */
1059 if (o_ptr->tval == TV_RING && !gauche) {
1060 i -= 2;
1061 gauche = TRUE;
1062 }
1063
1064 break;
1065 }
1066 }
1067 return;
1068 }
1069 /* Display extra information */
1070 else if (prefix(message, "/extra") ||
1071 prefix(message, "/examine") ||
1072 (prefix(message, "/ex") && !prefix(message, "/exit")))
1073 {
1074 do_cmd_check_extra_info(Ind, (admin && !tk));
1075 return;
1076 }
1077 else if (prefix(message, "/time")) {
1078 do_cmd_time(Ind);
1079 return;
1080 }
1081 /* Please add here anything you think is needed. */
1082 else if ((prefix(message, "/refresh")) ||
1083 prefix(message, "/ref"))
1084 {
1085 do_cmd_refresh(Ind);
1086 return;
1087 }
1088 else if ((prefix(message, "/target")) ||
1089 prefix(message, "/tar"))
1090 {
1091 int tx, ty;
1092
1093 /* Clear the target */
1094 p_ptr->target_who = 0;
1095
1096 /* at least 2 arguments required */
1097 if (tk < 2)
1098 {
1099 msg_print(Ind, "\377oUsage: /target (X) (Y) <from your position>");
1100 return;
1101 }
1102
1103 tx = p_ptr->px + k;
1104 ty = p_ptr->py + atoi(token[2]);
1105
1106 if (!in_bounds(ty,tx))
1107 {
1108 msg_print(Ind, "\377oIllegal position!");
1109 return;
1110 }
1111
1112 /* Set the target */
1113 p_ptr->target_row = ty;
1114 p_ptr->target_col = tx;
1115
1116 /* Set 'stationary' target */
1117 p_ptr->target_who = 0 - MAX_PLAYERS - 2;
1118
1119 return;
1120 }
1121 /* Now this command is opened for everyone */
1122 else if (prefix(message, "/recall") ||
1123 prefix(message, "/rec"))
1124 {
1125 if (admin) set_recall_timer(Ind, 1);
1126 else {
1127 int item = -1, spell = -1, spell_rec = -1, spell_rel = -1;
1128 bool spell_rec_found = FALSE, spell_rel_found = FALSE;
1129 object_type *o_ptr;
1130
1131 /* Paralyzed or just not enough energy left to perform a move? */
1132
1133 /* this also prevents recalling while resting, too harsh maybe */
1134 // if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1135 if (p_ptr->paralyzed) return;
1136
1137 /* Don't drain energy far below zero - mikaelh */
1138 if (p_ptr->energy < 0) return;
1139 /* All of this isn't perfect. In theory, the command to use a specific rec-item would need to be added to the client's command queue I guess. oO */
1140 #if 0 /* can't use /rec while resting with this enabled, oops. */
1141 /* hm, how about this? - C. Blue */
1142 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1143 #endif
1144
1145 /* Test for 'Recall' istar spell and for 'Relocation' astral spell */
1146 #if 0 /* hm, which version might be easier/better?.. */
1147 spell_rec = exec_lua(Ind, "return find_spell(\"Recall\")");
1148 #ifdef ENABLE_MAIA
1149 spell_rel = exec_lua(Ind, "return find_spell(\"Relocation\")");
1150 #endif
1151 #else
1152 spell_rec = exec_lua(Ind, "return RECALL");
1153 #ifdef ENABLE_MAIA
1154 spell_rel = exec_lua(Ind, "return RELOCATION");
1155 #endif
1156 #endif
1157
1158 /* Turn off resting mode */
1159 disturb(Ind, 0, 0);
1160
1161 // for (i = 0; i < INVEN_PACK; i++)
1162 for (i = 0; i < INVEN_TOTAL; i++) { /* allow to activate equipped items for recall (some art(s)!) */
1163 o_ptr = &(p_ptr->inventory[i]);
1164 if (!o_ptr->tval) continue;
1165 if (!find_inscription(o_ptr->note, "@R")) continue;
1166
1167 /* For spell books: Test if we can actually use this item at all,
1168 ie have learned the spell yet, otherwise skip it completely!
1169 This is because we might've picked up books from someone else. */
1170 if (o_ptr->tval == TV_BOOK) {
1171 if (o_ptr->sval == SV_SPELLBOOK) {
1172 if (o_ptr->pval == spell_rec || o_ptr->pval == spell_rel) {
1173 /* Have we learned this spell yet at all? */
1174 if (!exec_lua(Ind, format("return is_ok_spell(%d, %d)", Ind, o_ptr->pval)))
1175 /* Just continue&ignore instead of return, since we
1176 might just have picked up someone else's book! */
1177 continue;
1178 /* If so then use it */
1179 spell = o_ptr->pval;
1180 } else {
1181 /* "No recall spell found in this book!" */
1182 //continue;
1183 /* Be severe and point out the wrong inscription: */
1184 msg_print(Ind, "\377oThe inscribed spell scroll isn't a recall spell.");
1185 return;
1186 }
1187 } else {
1188 if (MY_VERSION < (4 << 12 | 4 << 8 | 1 << 4 | 8)) {
1189 /* now <4.4.1.8 is no longer supported! to make s_aux.lua slimmer */
1190 spell_rec_found = exec_lua(Ind, format("return spell_in_book(%d, %d)", o_ptr->sval, spell_rec));//NO LONGER SUPPORTED
1191 #ifdef ENABLE_MAIA
1192 spell_rel_found = exec_lua(Ind, format("return spell_in_book(%d, %d)", o_ptr->sval, spell_rel));//NO LONGER SUPPORTED
1193 #endif
1194 if (!spell_rec_found && !spell_rel_found) {
1195 /* Be severe and point out the wrong inscription: */
1196 msg_print(Ind, "\377oThe inscribed book doesn't contain a recall spell.");
1197 return;
1198 }
1199 } else {
1200 spell_rec_found = exec_lua(Ind, format("return spell_in_book2(%d, %d, %d)", i, o_ptr->sval, spell_rec));
1201 #ifdef ENABLE_MAIA
1202 spell_rel_found = exec_lua(Ind, format("return spell_in_book2(%d, %d, %d)", i, o_ptr->sval, spell_rel));
1203 #endif
1204 if (!spell_rec_found && !spell_rel_found) {
1205 /* Be severe and point out the wrong inscription: */
1206 msg_print(Ind, "\377oThe inscribed book doesn't contain a recall spell.");
1207 return;
1208 }
1209 }
1210 /* Have we learned this spell yet at all? */
1211 if (spell_rec_found && exec_lua(Ind, format("return is_ok_spell(%d, %d)", Ind, spell_rec)))
1212 spell = spell_rec;
1213 if (spell_rel_found && exec_lua(Ind, format("return is_ok_spell(%d, %d)", Ind, spell_rel)))
1214 spell = spell_rel;
1215 /* Just continue&ignore instead of return, since we
1216 might just have picked up someone else's book! */
1217 if (spell == -1) continue;
1218 }
1219 }
1220
1221 item = i;
1222 break;
1223 }
1224
1225 if (item == -1) {
1226 msg_print(Ind, "\377oNo usable item with '@R' inscription found.");
1227 return;
1228 }
1229
1230 disturb(Ind, 1, 0);
1231
1232 /* ALERT! Hard-coded! */
1233 switch (o_ptr->tval) {
1234 case TV_SCROLL:
1235 do_cmd_read_scroll(Ind, item);
1236 break;
1237 case TV_ROD:
1238 do_cmd_zap_rod(Ind, item, 0);
1239 break;
1240 /* Cast Recall spell - mikaelh */
1241 case TV_BOOK:
1242 #if 0
1243 if (o_ptr->sval == SV_SPELLBOOK) {
1244 /* Test for 'Recall' istar spell: */
1245 if (o_ptr->pval != spell_rec) {
1246 msg_print(Ind, "\377oThis is not a Spell Scroll of Recall.");
1247 return;
1248 }
1249 /* Test for 'Relocation' astral spell: */
1250 } else {
1251 if (MY_VERSION < (4 << 12 | 4 << 8 | 1 << 4 | 8)) {
1252 /* no longer supported! to make s_aux.lua slimmer */
1253 if (exec_lua(Ind, format("return spell_in_book(%d, %d)", o_ptr->sval, spell)) == FALSE) {
1254 msg_print(Ind, "\377oRecall spell not found in this book.");
1255 return;
1256 }
1257 } else {
1258 if (exec_lua(Ind, format("return spell_in_book2(%d, %d, %d)", item, o_ptr->sval, spell)) == FALSE) {
1259 msg_print(Ind, "\377oRecall spell not found in this book.");
1260 return;
1261 }
1262 }
1263 }
1264 #endif
1265 cast_school_spell(Ind, item, spell, -1, -1, 0);
1266 break;
1267 default:
1268 do_cmd_activate(Ind, item, 0);
1269 //msg_print(Ind, "\377oYou cannot recall with that.");
1270 break;
1271 }
1272 }
1273
1274 switch (tk) {
1275 case 1:
1276 /* depth in feet */
1277 p_ptr->recall_pos.wx = p_ptr->wpos.wx;
1278 p_ptr->recall_pos.wy = p_ptr->wpos.wy;
1279 p_ptr->recall_pos.wz = k / (p_ptr->depth_in_feet ? 50 : 1);
1280 break;
1281 case 2:
1282 p_ptr->recall_pos.wx = k % MAX_WILD_X;
1283 p_ptr->recall_pos.wy = atoi(token[2]) % MAX_WILD_Y;
1284 p_ptr->recall_pos.wz = 0;
1285 /* fix negative modulo results, sigh */
1286 if (p_ptr->recall_pos.wx < 0) p_ptr->recall_pos.wx = 0;
1287 if (p_ptr->recall_pos.wy < 0) p_ptr->recall_pos.wy = 0;
1288 break;
1289 // default: /* follow the inscription */
1290 /* TODO: support tower */
1291 // p_ptr->recall_pos.wz = 0 - p_ptr->max_dlv;
1292 // p_ptr->recall_pos.wz = 0;
1293 }
1294
1295 return;
1296 }
1297 /* TODO: remove &7 viewer commands */
1298 /* view RFE file or any other files in lib/data. */
1299 else if (prefix(message, "/less"))
1300 {
1301 char path[MAX_PATH_LENGTH];
1302 if (tk && is_admin(p_ptr))
1303 {
1304 // if (strstr(token[1], "log") && is_admin(p_ptr))
1305 {
1306 // path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_TEXT, "mangband.log");
1307 path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_DATA, token[1]);
1308 do_cmd_check_other_prepare(Ind, path, "");
1309 return;
1310 }
1311 // else if (strstr(token[1], "rfe") &&
1312
1313 }
1314 /* default is "mangband.rfe" */
1315 else if ((is_admin(p_ptr) || cfg.public_rfe))
1316 {
1317 path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_DATA, "tomenet.rfe");
1318 do_cmd_check_other_prepare(Ind, path, "RFE/Bug file");
1319 return;
1320 }
1321 else msg_print(Ind, "\377o/less is not opened for use...");
1322 return;
1323 }
1324 else if (prefix(message, "/news"))
1325 {
1326 char path[MAX_PATH_LENGTH];
1327 path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_TEXT, "news.txt");
1328 do_cmd_check_other_prepare(Ind, path, "News");
1329 return;
1330 }
1331 else if (prefix(message, "/version") ||
1332 prefix(message, "/ver"))
1333 {
1334 if (tk) do_cmd_check_server_settings(Ind);
1335 else msg_print(Ind, longVersion);
1336
1337 return;
1338 }
1339 else if (prefix(message, "/help") ||
1340 prefix(message, "/he") ||
1341 prefix(message, "/?"))
1342 {
1343 char path[MAX_PATH_LENGTH];
1344
1345 #if 0 /* this invokes the old slash command help */
1346 /* Build the filename */
1347 if (admin && !tk) path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_TEXT, "slash_ad.hlp");
1348 else path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_TEXT, "slash.hlp");
1349 do_cmd_check_other_prepare(Ind, path, "Help");
1350 #else /* this is the same help file you get by pressing '?' key */
1351 /* mimic pressing '?' key, which does cmd_help() on client-side, invoking do_cmd_help() */
1352 cptr q = format("tomenet.hlp");
1353 path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_TEXT, q);
1354 do_cmd_check_other_prepare(Ind, path, "");
1355 #endif
1356 return;
1357 }
1358 else if(prefix(message, "/pkill") ||
1359 prefix(message, "/pk"))
1360 {
1361 set_pkill(Ind, admin? 10 : 200);
1362 return;
1363 }
1364 /* TODO: move it to the Mayor's house */
1365 else if(prefix(message, "/xorder") || prefix(message, "/xo")) {
1366 j = Ind; //k=0;
1367 u16b r, num;
1368 int lev;
1369 u16b flags = (QUEST_MONSTER|QUEST_RANDOM);
1370
1371 if (tk && !strcmp(token[1], "reset")) {
1372 int qn;
1373 if (!admin) return;
1374 for (qn = 0; qn < MAX_XORDERS; qn++) {
1375 xorders[qn].active = 0;
1376 xorders[qn].type = 0;
1377 xorders[qn].id = 0;
1378 }
1379 msg_broadcast(0, "\377yExtermination orders are reset");
1380 for (i = 1; i <= NumPlayers; i++) {
1381 if (Players[i]->conn == NOT_CONNECTED) continue;
1382 Players[i]->xorder_id = 0;
1383 }
1384 return;
1385 }
1386
1387 if (p_ptr->IDDC_logscum) {
1388 msg_print(Ind, "\377yYou cannot acquire an extermination order on a stale floor.");
1389 msg_print(Ind, "\377yTake a staircase to move on to a different dungeon level.");
1390 return;
1391 }
1392
1393 if (tk && !strcmp(token[1], "guild")) {
1394 if (!p_ptr->guild || guilds[p_ptr->guild].master != p_ptr->id) {
1395 msg_print(Ind, "\377rYou are not a guildmaster");
1396 return;
1397 }
1398 if (tk == 2) {
1399 if ((j = name_lookup_loose(Ind, token[2], FALSE, FALSE))) {
1400 if(Players[j]->xorder_id){
1401 msg_format(Ind, "\377y%s already received an extermination order.", Players[j]->name);
1402 return;
1403 }
1404 } else {
1405 msg_format(Ind, "Player %s is not here", token[2]);
1406 return;
1407 }
1408 } else {
1409 msg_print(Ind, "Usage: /xorder guild <name>");
1410 return;
1411 }
1412 flags |= QUEST_GUILD;
1413 lev = Players[j]->lev + 5;
1414 }
1415 else if (admin && tk) {
1416 if ((j = name_lookup_loose(Ind, token[1], FALSE, FALSE))) {
1417 if (Players[j]->xorder_id) {
1418 msg_format(Ind, "\377y%s already received an extermination order.", Players[j]->name);
1419 return;
1420 }
1421 lev = Players[j]->lev; /* for now */
1422 }
1423 else return;
1424 } else {
1425 flags |= QUEST_RACE;
1426 lev = Players[j]->lev;
1427 }
1428 if (prepare_xorder(Ind, j, flags, &lev, &r, &num))
1429 add_xorder(Ind, j, r, num, flags);
1430 return;
1431 }
1432 else if (prefix(message, "/feeling") ||
1433 prefix(message, "/fe"))
1434 {
1435 cave_type **zcave = getcave(&p_ptr->wpos);
1436 bool no_tele = FALSE;
1437 if (zcave)
1438 no_tele = (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) != 0;
1439
1440 if (!show_floor_feeling(Ind, FALSE) && !no_tele)
1441 msg_print(Ind, "You feel nothing special.");
1442
1443 if (no_tele)
1444 msg_print(Ind, "\377DThe air in here feels very still.");
1445 return;
1446 }
1447 else if (prefix(message, "/monster") || /* syntax: /mon [<char>] [+minlev] */
1448 prefix(message, "/mon")) {
1449 int r_idx, num;
1450 monster_race *r_ptr;
1451 if (!tk) {
1452 do_cmd_show_monster_killed_letter(Ind, NULL, 0);
1453 return;
1454 }
1455
1456 /* Handle specification like 'D', 'k' */
1457 if (strlen(token[1]) == 1) {
1458 if (tk == 2) do_cmd_show_monster_killed_letter(Ind, token[1], atoi(token[2]));
1459 else do_cmd_show_monster_killed_letter(Ind, token[1], 0);
1460 return;
1461 } else if (token[1][0] == '+') {
1462 do_cmd_show_monster_killed_letter(Ind, NULL, atoi(token[1]));
1463 return;
1464 }
1465
1466 /* Directly specify a name (tho no1 would use it..) */
1467 r_idx = race_index(message3);
1468 if (!r_idx) {
1469 msg_print(Ind, "No such monster.");
1470 return;
1471 }
1472
1473 r_ptr = &r_info[r_idx];
1474 num = p_ptr->r_killed[r_idx];
1475
1476 if (r_ptr->flags1 & RF1_UNIQUE) {
1477 if (!num) msg_format(Ind, "%s : not slain.", r_name + r_ptr->name);
1478 else if (num == 1) msg_format(Ind, "%s : slain.", r_name + r_ptr->name);
1479 else msg_format(Ind, "%s : assisted in slaying.", r_name + r_ptr->name);
1480 } else if (get_skill(p_ptr, SKILL_MIMIC) &&
1481 !((p_ptr->pclass == CLASS_DRUID) && !mimic_druid(r_idx, p_ptr->lev)) &&
1482 !((p_ptr->prace == RACE_VAMPIRE) && !mimic_vampire(r_idx, p_ptr->lev)) &&
1483 !((p_ptr->pclass == CLASS_SHAMAN) && !mimic_shaman(r_idx)))
1484 {
1485 i = r_ptr->level - num;
1486 if (p_ptr->tim_mimic && r_idx == p_ptr->tim_mimic_what) {
1487 if (r_idx == p_ptr->body_monster)
1488 msg_format(Ind, "%s : %4d slain (%d more to go) ** Infused %d turns **",
1489 r_name + r_ptr->name, num, i, p_ptr->tim_mimic);
1490 else
1491 msg_format(Ind, "%s : %4d slain (%d more to go) (infused %d turns)",
1492 r_name + r_ptr->name, num, i, p_ptr->tim_mimic);
1493 } else if (!((p_ptr->pclass == CLASS_DRUID) && mimic_druid(r_idx, p_ptr->lev))
1494 && !((p_ptr->prace == RACE_VAMPIRE) && mimic_vampire(r_idx, p_ptr->lev))) {
1495 if (i > 0) msg_format(Ind, "%s : %4d slain (%d more to go)", r_name + r_ptr->name, num, i);
1496 else if (p_ptr->body_monster == r_idx) msg_format(Ind, "%s : %4d slain ** Your current form **", r_name + r_ptr->name, num);
1497 else msg_format(Ind, "%s : %4d slain (learnt)", r_name + r_ptr->name, num);
1498 } else {
1499 if (r_idx == p_ptr->body_monster) msg_format(Ind, "%s : %4d slain ** Your current form **", r_name + r_ptr->name, num, i);
1500 else msg_format(Ind, "%s : %4d slain (learnt)", r_name + r_ptr->name, num);
1501 }
1502 } else msg_format(Ind, "%s : %4d slain.", r_name + r_ptr->name, num);
1503
1504 /* TODO: show monster description */
1505
1506 return;
1507 }
1508 /* add inscription to books */
1509 else if (prefix(message, "/autotag") ||
1510 prefix(message, "/at"))
1511 {
1512 object_type *o_ptr;
1513 for(i = 0; i < INVEN_PACK; i++)
1514 {
1515 o_ptr = &(p_ptr->inventory[i]);
1516 auto_inscribe(Ind, o_ptr, tk);
1517 }
1518 /* Window stuff */
1519 p_ptr->window |= (PW_INVEN);// | PW_EQUIP);
1520
1521 return;
1522 }
1523 else if (prefix(message, "/house") ||
1524 prefix(message, "/hou"))
1525 /* /hou [o][l] to only show the houses we actually own/that are actually here/both */
1526 {
1527 bool local = FALSE, own = FALSE;
1528 if (tk) {
1529 if (token[1][0] == '?') {
1530 msg_print(Ind, "Usage: /hou [o][l] (to filter for 'own' and/or 'local' houses)");
1531 return;
1532 }
1533 if (strchr(message3, 'l')) local = TRUE;
1534 if (strchr(message3, 'o')) own = TRUE;
1535 }
1536 do_cmd_show_houses(Ind, local, own);
1537 return;
1538 }
1539 else if (prefix(message, "/object") ||
1540 prefix(message, "/obj"))
1541 {
1542 if (!tk)
1543 {
1544 do_cmd_show_known_item_letter(Ind, NULL);
1545 return;
1546 }
1547
1548 if (strlen(token[1]) == 1)
1549 {
1550 do_cmd_show_known_item_letter(Ind, token[1]);
1551 return;
1552 }
1553
1554 return;
1555 }
1556 else if (prefix(message, "/sip")) {
1557 /* Paralyzed? */
1558 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1559
1560 do_cmd_drink_fountain(Ind);
1561 return;
1562 }
1563 else if (prefix(message, "/fill")) {
1564 /* Paralyzed? */
1565 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1566
1567 do_cmd_fill_bottle(Ind);
1568 return;
1569 }
1570 else if (prefix(message, "/empty") || prefix(message, "/emp")) {
1571 int slot;
1572 return;//disabled for anti-cheeze
1573 if (!tk)
1574 {
1575 msg_print(Ind, "\377oUsage: /empty (inventory slot letter)");
1576 return;
1577 }
1578 slot = (char)(token[1][0]);
1579 /* convert to upper case ascii code */
1580 if (slot >= 97 && slot <= 122) slot -= 32;
1581 /* check for valid inventory slot */
1582 if (slot < 65 || slot > (90 - 3))
1583 {
1584 msg_print(Ind, "\377oValid inventory slots are a-w (or A-W). Please try again.");
1585 return;
1586 }
1587 do_cmd_empty_potion(Ind, slot - 65);
1588 return;
1589 }
1590 else if (prefix(message, "/dice") || !strcmp(message, "/d")) {
1591 int rn = 0;
1592
1593 if (p_ptr->body_monster) {
1594 monster_race *r_ptr = &r_info[p_ptr->body_monster];
1595 /* be nice to bats: they only have arms */
1596 if (!(r_ptr->body_parts[BODY_WEAPON] || r_ptr->body_parts[BODY_FINGER] || r_ptr->body_parts[BODY_ARMS])) {
1597 msg_print(Ind, "You cannot roll dice in your current form.");
1598 return;
1599 }
1600 }
1601
1602 if (!strcmp(message, "/d")) k = 2;
1603 else {
1604 if (tk < 1) {
1605 msg_print(Ind, "\377oUsage: /dice <number of dice>");
1606 msg_print(Ind, "\377oShortcut to throw 2 dice: /d");
1607 return;
1608 }
1609 if ((k < 1) || (k > 100)) {
1610 msg_print(Ind, "\377oNumber of dice must be between 1 and 100!");
1611 return;
1612 }
1613 }
1614
1615 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1616 p_ptr->energy -= level_speed(&p_ptr->wpos);
1617
1618 for (i = 0; i < k; i++) rn += randint(6);
1619 msg_format(Ind, "\374\377%cYou throw %d dice and get a %d", COLOUR_GAMBLE, k, rn);
1620 msg_format_near(Ind, "\374\377%c%s throws %d dice and gets a %d", COLOUR_GAMBLE, p_ptr->name, k, rn);
1621 #ifdef USE_SOUND_2010
1622 sound(Ind, "dice_roll", NULL, SFX_TYPE_MISC, TRUE);
1623 #endif
1624 return;
1625 }
1626 else if (prefix(message, "/coin") || prefix(message, "/flip") || !strcmp(message, "/f")) {
1627 bool coin;
1628
1629 if (!p_ptr->au) {
1630 msg_print(Ind, "You don't have any coins.");
1631 return;
1632 }
1633 if (p_ptr->body_monster) {
1634 monster_race *r_ptr = &r_info[p_ptr->body_monster];
1635 /* be nice to bats: they only have arms */
1636 if (!(r_ptr->body_parts[BODY_WEAPON] || r_ptr->body_parts[BODY_FINGER] || r_ptr->body_parts[BODY_ARMS])) {
1637 msg_print(Ind, "You cannot catch coins in your current form.");
1638 return;
1639 }
1640 }
1641
1642 coin = (rand_int(2) == 0);
1643 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1644 p_ptr->energy -= level_speed(&p_ptr->wpos);
1645
1646 msg_format(Ind, "\374\377%cYou flip a coin and get %s.", COLOUR_GAMBLE, coin ? "heads" : "tails");
1647 msg_format_near(Ind, "\374\377%c%s flips a coin and gets %s.", COLOUR_GAMBLE, p_ptr->name, coin ? "heads" : "tails");
1648 #ifdef USE_SOUND_2010
1649 sound(Ind, "coin_flip", NULL, SFX_TYPE_MISC, TRUE);
1650 #endif
1651 return;
1652 }
1653 #ifdef RPG_SERVER /* too dangerous on the pm server right now - mikaelh */
1654 /* Oops, meant to be on RPG only for now. forgot to add it. thanks - the_sandman */
1655 #if 0 //moved the old code here.
1656 else if (prefix(message, "/pet")){
1657 if (tk && prefix(token[1], "force"))
1658 {
1659 summon_pet(Ind, 1);
1660 msg_print(Ind, "You summon a pet");
1661 }
1662 else
1663 {
1664 msg_print(Ind, "Pet code is under working; summoning is bad for your server's health.");
1665 msg_print(Ind, "If you still want to summon one, type \377o/pet force\377w.");
1666 }
1667 return;
1668 }
1669 #endif
1670 else if (prefix(message, "/pet")) {
1671 if (strcmp(Players[Ind]->accountname, "The_sandman")) {
1672 msg_print(Ind, "\377rPet system is disabled.");
1673 return;
1674 }
1675 if (Players[Ind]->has_pet == 2) {
1676 msg_print(Ind, "\377rYou cannot have anymore pets!");
1677 return;
1678 }
1679 if (pet_creation(Ind))
1680 msg_print(Ind, "\377USummoning a pet.");
1681 else
1682 msg_print(Ind, "\377rYou already have a pet!");
1683 return;
1684 }
1685 #endif
1686 else if (prefix(message, "/unpet")) {
1687 #ifdef RPG_SERVER
1688 msg_print(Ind, "\377RYou abandon your pet! You cannot have anymore pets!");
1689 if (strcmp(Players[Ind]->accountname, "The_sandman")) return;
1690 // if (Players[Ind]->wpos.wz != 0) {
1691 for (i = m_top-1; i >= 0; i--) {
1692 monster_type *m_ptr = &m_list[i];
1693 if (!m_ptr->pet) continue;
1694 if (find_player(m_ptr->owner) == Ind) {
1695 m_ptr->pet = 0; //default behaviour!
1696 m_ptr->owner = 0;
1697 Players[Ind]->has_pet = 0; //spec value
1698 i = -1; //quit early
1699 }
1700 }
1701 // } else {
1702 // msg_print(Ind, "\377yYou cannot abandon your pet while the whole town is looking!");
1703 // }
1704 #endif
1705 return;
1706 }
1707 /* added shuffling >_> - C. Blue */
1708 else if (prefix(message, "/shuffle")) { /* usage: /shuffle [<32|52> [# of jokers]] */
1709 /* Notes:
1710 0x1FFF = 13 bits = 13 cards (Ace,2..10,J/Q/K)
1711 All further bits (bit 14, 15 and 16) would add a joker each.
1712 So 0xFFFF would add _3_ jokers (for that flower -
1713 but jokers aren't shown with any flower, so it doesn't matter).
1714 The usual values here are:
1715 0x1FC1 -> 8 cards (Ace,7..10,J/Q/K)
1716 0x1FFF -> 13 cards (Ace,2..10,J/Q/K)
1717 0x3FFF/0x7FFF/0xFFFF for one flower and 0x1FFF for the other three ->
1718 13 cards each, and 1/2/3 jokers in addition to that.
1719 0xFFFF for one flower, 0x3FFF for another flower and 0x1FFF for the
1720 remaining two flowers -> 52 cards deck with 4 jokers. */
1721
1722 if (p_ptr->body_monster) {
1723 monster_race *r_ptr = &r_info[p_ptr->body_monster];
1724 /* be nice to bats: they only have arms */
1725 if (!(r_ptr->body_parts[BODY_WEAPON] || r_ptr->body_parts[BODY_FINGER] || r_ptr->body_parts[BODY_ARMS])) {
1726 msg_print(Ind, "You cannot shuffle cards in your current form.");
1727 return;
1728 }
1729 }
1730
1731 if (!tk) {
1732 msg_format(Ind, "\377%cYou shuffle a deck of 52 cards", COLOUR_GAMBLE);
1733 msg_format_near(Ind, "\377%c%s shuffles a deck of 52 cards", COLOUR_GAMBLE, p_ptr->name);
1734
1735 p_ptr->cards_diamonds = 0x1FFF;
1736 p_ptr->cards_hearts = 0x1FFF;
1737 p_ptr->cards_spades = 0x1FFF;
1738 p_ptr->cards_clubs = 0x1FFF;
1739 } else {
1740 if ((k != 32 && k != 52) || tk > 2) {
1741 msg_print(Ind, "\377oUsage: /shuffle <32|52> [# of jokers]");
1742 return;
1743 }
1744 if (k == 32) {
1745 p_ptr->cards_diamonds = 0x1FC1;
1746 p_ptr->cards_hearts = 0x1FC1;
1747 p_ptr->cards_spades = 0x1FC1;
1748 p_ptr->cards_clubs = 0x1FC1;
1749 } else {
1750 p_ptr->cards_diamonds = 0x1FFF;
1751 p_ptr->cards_hearts = 0x1FFF;
1752 p_ptr->cards_spades = 0x1FFF;
1753 p_ptr->cards_clubs = 0x1FFF;
1754 }
1755 if (tk == 2) {
1756 j = atoi(token[2]);
1757 if (j < 0) {
1758 msg_print(Ind, "\377oNumber of jokers must not be negative.");
1759 return;
1760 }
1761 if (j > 12) {
1762 msg_print(Ind, "\377oA maximum of 12 jokers is allowed.");
1763 return;
1764 }
1765 if (j > 9) {
1766 p_ptr->cards_diamonds |= 0xE000;
1767 p_ptr->cards_hearts |= 0xE000;
1768 p_ptr->cards_spades |= 0xE000;
1769 if (j == 12) p_ptr->cards_clubs |= 0xE000;
1770 else if (j == 11) p_ptr->cards_clubs |= 0x6000;
1771 else p_ptr->cards_clubs |= 0x2000;
1772 } else if (j > 6) {
1773 p_ptr->cards_diamonds |= 0xE000;
1774 p_ptr->cards_hearts |= 0xE000;
1775 if (j == 9) p_ptr->cards_spades |= 0xE000;
1776 else if (j == 8) p_ptr->cards_spades |= 0x6000;
1777 else p_ptr->cards_spades |= 0x2000;
1778 } else if (j > 3) {
1779 p_ptr->cards_diamonds |= 0xE000;
1780 if (j == 6) p_ptr->cards_hearts |= 0xE000;
1781 else if (j == 5) p_ptr->cards_hearts |= 0x6000;
1782 else p_ptr->cards_hearts |= 0x2000;
1783 } else if (j > 0) {
1784 if (j == 3) p_ptr->cards_diamonds |= 0xE000;
1785 else if (j == 2) p_ptr->cards_diamonds |= 0x6000;
1786 else p_ptr->cards_diamonds |= 0x2000;
1787 }
1788 }
1789 if (!j) {
1790 msg_format(Ind, "\377%cYou shuffle a deck of %d cards", COLOUR_GAMBLE, k);
1791 msg_format_near(Ind, "\377%c%s shuffles a deck of %d cards", COLOUR_GAMBLE, p_ptr->name, k);
1792 } else if (j == 1) {
1793 msg_format(Ind, "\377%cYou shuffle a deck of %d cards and a joker", COLOUR_GAMBLE, k);
1794 msg_format_near(Ind, "\377%c%s shuffles a deck of %d cards and a joker", COLOUR_GAMBLE, p_ptr->name, k);
1795 } else {
1796 msg_format(Ind, "\377%cYou shuffle a deck of %d cards and %d jokers", COLOUR_GAMBLE, k, j);
1797 msg_format_near(Ind, "\377%c%s shuffles a deck of %d cards and %d jokers", COLOUR_GAMBLE, p_ptr->name, k, j);
1798 }
1799 }
1800 #ifdef USE_SOUND_2010
1801 sound(Ind, "playing_cards_shuffle", NULL, SFX_TYPE_MISC, TRUE);
1802 #endif
1803 return;
1804 }
1805 else if (prefix(message, "/dealer")) { /* hand own card stack to someone else, making him the "dealer" */
1806 player_type *q_ptr;
1807
1808 if (!tk) {
1809 msg_print(Ind, "\377oUsage: /dealer <character name>");
1810 return;
1811 }
1812 if (!p_ptr->cards_diamonds && !p_ptr->cards_hearts && !p_ptr->cards_spades && !p_ptr->cards_clubs) {
1813 msg_print(Ind, "\377wYou are out of cards! You must /shuffle a new deck of cards first.");
1814 return;
1815 }
1816
1817 i = name_lookup_loose(Ind, message3, FALSE, FALSE);
1818 if (!i || !p_ptr->play_vis[i]) {
1819 msg_print(Ind, "You don't see anyone of that name.");
1820 return;
1821 }
1822 q_ptr = Players[i];
1823
1824 if (!inarea(&p_ptr->wpos, &q_ptr->wpos)) {
1825 msg_print(Ind, "\377yThat player is not nearby.");
1826 return;
1827 }
1828 if (distance(p_ptr->py, p_ptr->px, q_ptr->py, q_ptr->px) > 6) {
1829 msg_print(Ind, "\377yThat player is standing too far away from you.");
1830 return;
1831 }
1832
1833 msg_format(Ind, "\377%cYou hand your stack of cards over to %s.", COLOUR_GAMBLE, q_ptr->name);
1834 msg_format_near(Ind, "\377%c%s hands his stack of cards over to %s.", COLOUR_GAMBLE, p_ptr->name, q_ptr->name);
1835 #ifdef USE_SOUND_2010
1836 sound(Ind, "playing_cards_dealer", "item_rune", SFX_TYPE_MISC, TRUE);
1837 #endif
1838
1839 q_ptr->cards_diamonds = p_ptr->cards_diamonds;
1840 q_ptr->cards_hearts = p_ptr->cards_hearts;
1841 q_ptr->cards_spades = p_ptr->cards_spades;
1842 q_ptr->cards_clubs = p_ptr->cards_clubs;
1843 p_ptr->cards_diamonds = 0x0;
1844 p_ptr->cards_hearts = 0x0;
1845 p_ptr->cards_spades = 0x0;
1846 p_ptr->cards_clubs = 0x0;
1847 return;
1848 }
1849 /* An alternative to dicing :) -the_sandman */
1850 else if (prefix(message, "/deal")
1851 #if 0 /* no support for shuffling? */
1852 ) {
1853 int value, flower;
1854 char* temp;
1855 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1856 p_ptr->energy -= level_speed(&p_ptr->wpos);
1857
1858 temp = (char*)malloc(10*sizeof(char));
1859 value = randint(13); flower = randint(4);
1860 switch (value) {
1861 case 1: strcpy(temp, "Ace"); break;
1862 case 2: strcpy(temp, "Two"); break;
1863 case 3: strcpy(temp, "Three"); break;
1864 case 4: strcpy(temp, "Four"); break;
1865 case 5: strcpy(temp, "Five"); break;
1866 case 6: strcpy(temp, "Six"); break;
1867 case 7: strcpy(temp, "Seven"); break;
1868 case 8: strcpy(temp, "Eight"); break;
1869 case 9: strcpy(temp, "Nine"); break;
1870 case 10: strcpy(temp, "Ten"); break;
1871 case 11: strcpy(temp, "Jack"); break;
1872 case 12: strcpy(temp, "Queen"); break;
1873 case 13: strcpy(temp, "King"); break;
1874 default: strcpy(temp, "joker ^^"); break;
1875 }
1876 switch (flower) {
1877 case 1:
1878 msg_format(Ind, "\377%c%s was dealt the %s of Diamond", COLOUR_GAMBLE, p_ptr->name, temp);
1879 msg_format_near(Ind, "\377%c%s was dealt the %s of Diamond", COLOUR_GAMBLE, p_ptr->name, temp);
1880 break;
1881 case 2:
1882 msg_format(Ind, "\377%c%s was dealt the %s of Club", COLOUR_GAMBLE, p_ptr->name, temp);
1883 msg_format_near(Ind, "\377%c%s was dealt the %s of Club", COLOUR_GAMBLE, p_ptr->name, temp);
1884 break;
1885 case 3:
1886 msg_format(Ind, "\377%c%s was dealt the %s of Heart", COLOUR_GAMBLE, p_ptr->name, temp);
1887 msg_format_near(Ind, "\377%c%s was dealt the %s of Heart", COLOUR_GAMBLE, p_ptr->name, temp);
1888 break;
1889 case 4:
1890 msg_format(Ind, "\377%c%s was dealt the %s of Spade", COLOUR_GAMBLE, p_ptr->name, temp);
1891 msg_format_near(Ind, "\377%c%s was dealt the %s of Spade", COLOUR_GAMBLE, p_ptr->name, temp);
1892 break;
1893 default:
1894 break;
1895 }
1896 free(temp);
1897 #else /* support shuffling */
1898 || prefix(message, "/draw")) {
1899 cptr value = "Naught", flower = "Void"; //compiler warnings
1900 int p = 0;
1901 bool draw = FALSE;
1902
1903 if (p_ptr->body_monster) {
1904 monster_race *r_ptr = &r_info[p_ptr->body_monster];
1905 /* be nice to bats: they only have arms */
1906 if (!(r_ptr->body_parts[BODY_WEAPON] || r_ptr->body_parts[BODY_FINGER] || r_ptr->body_parts[BODY_ARMS])) {
1907 msg_print(Ind, "You cannot fetch cards in your current form.");
1908 return;
1909 }
1910 }
1911
1912 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
1913 p_ptr->energy -= level_speed(&p_ptr->wpos);
1914
1915 if (tk) {
1916 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
1917 if ((!p || !p_ptr->play_vis[p]) && p != Ind) {
1918 msg_print(Ind, "You don't see anyone of that name.");
1919 return;
1920 }
1921
1922 if (!inarea(&p_ptr->wpos, &Players[p]->wpos)) {
1923 msg_print(Ind, "\377yThat player is not nearby.");
1924 return;
1925 }
1926 if (distance(p_ptr->py, p_ptr->px, Players[p]->py, Players[p]->px) > 6) {
1927 msg_print(Ind, "\377yThat player is standing too far away from you.");
1928 return;
1929 }
1930 }
1931
1932 if (prefix(message, "/draw")) {
1933 if (!p) {
1934 msg_print(Ind, "Usage: /draw <dealer name>");
1935 return;
1936 }
1937 draw = TRUE;
1938 /* switch drawer and dealer */
1939 p_ptr = Players[p];
1940 p = Ind;
1941 Ind = p_ptr->Ind;
1942 }
1943
1944 if (!p_ptr->cards_diamonds && !p_ptr->cards_hearts && !p_ptr->cards_spades && !p_ptr->cards_clubs) {
1945 if (draw) msg_format(p, "\377w%s is out of cards and must /shuffle a new deck of cards first!", p_ptr->name);
1946 else msg_print(Ind, "\377wYou are out of cards! You must /shuffle a new deck of cards first.");
1947 return;
1948 }
1949
1950 /* count amount of cards remaining in our deck */
1951 k = 0;
1952 for (i = 0; i < 16; i++) {
1953 if (p_ptr->cards_diamonds & (0x1 << i)) k++;
1954 if (p_ptr->cards_hearts & (0x1 << i)) k++;
1955 if (p_ptr->cards_spades & (0x1 << i)) k++;
1956 if (p_ptr->cards_clubs & (0x1 << i)) k++;
1957 }
1958
1959 /* draw one */
1960 j = randint(k);
1961 for (i = 0; i < 16; i++) {
1962 if (p_ptr->cards_diamonds & (0x1 << i)) {
1963 j--;
1964 if (!j) {
1965 p_ptr->cards_diamonds &= ~(0x1 << i);
1966 flower = "Diamonds";
1967 break;
1968 }
1969 }
1970 if (p_ptr->cards_hearts & (0x1 << i)) {
1971 j--;
1972 if (!j) {
1973 p_ptr->cards_hearts &= ~(0x1 << i);
1974 flower = "Hearts";
1975 break;
1976 }
1977 }
1978 if (p_ptr->cards_spades & (0x1 << i)) {
1979 j--;
1980 if (!j) {
1981 p_ptr->cards_spades &= ~(0x1 << i);
1982 flower = "Spades";
1983 break;
1984 }
1985 }
1986 if (p_ptr->cards_clubs & (0x1 << i)) {
1987 j--;
1988 if (!j) {
1989 p_ptr->cards_clubs &= ~(0x1 << i);
1990 flower = "Clubs";
1991 break;
1992 }
1993 }
1994 }
1995 switch (i) {
1996 case 0: value = "Ace"; break;
1997 case 1: value = "Two"; break;
1998 case 2: value = "Three"; break;
1999 case 3: value = "Four"; break;
2000 case 4: value = "Five"; break;
2001 case 5: value = "Six"; break;
2002 case 6: value = "Seven"; break;
2003 case 7: value = "Eight"; break;
2004 case 8: value = "Nine"; break;
2005 case 9: value = "Ten"; break;
2006 case 10: value = "Jack"; break;
2007 case 11: value = "Queen"; break;
2008 case 12: value = "King"; break;
2009 case 13: value = "Joker"; break;
2010 case 14: value = "Joker"; break;
2011 case 15: value = "Joker"; break;
2012 }
2013
2014 if (draw) {
2015 /* draw it */
2016 if (i < 13) {
2017 msg_format(p, "\377%cYou draw the %s of %s from %s", COLOUR_GAMBLE, value, flower, p_ptr->name);
2018 msg_format_near(p, "\377%c%s draws the %s of %s from %s", COLOUR_GAMBLE, Players[p]->name, value, flower, p_ptr->name);
2019 } else {
2020 msg_format(p, "\377%cYou draw a %s from %s", COLOUR_GAMBLE, value, p_ptr->name);
2021 msg_format_near(p, "\377%c%s draws a %s from %s", COLOUR_GAMBLE, Players[p]->name, value, p_ptr->name);
2022 }
2023 } else {
2024 /* deal it */
2025 if (!p) {
2026 if (i < 13) {
2027 msg_format(Ind, "\377%cYou deal the %s of %s", COLOUR_GAMBLE, value, flower);
2028 msg_format_near(Ind, "\377%c%s deals the %s of %s", COLOUR_GAMBLE, p_ptr->name, value, flower);
2029 } else {
2030 msg_format(Ind, "\377%cYou deal a %s", COLOUR_GAMBLE, value);
2031 msg_format_near(Ind, "\377%c%s deals a %s", COLOUR_GAMBLE, p_ptr->name, value);
2032 }
2033 } else {
2034 if (i < 13) {
2035 msg_format(Ind, "\377%cYou deal the %s of %s to %s", COLOUR_GAMBLE, value, flower, Players[p]->name);
2036 msg_format_near(Ind, "\377%c%s deals the %s of %s to %s", COLOUR_GAMBLE, p_ptr->name, value, flower, Players[p]->name);
2037 } else {
2038 msg_format(Ind, "\377%cYou deal a %s to %s", COLOUR_GAMBLE, value, Players[p]->name);
2039 msg_format_near(Ind, "\377%c%s deals a %s to %s", COLOUR_GAMBLE, p_ptr->name, value, Players[p]->name);
2040 }
2041 }
2042 }
2043
2044 if (!p_ptr->cards_diamonds && !p_ptr->cards_hearts && !p_ptr->cards_spades && !p_ptr->cards_clubs) {
2045 msg_format(Ind, "\377%cThat was the final card of your stack of cards.", COLOUR_GAMBLE);
2046 msg_format_near(Ind, "\377%cThat was the final card of the stack of cards.", COLOUR_GAMBLE);
2047 }
2048 #endif
2049 #ifdef USE_SOUND_2010
2050 sound(Ind, "playing_cards", NULL, SFX_TYPE_MISC, TRUE);//same for 'draw' and 'deal' actually
2051 #endif
2052 return;
2053 }
2054 else if (prefix(message, "/martyr") || prefix(message, "/mar")) {
2055 /* we cannot cast 'martyr' spell at all? */
2056 //if (lua_get_level(Ind, exec_lua(0, "return HMARTYR"), s32b lvl, 50, 0, 0) < 1)
2057 if (exec_lua(0, format("return get_level(%d, HMARTYR, 50, 0)", Ind)) < 1) {
2058 msg_print(Ind, "You know not how to open the heavens.");
2059 return;
2060 }
2061
2062 if (Players[Ind]->martyr_timeout)
2063 msg_print(Ind, "\377yThe heavens are not yet willing to accept your martyrium.");
2064 else
2065 msg_print(Ind, "The heavens are willing to accept your martyrium.");
2066 return;
2067 }
2068 else if (prefix(message, "/pnote"))
2069 {
2070 j = 0;
2071 if (!p_ptr->party) {
2072 msg_print(Ind, "\377oYou are not in a party.");
2073 return;
2074 }
2075 #if 0 /* allow only a party owner to write the note */
2076 if (strcmp(parties[p_ptr->party].owner, p_ptr->name)) {
2077 msg_print(Ind, "\377oYou aren't a party owner.");
2078 return;
2079 }
2080 #endif
2081
2082 if (tk == 1 && !strcmp(token[1], "*")) {
2083 /* Erase party note */
2084 for (i = 0; i < MAX_PARTYNOTES; i++) {
2085 /* search for pending party note */
2086 if (!strcmp(party_note_target[i], parties[p_ptr->party].name)) {
2087 /* found a matching note */
2088 /* delete the note */
2089 strcpy(party_note_target[i], "");
2090 strcpy(party_note[i], "");
2091 break;
2092 }
2093 }
2094 // msg_print(Ind, "\377oParty note has been erased.");
2095 msg_party_format(Ind, "\377b%s erased the party note.", p_ptr->name);
2096 return;
2097 }
2098 if (tk == 0) {
2099 /* Display party note */
2100 bool found_note = FALSE;
2101 for (i = 0; i < MAX_PARTYNOTES; i++) {
2102 if (!strcmp(party_note_target[i], parties[p_ptr->party].name)) {
2103 if (strcmp(party_note[i], "")) {
2104 msg_format(Ind, "\377bParty Note: %s", party_note[i]);
2105 found_note = TRUE;
2106 }
2107 break;
2108 }
2109 }
2110 if (!found_note) msg_print(Ind, "\377bNo party note stored.");
2111 return;
2112 }
2113 if (tk > 0) /* Set new party note */
2114 {
2115 /* Search for begin of parms ( == text of the note) */
2116 for (i = 6; i < (int)strlen(message2); i++)
2117 if (message2[i] == ' ')
2118 for (j = i; j < (int)strlen(message2); j++)
2119 if (message2[j] != ' ') {
2120 /* save start pos in j for latter use */
2121 i = strlen(message2);
2122 break;
2123 }
2124
2125 /* search for pending party note to change it */
2126 for (i = 0; i < MAX_PARTYNOTES; i++) {
2127 if (!strcmp(party_note_target[i], parties[p_ptr->party].name)) {
2128 /* found a matching note */
2129 break;
2130 }
2131 }
2132
2133 /* Limit */
2134 message2[j + MAX_CHARS_WIDE - 1] = '\0';
2135
2136 if (i < MAX_PARTYNOTES) {
2137 /* change existing party note to new text */
2138 strcpy(party_note[i], &message2[j]);
2139 // msg_print(Ind, "\377yNote has been stored.");
2140 msg_party_format(Ind, "\377b%s changed party note to: %s", p_ptr->name, party_note[i]);
2141 return;
2142 }
2143
2144 /* seach for free spot to create a new party note */
2145 for (i = 0; i < MAX_PARTYNOTES; i++) {
2146 if (!strcmp(party_note[i], "")) {
2147 /* found a free memory spot */
2148 break;
2149 }
2150 }
2151 if (i == MAX_PARTYNOTES) {
2152 msg_format(Ind, "\377oSorry, the server reached the maximum of %d party notes.", MAX_PARTYNOTES);
2153 return;
2154 }
2155 strcpy(party_note_target[i], parties[p_ptr->party].name);
2156 strcpy(party_note[i], &message2[j]);
2157 // msg_print(Ind, "\377yNote has been stored.");
2158 msg_party_format(Ind, "\377b%s set party note to: %s", p_ptr->name, party_note[i]);
2159 return;
2160 }
2161 }
2162 else if (prefix(message, "/gnote"))
2163 {
2164 j = 0;
2165 if (!p_ptr->guild) {
2166 msg_print(Ind, "\377oYou are not in a guild.");
2167 return;
2168 }
2169 #if 0 /* only allow the guild master to write the note? */
2170 if (guilds[p_ptr->guild].master != p_ptr->id) {
2171 msg_print(Ind, "\377oYou aren't a guild master.");
2172 return;
2173 }
2174 #endif
2175
2176 if (tk == 1 && !strcmp(token[1], "*")) {
2177 /* Erase guild note */
2178 for (i = 0; i < MAX_GUILDNOTES; i++) {
2179 /* search for pending guild note */
2180 if (!strcmp(guild_note_target[i], guilds[p_ptr->guild].name)) {
2181 /* found a matching note */
2182 /* delete the note */
2183 strcpy(guild_note_target[i], "");
2184 strcpy(guild_note[i], "");
2185 break;
2186 }
2187 }
2188 // msg_print(Ind, "\377oGuild note has been erased.");
2189 msg_guild_format(Ind, "\377b%s erased the guild note.", p_ptr->name);
2190 return;
2191 }
2192 if (tk == 0) {
2193 /* Display guild note */
2194 bool found_note = FALSE;
2195 for (i = 0; i < MAX_GUILDNOTES; i++) {
2196 if (!strcmp(guild_note_target[i], guilds[p_ptr->guild].name)) {
2197 if (strcmp(guild_note[i], "")) {
2198 msg_format(Ind, "\377bGuild Note: %s", guild_note[i]);
2199 found_note = TRUE;
2200 }
2201 break;
2202 }
2203 }
2204 if (!found_note) msg_print(Ind, "\377bNo guild note stored.");
2205 return;
2206 }
2207 if (tk > 0) { /* Set new Guild note */
2208 /* Search for begin of parms ( == text of the note) */
2209 for (i = 6; i < (int)strlen(message2); i++)
2210 if (message2[i] == ' ')
2211 for (j = i; j < (int)strlen(message2); j++)
2212 if (message2[j] != ' ') {
2213 /* save start pos in j for latter use */
2214 i = strlen(message2);
2215 break;
2216 }
2217
2218 /* search for pending guild note to change it */
2219 for (i = 0; i < MAX_GUILDNOTES; i++) {
2220 if (!strcmp(guild_note_target[i], guilds[p_ptr->guild].name)) {
2221 /* found a matching note */
2222 break;
2223 }
2224 }
2225 if (i < MAX_GUILDNOTES) {
2226 /* change existing guild note to new text */
2227 message2[j + MAX_CHARS_WIDE - 1] = '\0'; /* Limit */
2228 strcpy(guild_note[i], &message2[j]);
2229 // msg_print(Ind, "\377yNote has been stored.");
2230 msg_guild_format(Ind, "\377b%s changed the guild note to: %s", p_ptr->name, guild_note[i]);
2231 return;
2232 }
2233
2234 /* seach for free spot to create a new guild note */
2235 for (i = 0; i < MAX_GUILDNOTES; i++) {
2236 if (!strcmp(guild_note[i], "")) {
2237 /* found a free memory spot */
2238 break;
2239 }
2240 }
2241 if (i == MAX_GUILDNOTES) {
2242 msg_format(Ind, "\377oSorry, the server reached the maximum of %d guild notes.", MAX_GUILDNOTES);
2243 return;
2244 }
2245 strcpy(guild_note_target[i], guilds[p_ptr->guild].name);
2246 strcpy(guild_note[i], &message2[j]);
2247 // msg_print(Ind, "\377yNote has been stored.");
2248 msg_guild_format(Ind, "\377b%s set the guild note to: %s", p_ptr->name, guild_note[i]);
2249 return;
2250 }
2251 }
2252 else if (prefix(message, "/snotes") ||
2253 prefix(message, "/motd")) { /* same as /anotes for admins basically */
2254 for (i = 0; i < MAX_ADMINNOTES; i++) {
2255 if (strcmp(admin_note[i], "")) {
2256 msg_format(Ind, "\377sMotD: %s", admin_note[i]);
2257 }
2258 }
2259 if (server_warning[0]) msg_format(Ind, "\377R*** Note: %s ***", server_warning);
2260 return;
2261 }
2262 else if (prefix(message, "/notes")) {
2263 int notes = 0;
2264 for (i = 0; i < MAX_NOTES; i++) {
2265 /* search for pending notes of this player */
2266 if (!strcmp(priv_note_sender[i], p_ptr->name) ||
2267 !strcmp(priv_note_sender[i], p_ptr->accountname)) {
2268 /* found a matching note */
2269 notes++;
2270 }
2271 }
2272 if (notes > 0) msg_format(Ind, "\377oYou wrote %d currently pending notes:", notes);
2273 else msg_print(Ind, "\377oYou didn't write any pending notes.");
2274 for (i = 0; i < MAX_NOTES; i++) {
2275 /* search for pending notes of this player */
2276 if (!strcmp(priv_note_sender[i], p_ptr->name) ||
2277 !strcmp(priv_note_sender[i], p_ptr->accountname)) {
2278 /* found a matching note */
2279 msg_format(Ind, "\377oTo %s: %s", priv_note_target[i], priv_note[i]);
2280 }
2281 }
2282 return;
2283 }
2284 else if (prefix(message, "/note")) {
2285 int notes = 0, found_note = MAX_NOTES;
2286 j = 0;
2287 bool colon = FALSE;
2288 char tname[MAX_SLASH_LINE_LEN], *tpname; /* target's account name (must be *long* cause we temporarily store whole message2 in it..pft */
2289 struct account *c_acc;
2290
2291 if (tk < 1) { /* Explain command usage */
2292 msg_print(Ind, "Usage: /note <character or account name>:<text>");
2293 msg_print(Ind, "Example: /note Mithrandir:Your weapon is in the guild hall!");
2294 msg_print(Ind, "Usage 2: /note <name> will clear all pending notes to that player.");
2295 msg_print(Ind, "Usage 3: /note * will clear all pending notes to all players.");
2296 return;
2297 }
2298
2299 /* cut off, uh, many bytes, to avoid overflow --paranoia, I haven't counted */
2300 message2[MAX_SLASH_LINE_LEN - 15] = 0;
2301 message3[MAX_SLASH_LINE_LEN - 15] = 0;
2302
2303 /* translate character name to account name */
2304 if (!(tpname = strchr(message2 + 6, ':'))) {
2305 /* no text given */
2306 if (!lookup_player_id(message2 + 6)) {
2307 /* character name not found, try to match account name instead */
2308 c_acc = GetAccount(message2 + 6, NULL, FALSE);
2309 if (!c_acc) {
2310 msg_print(Ind, "\377oNo character or account of that name exists.");
2311 return;
2312 }
2313 KILL(c_acc, struct account);
2314 tpname[0] = ':';
2315 } else {
2316 strcpy(tname, "/note ");
2317 strcat(tname, lookup_accountname(lookup_player_id(message2 + 6)));
2318 strcpy(message2, tname);
2319 strcpy(tname, "");
2320 }
2321 } else {
2322 /* note text given */
2323 tpname[0] = 0;
2324 if (!lookup_player_id(message2 + 6)) {
2325 /* character name not found, try to match account name instead */
2326 c_acc = GetAccount(message2 + 6, NULL, FALSE);
2327 if (!c_acc) {
2328 msg_print(Ind, "\377oNo character or account of that name exists.");
2329 return;
2330 }
2331 KILL(c_acc, struct account);
2332 tpname[0] = ':';
2333 } else {
2334 strcpy(tname, "/note ");
2335 strcat(tname, lookup_accountname(lookup_player_id(message2 + 6)));
2336 strcat(tname, ":");
2337 strcat(tname, tpname + 1);
2338 strcpy(message2, tname);
2339 strcpy(tname, "");
2340 }
2341 }
2342
2343 /* Does a colon appear? */
2344 for (i = 0; i < (int)strlen(message2); i++)
2345 if (message2[i] == ':') colon = TRUE;
2346 /* Depending on colon existence, extract the target name */
2347 for (i = 5; i < (int)strlen(message2); i++)
2348 if (message2[i] == ' ') {
2349 for (j = i; j < (int)strlen(message2); j++)
2350 /* find where target name starts, save pos in j */
2351 if (message2[j] != ' ') {
2352 for (i = j; i < (int)strlen(message2); i++) {
2353 /* find ':' which terminates target name, save pos in i */
2354 if (message2[i] == ':') {
2355 /* extract target name up to the ':' */
2356 strncpy(tname, message2 + j, NAME_LEN);
2357 if (i - j >= NAME_LEN) i = j + NAME_LEN - 1;
2358 tname[i - j] = '\0';
2359 /* save i in j for latter use */
2360 j = i;
2361 break;
2362 }
2363 }
2364 if (i == (int)strlen(message2)) {
2365 /* extract name till end of line (it's the only parm) */
2366 strcpy(tname, message2 + j);
2367 }
2368 break;
2369 }
2370 break;
2371 }
2372
2373 /* was it just a '/note *' ? */
2374 if (!colon && !strcmp(tname, "*")) { /* Delete all pending notes to all players */
2375 for (i = 0; i < MAX_NOTES; i++) {
2376 /* search for pending notes of this player */
2377 if (!strcmp(priv_note_sender[i], p_ptr->name) ||
2378 !strcmp(priv_note_sender[i], p_ptr->accountname)) {
2379 notes++;
2380 strcpy(priv_note_sender[i], "");
2381 strcpy(priv_note_target[i], "");
2382 strcpy(priv_note[i], "");
2383 }
2384 }
2385 msg_format(Ind, "\377oDeleted %d notes.", notes);
2386 return;
2387 }
2388
2389 /* No colon found -> only a name parm give */
2390 if (!colon) { /* Delete all pending notes to a specified player */
2391 for (i = 0; i < MAX_NOTES; i++) {
2392 /* search for pending notes of this player to the specified player */
2393 if ((!strcmp(priv_note_sender[i], p_ptr->name) ||
2394 !strcmp(priv_note_sender[i], p_ptr->accountname)) &&
2395 !strcmp(priv_note_target[i], tname)) {
2396 /* found a matching note */
2397 notes++;
2398 strcpy(priv_note_sender[i], "");
2399 strcpy(priv_note_target[i], "");
2400 strcpy(priv_note[i], "");
2401 }
2402 }
2403 msg_format(Ind, "\377oDeleted %d notes.", notes);
2404 return;
2405 }
2406
2407 /* Colon found, store a note to someone */
2408 /* Store a new note from this player to the specified player */
2409
2410 /* does target account exist? -- paranoia at this point! */
2411 c_acc = GetAccount(tname, NULL, FALSE);
2412 if (!c_acc) {
2413 msg_print(Ind, "\377oError: Player's account not found.");
2414 return;
2415 }
2416 KILL(c_acc, struct account);
2417
2418 /* Check whether player has his notes quota exceeded */
2419 for (i = 0; i < MAX_NOTES; i++) {
2420 if (!strcmp(priv_note_sender[i], p_ptr->name) ||
2421 !strcmp(priv_note_sender[i], p_ptr->accountname)) notes++;
2422 }
2423 if ((notes >= 5) && !is_admin(p_ptr)) {
2424 msg_print(Ind, "\377oYou have already reached the maximum of 5 pending notes per player.");
2425 return;
2426 }
2427
2428 /* Look for free space to store the new note */
2429 for (i = 0; i < MAX_NOTES; i++) {
2430 if (!strcmp(priv_note[i], "")) {
2431 /* found a free memory spot */
2432 found_note = i;
2433 break;
2434 }
2435 }
2436 if (found_note == MAX_NOTES) {
2437 msg_format(Ind, "\377oSorry, the server reached the maximum of %d pending notes.", MAX_NOTES);
2438 return;
2439 }
2440
2441 /* limit */
2442 message2[j + MAX_CHARS_WIDE - 1] = '\0';
2443
2444 /* Check whether target is actually online by now :) */
2445 if ((i = name_lookup_loose_quiet(Ind, tname, FALSE, FALSE))
2446 && !check_ignore(i, Ind)) {
2447 player_type *q_ptr = Players[i];
2448
2449 if ((q_ptr->page_on_privmsg ||
2450 (q_ptr->page_on_afk_privmsg && q_ptr->afk)) &&
2451 q_ptr->paging == 0)
2452 q_ptr->paging = 1;
2453
2454 msg_format(i, "\374\377RNote from %s: %s", p_ptr->name, message2 + j + 1);
2455 // return; //so double-msg him just to be safe he sees it
2456 }
2457
2458 strcpy(priv_note_sender[found_note], p_ptr->accountname);
2459 strcpy(priv_note_target[found_note], tname);
2460 strcpy(priv_note[found_note], message2 + j + 1);
2461 msg_format(Ind, "\377yNote for account '%s' has been stored.", priv_note_target[found_note]);
2462 return;
2463 }
2464 else if (prefix(message, "/play") /* for joining games - mikaelh */
2465 && !prefix(message, "/playgo"))
2466 {
2467 if (p_ptr->team != 0 && gametype == EEGAME_RUGBY)
2468 {
2469 teams[p_ptr->team - 1]--;
2470 p_ptr->team = 0;
2471 msg_print(Ind, "\377gYou are no more playing!");
2472 return;
2473 }
2474 if (gametype == EEGAME_RUGBY)
2475 {
2476 msg_print(Ind, "\377gThere's a rugby game going on!");
2477 if (teams[0] > teams[1])
2478 {
2479 p_ptr->team = 2;
2480 teams[1]++;
2481 msg_print(Ind, "\377gYou have been added to the light blue team!");
2482 }
2483 else
2484 {
2485 p_ptr->team = 1;
2486 teams[0]++;
2487 msg_print(Ind, "\377gYou have been added to the light red team!");
2488 }
2489 }
2490 else
2491 {
2492 msg_print(Ind, "\377gThere's no game going on!");
2493 }
2494 return;
2495 }
2496
2497 #ifdef FUN_SERVER /* make wishing available to players for fun, until rollback happens - C. Blue */
2498 else if (prefix(message, "/wish"))
2499 {
2500 object_type forge;
2501 object_type *o_ptr = &forge;
2502 WIPE(o_ptr, object_type);
2503 int tval, sval, kidx;
2504
2505 if (tk < 1 || !k)
2506 {
2507 msg_print(Ind, "\377oUsage: /wish (tval) (sval) (pval) [discount] [name] or /wish (o_idx)");
2508 return;
2509 }
2510
2511 if (tk > 1) {
2512 tval = k; sval = atoi(token[2]);
2513 kidx = lookup_kind(tval, sval);
2514 }
2515 else kidx = k;
2516 // if (kidx == 238 || kidx == 909 || kidx == 888 || kidx == 920) return; /* Invuln pots, Learning pots, Invinc + Highland ammys */
2517 if (kidx == 239 || kidx == 616 || kidx == 626 || kidx == 595 || kidx == 179) return; /* ..and rumour scrolls (spam) */
2518 msg_format(Ind, "%d", kidx);
2519 invcopy(o_ptr, kidx);
2520
2521 if(tk > 2) o_ptr->pval = (atoi(token[3]) < 15) ? atoi(token[3]) : 15;
2522 /* the next check is not needed (bpval is used, not pval) */
2523 if (kidx == 428 && o_ptr->pval > 3) o_ptr->pval = 3; //436 (limit EA ring +BLOWS)
2524
2525 /* Wish arts out! */
2526 if (tk > 4) {
2527 object_type forge;
2528 int nom = atoi(token[5]);
2529
2530 forge.name1 = nom;
2531 if (nom == ART_PHASING || admin_artifact_p(&forge)) return; /* Phasing ring, admin-only items */
2532 o_ptr->number = 1;
2533
2534 if (nom > 0) o_ptr->name1 = nom;
2535 else
2536 {
2537 /* It's ego or randarts */
2538 if (nom) {
2539 o_ptr->name2 = 0 - nom;
2540 if (tk > 4) o_ptr->name2b = 0 - atoi(token[5]);
2541 /* the next check might not be needed (bpval is used, not pval?) */
2542 if ((o_ptr->name2 == 65 || o_ptr->name2b == 65 ||
2543 o_ptr->name2 == 70 || o_ptr->name2b == 70 ||
2544 o_ptr->name2 == 173 || o_ptr->name2b == 173 ||
2545 o_ptr->name2 == 176 || o_ptr->name2b == 176 ||
2546 o_ptr->name2 == 187 || o_ptr->name2b == 187)
2547 && (o_ptr->pval > 3)) /* all +BLOWS items */
2548 o_ptr->pval = 3;
2549 }
2550 else o_ptr->name1 = ART_RANDART;
2551
2552 /* Piece together a 32-bit random seed */
2553 o_ptr->name3 = rand_int(0xFFFF) << 16;
2554 o_ptr->name3 += rand_int(0xFFFF);
2555 }
2556 }
2557 else
2558 {
2559 o_ptr->number = o_ptr->weight > 100 ? 2 : 99;
2560 }
2561
2562 apply_magic(&p_ptr->wpos, o_ptr, -1, !o_ptr->name2, TRUE, TRUE, FALSE, RESF_NONE);
2563 if (tk > 3) o_ptr->discount = atoi(token[4]);
2564 else o_ptr->discount = 100;
2565 object_known(o_ptr);
2566 o_ptr->owner = 0;
2567 // if(tk > 2) o_ptr->pval = (atoi(token[3]) < 15) ? atoi(token[3]) : 15;
2568 //o_ptr->owner = p_ptr->id;
2569 o_ptr->level = 1;
2570 (void)inven_carry(Ind, o_ptr);
2571
2572 return;
2573 }
2574 #endif
2575 else if (prefix(message, "/evinfo")) /* get info on a global event */
2576 {
2577 int n = 0;
2578 char ppl[75];
2579 bool found = FALSE;
2580 if (tk < 1) {
2581 msg_print(Ind, "\377d ");
2582 for (i = 0; i < MAX_GLOBAL_EVENTS; i++) if ((global_event[i].getype != GE_NONE) && (global_event[i].hidden == FALSE || admin)) {
2583 n++;
2584 if (n == 1) msg_print(Ind, "\377WCurrently ongoing events:");
2585 /* Event still in announcement phase? */
2586 if (global_event[i].announcement_time - ((turn - global_event[i].start_turn) / cfg.fps) > 0)
2587 //msg_format(Ind, " %d) '%s' \377grecruits\377w for %d mins.", i+1, global_event[i].title, (global_event[i].announcement_time - ((turn - global_event[i].start_turn) / cfg.fps)) / 60);
2588 msg_format(Ind, " \377U%d\377W) '%s' recruits for %d more minutes.", i+1, global_event[i].title, (global_event[i].announcement_time - ((turn - global_event[i].start_turn) / cfg.fps)) / 60);
2589 /* or has already begun? */
2590 else msg_format(Ind, " \377U%d\377W) '%s' began %d minutes ago.", i+1, global_event[i].title, -(global_event[i].announcement_time - ((turn - global_event[i].start_turn) / cfg.fps)) / 60);
2591 }
2592 if (!n) msg_print(Ind, "\377WNo events are currently running.");
2593 else {
2594 msg_print(Ind, " \377WType \377U/evinfo number\377W for information on the event of that number.");
2595 msg_print(Ind, " \377WType \377U/evsign number\377W to participate in the event of that number.");
2596 }
2597 msg_print(Ind, "\377d ");
2598 } else if ((k < 1) || (k > MAX_GLOBAL_EVENTS)) {
2599 msg_format(Ind, "Usage: /evinfo or /evinfo 1..%d", MAX_GLOBAL_EVENTS);
2600 } else if ((global_event[k-1].getype == GE_NONE) && (global_event[k-1].hidden == FALSE || admin)) {
2601 msg_print(Ind, "\377yThere is currently no running event of that number.");
2602 } else {
2603 /* determine if we can still sign up, to display the appropriate signup-command too */
2604 char signup[MAX_CHARS];
2605 signup[0] = '\0';
2606 if (!(global_event[k-1].signup_time == -1) &&
2607 !(!global_event[k-1].signup_time &&
2608 (!global_event[k-1].announcement_time ||
2609 (global_event[k-1].announcement_time - (turn - global_event[k-1].start_turn) / cfg.fps <= 0))) &&
2610 !(global_event[k-1].signup_time &&
2611 (global_event[k-1].signup_time - (turn - global_event[k-1].start_turn) / cfg.fps <= 0)))
2612 strcpy(signup, format(" Type \377U/evsign %d\377W to sign up!", k));
2613
2614 msg_format(Ind, "\377sInfo on event #%d '\377s%s\377s':", k, global_event[k-1].title);
2615 for (i = 0; i < 10; i++) if (strcmp(global_event[k-1].description[i], ""))
2616 msg_print(Ind, global_event[k-1].description[i]);
2617 if (global_event[k-1].noghost) msg_print(Ind, "\377RIn this event death is permanent - if you die your character will be erased!");
2618
2619 // msg_print(Ind, "\377d ");
2620 if ((global_event[k-1].announcement_time - (turn - global_event[k-1].start_turn) / cfg.fps) >= 120) {
2621 msg_format(Ind, "\377WThis event will start in %d minutes.%s",
2622 (global_event[k-1].announcement_time - ((turn - global_event[k-1].start_turn) / cfg.fps)) / 60,
2623 signup);
2624 } else if ((global_event[k-1].announcement_time - (turn - global_event[k-1].start_turn) / cfg.fps) > 0) {
2625 msg_format(Ind, "\377WThis event will start in %d seconds.%s",
2626 global_event[k-1].announcement_time - ((turn - global_event[k-1].start_turn) / cfg.fps),
2627 signup);
2628 } else if ((global_event[k-1].announcement_time - (turn - global_event[k-1].start_turn) / cfg.fps) > -120) {
2629 msg_format(Ind, "\377WThis event has been running for %d seconds.%s",
2630 -global_event[k-1].announcement_time + ((turn - global_event[k-1].start_turn) / cfg.fps),
2631 signup);
2632 } else {
2633 msg_format(Ind, "\377WThis event has been running for %d minutes.%s",
2634 -(global_event[k-1].announcement_time - ((turn - global_event[k-1].start_turn) / cfg.fps)) / 60,
2635 signup);
2636 }
2637
2638 strcpy(ppl, "\377WSubscribers: ");
2639 for (j = 0; j < MAX_GE_PARTICIPANTS; j++) {
2640 if (!global_event[k-1].participant[j]) continue;
2641 for (i = 1; i <= NumPlayers; i++) {
2642 if (global_event[k-1].participant[j] == Players[i]->id) {
2643 if (found) strcat(ppl, ", ");
2644 strcat(ppl, Players[i]->name);
2645 found = TRUE;
2646 }
2647 }
2648 }
2649 if (found) msg_format(Ind, "%s", ppl);
2650 msg_print(Ind, "\377d ");
2651 }
2652 return;
2653 }
2654 else if (prefix(message, "/evsign")) /* sign up for a global event */
2655 {
2656 /* get some 'real' event index number for our example ;) */
2657 for (i = 0; i < MAX_GLOBAL_EVENTS; i++)
2658 if (global_event[i].getype != GE_NONE) break;
2659
2660 if ((tk < 1) || (k < 1) || (k > MAX_GLOBAL_EVENTS)) {
2661 msg_format(Ind, "Usage: /evsign 1..%d [options..] -- Also try: /evinfo", MAX_GLOBAL_EVENTS);
2662 msg_format(Ind, "Example: /evsign %d", i == MAX_GLOBAL_EVENTS ? randint(MAX_GLOBAL_EVENTS): i + 1);
2663 } else if ((global_event[k-1].getype == GE_NONE) && (global_event[k-1].hidden == FALSE || admin))
2664 msg_print(Ind, "\377yThere is currently no running event of that number.");
2665 else if (global_event[k-1].signup_time == -1)
2666 msg_print(Ind, "\377yThat event doesn't offer to sign up.");
2667 else if (!global_event[k-1].signup_time &&
2668 (!global_event[k-1].announcement_time ||
2669 (global_event[k-1].announcement_time - (turn - global_event[k-1].start_turn) / cfg.fps <= 0)))
2670 msg_print(Ind, "\377yThat event has already started.");
2671 else if (global_event[k-1].signup_time &&
2672 (global_event[k-1].signup_time - (turn - global_event[k-1].start_turn) / cfg.fps <= 0))
2673 msg_print(Ind, "\377yThat event does not allow signing up anymore now.");
2674 else {
2675 if (tk < 2) global_event_signup(Ind, k-1, NULL);
2676 else global_event_signup(Ind, k-1, message3 + 1 + strlen(format("%d", k)));
2677 }
2678 return;
2679 }
2680 else if (prefix(message, "/bbs")) /* write a short text line to the server's in-game message board,
2681 readable by all players via '!' key. For example to warn about
2682 static (deadly) levels - C. Blue */
2683 {
2684 if (!strcmp(message3, "")) {
2685 #if 0
2686 msg_print(Ind, "Usage: /bbs <line of text for others to read>");
2687 #else
2688 bool bbs_empty = TRUE;
2689 /* Look at in-game bbs, instead of "usage" msg above */
2690 msg_print(Ind, "\377sBulletin board (type '/bbs <text>' in chat to write something):");
2691 censor_message = TRUE;
2692 for (i = 0; i < BBS_LINES; i++)
2693 if (strcmp(bbs_line[i], "")) {
2694 censor_length = strlen(bbs_line[i]) + bbs_line[i] - strchr(bbs_line[i], ':') - 4;
2695 msg_format(Ind, "\377s %s", bbs_line[i]);
2696 bbs_empty = FALSE;
2697 }
2698 censor_message = FALSE;
2699 if (bbs_empty) msg_print(Ind, "\377s <nothing has been written on the board so far>");
2700 #endif
2701 return;
2702 }
2703
2704 if (p_ptr->inval) {
2705 msg_print(Ind, "\377oYou must be validated to write to the in-game bbs.");
2706 return;
2707 }
2708
2709 /* cut off 7 bytes + 1 reserve to avoid overflow */
2710 message3[MAX_SLASH_LINE_LEN - 8] = 0;
2711
2712 censor_message = TRUE;
2713 censor_length = strlen(message3);
2714 msg_broadcast_format(0, "\374\377s[%s->BBS]\377W %s", p_ptr->name, message3);
2715 censor_message = FALSE;
2716 handle_punish(Ind, censor_punish);
2717 // bbs_add_line(format("%s %s: %s",showtime() + 7, p_ptr->name, message3));
2718 bbs_add_line(format("\377s%s %s:\377W %s",showdate(), p_ptr->name, message3));
2719 return;
2720 }
2721 else if (prefix(message, "/stime")) { /* show time / date */
2722 msg_format(Ind, "Current server time is %s", showtime());
2723 return;
2724 }
2725 else if (prefix(message, "/pvp")) { /* enter pvp-arena (for MODE_PVP) */
2726 struct worldpos apos;
2727 int ystart = 0, xstart = 0;
2728 bool fresh_arena = FALSE;
2729
2730 /* can't get in if not PvP mode */
2731 if (!(p_ptr->mode & MODE_PVP)) {
2732 msg_print(Ind, "\377yYour character is not PvP mode.");
2733 if (!is_admin(p_ptr)) return;
2734 }
2735
2736 /* transport out of arena? */
2737 if (!p_ptr->wpos.wx && !p_ptr->wpos.wy &&
2738 p_ptr->wpos.wz == 1) {
2739 if (p_ptr->pvp_prevent_tele) {
2740 msg_print(Ind, "\377oThere is no easy way out of this fight!");
2741 if (!is_admin(p_ptr)) return;
2742 }
2743 p_ptr->recall_pos.wx = cfg.town_x;
2744 p_ptr->recall_pos.wy = cfg.town_y;
2745 p_ptr->recall_pos.wz = 0;
2746 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
2747 recall_player(Ind, "");
2748 msg_format(Ind, "\377%cYou leave the arena again.", COLOUR_DUNGEON);
2749 return;
2750 }
2751
2752 /* prevent exploit */
2753 if (!istown(&p_ptr->wpos)) {
2754 if (isdungeontown(&p_ptr->wpos)) {
2755 msg_print(Ind, "\377yYou cannot enter the arena from within a dungeon!");
2756 if (!is_admin(p_ptr)) return;
2757 }
2758 msg_print(Ind, "\377yYou need to be in town to enter the arena!");
2759 if (!is_admin(p_ptr)) return;
2760 }
2761
2762 msg_print(Ind, "\377fYou enter the arena to fight as Gladiator!");
2763 if (!admin_p(Ind)) {
2764 msg_broadcast(Ind, "\377cSomeone entered the gladiators' arena!");
2765 /* prevent instant-leavers if they see roaming monsters or whatever */
2766 if (p_ptr->pvp_prevent_tele < PVP_COOLDOWN_TELEPORT) p_ptr->pvp_prevent_tele = PVP_COOLDOWN_TELEPORT;
2767 }
2768
2769 /* actually create temporary Arena tower at reserved wilderness sector 0,0! */
2770 apos.wx = 0; apos.wy = 0; apos.wz = 0;
2771 if (!wild_info[apos.wy][apos.wx].tower) {
2772 add_dungeon(&apos, 1, 1, DF1_NO_RECALL | DF1_SMALLEST,
2773 DF2_NO_ENTRY_MASK | DF2_NO_EXIT_MASK, 0x0, TRUE, 0, 0, 0, 0);
2774 fresh_arena = TRUE;
2775 }
2776 apos.wz = 1;
2777 if (!getcave(&apos)) {
2778 alloc_dungeon_level(&apos);
2779 fresh_arena = TRUE;
2780 }
2781 if (fresh_arena) generate_cave(&apos, p_ptr); /* <- required or panic save: py,px will be far negative (haven't checked why) */
2782
2783 p_ptr->recall_pos = apos;
2784 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
2785 recall_player(Ind, "");
2786
2787 if (fresh_arena) {
2788 wipe_m_list(&apos);
2789 wipe_o_list_safely(&apos);
2790 process_dungeon_file("t_arena_pvp.txt", &apos, &ystart, &xstart, MAX_HGT, MAX_WID, TRUE);
2791
2792 timer_pvparena1 = 1; /* (hack: generate 1st cycle) // seconds countdown */
2793 timer_pvparena2 = 1; /* start with releasing 1st monster */
2794 timer_pvparena3 = 0; /* 'basic monsters' cycle active */
2795 }
2796 return;
2797 }
2798 #ifdef AUCTION_SYSTEM
2799 else if (prefix(message, "/auc")) {
2800 int n;
2801
2802 if (p_ptr->inval) {
2803 msg_print(Ind, "\377oYou must be validated to use the auction system.");
2804 return;
2805 }
2806
2807 if (p_ptr->wpos.wz && !is_admin(p_ptr))
2808 {
2809 if (p_ptr->wpos.wz < 0) msg_print(Ind, "\377B[@] \377rYou can't use the auction system while in a dungeon!");
2810 else msg_print(Ind, "\377B[@] \377rYou can't use the auction system while in a tower!");
2811 return;
2812 }
2813
2814 if ((tk < 1) || ((tk < 2) && (!strcmp("help", token[1]))))
2815 {
2816 msg_print(Ind, "\377B[@] \377wTomeNET Auction system");
2817 msg_print(Ind, "\377B[@] \377oUsage: /auction <subcommand> ...");
2818 msg_print(Ind, "\377B[@] \377GAvailable subcommands:");
2819 msg_print(Ind, "\377B[@] \377w bid buyout cancel examine list");
2820 msg_print(Ind, "\377B[@] \377w retrieve search show set start");
2821 msg_print(Ind, "\377B[@] \377GFor help about a specific subcommand:");
2822 msg_print(Ind, "\377B[@] \377o /auction help <subcommand>");
2823 }
2824 else if (!strcmp("help", token[1]))
2825 {
2826 if (!strcmp("bid", token[2]))
2827 {
2828 msg_print(Ind, "\377B[@] \377oUsage: /auction bid <auction id> <bid>");
2829 msg_print(Ind, "\377B[@] \377wPlaces a bid on an item.");
2830 msg_print(Ind, "\377B[@] \377wYou must be able to pay your bid in order to win.");
2831 msg_print(Ind, "\377B[@] \377wYou also have to satisfy the level requirement when placing your bid.");
2832 }
2833 else if (!strcmp("buyout", token[2]))
2834 {
2835 msg_print(Ind, "\377B[@] \377oUsage: /auction buyout <auction id>");
2836 msg_print(Ind, "\377B[@] \377wInstantly buys an item.");
2837 msg_print(Ind, "\377B[@] \377wUse the \377Gretrieve \377wcommand to get the item.");
2838 }
2839 else if (!strcmp("cancel", token[2]))
2840 {
2841 msg_print(Ind, "\377B[@] \377oUsage: /auction cancel [auction id]");
2842 msg_print(Ind, "\377B[@] \377wCancels your bid on an item or aborts the auction on your item.");
2843 }
2844 else if (!strcmp("examine", token[2]))
2845 {
2846 msg_print(Ind, "\377B[@] \377oUsage: /auction examine <auction id>");
2847 msg_print(Ind, "\377B[@] \377wTells you everything about an item.");
2848 }
2849 else if (!strcmp("list", token[2]))
2850 {
2851 msg_print(Ind, "\377B[@] \377oUsage: /auction list");
2852 msg_print(Ind, "\377B[@] \377wShows a list of all items available.");
2853 }
2854 else if (!strcmp("retrieve", token[2]))
2855 {
2856 msg_print(Ind, "\377B[@] \377oUsage: /auction retrieve");
2857 msg_print(Ind, "\377B[@] \377wRetrieve won and cancelled items.");
2858 }
2859 else if (!strcmp("search", token[2]))
2860 {
2861 msg_print(Ind, "\377B[@] \377oUsage: /auction search <description>");
2862 msg_print(Ind, "\377B[@] \377wSearches for items with matching descriptions.");
2863 }
2864 else if (!strcmp("show", token[2]))
2865 {
2866 msg_print(Ind, "\377B[@] \377oUsage: /auction show <auction id>");
2867 msg_print(Ind, "\377B[@] \377wShows auction-related information about an item.");
2868 }
2869 else if (!strcmp("set", token[2]))
2870 {
2871 char *time_string;
2872 msg_print(Ind, "\377B[@] \377oUsage: /auction set <inventory slot> <starting price> <buyout price> <duration>");
2873 msg_print(Ind, "\377B[@] \377wSets up an auction.");
2874 msg_print(Ind, "\377B[@] \377wInventory slot is the item's letter in your inventory.");
2875 #ifdef AUCTION_MINIMUM_STARTING_PRICE
2876 msg_format(Ind, "\377B[@] \377wMinimum starting price is %d%% of the item's real value.", AUCTION_MINIMUM_STARTING_PRICE);
2877 #endif
2878 #ifdef AUCTION_MAXIMUM_STARTING_PRICE
2879 msg_format(Ind, "\377B[@] \377wMaximum starting price is %d%% of the item's real value.", AUCTION_MAXIMUM_STARTING_PRICE);
2880 #endif
2881 #ifdef AUCTION_MINIMUM_BUYOUT_PRICE
2882 msg_format(Ind, "\377B[@] \377wMinimum buyout price is %d%% of the item's real value.", AUCTION_MINIMUM_BUYOUT_PRICE);
2883 #endif
2884 #ifdef AUCTION_MAXIMUM_BUYOUT_PRICE
2885 msg_format(Ind, "\377B[@] \377wMaximum buyout price is %d%% of the item's real value.", AUCTION_MAXIMUM_BUYOUT_PRICE);
2886 #endif
2887 #ifdef AUCTION_MINIMUM_DURATION
2888 time_string = auction_format_time(AUCTION_MINIMUM_DURATION);
2889 msg_format(Ind, "\377B[@] \377wShortest duration allowed is %s.", time_string);
2890 C_KILL(time_string, strlen(time_string), char);
2891 #endif
2892 #ifdef AUCTION_MAXIMUM_DURATION
2893 time_string = auction_format_time(AUCTION_MAXIMUM_DURATION);
2894 msg_format(Ind, "\377B[@] \377wLongest duration allowed is %s.", time_string);
2895 C_KILL(time_string, strlen(time_string), char);
2896 #endif
2897 }
2898 else if (!strcmp("start", token[2]))
2899 {
2900 msg_print(Ind, "\377B[@] \377oUsage: /auction start");
2901 msg_print(Ind, "\377B[@] \377wConfirms that you want to start start an auction.");
2902 }
2903 else
2904 {
2905 msg_print(Ind, "\377B[@] \377oUsage: /auction help <subcommand>");
2906 msg_print(Ind, "\377B[@] \377ySee \"\377G/auction help\377y\" for list of valid subcommands.");
2907 }
2908 }
2909 else if (!strncmp("bid", token[1], 3))
2910 {
2911 if (tk < 3)
2912 {
2913 msg_print(Ind, "\377B[@] \377oUsage: /auction bid <auction id> <bid>");
2914 }
2915 else
2916 {
2917 k = atoi(token[2]);
2918 n = auction_place_bid(Ind, k, token[3]);
2919 if (n)
2920 {
2921 auction_print_error(Ind, n);
2922 }
2923 }
2924 }
2925 else if (!strncmp("buyout", token[1], 3))
2926 {
2927 if (tk < 2)
2928 {
2929 msg_print(Ind, "\377B[@] \377oUsage: /auction buyout <auction id>");
2930 }
2931 else
2932 {
2933 k = atoi(token[2]);
2934 n = auction_buyout(Ind, k);
2935 if (n)
2936 {
2937 auction_print_error(Ind, n);
2938 }
2939 }
2940 }
2941 else if (!strncmp("cancel", token[1], 3))
2942 {
2943 if (tk < 2)
2944 {
2945 if (p_ptr->current_auction)
2946 {
2947 auction_cancel(Ind, p_ptr->current_auction);
2948 }
2949 else
2950 {
2951 msg_print(Ind, "\377B[@] \377rNo item to cancel!");
2952 msg_print(Ind, "\377B[@] \377oUsage: /auction cancel [auction id]");
2953 }
2954 }
2955 else
2956 {
2957 k = atoi(token[2]);
2958 n = auction_cancel(Ind, k);
2959 if (n)
2960 {
2961 auction_print_error(Ind, n);
2962 }
2963 }
2964 }
2965 else if (!strncmp("examine", token[1], 3))
2966 {
2967 if (tk < 2)
2968 {
2969 msg_print(Ind, "\377B[@] \377oUsage: /auction examine <auction id>");
2970 }
2971 else
2972 {
2973 k = atoi(token[2]);
2974 n = auction_examine(Ind, k);
2975 if (n)
2976 {
2977 auction_print_error(Ind, n);
2978 }
2979 }
2980 }
2981 else if (!strncmp("list", token[1], 3))
2982 {
2983 auction_list(Ind);
2984 }
2985 else if (!strncmp("retrieve", token[1], 3))
2986 {
2987 int retrieved, unretrieved;
2988 auction_retrieve_items(Ind, &retrieved, &unretrieved);
2989 if (!unretrieved) msg_format(Ind, "\377B[@] \377wRetrieved %d item(s).", retrieved);
2990 else msg_format(Ind, "\377B[@] \377wRetrieved %d items, you didn't have room for %d more item(s).", retrieved, unretrieved);
2991 }
2992 else if (!strncmp("search", token[1], 3))
2993 {
2994 if (tk < 2)
2995 {
2996 msg_print(Ind, "\377B[@] \377oUsage: /auction search <name>");
2997 }
2998 else
2999 {
3000 auction_search(Ind, message3 + 7);
3001 }
3002 }
3003 else if (!strncmp("show", token[1], 3))
3004 {
3005 if (tk < 2)
3006 {
3007 msg_print(Ind, "\377B[@] \377oUsage: /auction show <auction id>");
3008 }
3009 else
3010 {
3011 k = atoi(token[2]);
3012 n = auction_show(Ind, k);
3013 if (n)
3014 {
3015 auction_print_error(Ind, n);
3016 }
3017 }
3018 }
3019 else if (!strncmp("set", token[1], 3))
3020 {
3021 if (tk < 5)
3022 {
3023 msg_print(Ind, "\377B[@] \377oUsage: /auction set <inventory slot> <starting price> <buyout price> <duration>");
3024 }
3025 else
3026 {
3027 n = auction_set(Ind, token[2][0] - 'a', token[3], token[4], token[5]);
3028 if (n)
3029 {
3030 auction_print_error(Ind, n);
3031 }
3032 }
3033 }
3034 else if (!strncmp("start", token[1], 3))
3035 {
3036 if (!p_ptr->current_auction)
3037 {
3038 msg_print(Ind, "\377B[@] \377rNo item!");
3039 }
3040 else
3041 {
3042 n = auction_start(Ind);
3043 if (n)
3044 {
3045 auction_print_error(Ind, n);
3046 }
3047 }
3048 }
3049 else
3050 {
3051 msg_print(Ind, "\377B[@] \377rUnknown subcommand!");
3052 msg_print(Ind, "\377B[@] \377ySee \"/auction help\" for list of valid subcommands.");
3053 }
3054 return;
3055 }
3056 #endif
3057 /* workaround - refill ligth source (outdated clients cannot use 'F' due to INVEN_ order change */
3058 else if (prefix(message, "/lite"))
3059 {
3060 if (tk != 1) {
3061 msg_print(Ind, "Usage: /lite a...w");
3062 return;
3063 }
3064 k = message3[0] - 97;
3065 if (k < 0 || k >= INVEN_PACK) {
3066 msg_print(Ind, "Usage: /lite a...w");
3067 return;
3068 }
3069 do_cmd_refill(Ind, k);
3070 return;
3071 }
3072
3073 /* Allow players to undo some of their skills - mikaelh */
3074 else if (prefix(message, "/undoskills") ||
3075 prefix(message, "/undos"))
3076 {
3077 /* Skill points gained */
3078 int gain = p_ptr->skill_points_old - p_ptr->skill_points;
3079
3080 if (gain && p_ptr->reskill_possible)
3081 {
3082 memcpy(p_ptr->s_info, p_ptr->s_info_old, MAX_SKILLS * sizeof(skill_player));
3083 p_ptr->skill_points = p_ptr->skill_points_old;
3084
3085 msg_format(Ind, "\377GYou have regained %d skill points.", gain);
3086
3087 /* in case we changed mimicry skill */
3088 if (p_ptr->body_monster &&
3089 r_info[p_ptr->body_monster].level > get_skill_scale(p_ptr, SKILL_MIMIC, 100))
3090 do_mimic_change(Ind, 0, TRUE);
3091 /* in case we changed meta skill */
3092 if (p_ptr->spell_project &&
3093 get_skill(p_ptr, SKILL_META) < 10) { // WARNING, HARDCODED spell level from s_meta.lua
3094 p_ptr->spell_project = 0;
3095 msg_print(Ind, "Your utility spells will now only affect yourself.");
3096 }
3097 /* auras.. */
3098 if (!get_skill(p_ptr, SKILL_AURA_FEAR) && p_ptr->aura[0]) {
3099 msg_print(Ind, "Your aura of fear ceases.");
3100 p_ptr->aura[0] = FALSE;
3101 }
3102 if (!get_skill(p_ptr, SKILL_AURA_SHIVER) && p_ptr->aura[1]) {
3103 msg_print(Ind, "Your aura of shivering ceases.");
3104 p_ptr->aura[1] = FALSE;
3105 }
3106 if (!get_skill(p_ptr, SKILL_AURA_DEATH) && p_ptr->aura[2]) {
3107 msg_print(Ind, "Your aura of death ceases.");
3108 p_ptr->aura[2] = FALSE;
3109 }
3110 /* health (sanity display) */
3111 if (get_skill(p_ptr, SKILL_HEALTH) < 10) {
3112 if (p_ptr->sanity_bar > 0) {
3113 p_ptr->sanity_bar = 0;
3114 p_ptr->redraw |= PR_SANITY;
3115 }
3116 } else if (get_skill(p_ptr, SKILL_HEALTH) < 20) {
3117 if (p_ptr->sanity_bar > 1) {
3118 p_ptr->sanity_bar = 1;
3119 p_ptr->redraw |= PR_SANITY;
3120 }
3121 } else if (get_skill(p_ptr, SKILL_HEALTH) < 40) {
3122 if (p_ptr->sanity_bar > 2) {
3123 p_ptr->sanity_bar = 2;
3124 p_ptr->redraw |= PR_SANITY;
3125 }
3126 }
3127
3128 /* Update all skills */
3129 calc_techniques(Ind);
3130 for (i = 0; i < MAX_SKILLS; i++)
3131 Send_skill_info(Ind, i, FALSE);
3132
3133 p_ptr->update |= (PU_SKILL_MOD | PU_BONUS | PU_MANA | PU_HP);
3134 p_ptr->redraw |= (PR_SKILLS | PR_PLUSSES);
3135
3136 /* No more reskills */
3137 p_ptr->reskill_possible = FALSE;
3138 }
3139 else
3140 {
3141 msg_print(Ind, "\377yNo skills could be undone.");
3142 }
3143 return;
3144 }
3145 #if 1
3146 else if (prefix(message, "/info")) { /* set a personal info message - C. Blue */
3147 char to_strip[80];
3148 if (strlen(message2) > 6) {
3149 strncpy(to_strip, message2 + 6, MAX_CHARS);
3150 if (strlen(message2 + 6) >= MAX_CHARS) to_strip[MAX_CHARS - 1] = '\0';
3151 else to_strip[strlen(message2 + 6)] = '\0';
3152 strip_control_codes(p_ptr->info_msg, to_strip);
3153 msg_print(Ind, "Personal info message has been changed.");
3154 } else {
3155 strcpy(p_ptr->info_msg, "");
3156 msg_print(Ind, "Personal info message has been cleared.");
3157 }
3158 return;
3159 }
3160 #endif
3161 #if 0
3162 else if (prefix(message, "/pray")) { /* hidden broadcast to all admins :) */
3163 msg_admin("\377b[\377U%s\377b]\377D %s", p_ptr->name, 'w', message3);
3164 return;
3165 }
3166 #endif
3167 else if (prefix(message, "/pbbs")) {
3168 /* Look at or write to in-game party bbs, as suggested by Caine/Goober - C. Blue */
3169 bool bbs_empty = TRUE;
3170 int n;
3171
3172 if (!p_ptr->party) {
3173 msg_print(Ind, "You have to be in a party to interact with a party BBS.");
3174 return;
3175 }
3176
3177 /* cut off 7 bytes + 1 reserve to avoid overflow */
3178 message3[MAX_SLASH_LINE_LEN - 8] = 0;
3179
3180 if (tk) {
3181 /* write something */
3182 msg_party_format(Ind, "\374\377B[%s->PBBS]\377W %s", p_ptr->name, message3);
3183 pbbs_add_line(p_ptr->party, format("\377B%s %s:\377W %s",showdate(), p_ptr->name, message3));
3184 return;
3185 }
3186 msg_print(Ind, "\377BParty bulletin board (type '/pbbs <text>' in chat to write something):");
3187 for (n = 0; n < BBS_LINES; n++)
3188 if (strcmp(pbbs_line[p_ptr->party][n], "")) {
3189 msg_format(Ind, "\377B %s", pbbs_line[p_ptr->party][n]);
3190 bbs_empty = FALSE;
3191 }
3192 if (bbs_empty) msg_print(Ind, "\377B <nothing has been written on the party board so far>");
3193 return;
3194 }
3195 else if (prefix(message, "/gbbs")) {
3196 /* Look at or write to in-game guild bbs - C. Blue */
3197 bool bbs_empty = TRUE;
3198 int n;
3199
3200 if (!p_ptr->guild) {
3201 msg_print(Ind, "You have to be in a guild to interact with a guild BBS.");
3202 return;
3203 }
3204
3205 /* cut off 7 bytes + 1 reserve to avoid overflow */
3206 message3[MAX_SLASH_LINE_LEN - 8] = 0;
3207
3208 if (tk) {
3209 /* write something */
3210 msg_guild_format(Ind, "\374\377%c[%s->GBBS]\377W %s", COLOUR_CHAT_GUILD, p_ptr->name, message3);
3211 gbbs_add_line(p_ptr->guild, format("\377%c%s %s:\377W %s", COLOUR_CHAT_GUILD, showdate(), p_ptr->name, message3));
3212 return;
3213 }
3214 msg_format(Ind, "\377%cGuild bulletin board (type '/gbbs <text>' in chat to write something):", COLOUR_CHAT_GUILD);
3215 for (n = 0; n < BBS_LINES; n++)
3216 if (strcmp(gbbs_line[p_ptr->guild][n], "")) {
3217 msg_format(Ind, "\377%c %s", COLOUR_CHAT_GUILD, gbbs_line[p_ptr->guild][n]);
3218 bbs_empty = FALSE;
3219 }
3220 if (bbs_empty) msg_format(Ind, "\377%c <nothing has been written on the guild board so far>", COLOUR_CHAT_GUILD);
3221 return;
3222 }
3223 else if (prefix(message, "/ftkon")) {
3224 msg_print(Ind, "\377wFire-till-kill mode now on.");
3225 p_ptr->shoot_till_kill = TRUE;
3226 s_printf("SHOOT_TILL_KILL: Player %s sets true.\n", p_ptr->name);
3227 p_ptr->redraw |= PR_STATE;
3228 return;
3229 } else if (prefix(message, "/ftkoff")) {
3230 msg_print(Ind, "\377wFire-till-kill mode now off.");
3231 p_ptr->shoot_till_kill = p_ptr->shooting_till_kill = FALSE;
3232 s_printf("SHOOT_TILL_KILL: Player %s sets false.\n", p_ptr->name);
3233 p_ptr->redraw |= PR_STATE;
3234 return;
3235 }
3236 #ifdef PLAYER_STORES
3237 else if (prefix(message, "/pstore")) {
3238 int x, y;
3239 cave_type **zcave = getcave(&p_ptr->wpos);
3240 /* Enter a player store next to us */
3241 for (x = p_ptr->px - 1; x <= p_ptr->px + 1; x++)
3242 for (y = p_ptr->py - 1; y <= p_ptr->py + 1; y++) {
3243 if (!in_bounds(y, x)) continue;
3244 if (zcave[y][x].feat != FEAT_HOME &&
3245 zcave[y][x].feat != FEAT_HOME_OPEN)
3246 continue;
3247 disturb(Ind, 1, 0);
3248 if (do_cmd_player_store(Ind, x, y)) return;
3249 }
3250 msg_print(Ind, "There is no player store next to you.");
3251 return;
3252 }
3253 #endif
3254 #ifdef HOUSE_PAINTING /* goes hand in hand with player stores.. */
3255 else if (prefix(message, "/paint")) { /* paint a house that we own */
3256 int x, y;
3257 bool found = FALSE;
3258 cave_type **zcave = getcave(&p_ptr->wpos);
3259
3260 /* need to specify one parm: the potion used for colouring */
3261 if (tk == 1) k = message3[0] - 97;
3262 if (!tk || tk > 1 || k < 0 || k >= INVEN_PACK) {
3263 msg_print(Ind, "\377oUsage: /paint <inventory slot>");
3264 msg_print(Ind, "\377oExample: /paint f");
3265 msg_print(Ind, "\377oWhere the slot must be a potion which determines the colour.");
3266 return;
3267 }
3268
3269 /* Check for a house door next to us */
3270 for (x = p_ptr->px - 1; x <= p_ptr->px + 1; x++) {
3271 for (y = p_ptr->py - 1; y <= p_ptr->py + 1; y++) {
3272 if (!in_bounds(y, x)) continue;
3273 if (zcave[y][x].feat != FEAT_HOME &&
3274 zcave[y][x].feat != FEAT_HOME_OPEN)
3275 continue;
3276
3277 /* found a home door, assume it is a house */
3278 found = TRUE;
3279 break;
3280 }
3281 if (found) break;
3282 }
3283 if (!found) {
3284 msg_print(Ind, "There is no house next to you.");
3285 return;
3286 }
3287
3288 /* possibly paint it */
3289 paint_house(Ind, x, y, k);
3290 return;
3291 }
3292 #endif
3293 else if (prefix(message, "/knock")) { /* knock on a house door */
3294 int x, y;
3295 bool found = FALSE;
3296 cave_type **zcave = getcave(&p_ptr->wpos);
3297
3298 if (tk) {
3299 msg_print(Ind, "\377oUsage: /knock");
3300 return;
3301 }
3302
3303 /* Check for a house door next to us */
3304 for (x = p_ptr->px - 1; x <= p_ptr->px + 1; x++) {
3305 for (y = p_ptr->py - 1; y <= p_ptr->py + 1; y++) {
3306 if (!in_bounds(y, x)) continue;
3307 if (zcave[y][x].feat != FEAT_HOME &&
3308 zcave[y][x].feat != FEAT_HOME_OPEN)
3309 continue;
3310
3311 /* found a home door, assume it is a house */
3312 found = TRUE;
3313 break;
3314 }
3315 if (found) break;
3316 }
3317 if (!found) {
3318 msg_print(Ind, "There is no house next to you.");
3319 return;
3320 }
3321
3322 /* knock on the door */
3323 knock_house(Ind, x, y);
3324 return;
3325 }
3326 else if (prefix(message, "/slap")) { /* Slap someone around :-o */
3327 cave_type **zcave = getcave(&p_ptr->wpos);
3328 if (!tk) {
3329 msg_print(Ind, "Usage: /slap <player name>");
3330 return;
3331 }
3332 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
3333 p_ptr->energy -= level_speed(&p_ptr->wpos);
3334
3335 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
3336 if (!j || (!p_ptr->play_vis[j] && j != Ind)) {
3337 msg_print(Ind, "You don't see anyone of that name.");
3338 return;
3339 }
3340
3341 for (i = 1; i <= 9; i++) {
3342 // if (i == 5) continue;
3343 if (zcave[p_ptr->py + ddy[i]][p_ptr->px + ddx[i]].m_idx == -j) break;
3344 }
3345 if (i == 10) {
3346 msg_print(Ind, "Player is not standing next to you.");
3347 return;
3348 }
3349
3350 #ifdef USE_SOUND_2010
3351 sound_near_site(p_ptr->py, p_ptr->px, &p_ptr->wpos, 0, "slap", "", SFX_TYPE_COMMAND, TRUE);
3352 #endif
3353 if (Ind != j) {
3354 msg_format(j, "\377o%s slaps you!", p_ptr->name);
3355 msg_format_near(j, "\377y%s slaps %s!", p_ptr->name, Players[j]->name);
3356 } else {
3357 msg_print(j, "\377oYou slap yourself.");
3358 msg_format_near(j, "\377y%s slaps %s.", p_ptr->name, p_ptr->male ? "himself" : "herself");
3359 }
3360 return;
3361 }
3362 else if (prefix(message, "/pat")) { /* Counterpart to /slap :-p */
3363 cave_type **zcave = getcave(&p_ptr->wpos);
3364 if (!tk) {
3365 msg_print(Ind, "Usage: /pat <player name>");
3366 return;
3367 }
3368 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
3369 p_ptr->energy -= level_speed(&p_ptr->wpos);
3370
3371 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
3372 if (!j || (!p_ptr->play_vis[j] && j != Ind)) {
3373 msg_print(Ind, "You don't see anyone of that name.");
3374 return;
3375 }
3376
3377 for (i = 1; i <= 9; i++) {
3378 // if (i == 5) continue;
3379 if (zcave[p_ptr->py + ddy[i]][p_ptr->px + ddx[i]].m_idx == -j) break;
3380 }
3381 if (i == 10) {
3382 msg_print(Ind, "Player is not standing next to you.");
3383 return;
3384 }
3385
3386 if (Ind != j) {
3387 msg_format(j, "\377o%s pats you.", p_ptr->name);
3388 msg_format_near(j, "\377y%s pats %s.", p_ptr->name, Players[j]->name);
3389 } else {
3390 msg_print(j, "\377oYou pat yourself.");
3391 msg_format_near(j, "\377y%s pats %s.", p_ptr->name, p_ptr->male ? "himself" : "herself");
3392 }
3393 return;
3394 }
3395 else if (prefix(message, "/hug")) { /* Counterpart to /slap :-p */
3396 cave_type **zcave = getcave(&p_ptr->wpos);
3397 if (!tk) {
3398 msg_print(Ind, "Usage: /hug <player name>");
3399 return;
3400 }
3401 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
3402 p_ptr->energy -= level_speed(&p_ptr->wpos);
3403
3404 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
3405 if (!j || (!p_ptr->play_vis[j] && j != Ind)) {
3406 msg_print(Ind, "You don't see anyone of that name.");
3407 return;
3408 }
3409
3410 for (i = 1; i <= 9; i++) {
3411 // if (i == 5) continue;
3412 if (zcave[p_ptr->py + ddy[i]][p_ptr->px + ddx[i]].m_idx == -j) break;
3413 }
3414 if (i == 10) {
3415 msg_print(Ind, "Player is not standing next to you.");
3416 return;
3417 }
3418
3419 if (Ind != j) {
3420 msg_format(j, "\377o%s hugs you.", p_ptr->name);
3421 msg_format_near(j, "\377y%s hugs %s.", p_ptr->name, Players[j]->name);
3422 } else {
3423 msg_print(j, "\377oYou hug yourself.");
3424 msg_format_near(j, "\377y%s hugs %s.", p_ptr->name, p_ptr->male ? "himself" : "herself");
3425 }
3426 return;
3427 }
3428 else if (prefix(message, "/poke")) {
3429 cave_type **zcave = getcave(&p_ptr->wpos);
3430 if (!tk) {
3431 msg_print(Ind, "Usage: /poke <player name>");
3432 return;
3433 }
3434 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
3435 p_ptr->energy -= level_speed(&p_ptr->wpos);
3436
3437 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
3438 if (!j || (!p_ptr->play_vis[j] && j != Ind)) {
3439 msg_print(Ind, "You don't see anyone of that name.");
3440 return;
3441 }
3442
3443 for (i = 1; i <= 9; i++) {
3444 // if (i == 5) continue;
3445 if (zcave[p_ptr->py + ddy[i]][p_ptr->px + ddx[i]].m_idx == -j) break;
3446 }
3447 if (i == 10) {
3448 msg_print(Ind, "Player is not standing next to you.");
3449 return;
3450 }
3451
3452 if (Ind != j) {
3453 msg_format(j, "\377o%s pokes you.", p_ptr->name);
3454 msg_format_near(j, "\377y%s pokes %s.", p_ptr->name, Players[j]->name);
3455 } else {
3456 msg_print(j, "\377oYou poke yourself.");
3457 msg_format_near(j, "\377y%s pokes %s.", p_ptr->name, p_ptr->male ? "himself" : "herself");
3458 }
3459 return;
3460 }
3461 else if (prefix(message, "/tip")) { /* put some cash (level ^ 2) in player's waistcoat pocket~ */
3462 cave_type **zcave = getcave(&p_ptr->wpos);
3463 u32b tip;
3464 player_type *q_ptr;
3465
3466 if (!tk) {
3467 msg_print(Ind, "Usage: /tip <player name>");
3468 return;
3469 }
3470
3471 /* Handle the newbies_cannot_drop option */
3472 if ((p_ptr->max_plv < cfg.newbies_cannot_drop) && !is_admin(p_ptr)) {
3473 msg_print(Ind, "You are not experienced enough to drop gold.");
3474 return;
3475 }
3476
3477 //if (p_ptr->au < p_ptr->lev * p_ptr->lev) {
3478 if (!p_ptr->au) {
3479 msg_print(Ind, "You don't have any money with you.");
3480 return;
3481 }
3482 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
3483 p_ptr->energy -= level_speed(&p_ptr->wpos);
3484
3485 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
3486 if (!j || (!p_ptr->play_vis[j] && j != Ind)) {
3487 msg_print(Ind, "You don't see anyone of that name.");
3488 return;
3489 }
3490 for (i = 1; i <= 9; i++) {
3491 // if (i == 5) continue;
3492 if (zcave[p_ptr->py + ddy[i]][p_ptr->px + ddx[i]].m_idx == -j) break;
3493 }
3494 if (i == 10) {
3495 msg_print(Ind, "Player is not standing next to you.");
3496 return;
3497 }
3498 if (Ind == j) {
3499 msg_print(Ind, "You cannot tip yourself.");
3500 return;
3501 }
3502 if (compat_pmode(Ind, j, FALSE)) {
3503 msg_format(Ind, "You may not tip %s players.", compat_pmode(Ind, j, FALSE));
3504 return;
3505 }
3506
3507 q_ptr = Players[j];
3508
3509 /* To avoid someone ruining IDDC or event participation */
3510 if (!q_ptr->max_exp) {
3511 msg_print(Ind, "You may not tip players who have zero experience points.");
3512 return;
3513 }
3514
3515 if (p_ptr->au < p_ptr->lev * p_ptr->lev) tip = p_ptr->au;
3516 else tip = p_ptr->lev * p_ptr->lev;
3517
3518 if (2000000000 - tip < q_ptr->au) {
3519 msg_format(Ind, "%s's pockets are already bulging from money, you cannot tip this filthy rich bastard.", q_ptr->name);
3520 return;
3521 }
3522
3523 #ifdef USE_SOUND_2010
3524 //sound(Ind, "drop_gold", NULL, SFX_TYPE_COMMAND, TRUE);
3525 sound(j, "drop_gold", NULL, SFX_TYPE_COMMAND, TRUE);
3526 #endif
3527 if (!q_ptr->max_exp) gain_exp(j, 1); /* for global events that forbid transactions */
3528 p_ptr->au -= tip;
3529 q_ptr->au += tip;
3530 p_ptr->redraw |= PR_GOLD;
3531 q_ptr->redraw |= PR_GOLD;
3532
3533 msg_format(Ind, "\377yYou tip %s for %d Au!", q_ptr->name, tip);
3534 msg_format(j, "\377y%s tips you for %d Au!", p_ptr->name, tip);
3535 // msg_format_near(j, "\377y%s tips %s!", p_ptr->name, Players[j]->name);
3536
3537 /* consume a partial turn */
3538 p_ptr->energy -= level_speed(&p_ptr->wpos) / 2;
3539
3540 return;
3541 }
3542 else if (prefix(message, "/guild_adder")) {
3543 u32b *flags;
3544 guild_type *guild;
3545 player_type *q_ptr;
3546
3547 if (!tk) {
3548 msg_print(Ind, "Usage: /guild_adder name");
3549 msg_print(Ind, "Will add/remove that player to/from the list of 'adders', ie players");
3550 msg_print(Ind, "allowed to add others to the guild in the guild master's stead.");
3551 }
3552
3553 if (!p_ptr->guild) {
3554 msg_print(Ind, "You are not in a guild.");
3555 return;
3556 }
3557 guild = &guilds[p_ptr->guild];
3558 if (guild->master != p_ptr->id) {
3559 msg_print(Ind, "You are not the guild master.");
3560 return;
3561 }
3562 flags = &guild->flags;
3563 if (!tk) {
3564 msg_print(Ind, "Usage: /guild_adder <player name>");
3565 return;
3566 }
3567 i = name_lookup_loose(Ind, message3, FALSE, FALSE);
3568 if (!i) {
3569 #ifdef GUILD_ADDERS_LIST
3570 /* Handle de-authorization */
3571 message3[0] = toupper(message[3]); /* be helpful */
3572 for (j = 0; j < 5; j++) if (streq(guild->adder[j], message3)) break;
3573 if (j == 5) {
3574 msg_print(Ind, "Player must be online to become an adder.");
3575 return;
3576 }
3577 if (streq(p_ptr->name, message3)) {
3578 msg_print(Ind, "As guild master you can always add others.");
3579 return;
3580 }
3581 guild->adder[j][0] = '\0';
3582 msg_format(Ind, "Player \377r%s\377w is no longer authorized to add others.", message3);
3583 return;
3584 #else
3585 msg_print(Ind, "Player not online.");
3586 return;
3587 #endif
3588 }
3589 if (i == Ind) {
3590 msg_print(Ind, "As guild master you can always add others.");
3591 return;
3592 }
3593 q_ptr = Players[i];
3594 if (q_ptr->guild != p_ptr->guild) {
3595 msg_print(Ind, "That player is not in your guild.");
3596 return;
3597 }
3598
3599 if ((q_ptr->guild_flags & PGF_ADDER)) {
3600 #ifdef GUILD_ADDERS_LIST
3601 for (j = 0; j < 5; j++) if (streq(guild->adder[j], q_ptr->name)) {
3602 guild->adder[j][0] = '\0';
3603 break;
3604 }
3605 #endif
3606
3607 q_ptr->guild_flags &= ~PGF_ADDER;
3608 msg_format(Ind, "Player \377r%s\377w is no longer authorized to add others.", q_ptr->name);
3609 msg_format(i, "\374\377%cGuild master %s \377rretracted\377%c your authorization to add others.", COLOUR_CHAT_GUILD, p_ptr->name, COLOUR_CHAT_GUILD);
3610 } else {
3611 #ifdef GUILD_ADDERS_LIST
3612 /* look if we have less than 5 adders still */
3613 for (j = 0; j < 5; j++) if (guild->adder[j][0] == '\0') break; /* found a vacant slot? */
3614 if (j == 5) {
3615 msg_print(Ind, "You cannot designate more than 5 adders.");
3616 return;
3617 }
3618 strcpy(guild->adder[j], q_ptr->name);
3619 #endif
3620
3621 q_ptr->guild_flags |= PGF_ADDER;
3622 msg_format(Ind, "Player \377G%s\377w is now authorized to add other players.", q_ptr->name);
3623 msg_format(i, "\374\377%cGuild master %s \377Gauthorized\377%c you to add other players.", COLOUR_CHAT_GUILD, p_ptr->name, COLOUR_CHAT_GUILD);
3624 if (!(*flags & GFLG_ALLOW_ADDERS)) {
3625 msg_print(Ind, "However, note that currently the guild configuration still prevent this!");
3626 msg_print(Ind, "To toggle the corresponding flag, use '/guild_cfg adders' command.");
3627 }
3628 }
3629 return;
3630 }
3631 else if (prefix(message, "/guild_cfg")) {
3632 u32b *flags;
3633 guild_type *guild;
3634 bool master;
3635 char buf[(NAME_LEN + 1) * 5 + 1];
3636 if (!p_ptr->guild) {
3637 msg_print(Ind, "You are not in a guild.");
3638 return;
3639 }
3640 guild = &guilds[p_ptr->guild];
3641 master = (guild->master == p_ptr->id);
3642 if (tk && !master) {
3643 msg_print(Ind, "You are not the guild master.");
3644 return;
3645 }
3646 flags = &guild->flags;
3647
3648 if (!tk) {
3649 if (master)
3650 msg_format(Ind, "\377%cCurrent guild configuration (use /guild_cfg <flag name> command to change):", COLOUR_CHAT_GUILD);
3651 else
3652 msg_format(Ind, "\377%cCurrent guild configuration:", COLOUR_CHAT_GUILD);
3653 msg_format(Ind, "\377w adders : %s", *flags & GFLG_ALLOW_ADDERS ? "\377GYES" : "\377rno");
3654 msg_print(Ind, "\377W Allows players designated via /guild_adder command to add others.");
3655 msg_format(Ind, "\377w autoreadd : %s", *flags & GFLG_AUTO_READD ? "\377GYES" : "\377rno");
3656 msg_print(Ind, "\377W If a guild mate ghost-dies then the next character he logs on with");
3657 msg_print(Ind, "\377W - if it is newly created - is automatically added to the guild again.");
3658 msg_format(Ind, "\377w minlev : \377%c%d", guild->minlev <= 1 ? 'w' : (guild->minlev <= 10 ? 'G' : (guild->minlev < 20 ? 'g' :
3659 (guild->minlev < 30 ? 'y' : (guild->minlev < 40 ? 'o' : (guild->minlev <= 50 ? 'r' : 'v'))))), guild->minlev);
3660 msg_print(Ind, "\377W Minimum character level required to get added to the guild.");
3661
3662 #ifdef GUILD_ADDERS_LIST
3663 for (i = 0; i < 5; i++) if (guild->adder[i][0] != '\0') {
3664 sprintf(buf, "\377s Adders are: ");
3665 strcat(buf, guild->adder[i]);
3666 for (i++; i < 5; i++) {
3667 if (guild->adder[i][0] == '\0') continue;
3668 strcat(buf, ", ");
3669 strcat(buf, guild->adder[i]);
3670 }
3671 msg_print(Ind, buf);
3672 break;
3673 }
3674 #endif
3675 return;
3676 }
3677
3678 if (streq(token[1], "adders")) {
3679 if (*flags & GFLG_ALLOW_ADDERS) {
3680 msg_print(Ind, "Flag 'adders' set to NO.");
3681 *flags &= ~GFLG_ALLOW_ADDERS;
3682 } else {
3683 msg_print(Ind, "Flag 'adders' set to YES.");
3684 *flags |= GFLG_ALLOW_ADDERS;
3685 }
3686 } else if (streq(token[1], "autoreadd")) {
3687 if (*flags & GFLG_AUTO_READD) {
3688 msg_print(Ind, "Flag 'autoreadd' set to NO.");
3689 *flags &= ~GFLG_AUTO_READD;
3690 } else {
3691 msg_print(Ind, "Flag 'autoreadd' set to YES.");
3692 *flags |= GFLG_AUTO_READD;
3693 }
3694 } else if (streq(token[1], "minlev")) {
3695 if (tk < 2) {
3696 msg_print(Ind, "Usage: /guild_cfg minlev <level>");
3697 return;
3698 }
3699 msg_format(Ind, "Minimum level required to join the guild so far was %d..", guild->minlev);
3700 guild->minlev = atoi(token[2]);
3701 msg_format(Ind, "..and has now been set to %d.", guild->minlev);
3702 } else msg_print(Ind, "Unknown guild flag specified.");
3703 return;
3704 }
3705 else if (prefix(message, "/testyourmight") ||
3706 prefix(message, "/tym")) {
3707 long tmp;
3708 if (tk > 1 ||
3709 (tk == 1 && strcmp(token[1], "rs"))) {
3710 msg_print(Ind, "Usage: /testyourmight [rs]");
3711 msg_print(Ind, " Just the command will display your current damage/heal stats,");
3712 msg_print(Ind, " based on your number of *successful* attacks and over the time");
3713 msg_print(Ind, " passed, in seconds.");
3714 msg_print(Ind, " Typing '/testyourmight rs' will reset the recorded stats to zero.");
3715 return;
3716 }
3717 if (tk) {
3718 p_ptr->test_count = p_ptr->test_dam = p_ptr->test_heal = 0;
3719 p_ptr->test_turn = turn;
3720 msg_print(Ind, "Attack count, damage and healing done have been reset to zero.");
3721 #ifdef TEST_SERVER
3722 p_ptr->test_attacks = 0;
3723 #endif
3724 return;
3725 }
3726 msg_print(Ind, "Your total damage and healing done:");
3727 msg_format(Ind, " \377oTotal damage done : %8d", p_ptr->test_dam);
3728 msg_format(Ind, " \377gTotal healing done : %8d", p_ptr->test_heal);
3729 msg_print(Ind, "Your damage and healing done over # of attacks and amount of time passed:");
3730
3731 if (p_ptr->test_count == 0)
3732 msg_print(Ind, " \377sNo count-based result available: # of successful attacks is still zero.");
3733 else {
3734 msg_format(Ind, " \377w# of successful attacks: %8d", p_ptr->test_count);
3735 tmp = p_ptr->test_dam / p_ptr->test_count;
3736 if (tmp != 0 && tmp < 100) msg_format(Ind, " \377o Average damage done : %8d.%1d",
3737 tmp, ((p_ptr->test_dam * 10) / p_ptr->test_count) % 10);
3738 else msg_format(Ind, " \377o Average damage done : %8d", tmp);
3739 tmp = p_ptr->test_heal / p_ptr->test_count;
3740 if (tmp != 0 && tmp < 100) msg_format(Ind, " \377g Average healing done: %8d.%1d",
3741 tmp, ((p_ptr->test_heal * 10) / p_ptr->test_count) % 10);
3742 else msg_format(Ind, " \377g Average healing done: %8d", tmp);
3743 }
3744 #ifdef TEST_SERVER
3745 if (p_ptr->test_attacks == 0)
3746 msg_print(Ind, " \377wNo attempts to attack were made yet.");
3747 else
3748 msg_format(Ind, " \377wHit with %d out of %d attacks (%d%%)", p_ptr->test_count, p_ptr->test_attacks, (100 * p_ptr->test_count) / p_ptr->test_attacks);
3749 #endif
3750
3751 if (p_ptr->test_turn == 0)
3752 msg_print(Ind, " \377sNo time-based result available: Initialize via '/testyourmight rs'.");
3753 /* this shouldn't happen.. */
3754 else if ((turn - p_ptr->test_turn) < cfg.fps)
3755 msg_print(Ind, " \377sNo time-based result available: No second has passed yet.");
3756 else {
3757 msg_format(Ind, " \377w# of seconds passed: %8d.%1d", (turn - p_ptr->test_turn) / cfg.fps, (((turn - p_ptr->test_turn) * 10) / cfg.fps) % 10);
3758 tmp = (p_ptr->test_dam * 10) / (((turn - p_ptr->test_turn) * 10) / cfg.fps);
3759 if (tmp != 0 && tmp < 100) msg_format(Ind, " \377o Average damage done : %8d.%1d",
3760 tmp, ((p_ptr->test_dam * 10) / ((turn - p_ptr->test_turn) / cfg.fps)) % 10);
3761 else msg_format(Ind, " \377o Average damage done : %8d", tmp);
3762 tmp = (p_ptr->test_heal * 10) / (((turn - p_ptr->test_turn) * 10) / cfg.fps);
3763 if (tmp != 0 && tmp < 100) msg_format(Ind, " \377g Average healing done: %8d.%1d",
3764 tmp, ((p_ptr->test_heal * 10) / ((turn - p_ptr->test_turn) / cfg.fps)) % 10);
3765 else msg_format(Ind, " \377g Average healing done: %8d", tmp);
3766 }
3767 return;
3768 }
3769 /* request back real estate that was previously backed up via /backup_estate */
3770 else if (prefix(message, "/request_estate") || prefix(message, "/request")) {
3771 if (!allow_requesting_estate) {
3772 msg_print(Ind, "This command is currently not available.");
3773 return;
3774 }
3775
3776 restore_estate(Ind);
3777 return;
3778 }
3779 /* Specialty: Convert current character into a 'slot-exclusive' character if possible */
3780 else if (prefix(message, "/convertexclusive")) {
3781 int ok;
3782
3783 #if 0 /* was because of Destroy_connection().. */
3784 if (!istown(&p_ptr->wpos)) {
3785 msg_print(Ind, "\377oThis command is only available when in town!");
3786 return;
3787 }
3788 #endif
3789 if (!tk || strcmp(p_ptr->name, message3)) {
3790 msg_print(Ind, "\377oThis command converts your CURRENT character into a 'slot-exclusive' character if possible!");
3791 msg_print(Ind, "\377oUsage: /convertexclusive <your-current-character-name>");
3792 msg_format(Ind, "\377oExample: /convertexclusive %s", p_ptr->name);
3793 msg_format(Ind, "\377RWarning: This process is NOT REVERSIBLE!");
3794 return;
3795 }
3796 if ((p_ptr->mode & (MODE_DED_PVP | MODE_DED_IDDC))) {
3797 msg_print(Ind, "\377yThis character is already a slot-exclusive character.");
3798 return;
3799 }
3800
3801 /* check what's possible for us to convert into */
3802 ok = check_account(p_ptr->accountname, "");
3803 s_printf("CONVEXCL: '%s' (%d) -> %d\n", p_ptr->name, p_ptr->mode, ok);
3804
3805 /* We want to convert into ded.pvp? */
3806 if ((p_ptr->mode & MODE_PVP)) {
3807 #if 0 /* old: only allow one pvp-dedicated char */
3808 if (ok == -4 || ok == -9 || ok == -6 || ok == -7) {
3809 p_ptr->mode |= MODE_DED_PVP;
3810 msg_print(Ind, "\377BYour character has been converted to a slot-exclusive PvP-character!");
3811 verify_player(p_ptr->name, p_ptr->id, p_ptr->account, p_ptr->prace, p_ptr->pclass, p_ptr->mode, p_ptr->lev, 0, 0, 0, 0, 0, 0, p_ptr->wpos);//assume NO ADMIN!
3812 // Destroy_connection(Players[Ind]->conn, "Success -- You need to login again to complete the process!");
3813 return;
3814 }
3815 msg_print(Ind, "\377yYou already have a slot-exclusive PvP-mode character.");
3816 #else /* allow unlimitid pvp-dedicated chars */
3817 p_ptr->mode |= MODE_DED_PVP;
3818 msg_print(Ind, "\377BYour character has been converted to a slot-exclusive PvP-character!");
3819 verify_player(p_ptr->name, p_ptr->id, p_ptr->account, p_ptr->prace, p_ptr->pclass, p_ptr->mode, p_ptr->lev, 0, 0, 0, 0, 0, 0, p_ptr->wpos);//assume NO ADMIN!
3820 // Destroy_connection(Players[Ind]->conn, "Success -- You need to login again to complete the process!");
3821 #endif
3822 return;
3823 }
3824 /* We want to convert into ded.iddc? */
3825 else {
3826 #if 0 /* old, simple way (only allow within IDDC) */
3827 if (!in_irondeepdive(&p_ptr->wpos)) {
3828 msg_print(Ind, "\377yYou must be inside the Ironman Deep Dive Challenge when converting!");
3829 s_printf("FAILED.\n");
3830 return;
3831 }
3832 if (ok == -5 || ok == -8 || ok == -6 || ok == -7) {
3833 p_ptr->mode |= MODE_DED_IDDC;
3834 p_ptr->mode &= ~MODE_EVERLASTING;
3835 p_ptr->mode |= MODE_NO_GHOST;
3836 msg_print(Ind, "\377BYour character has been converted to a slot-exclusive IDDC-character!");
3837 verify_player(p_ptr->name, p_ptr->id, p_ptr->account, p_ptr->prace, p_ptr->pclass, p_ptr->mode, p_ptr->lev, 0, 0, 0, 0, 0, 0, p_ptr->wpos);//assume NO ADMIN!
3838 // Destroy_connection(Players[Ind]->conn, "Success -- You need to login again to complete the process!");
3839 return;
3840 }
3841 msg_print(Ind, "\377yYou already have a slot-exclusive IDDC-mode character.");
3842 #else /* new way: ANY character may be convert, already in town even */
3843 if ((p_ptr->max_exp || p_ptr->max_plv > 1) &&
3844 !in_irondeepdive(&p_ptr->wpos)) {
3845 msg_print(Ind, "\377yYou must have zero experience points to be eligible to convert to IDDC!");
3846 s_printf("FAILED.\n");
3847 return;
3848 }
3849
3850 p_ptr->mode |= MODE_DED_IDDC;
3851 p_ptr->mode &= ~MODE_EVERLASTING;
3852 p_ptr->mode |= MODE_NO_GHOST;
3853 /* (get rid of his houses -- not needed though since you can't currently buy houses at level 1) */
3854
3855 msg_print(Ind, "\377BYour character has been converted to a slot-exclusive IDDC-character!");
3856 verify_player(p_ptr->name, p_ptr->id, p_ptr->account, p_ptr->prace, p_ptr->pclass, p_ptr->mode, p_ptr->lev, 0, 0, 0, 0, 0, 0, p_ptr->wpos);//assume NO ADMIN!
3857
3858 /* set typical character parameters as if we were born like this */
3859 if (!in_irondeepdive(&p_ptr->wpos)) {
3860 #ifdef EVENT_TOWNIE_GOLD_LIMIT
3861 if (EVENT_TOWNIE_GOLD_LIMIT != -1) {
3862 p_ptr->au += EVENT_TOWNIE_GOLD_LIMIT - p_ptr->gold_picked_up;
3863 p_ptr->gold_picked_up = EVENT_TOWNIE_GOLD_LIMIT;
3864 p_ptr->redraw |= PR_GOLD;
3865 }
3866 #endif
3867 #if 1 /* note that this allows use of WoR to get to IDDC :) */
3868 /* automatically know the location of IDDC dungeon */
3869 p_ptr->wild_map[(WPOS_IRONDEEPDIVE_X + WPOS_IRONDEEPDIVE_Y * MAX_WILD_X) / 8] |=
3870 (1 << ((WPOS_IRONDEEPDIVE_X + WPOS_IRONDEEPDIVE_Y * MAX_WILD_X) % 8));
3871 #endif
3872 }
3873 p_ptr->warning_worldmap = 1;
3874 p_ptr->warning_dungeon = 1;
3875 p_ptr->warning_wor = 1;
3876 p_ptr->warning_ghost = 1;
3877 p_ptr->warning_death = 1;
3878 p_ptr->warning_instares = 1;
3879 #endif
3880 return;
3881 }
3882 return;
3883 } else if (prefix(message, "/pquit") || prefix(message, "/pleave")) {
3884 if (!p_ptr->party) {
3885 msg_print(Ind, "You are not in a party.");
3886 return;
3887 }
3888 party_leave(Ind, TRUE);
3889 return;
3890 } else if (prefix(message, "/gquit") || prefix(message, "/gleave")) {
3891 if (!p_ptr->guild) {
3892 msg_print(Ind, "You are not in a guild.");
3893 return;
3894 }
3895 guild_leave(Ind, TRUE);
3896 return;
3897 } else if (prefix(message, "/quit") || prefix(message, "/exit") || prefix(message, "/leave")) {
3898 do_quit(Players[Ind]->conn, 0);
3899 return;
3900 #ifdef ENABLE_DRACONIAN_TRAITS
3901 } else if (prefix(message, "/trait")) {
3902 if (p_ptr->prace != RACE_DRACONIAN) {
3903 msg_print(Ind, "This command is only available to draconians.");
3904 return;
3905 }
3906 if (p_ptr->ptrait) {
3907 msg_print(Ind, "You already have a trait.");
3908 return;
3909 }
3910 if (!tk) {
3911 msg_print(Ind, "\377U------------------------------------------------");
3912 msg_print(Ind, "\377yUse this command like this:");
3913 msg_print(Ind, "\377o /trait colour");
3914 msg_print(Ind, "\377yWhere colour is one of these:");
3915 msg_print(Ind, "\377o blue, white, red, black, green, multi,");
3916 msg_print(Ind, "\377o bronze, silver, gold, law, chaos, balance.");
3917 msg_print(Ind, "\377yWARNING: Once you set a trait, it will be FINAL.");
3918 msg_print(Ind, "\377yPlease check the guide (6.4) for trait details.");
3919 msg_print(Ind, "\377U------------------------------------------------");
3920 return;
3921 }
3922
3923 if (!strcmp(message3, "blue")) p_ptr->ptrait = 1;
3924 else if (!strcmp(message3, "white")) p_ptr->ptrait = 2;
3925 else if (!strcmp(message3, "red")) p_ptr->ptrait = 3;
3926 else if (!strcmp(message3, "black")) p_ptr->ptrait = 4;
3927 else if (!strcmp(message3, "green")) p_ptr->ptrait = 5;
3928 else if (!strcmp(message3, "multi")) p_ptr->ptrait = 6;
3929 else if (!strcmp(message3, "bronze")) p_ptr->ptrait = 7;
3930 else if (!strcmp(message3, "silver")) p_ptr->ptrait = 8;
3931 else if (!strcmp(message3, "gold")) p_ptr->ptrait = 9;
3932 else if (!strcmp(message3, "law")) p_ptr->ptrait = 10;
3933 else if (!strcmp(message3, "chaos")) p_ptr->ptrait = 11;
3934 else if (!strcmp(message3, "balance")) p_ptr->ptrait = 12;
3935 else {
3936 msg_print(Ind, "You entered an invalid colour, please try again.");
3937 return;
3938 }
3939 msg_format(Ind, "\377U*** Your trait has been set to '%s' ***.", trait_info[p_ptr->ptrait].title);
3940 s_printf("TRAIT_SET: %s (%s) -> %d\n", p_ptr->name, p_ptr->accountname, p_ptr->ptrait);
3941 p_ptr->redraw |= PR_MISC;
3942
3943 get_history(Ind);
3944 p_ptr->redraw |= PR_HISTORY;
3945
3946 p_ptr->s_info[SKILL_BREATH].value = 1000;
3947 Send_skill_info(Ind, SKILL_BREATH, TRUE);
3948 return;
3949 #endif
3950 #ifdef AUTO_RET_CMD
3951 } else if (prefix(message, "/autoret") || prefix(message, "/ar")) {
3952 char *p = token[1];
3953
3954 if (p_ptr->prace == RACE_VAMPIRE || !get_skill(p_ptr, SKILL_MIMIC)) {
3955 msg_print(Ind, "You cannot use mimic powers.");
3956 return;
3957 }
3958
3959 /* Set up a spell by name for auto-retaliation, so mimics can use it too */
3960 if (!tk) {
3961 if (p_ptr->autoret) {
3962 if (p_ptr->autoret >= 100)
3963 msg_format(Ind, "You have set mimic power '%c)' for auto-retaliation in towns.", p_ptr->autoret - 101 + 'a');
3964 else
3965 msg_format(Ind, "You have set mimic power '%c)' for auto-retaliation.", p_ptr->autoret - 1 + 'a');
3966 } else {
3967 msg_print(Ind, "You have not set a mimic power for auto-retaliation. ('/ar help' for details.)");
3968 //msg_print(Ind, " (Enter '/ar help' to see command usage and examples.)");
3969 }
3970 return;
3971 }
3972 if (streq(token[1], "help")) {
3973 msg_print(Ind, "Set up a monster spell for auto-retaliation by specifying the spell slot letter");
3974 msg_print(Ind, "starting with e), or '-' to disable. Optional prefix 't' for 'in town only'.");
3975 msg_print(Ind, " Usage: /ar [t]<mimic power slot (e..z)>");
3976 msg_print(Ind, " Example: /ar e sets the first mimic power to auto-retaliate");
3977 msg_print(Ind, " Example: /ar th sets the fourth mimic power, but only when in town");
3978 msg_print(Ind, " Example: /ar - disables auto-retaliation with mimic powers");
3979 return;
3980 }
3981
3982 if (*p == 't') {
3983 p_ptr->autoret = 100;
3984 p++;
3985 }
3986 else p_ptr->autoret = 0;
3987
3988 if (*p == '-') {
3989 msg_print(Ind, "Mimic power auto-retaliation is now disabled.");
3990 return;
3991 }
3992
3993 if (*p < 'e' || *p > 'z') {
3994 msg_print(Ind, "\377yMimic power must be within range 'e' to 'z'!");
3995 return;
3996 }
3997
3998 msg_format(Ind, "Mimic power '%c)' is now set for auto-retaliation.", *p);
3999 p_ptr->autoret += *p - 'a' + 1;
4000 return;
4001 #endif
4002 #ifdef ENABLE_SELF_FLASHING
4003 } else if (prefix(message, "/flash")) {
4004 if (p_ptr->flash_self == -1) {
4005 p_ptr->flash_self = 0;
4006 msg_print(Ind, "Self-flashing when changing dungeon floor is now ENABLED.");
4007 } else {
4008 p_ptr->flash_self = -1;
4009 msg_print(Ind, "Self-flashing when changing dungeon floor is now DISABLED.");
4010 }
4011 return;
4012 #endif
4013 } else if (prefix(message, "/partymembers")) {
4014 int slot, p = p_ptr->party, members = 0;
4015 hash_entry *ptr;
4016
4017 if (!p) {
4018 msg_print(Ind, "You are not in a party.");
4019 return;
4020 }
4021
4022 msg_format(Ind, "-- Players in your party '%s' --", parties[p].name);
4023 for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4024 ptr = hash_table[slot];
4025 while (ptr) {
4026 if (ptr->party == p) {
4027 if (ptr->admin == 1) {
4028 if (is_admin(p_ptr)) msg_format(Ind, " \377r%-20s (%s)", ptr->name, ptr->accountname);
4029 else {
4030 ptr = ptr->next;
4031 continue;
4032 }
4033 } else msg_format(Ind, " %-20s (%s)", ptr->name, ptr->accountname);
4034 members++;
4035 }
4036 ptr = ptr->next;
4037 }
4038 }
4039 msg_format(Ind, " %d member%s total.", members, members == 1 ? "" : "s");
4040 return;
4041 } else if (prefix(message, "/guildmembers")) {
4042 int slot, g = p_ptr->guild, members = 0;
4043 hash_entry *ptr;
4044
4045 if (!g) {
4046 msg_print(Ind, "You are not in a guild.");
4047 return;
4048 }
4049
4050 msg_format(Ind, "-- Players in your guild '%s' --", guilds[g].name);
4051 for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
4052 ptr = hash_table[slot];
4053 while (ptr) {
4054 if (ptr->guild == g) {
4055 if (ptr->admin == 1) {
4056 if (is_admin(p_ptr)) msg_format(Ind, " \377r%-20s (%s)", ptr->name, ptr->accountname);
4057 else {
4058 ptr = ptr->next;
4059 continue;
4060 }
4061 } else msg_format(Ind, " %-20s (%s)", ptr->name, ptr->accountname);
4062 members++;
4063 }
4064 ptr = ptr->next;
4065 }
4066 }
4067 msg_format(Ind, " %d member%s total.", members, members == 1 ? "" : "s");
4068 return;
4069 }
4070 else if (prefix(message, "/snbar")) {
4071 int skill = get_skill(p_ptr, SKILL_HEALTH), guis;
4072
4073 if (skill >= 40) guis = 4;
4074 else if (skill >= 20) guis = 3;
4075 else if (skill >= 10) guis = 2;
4076 else guis = 1;
4077
4078 p_ptr->sanity_bar = (p_ptr->sanity_bar + 1) % guis;
4079 switch (p_ptr->sanity_bar) {
4080 case 0: msg_print(Ind, "Sanity is now displayed as label."); break;
4081 case 1: msg_print(Ind, "Sanity is now displayed as bar."); break;
4082 case 2: msg_print(Ind, "Sanity is now displayed as percentage."); break;
4083 case 3: msg_print(Ind, "Sanity is now displayed as value."); break;
4084 }
4085 p_ptr->redraw |= PR_SANITY;
4086 return;
4087 }
4088 else if (prefix(message, "/seen")) {
4089 char response[MAX_CHARS_WIDE];
4090 get_laston(message3, response, admin_p(Ind));
4091 msg_print(Ind, response);
4092 return;
4093 }
4094 else if (prefix(message, "/quest") || prefix(message, "/que")/*quIt*/) { /* display our quests or drop a quest we're on */
4095 if (tk != 1) {
4096 int qa = 0;
4097
4098 for (i = 0; i < MAX_CONCURRENT_QUESTS; i++)
4099 if (p_ptr->quest_idx[i] != -1) qa++;
4100
4101 msg_print(Ind, "");
4102 if (!qa) msg_print(Ind, "\377UYou're not currently pursuing any quests.");
4103 else {
4104 if (qa == 1) msg_print(Ind, "\377UYou're currently pursuing the following quest:");
4105 else msg_print(Ind, "\377UYou're currently pursuing the following quests:");
4106 for (i = 0; i < MAX_CONCURRENT_QUESTS; i++) {
4107 if (p_ptr->quest_idx[i] == -1) continue;
4108 msg_format(Ind, " %2d) %s", i + 1, q_name + q_info[p_ptr->quest_idx[i]].name);
4109 }
4110 #if 0
4111 msg_print(Ind, "\377s To drop a quest type \377D/quest <questnumber>\377s - to drop all quests type \377D/quest *");
4112 msg_print(Ind, "\377s Warning! Depending on the quest you might not be able to pick it up again.");
4113 #else
4114 msg_print(Ind, "\377s To drop a quest use \377D/quest num\377s, * for all. Quests might not be re-acquirable!");
4115 #endif
4116 }
4117 return;
4118 }
4119 if (token[1][0] == '*') {
4120 msg_print(Ind, "You are no longer pursuing any quest!");
4121 for (i = 0; i < MAX_CONCURRENT_QUESTS; i++)
4122 quest_abandon(Ind, i);
4123 return;
4124 }
4125 if (k < 1 || k > MAX_CONCURRENT_QUESTS) {
4126 msg_print(Ind, "\377yThe quest number must be from 1 to 5!");
4127 return;
4128 }
4129 if (p_ptr->quest_idx[k - 1] == -1) {
4130 msg_format(Ind, "\377yYou are not pursing a quest numbered %d.", k);
4131 return;
4132 }
4133 msg_format(Ind, "You are no longer pursuing the quest '%s'!", q_name + q_info[p_ptr->quest_idx[k - 1]].name);
4134 quest_abandon(Ind, k - 1);
4135 return;
4136 }
4137 else if (prefix(message, "/who")) { /* returns account name to which the given character name belongs -- user version of /characc[l] */
4138 u32b p_id;
4139 cptr acc;
4140
4141 if (tk < 1) {
4142 msg_print(Ind, "Usage: /who <character name>");
4143 return;
4144 }
4145
4146 /* hack: consume a partial turn to avoid exploit-spam... */
4147 if (p_ptr->energy < level_speed(&p_ptr->wpos)) return;
4148 p_ptr->energy -= level_speed(&p_ptr->wpos) / 2;
4149
4150 /* char names always start on upper-case */
4151 message3[0] = toupper(message3[0]);
4152
4153 if (!(p_id = lookup_player_id(message3))) {
4154 #if 0 /* don't check for account name */
4155 msg_print(Ind, "That character name does not exist.");
4156 #else /* check for account name */
4157 if (!GetAccount(message3, NULL, FALSE)) msg_print(Ind, "That character or account name does not exist.");
4158 else msg_print(Ind, "There is no such character, but there is an account of that name.");
4159 #endif
4160 return;
4161 }
4162 acc = lookup_accountname(p_id);
4163 if (!acc) {
4164 msg_print(Ind, "***ERROR: No account found.");
4165 return;
4166 }
4167 //msg_format(Ind, "That character belongs to: \377s%s", acc);
4168 if (lookup_player_admin(p_id))
4169 msg_format(Ind, "That administrative character belongs to: \377s%s", acc);
4170 else {
4171 u16b ptype = lookup_player_type(p_id);
4172 msg_format(Ind, "That %s %s belongs to: \377s%s",
4173 //race_info[ptype & 0xff].title,
4174 special_prace_lookup[ptype & 0xff],
4175 class_info[ptype >> 8].title, acc);
4176 }
4177 return;
4178 }
4179 else if (prefix(message, "/dun")) {//dungeon name
4180 dungeon_type *d_ptr = NULL;
4181
4182 if (!p_ptr->wpos.wz) {
4183 msg_print(Ind, "You are not in a dungeon or tower.");
4184 return;
4185 }
4186
4187 if (p_ptr->wpos.wz > 0) d_ptr = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].tower;
4188 else d_ptr = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].dungeon;
4189
4190 msg_format(Ind, "\377uYou are currently in %s.", get_dun_name(p_ptr->wpos.wx, p_ptr->wpos.wy, (p_ptr->wpos.wz > 0), d_ptr, 0, TRUE));
4191 return;
4192 }
4193
4194
4195
4196 /*
4197 * Privileged commands
4198 *
4199 * (Admins might have different versions of these commands)
4200 */
4201 else if (!admin && p_ptr->privileged) {
4202 /*
4203 * Privileged commands, level 2
4204 */
4205 if (p_ptr->privileged == 2) {
4206 }
4207
4208
4209
4210 /*
4211 * Privileged commands, level 1
4212 */
4213 if (prefix(message, "/val")){
4214 if(!tk) return;
4215 /* added checking for account existence - mikaelh */
4216 switch(validate(message3)) {
4217 case -1: msg_format(Ind, "\377GValidating %s", message3);
4218 break;
4219 case 0: msg_format(Ind, "\377rAccount %s not found", message3);
4220 break;
4221 case 1: msg_format(Ind, "\377rAccount %s already completely valid", message3);
4222 }
4223 return;
4224 }
4225 if (prefix(message, "/inval")){
4226 if(!tk) return;
4227 /* added checking for account existence - mikaelh */
4228 switch(invalidate(message3, FALSE)) {
4229 case -1: msg_format(Ind, "\377GInvalidating %s", message3);
4230 break;
4231 case 0: msg_format(Ind, "\377rAccount %s not found", message3);
4232 break;
4233 case 1: msg_format(Ind, "\377rAccount %s already completely invalid", message3);
4234 break;
4235 case 2: msg_print(Ind, "\377rYou may not invalidate admin accounts");
4236 s_printf("ATTEMPT_INVAL_ADMIN: %s -> %s\n", p_ptr->name, message3);
4237 break;
4238 }
4239 return;
4240 }
4241 }
4242
4243
4244
4245 /*
4246 * Admin commands
4247 *
4248 * These commands should be replaced by LUA scripts in the future.
4249 */
4250 else if (admin) {
4251 /* presume worldpos */
4252 switch (tk) {
4253 case 1:
4254 /* depth in feet */
4255 wp.wz = (p_ptr->depth_in_feet ? k / 50 : k);
4256 break;
4257 case 3:
4258 /* depth in feet */
4259 wp.wx = k % MAX_WILD_X;
4260 wp.wy = atoi(token[2]) % MAX_WILD_Y;
4261 wp.wz = atoi(token[3]) / (p_ptr->depth_in_feet ? 50 : 1);
4262 break;
4263 case 2:
4264 wp.wx = k % MAX_WILD_X;
4265 wp.wy = atoi(token[2]) % MAX_WILD_Y;
4266 wp.wz = 0;
4267 break;
4268 default:
4269 break;
4270 }
4271
4272 /* random temporary test output */
4273 if (prefix(message, "/tmp")) {
4274 if (!tk) return;
4275 return;
4276 }
4277
4278 #ifdef TOMENET_WORLDS
4279 else if (prefix(message, "/world")){
4280 world_connect(Ind);
4281 return;
4282 }
4283 #endif
4284
4285 else if (prefix(message, "/shutdown"))// || prefix(message, "/quit"))
4286 {
4287 bool kick = (cfg.runlevel == 1024);
4288
4289 //no effect if (tk && k == 0) msg_broadcast(0, "\377o** Server is being restarted and will be back immediately! **");
4290
4291 set_runlevel(tk ? k :
4292 ((cfg.runlevel < 6 || kick)? 6 : 5));
4293 msg_format(Ind, "Runlevel set to %d", cfg.runlevel);
4294
4295 /* Hack -- character edit mode */
4296 if (k == 1024 || kick)
4297 {
4298 if (k == 1024) msg_print(Ind, "\377rEntering edit mode!");
4299 else msg_print(Ind, "\377rLeaving edit mode!");
4300
4301 for (i = NumPlayers; i > 0; i--)
4302 {
4303 /* Check connection first */
4304 if (Players[i]->conn == NOT_CONNECTED)
4305 continue;
4306
4307 /* Check for death */
4308 if (!is_admin(Players[i]))
4309 Destroy_connection(Players[i]->conn, "Server maintenance");
4310 }
4311 }
4312 time(&cfg.closetime);
4313 return;
4314 }
4315 else if (prefix(message, "/shutempty")) {
4316 msg_admins(0, "\377y* Shutting down as soon as dungeons are empty *");
4317 cfg.runlevel = 2048;
4318 return;
4319 }
4320 else if (prefix(message, "/shutlow")) {
4321 msg_admins(0, "\377y* Shutting down as soon as dungeons are empty and few players are on *");
4322 cfg.runlevel = 2047;
4323 return;
4324 }
4325 else if (prefix(message, "/shutvlow")) {
4326 msg_admins(0, "\377y* Shutting down as soon as dungeons are empty and very few players are on *");
4327 cfg.runlevel = 2046;
4328 return;
4329 }
4330 else if (prefix(message, "/shutnone")) {
4331 msg_admins(0, "\377y* Shutting down as soon as no players are on anymore *");
4332 cfg.runlevel = 2045;
4333 return;
4334 }
4335 else if (prefix(message, "/shutactivevlow")) {
4336 msg_admins(0, "\377y* Shutting down as soon as dungeons are empty and very few players are active *");
4337 cfg.runlevel = 2044;
4338 return;
4339 }
4340 #if 0 /* not implemented yet - /shutempty is currently working this way */
4341 else if (prefix(message, "/shutsurface")) {
4342 msg_admins(0, "\377y* Shutting down as soon as noone is inside a dungeon/tower *");
4343 cfg.runlevel = 2050;
4344 return;
4345 }
4346 #endif
4347 else if (prefix(message, "/shutxlow")) {
4348 msg_admins(0, "\377y* Shutting down as soon as dungeons are empty and extremely few players are on *");
4349 cfg.runlevel = 2051;
4350 return;
4351 }
4352 else if (prefix(message, "/shutrec")) { /* /shutrec [<minutes>] [T] */
4353 if (!k) k = 5;
4354 if (strchr(message3, 'T')) timed_shutdown(k, TRUE);//terminate server for maintenance
4355 else timed_shutdown(k, FALSE);
4356 return;
4357 }
4358 else if (prefix(message, "/shutcancel")) {
4359 msg_admins(0, "\377w* Shut down cancelled *");
4360 if (cfg.runlevel == 2043 || cfg.runlevel == 2042)
4361 msg_broadcast_format(0, "\377I*** \377yServer-shutdown cancelled. \377I***");
4362 cfg.runlevel = 6;
4363 return;
4364 }
4365 else if (prefix(message, "/val")){
4366 if(!tk) return;
4367 /* added checking for account existence - mikaelh */
4368 switch(validate(message3)) {
4369 case -1: msg_format(Ind, "\377GValidating %s", message3);
4370 break;
4371 case 0: msg_format(Ind, "\377rAccount %s not found", message3);
4372 break;
4373 case 1: msg_format(Ind, "\377rAccount %s already completely valid", message3);
4374 }
4375 return;
4376 }
4377 else if (prefix(message, "/inval")){
4378 if(!tk) return;
4379 /* added checking for account existence - mikaelh */
4380 switch(invalidate(message3, TRUE)) {
4381 case -1: msg_format(Ind, "\377GInvalidating %s", message3);
4382 break;
4383 case 0: msg_format(Ind, "\377rAccount %s not found", message3);
4384 break;
4385 case 1: msg_format(Ind, "\377rAccount %s already completely invalid", message3);
4386 break;
4387 case 2: msg_print(Ind, "\377rAdmin accounts must be validated via accedit.");
4388 s_printf("CANNOT_INVAL_ADMIN: %s -> %s\n", p_ptr->name, message3);
4389 break;
4390 }
4391 return;
4392 }
4393 else if (prefix(message, "/makeadmin")){
4394 if(!tk) return;
4395 /* added checking for account existence - mikaelh */
4396 if (makeadmin(message3)) {
4397 msg_format(Ind, "\377GMaking %s an admin", message3);
4398 } else {
4399 msg_format(Ind, "\377rAccount %s not found", message3);
4400 }
4401 return;
4402 } else if (prefix(message, "/banip")) { /* note: banip doesn't enter a hostname, use /bancombo for that */
4403 char *reason = NULL;
4404 int time = tk > 1 ? atoi(token[2]) : 5; /* 5 minutes by default */
4405 char kickmsg[MAX_SLASH_LINE_LEN];
4406
4407 if (!tk) {
4408 msg_print(Ind, "\377oUsage: /banip <IP address> [time [reason]]");
4409 return;
4410 }
4411
4412 if (tk == 3) reason = message3 + strlen(token[1]) + strlen(token[2]) + 2;
4413 if (reason) snprintf(kickmsg, MAX_SLASH_LINE_LEN, "You have been banned for %d minutes: %s", time, reason);
4414 else snprintf(kickmsg, MAX_SLASH_LINE_LEN, "You have been banned for %d minutes", time);
4415
4416 if (reason) {
4417 msg_format(Ind, "Banning %s for %d minutes (%s).", token[1], time, reason);
4418 s_printf("Banning %s for %d minutes (%s).\n", token[1], time, reason);
4419 } else {
4420 msg_format(Ind, "Banning %s for %d minutes.", token[1], time);
4421 s_printf("Banning %s for %d minutes.\n", token[1], time);
4422 }
4423 add_banlist(NULL, token[1], NULL, time, reason);
4424 kick_ip(Ind, token[1], kickmsg, TRUE);
4425 return;
4426 } else if (prefix(message, "/ban") || prefix(message, "/bancombo")) { /* note: ban and bancombo enter a hostname too */
4427 /* ban bans an account name, banip bans an ip address,
4428 bancombo bans an account name and an ip address - if ip address is not specified, it uses the ip address of the
4429 account name, who must be currently online. if the account is offline, bancombo reverts to normal /ban. */
4430
4431 bool combo = prefix(message, "/bancombo"), found = FALSE, derived_ip = FALSE;
4432 char *reason = NULL, reasonstr[MAX_CHARS];
4433 char *hostname = NULL, hostnamestr[MAX_CHARS];
4434 int time = 5; /* 5 minutes by default */
4435 char ip_addr[MAX_CHARS] = { 0 };
4436 char kickmsg[MAX_SLASH_LINE_LEN];
4437 char tmp_buf[MSG_LEN], *tmp_buf_ptr = tmp_buf;
4438 struct account *l_acc;
4439
4440 if (!tk) {
4441 if (combo) msg_print(Ind, "\377oUsage: /bancombo <account name>:<IP address> [time [reason]]");
4442 else msg_print(Ind, "\377oUsage: /ban <account name>[:time [reason]]");
4443 return;
4444 }
4445
4446 /* remove trailing spaces and colon to be safe */
4447 while (message3[strlen(message3) - 1] == ' ' || message3[strlen(message3) - 1] == ':') message3[strlen(message3) - 1] = 0;
4448
4449 if (!strchr(message3, ':')) {
4450 l_acc = Admin_GetAccount(message3);
4451 if (l_acc) KILL(l_acc, struct account);
4452 else {
4453 msg_print(Ind, "Account not found.");
4454 return;
4455 }
4456
4457 if (combo) {
4458 bool found = FALSE;
4459 /* test for account being online to find its IP, else revert to normal /ban */
4460 for (i = 1; i <= NumPlayers; i++) {
4461 if (!strcmp(Players[i]->accountname, message3)) {
4462 found = TRUE;
4463 strcpy(ip_addr, get_player_ip(i));
4464 break;
4465 }
4466 }
4467 if (!found) {
4468 msg_print(Ind, "Account not online, reverting to normal account ban without IP ban!");
4469 combo = FALSE; /* superfluous here */
4470 }
4471 }
4472
4473 snprintf(kickmsg, MAX_SLASH_LINE_LEN, "You have been banned for %d minutes", time);
4474 msg_format(Ind, "Banning '%s' for %d minutes.", message3, time);
4475 s_printf("<%s> Banning '%s' for %d minutes.\n", p_ptr->name, message3, time);
4476 /* kick.. */
4477 for (i = 1; i <= NumPlayers; i++) {
4478 if (!Players[i]) continue;
4479 if (!strcmp(Players[i]->accountname, message3)) {
4480 /* save the first hostname too */
4481 if (!hostname) {
4482 strcpy(hostnamestr, Players[i]->hostname);
4483 hostname = hostnamestr;
4484 }
4485 kick_char(Ind, i, kickmsg);
4486 Ind = p_ptr->Ind;
4487 i--;
4488 }
4489 }
4490 /* ban! ^^ */
4491 add_banlist(message3, ip_addr[0] ? ip_addr : NULL, hostname, time, NULL);
4492 return;
4493 }
4494
4495 strcpy(tmp_buf, strchr(message3, ':') + 1);
4496 /* hack: terminate player name */
4497 *(strchr(message3, ':')) = 0;
4498 l_acc = Admin_GetAccount(message3);
4499 if (l_acc) KILL(l_acc, struct account);
4500 else {
4501 msg_print(Ind, "Account not found.");
4502 return;
4503 }
4504
4505 /* check if an IP was specified, otherwise take it from online account,
4506 if account isn't online, fallback to normal /ban. */
4507 if (combo) {
4508 char *ptr = tmp_buf;
4509 bool no_ip = FALSE;
4510 /* "it's not an IP, if there are only numbers until the next space or end of line" */
4511 while ((*ptr >= '0' && *ptr <= '9') || *ptr == ' ' || *ptr == 0) {
4512 if (*ptr == ' ' || *ptr == 0) {
4513 no_ip = TRUE;
4514 break;
4515 }
4516 ptr++;
4517 }
4518 /* try to derive IP from online account? */
4519 if (no_ip) {
4520 for (i = 1; i <= NumPlayers; i++) {
4521 if (!strcmp(Players[i]->accountname, message3)) {
4522 derived_ip = TRUE;
4523 strcpy(ip_addr, get_player_ip(i));
4524 break;
4525 }
4526 }
4527 if (!derived_ip) {
4528 msg_print(Ind, "Account not online, reverting to normal account ban without IP ban!");
4529 combo = FALSE;
4530 }
4531 }
4532 }
4533
4534 if (!combo) { /* read time/reason */
4535 time = atoi(tmp_buf);
4536 tmp_buf_ptr = strchr(tmp_buf, ' ');
4537 if (tmp_buf_ptr) {
4538 strcpy(reasonstr, tmp_buf_ptr + 1);
4539 reason = reasonstr;
4540 }
4541 } else if (!derived_ip) { /* read IP address and possibly time/reason */
4542 strncpy(ip_addr, tmp_buf, MAX_CHARS);
4543 ip_addr[MAX_CHARS - 1] = 0;
4544 /* if a time has been specified, terminate IP at next space accordingly */
4545 if ((tmp_buf_ptr = strchr(tmp_buf, ' '))) {
4546 *(strchr(ip_addr, ' ')) = 0;
4547
4548 time = atoi(tmp_buf_ptr + 1);
4549 tmp_buf_ptr = strchr(tmp_buf_ptr + 1, ' ');
4550 if (tmp_buf_ptr) {
4551 strcpy(reasonstr, tmp_buf_ptr + 1);
4552 reason = reasonstr;
4553 }
4554 }
4555 } else { /* IP was not specified but derived from account, we only need to check for time/reason now */
4556 time = atoi(tmp_buf_ptr);
4557 tmp_buf_ptr = strchr(tmp_buf_ptr, ' ');
4558 if (tmp_buf_ptr) {
4559 strcpy(reasonstr, tmp_buf_ptr + 1);
4560 reason = reasonstr;
4561 }
4562 }
4563
4564 if (combo) {
4565 if (reason) {
4566 snprintf(kickmsg, MAX_SLASH_LINE_LEN, "You have been banned for %d minutes: %s", time, reason);
4567 msg_format(Ind, "Banning '%s'/%s for %d minutes (%s).", message3, ip_addr, time, reason);
4568 s_printf("<%s> Banning '%s'/%s for %d minutes (%s).\n", p_ptr->name, message3, ip_addr, time, reason);
4569 } else {
4570 snprintf(kickmsg, MAX_SLASH_LINE_LEN, "You have been banned for %d minutes", time);
4571 msg_format(Ind, "Banning '%s'/%s for %d minutes.", message3, ip_addr, time);
4572 s_printf("<%s> Banning '%s'/%s for %d minutes.\n", p_ptr->name, message3, ip_addr, time);
4573 }
4574 } else {
4575 if (reason) {
4576 snprintf(kickmsg, MAX_SLASH_LINE_LEN, "You have been banned for %d minutes: %s", time, reason);
4577 msg_format(Ind, "Banning '%s' for %d minutes (%s).", message3, time, reason);
4578 s_printf("<%s> Banning '%s' for %d minutes (%s).\n", p_ptr->name, message3, time, reason);
4579 } else {
4580 snprintf(kickmsg, MAX_SLASH_LINE_LEN, "You have been banned for %d minutes", time);
4581 msg_format(Ind, "Banning '%s' for %d minutes.", message3, time);
4582 s_printf("<%s> Banning '%s' for %d minutes.\n", p_ptr->name, message3, time);
4583 }
4584 }
4585
4586 /* kick.. */
4587 for (i = 1; i <= NumPlayers; i++) {
4588 if (!Players[i]) continue;
4589 if (!strcmp(Players[i]->accountname, message3)) {
4590 /* save the first hostname too */
4591 if (!hostname) {
4592 found = TRUE;
4593 strcpy(hostnamestr, Players[i]->hostname);
4594 hostname = hostnamestr;
4595 }
4596 kick_char(Ind, i, kickmsg);
4597 Ind = p_ptr->Ind;
4598 i--;
4599 }
4600 }
4601 if (combo) kick_ip(Ind, ip_addr, kickmsg, !found);
4602 /* ban! ^^ */
4603 add_banlist(message3, combo ? ip_addr : NULL, hostname, time, reason);
4604 return;
4605 } else if (prefix(message, "/kickip")) {
4606 char *reason = NULL;
4607
4608 if (!tk) {
4609 msg_print(Ind, "\377oUsage: /kickip <IP address> [reason]");
4610 return;
4611 }
4612
4613 if (tk == 2) {
4614 reason = message3 + strlen(token[1]) + 1;
4615 s_printf("<%s> Kicking IP %s (%s).\n", p_ptr->name, token[1], reason);
4616 } else s_printf("<%s> Kicking IP %s.\n", p_ptr->name, token[1]);
4617 kick_ip(Ind, token[1], reason, TRUE);
4618 return;
4619 } else if (prefix(message, "/kick")) {
4620 char *reason = NULL;
4621 char reasonstr[MAX_CHARS];
4622
4623 if (!tk) {
4624 msg_print(Ind, "\377oUsage: /kick <character name>[:reason]");
4625 return;
4626 }
4627 if (strchr(message3, ':')) {
4628 strcpy(reasonstr, strchr(message3, ':') + 1);
4629 reason = reasonstr;
4630
4631 /* hack: terminate message3 after char name */
4632 *(strchr(message3, ':')) = 0;
4633 }
4634
4635 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
4636 if (!j) {
4637 msg_print(Ind, "Player not online.");
4638 return;
4639 }
4640 if (reason) s_printf("<%s> Kicking '%s' (%s).\n", p_ptr->name, Players[j]->name, reason);
4641 else s_printf("<%s> Kicking '%s'.\n", p_ptr->name, Players[j]->name);
4642 kick_char(Ind, j, reason);
4643 return;
4644 } else if (prefix(message, "/viewbans")) {
4645 bool found = FALSE;
4646 struct combo_ban *ptr;
4647 char buf[MAX_CHARS];
4648
4649 msg_print(Ind, "\377yACCOUNT@HOST \377w| \377yIP \377w| \377yTIME \377w| \377yREASON");
4650 for (ptr = banlist; ptr != (struct combo_ban*)NULL; ptr = ptr->next) {
4651 if (ptr->acc[0]) {
4652 /* start with account name, add '@' separator and.. */
4653 strcpy(buf, ptr->acc);
4654 if (ptr->hostname[0]) {
4655 strcat(buf, "@");
4656 /* .. append as much of the hostname as fits in */
4657 strncat(buf, ptr->hostname, MAX_CHARS - strlen(ptr->acc) - 1);
4658 buf[MAX_CHARS - 1] = 0;
4659 }
4660 } else strcpy(buf, "---");
4661 msg_format(Ind, "\377s%-20s \377w| \377s%-15s \377w| \377s%6d \377w| \377s%s",
4662 buf, ptr->ip[0] ? ptr->ip : "---.---.---.---", ptr->time, ptr->reason[0] ? ptr->reason : "<no reason>");
4663 found = TRUE;
4664 }
4665 if (!found) msg_print(Ind, " \377s<empty>");
4666 return;
4667 } else if (prefix(message, "/unban")) {
4668 /* unban unbans all entries of matching account name (no matter whether they also have an ip entry),
4669 unbancombo unbans all entries of matching account name or matching ip,
4670 unbanip unbans all entries of matching ip (no matter whether they also have an account name entry).
4671 unbanall just erases the whole banlist. */
4672 struct combo_ban *ptr, *new, *old = (struct combo_ban*)NULL;
4673 bool unban_ip = FALSE, unban_acc = FALSE, found = FALSE;
4674 char ip[MAX_CHARS], account[ACCOUNTNAME_LEN + 5];//paranoia-reserve if admin makes input error. todo: proper length check
4675
4676 if (prefix(message, "/unbanall")) {
4677 struct combo_ban *ptr, *new, *old = (struct combo_ban*)NULL;
4678 ptr = banlist;
4679 while (ptr != (struct combo_ban*)NULL) {
4680 if (!old) {
4681 banlist = ptr->next;
4682 new = banlist;
4683 } else {
4684 old->next = ptr->next;
4685 new = old->next;
4686 }
4687 free(ptr);
4688 ptr = new;
4689 }
4690 msg_print(Ind, "Ban list has been reset.");
4691 return;
4692 }
4693
4694 strcpy(ip, "-");
4695 strcpy(account, "-");
4696
4697 if (prefix(message, "/unbancombo")) {
4698 if (!tk || !strchr(message3, ' ')) {
4699 msg_print(Ind, "Usage: /unbancombo <ip address> <account name>");
4700 return;
4701 }
4702 unban_ip = TRUE;
4703 unban_acc = TRUE;
4704 strcpy(ip, message3);
4705 *(strchr(ip, ' ')) = 0;
4706 strcpy(account, strchr(message3, ' ') + 1);
4707 } else if (prefix(message, "/unbanip")) {
4708 if (!tk) {
4709 msg_print(Ind, "Usage: /unbanip <ip address>");
4710 return;
4711 }
4712 unban_ip = TRUE;
4713 strcpy(ip, message3);
4714 } else {
4715 if (!tk) {
4716 msg_print(Ind, "Usage: /unban <account name>");
4717 return;
4718 }
4719 unban_acc = TRUE;
4720 strcpy(account, message3);
4721 }
4722
4723 ptr = banlist;
4724 while (ptr != (struct combo_ban*)NULL) {
4725 if ((unban_acc && ptr->acc[0] && !strcmp(ptr->acc, account)) ||
4726 (unban_ip && ptr->ip[0] && !strcmp(ptr->ip, ip))) {
4727 found = TRUE;
4728 if (ptr->reason[0]) {
4729 msg_format(Ind, "Unbanning '%s'/%s (ban reason was '%s').", ptr->acc, ptr->ip[0] ? ptr->ip : "-", ptr->reason);
4730 s_printf("<%s> Unbanning '%s'/%s (ban reason was '%s').\n", p_ptr->name, ptr->acc, ptr->ip[0] ? ptr->ip : "-", ptr->reason);
4731 } else {
4732 msg_format(Ind, "Unbanning '%s'/%s.", ptr->acc, ptr->ip[0] ? ptr->ip : "-");
4733 s_printf("<%s> Unbanning '%s'/%s.\n", p_ptr->name, ptr->acc, ptr->ip[0] ? ptr->ip : "-");
4734 }
4735
4736 if (!old) {
4737 banlist = ptr->next;
4738 new = banlist;
4739 } else {
4740 old->next = ptr->next;
4741 new = old->next;
4742 }
4743 free(ptr);
4744 ptr = new;
4745 continue;
4746 }
4747 ptr = ptr->next;
4748 }
4749 if (!found) msg_print(Ind, "No matching ban found.");
4750 return;
4751 }
4752 /* The idea is to reduce the age of the target player because s/he was being
4753 * immature (and deny his/her chatting privilege). - the_sandman
4754 */
4755 else if (prefix(message, "/mute")) {
4756 if (tk) {
4757 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
4758 if (j) {
4759 Players[j]->muted = TRUE;
4760 msg_print(j, "\377fYou have been muted.");
4761 s_printf("<%s> muted '%s'.\n", p_ptr->name, Players[j]->name);
4762 }
4763 return;
4764 }
4765 msg_print(Ind, "\377oUsage: /mute <character name>");
4766 } else if (prefix(message, "/unmute")) { //oh no!
4767 if (tk) {
4768 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
4769 if (j) {
4770 Players[j]->muted = FALSE;
4771 msg_print(j, "\377fYou have been unmuted.");
4772 s_printf("<%s> unmuted '%s'.\n", p_ptr->name, Players[j]->name);
4773 }
4774 return;
4775 }
4776 msg_print(Ind, "\377oUsage: /unmute <character name>");
4777 }
4778 /* erase items and monsters */
4779 else if (prefix(message, "/clear-level") ||
4780 prefix(message, "/clv"))
4781 {
4782 bool full = (tk);
4783
4784 /* Wipe even if town/wilderness */
4785 if (full) {
4786 wipe_m_list(&wp);
4787 wipe_o_list(&wp);
4788 } else {
4789 wipe_m_list_admin(&wp);
4790 wipe_o_list_safely(&wp);
4791 }
4792 /* XXX trap clearance support dropped - reimplement! */
4793 // wipe_t_list(&wp);
4794
4795 msg_format(Ind, "\377rItems/%smonsters on %s are cleared.", full ? "ALL " : "", wpos_format(Ind, &wp));
4796 for (i = 1; i <= NumPlayers; i++) {
4797 if (!inarea(&wp, &Players[i]->wpos)) continue;
4798 Players[i]->redraw |= PR_MAP;
4799 }
4800 return;
4801 }
4802 /* erase items (prevent loot-mass-freeze) */
4803 else if (prefix(message, "/clear-items") ||
4804 prefix(message, "/cli"))
4805 {
4806 /* Wipe even if town/wilderness */
4807 wipe_o_list_safely(&wp);
4808
4809 msg_format(Ind, "\377rItems on %s are cleared.", wpos_format(Ind, &wp));
4810 return;
4811 }
4812 /* erase ALL items (never use this when houses are on the map sector) */
4813 else if (prefix(message, "/clear-extra") ||
4814 prefix(message, "/xcli"))
4815 {
4816 /* Wipe even if town/wilderness */
4817 wipe_o_list(&wp);
4818
4819 msg_format(Ind, "\377rItems on %s are cleared.", wpos_format(Ind, &wp));
4820 return;
4821 }
4822 else if (prefix(message, "/mdelete")) { /* delete the monster currently looked at */
4823 if (p_ptr->health_who <= 0) {//target_who
4824 msg_print(Ind, "No monster looked at.");
4825 return; /* no monster targetted */
4826 }
4827 delete_monster_idx(p_ptr->health_who, TRUE);
4828 return;
4829 }
4830 else if(prefix(message, "/cp")){
4831 party_check(Ind);
4832 account_check(Ind);
4833 return;
4834 }
4835 else if (prefix(message, "/geno-level") ||
4836 prefix(message, "/geno"))
4837 {
4838 bool full = (tk);
4839
4840 /* Wipe even if town/wilderness */
4841 if (full) wipe_m_list(&wp);
4842 else wipe_m_list_admin(&wp);
4843
4844 msg_format(Ind, "\377r%sMonsters on %s are cleared.", full ? "ALL " : "", wpos_format(Ind, &wp));
4845 return;
4846 }
4847 else if (prefix(message, "/vanitygeno") ||
4848 prefix(message, "/vgeno")) {
4849 for (i = m_max - 1; i >= 1; i--) {
4850 monster_type *m_ptr = &m_list[i];
4851
4852 if (!inarea(&m_ptr->wpos, &p_ptr->wpos)) continue;
4853 if (!(r_info[m_ptr->r_idx].flags7 & RF7_NO_DEATH)) continue;
4854
4855 delete_monster_idx(i, TRUE);
4856 }
4857 compact_monsters(0, FALSE);
4858
4859 msg_format(Ind, "\377rVanity monsters on %s are cleared.", wpos_format(Ind, &wp));
4860 return;
4861 }
4862 else if (prefix(message, "/mkill-level") ||
4863 prefix(message, "/mkill"))
4864 {
4865 bool fear, full = (tk);
4866
4867 /* Kill all the monsters */
4868 for (i = m_max - 1; i >= 1; i--) {
4869 monster_type *m_ptr = &m_list[i];
4870 if (!inarea(&m_ptr->wpos, &p_ptr->wpos)) continue;
4871 fear = FALSE;
4872 if (tk) mon_take_hit(Ind, i, m_ptr->hp + 1, &fear, " dies from a bolt from the blue");
4873 else monster_death(Ind, i);
4874 }
4875 if (full) wipe_m_list(&wp);
4876 else wipe_m_list_admin(&wp);
4877 msg_format(Ind, "\377r%sMonsters on %s were killed.", full ? "ALL " : "", wpos_format(Ind, &p_ptr->wpos));
4878 return;
4879 }
4880 else if (prefix(message, "/mgeno")) { /* remove the monster currently looked at (NOT the one targetted) - C. Blue */
4881 if (p_ptr->health_who <= 0) {//target_who
4882 msg_print(Ind, "No monster looked at.");
4883 return; /* no monster targetted */
4884 }
4885 delete_monster_idx(p_ptr->health_who, TRUE);
4886 return;
4887 }
4888 else if (prefix(message, "/game")){
4889 if (!tk) {
4890 msg_print(Ind, "Usage: /game stop or /game rugby");
4891 return;
4892 } else if (!strcmp(token[1], "rugby")) {
4893 object_type forge;
4894 object_type *o_ptr = &forge;
4895
4896 invcopy(o_ptr, lookup_kind(1, 9));
4897 o_ptr->number = 1;
4898 o_ptr->name1 = 0;
4899 o_ptr->name2 = 0;
4900 o_ptr->name3 = 0;
4901 o_ptr->pval = 0;
4902 o_ptr->level = 1;
4903 (void)inven_carry(Ind, o_ptr);
4904
4905 teamscore[0] = 0;
4906 teamscore[1] = 0;
4907 teams[0] = 0;
4908 teams[1] = 0;
4909 gametype = EEGAME_RUGBY;
4910 msg_broadcast(0, "\377pA new game of rugby has started!");
4911 for (k = 1; k <= NumPlayers; k++)
4912 Players[k]->team = 0;
4913 } else if (!strcmp(token[1], "stop")) { /* stop all games - mikaelh */
4914 char sstr[80];
4915 msg_broadcast(0, "\377pThe game has been stopped!");
4916 snprintf(sstr, MAX_CHARS, "Score: \377RReds: %d \377BBlues: %d", teamscore[0], teamscore[1]);
4917 msg_broadcast(0, sstr);
4918 teamscore[0] = 0;
4919 teamscore[1] = 0;
4920 teams[0] = 0;
4921 teams[1] = 0;
4922 gametype = 0;
4923 for (k = 1; k <= NumPlayers; k++)
4924 Players[k]->team = 0;
4925 }
4926 }
4927 else if (prefix(message, "/unstatic-level") ||
4928 prefix(message, "/unst")) {
4929 /* no sanity check, so be warned! */
4930 master_level_specific(Ind, &wp, "u");
4931 // msg_format(Ind, "\377rItems and monsters on %dft is cleared.", k * 50);
4932 return;
4933 }
4934 else if (prefix(message, "/treset")) {
4935 struct worldpos wpos;
4936 wpcopy(&wpos, &p_ptr->wpos);
4937 master_level_specific(Ind, &wp, "u");
4938 dealloc_dungeon_level(&wpos);
4939 return;
4940 }
4941 else if (prefix(message, "/static-level") ||
4942 prefix(message, "/stat")) {
4943 /* no sanity check, so be warned! */
4944 master_level_specific(Ind, &wp, "s");
4945 // msg_format(Ind, "\377rItems and monsters on %dft is cleared.", k * 50);
4946 return;
4947 }
4948 /* TODO: make this player command (using spells, scrolls etc) */
4949 else if (prefix(message, "/identify") ||
4950 prefix(message, "/id")) {
4951 identify_pack(Ind);
4952
4953 /* Combine the pack */
4954 p_ptr->notice |= (PN_COMBINE);
4955
4956 /* Window stuff */
4957 p_ptr->window |= (PW_INVEN | PW_EQUIP);
4958
4959 return;
4960 }
4961 else if (prefix(message, "/sartifact") ||
4962 prefix(message, "/sart")) {
4963 if (k) {
4964 if (a_info[k].cur_num) {
4965 a_info[k].cur_num = 0;
4966 a_info[k].known = FALSE;
4967 msg_format(Ind, "Artifact %d is now \377Gfindable\377w.", k);
4968 } else {
4969 a_info[k].cur_num = 1;
4970 a_info[k].known = TRUE;
4971 msg_format(Ind, "Artifact %d is now \377runfindable\377w.", k);
4972 }
4973 }
4974 else if (tk > 0 && prefix(token[1], "show")) {
4975 int count = 0;
4976 for (i = 0; i < MAX_A_IDX ; i++) {
4977 if (!a_info[i].cur_num || a_info[i].known) continue;
4978
4979 a_info[i].known = TRUE;
4980 count++;
4981 }
4982 msg_format(Ind, "%d 'found but unknown' artifacts are set as '\377Gknown\377w'.", count);
4983 } else if (tk > 0 && prefix(token[1], "fix")) {
4984 int count = 0;
4985 for (i = 0; i < MAX_A_IDX ; i++) {
4986 if (!a_info[i].cur_num || a_info[i].known) continue;
4987
4988 a_info[i].cur_num = 0;
4989 count++;
4990 }
4991 msg_format(Ind, "%d 'found but unknown' artifacts are set as '\377rfindable\377w'.", count);
4992 } else if (tk > 0 && prefix(token[1], "hack")) {
4993 int count = 0;
4994 for (i = 0; i < MAX_A_IDX ; i++) {
4995 if (!a_info[i].cur_num || !a_info[i].known) continue;
4996
4997 a_info[i].known = TRUE;
4998 count++;
4999 }
5000 msg_format(Ind, "%d 'found but unknown' artifacts are set as '\377yknown\377w'.", count);
5001 }
5002 // else if (tk > 0 && strchr(token[1],'*'))
5003 else if (tk > 0 && prefix(token[1], "reset!")) {
5004 for (i = 0; i < MAX_A_IDX ; i++) {
5005 a_info[i].cur_num = 0;
5006 a_info[i].known = FALSE;
5007 }
5008 msg_print(Ind, "All the artifacts are \377Gfindable\377w!");
5009 } else if (tk > 0 && prefix(token[1], "ban!")) {
5010 for (i = 0; i < MAX_A_IDX ; i++) {
5011 a_info[i].cur_num = 1;
5012 a_info[i].known = TRUE;
5013 }
5014 msg_print(Ind, "All the artifacts are \377runfindable\377w!");
5015 } else {
5016 msg_print(Ind, "Usage: /sartifact (No. | (show | fix | reset! | ban!)");
5017 }
5018 return;
5019 }
5020 else if (prefix(message, "/uniques"))
5021 {
5022 monster_race *r_ptr;
5023 if (!tk) {
5024 msg_print(Ind, "Usage: /uniques (seen | unseen | kill | nonkill)");
5025 return;
5026 }
5027 if (prefix(token[tk], "unseen")) {
5028 for (i = 0; i < MAX_R_IDX - 1 ; i++) {
5029 r_ptr = &r_info[i];
5030 if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;
5031 r_ptr->r_sights = 0;
5032 }
5033 msg_print(Ind, "All the uniques are set as '\377onot seen\377'.");
5034 } else if (prefix(token[tk], "nonkill")) {
5035 monster_race *r_ptr;
5036 for (i = 0; i < MAX_R_IDX - 1 ; i++) {
5037 r_ptr = &r_info[i];
5038 if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;
5039 r_ptr->r_tkills = 0;
5040 }
5041 msg_print(Ind, "All the uniques are set as '\377onever killed\377'.");
5042 } else if (prefix(token[tk], "seen")) {
5043 for (i = 0; i < MAX_R_IDX - 1 ; i++) {
5044 r_ptr = &r_info[i];
5045 if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;
5046 r_ptr->r_sights = 1;
5047 }
5048 msg_print(Ind, "All the uniques are set as '\377oseen\377'.");
5049 } else if (prefix(token[tk], "kill")) {
5050 monster_race *r_ptr;
5051 for (i = 0; i < MAX_R_IDX - 1 ; i++) {
5052 r_ptr = &r_info[i];
5053 if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;
5054 r_ptr->r_tkills = 1;
5055 }
5056 msg_print(Ind, "All the uniques are set as '\377okilled\377'.");
5057 }
5058 return;
5059 }
5060 else if (prefix(message, "/unidisable")) {
5061 if (k) {
5062 if (!(r_info[k].flags1 & RF1_UNIQUE)) return;
5063 if (r_info[k].max_num) {
5064 r_info[k].max_num = 0;
5065 msg_format(Ind, "(%d) %s is now \377runfindable\377w.", k, r_name + r_info[k].name);
5066 } else {
5067 r_info[k].max_num = 1;
5068 msg_format(Ind, "(%d) %s is now \377Gfindable\377w.", k, r_name + r_info[k].name);
5069 }
5070 } else {
5071 msg_print(Ind, "Usage: /unidisable <monster_index>");
5072 }
5073 return;
5074 }
5075 else if (prefix(message, "/uniunkill")) {
5076 if (k) {
5077 if (!(r_info[k].flags1 & RF1_UNIQUE)) {
5078 msg_print(Ind, "That's not a unique monster.");
5079 return;
5080 }
5081 if (!r_info[k].r_tkills) {
5082 msg_print(Ind, "That unique is already at zero kill count.");
5083 return;
5084 }
5085 r_info[k].r_tkills = 0;
5086 msg_format(Ind, "(%d) %s kill count reset to \377G0\377w.", k, r_name + r_info[k].name);
5087 } else {
5088 msg_print(Ind, "Usage: /uniunkill <monster_index>");
5089 }
5090 return;
5091 }
5092 else if (prefix(message, "/unicheck")) {
5093 if (!k || !(r_info[k].flags1 & RF1_UNIQUE)) {
5094 msg_print(Ind, "Usage: /unicheck <unique_monster_index>");
5095 return;
5096 }
5097 msg_format(Ind, "(%d) %s has cur_num/max_num of %d/%d.",
5098 k, r_name + r_info[k].name, r_info[k].cur_num, r_info[k].max_num);
5099 return;
5100 }
5101 else if (prefix(message, "/unifix")) {
5102 if (!k || !(r_info[k].flags1 & RF1_UNIQUE)) {
5103 msg_print(Ind, "Usage: /unifix <unique_monster_index>");
5104 return;
5105 }
5106 if (!r_info[k].max_num) {
5107 r_info[k].max_num = 1;
5108 msg_print(Ind, "Max num was 0 and is now set to 1.");
5109 if (!r_info[k].cur_num) return;
5110 } else if (!r_info[k].cur_num) {
5111 msg_print(Ind, "That monster is already at zero cur_num count.");
5112 return;
5113 }
5114 for (i = 1; i < m_max; i++)
5115 if (m_list[i].r_idx == k) {
5116 msg_print(Ind, "That monster is currently spawned!");
5117 return;
5118 }
5119 r_info[k].cur_num = 0;
5120 msg_format(Ind, "(%d) %s has been set to zero cur_num.", k, r_name + r_info[k].name);
5121 return;
5122 }
5123 else if (prefix(message, "/curnumcheck")) {
5124 int i;
5125 bool uniques_only = (tk);
5126
5127 /* First set all to zero */
5128 for (i = 0; i < MAX_R_IDX; i++) {
5129 if (uniques_only && !(r_info[i].flags1 & RF1_UNIQUE)) continue;
5130 j = 0;
5131 /* Now count how many monsters there are of each race */
5132 for (k = 0; k < m_max; k++)
5133 if (m_list[k].r_idx == i) j++;
5134 if (r_info[i].cur_num != j)
5135 msg_format(Ind, "(%d) %s mismatch: cur_num %d, real %d.",
5136 i, r_name + r_info[i].name, r_info[i].cur_num, j);
5137 }
5138
5139 msg_print(Ind, "done.");
5140 return;
5141 }
5142 else if (prefix(message, "/curnumfix")) {
5143 /* Fix r_info[i].cur_num counts */
5144 int i;
5145 bool uniques_only = (tk);
5146
5147 /* First set all to zero */
5148 for (i = 0; i < MAX_R_IDX; i++) {
5149 if (uniques_only && !(r_info[i].flags1 & RF1_UNIQUE)) continue;
5150 r_info[i].cur_num = 0;
5151 }
5152
5153 /* Now count how many monsters there are of each race */
5154 for (i = 1; i < m_max; i++) {
5155 if (m_list[i].r_idx && (!uniques_only || (r_info[i].flags1 & RF1_UNIQUE))) {
5156 r_info[m_list[i].r_idx].cur_num++;
5157 }
5158 }
5159
5160 msg_format(Ind, "cur_num fields fixed for all %s.", uniques_only ? "uniques" : "monsters");
5161 return;
5162 }
5163 else if (prefix(message, "/reload-config") ||
5164 prefix(message, "/cfg")) {
5165 if (tk) {
5166 if (MANGBAND_CFG != NULL) string_free(MANGBAND_CFG);
5167 MANGBAND_CFG = string_make(token[1]);
5168 }
5169
5170 // msg_print(Ind, "Reloading server option(tomenet.cfg).");
5171 msg_format(Ind, "Reloading server option(%s).", MANGBAND_CFG);
5172
5173 /* Reload the server preferences */
5174 load_server_cfg();
5175 return;
5176 }
5177 /* Admin wishing :)
5178 * TODO: better parser like
5179 * /wish 21 8 a117 d40
5180 * for Aule {40% off}
5181 */
5182 #ifndef FUN_SERVER /* disabled while server is being exploited */
5183 else if (prefix(message, "/wish"))
5184 {
5185 object_type forge;
5186 object_type *o_ptr = &forge;
5187 WIPE(o_ptr, object_type);
5188
5189 if (tk < 1 || !k) {
5190 msg_print(Ind, "\377oUsage: /wish (tval) (sval) (pval) [discount] [name] [name2b] --or /wish (o_idx)");
5191 return;
5192 }
5193
5194 invcopy(o_ptr, tk > 1 ? lookup_kind(k, atoi(token[2])) : k);
5195
5196 /* Wish arts out! */
5197 if (tk > 4) {
5198 int nom = atoi(token[5]);
5199 o_ptr->number = 1;
5200
5201 if (nom == ART_RANDART) { /* see defines.h */
5202 /* Piece together a 32-bit random seed */
5203 o_ptr->name1 = ART_RANDART;
5204 o_ptr->name3 = rand_int(0xFFFF) << 16;
5205 o_ptr->name3 += rand_int(0xFFFF);
5206 } else if (nom > 0) {
5207 o_ptr->name1 = nom;
5208 handle_art_inum(o_ptr->name1);
5209 } else if (nom < 0) {
5210 /* It's ego or randarts */
5211 o_ptr->name2 = 0 - nom;
5212 if (tk > 5) o_ptr->name2b = 0 - atoi(token[6]);
5213
5214 /* Piece together a 32-bit random seed */
5215 o_ptr->name3 = rand_int(0xFFFF) << 16;
5216 o_ptr->name3 += rand_int(0xFFFF);
5217 }
5218 } else {
5219 o_ptr->number = o_ptr->weight > 100 ? 2 : 99;
5220 }
5221
5222 // apply_magic(&p_ptr->wpos, o_ptr, -1, !o_ptr->name2, TRUE, TRUE, FALSE, RESF_NONE);
5223 apply_magic(&p_ptr->wpos, o_ptr, -1, !o_ptr->name2, o_ptr->name1 || o_ptr->name2, o_ptr->name1 || o_ptr->name2, FALSE, RESF_NONE);
5224 if (tk > 3) o_ptr->discount = atoi(token[4]);
5225 else o_ptr->discount = 100;
5226 object_known(o_ptr);
5227 o_ptr->owner = 0;
5228 if (tk > 2)
5229 o_ptr->pval = atoi(token[3]);
5230 //o_ptr->owner = p_ptr->id;
5231 o_ptr->level = 1;
5232 (void)inven_carry(Ind, o_ptr);
5233
5234 return;
5235 }
5236 #endif
5237 else if (prefix(message, "/trap"))// || prefix(message, "/tr")) conflicts with /trait maybe
5238 {
5239 if (k) {
5240 wiz_place_trap(Ind, k);
5241 } else {
5242 wiz_place_trap(Ind, TRAP_OF_FILLING);
5243 }
5244 return;
5245 }
5246 else if (prefix(message, "/enlight") ||
5247 prefix(message, "/en"))
5248 {
5249 wiz_lite(Ind);
5250 (void)detect_treasure(Ind, DEFAULT_RADIUS * 2);
5251 (void)detect_object(Ind, DEFAULT_RADIUS * 2);
5252 (void)detect_sdoor(Ind, DEFAULT_RADIUS * 2);
5253 (void)detect_trap(Ind, DEFAULT_RADIUS * 2);
5254 if (k)
5255 {
5256 // (void)detect_trap(Ind);
5257 identify_pack(Ind);
5258 self_knowledge(Ind);
5259
5260 /* Combine the pack */
5261 p_ptr->notice |= (PN_COMBINE);
5262
5263 /* Window stuff */
5264 p_ptr->window |= (PW_INVEN | PW_EQUIP);
5265 }
5266
5267 return;
5268 }
5269 else if (prefix(message, "/wizlitex")) {
5270 wiz_lite_extra(Ind);
5271 return;
5272 }
5273 else if (prefix(message, "/wizlite")) {
5274 wiz_lite(Ind);
5275 return;
5276 }
5277 else if (prefix(message, "/wizdark")) {
5278 wiz_dark(Ind);
5279 return;
5280 }
5281 else if (prefix(message, "/equip") ||
5282 prefix(message, "/eq"))
5283 {
5284 if (tk) admin_outfit(Ind, k);
5285 // else admin_outfit(Ind, -1);
5286 else {
5287 msg_print(Ind, "usage: /eq (realm no.)");
5288 msg_print(Ind, " Mage(0) Pray(1) sorc(2) fight(3) shad(4) hunt(5) psi(6) None(else)");
5289 }
5290 p_ptr->au = 50000000;
5291 p_ptr->skill_points = 9999;
5292 return;
5293 }
5294 else if (prefix(message, "/uncurse") ||
5295 prefix(message, "/unc")) {
5296 remove_all_curse(Ind);
5297 return;
5298 }
5299 /* do a wilderness cleanup */
5300 else if (prefix(message, "/purgewild")) {
5301 msg_format(Ind, "previous server status: m_max(%d) o_max(%d)",
5302 m_max, o_max);
5303 compact_monsters(0, TRUE);
5304 compact_objects(0, TRUE);
5305 // compact_traps(0, TRUE);
5306 msg_format(Ind, "current server status: m_max(%d) o_max(%d)",
5307 m_max, o_max);
5308
5309 return;
5310 }
5311 /* Refresh stores
5312 * XXX very slow */
5313 else if (prefix(message, "/store")) {
5314 if (tk && token[1][0] == 'f') {
5315 int i;
5316 for (i = 0; i < 10; i++) /* MAX_MAINTENANCES [10] */
5317 store_turnover();
5318 } else store_turnover();
5319
5320 if (tk && prefix(token[1], "owner")) {
5321 for (i = 0; i < numtowns; i++) {
5322 // for (k = 0; k < MAX_BASE_STORES - 2; k++)
5323 for (k = 0; k < max_st_idx; k++) {
5324 /* Shuffle a random shop (except home and auction house) */
5325 store_shuffle(&town[i].townstore[k]);
5326 }
5327 }
5328 msg_print(Ind, "\377oStore owners had been changed!");
5329 }
5330 else msg_print(Ind, "\377GStore inventory had been changed.");
5331
5332 return;
5333 }
5334 #if 0
5335 /* Empty a store */
5336 else if (prefix(message, "/stnew"))
5337 {
5338 if (!k) {
5339 msg_print(Ind, "\377oUsage: /stnew <store#>");
5340 return;
5341 }
5342 for (i = 0; i < numtowns; i++) {
5343 int what, num;
5344 object_type *o_ptr;
5345 store_type *st_ptr;
5346
5347 st_ptr = &town[i].townstore[k];
5348 /* Pick a random slot */
5349 what = rand_int(st_ptr->stock_num);
5350 /* Determine how many items are here */
5351 o_ptr = &st_ptr->stock[what];
5352 num = o_ptr->number;
5353
5354 store_item_increase(st_ptr, what, -num);
5355 store_item_optimize(st_ptr, what);
5356 st_ptr->stock[what].num = 0;
5357 }
5358 msg_print(Ind, "\377oStores were emptied!");
5359 return;
5360 }
5361 #endif
5362 /* take 'cheezelog'
5363 * result is output to the logfile */
5364 else if (prefix(message, "/cheeze")) {
5365 char path[MAX_PATH_LENGTH];
5366 object_type *o_ptr;
5367 for (i = 0; i < o_max; i++) {
5368 o_ptr = &o_list[i];
5369 cheeze(o_ptr);
5370 }
5371
5372 cheeze_trad_house();
5373
5374 path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_DATA, "tomenet.log");
5375 do_cmd_check_other_prepare(Ind, path, "Log File");
5376 return;
5377 }
5378 /* Respawn monsters on the floor
5379 * TODO: specify worldpos to respawn */
5380 else if (prefix(message, "/respawn")) {
5381 /* Set the monster generation depth */
5382 monster_level = getlevel(&p_ptr->wpos);
5383 msg_format(Ind, "Respawning monsters of level %d here.", monster_level);
5384 if (p_ptr->wpos.wz) alloc_monster(&p_ptr->wpos, MAX_SIGHT + 5, FALSE);
5385 else wild_add_monster(&p_ptr->wpos);
5386 return;
5387 }
5388 else if (prefix(message, "/log_u")) {
5389 if (tk) {
5390 if (!strcmp(token[1], "on")) {
5391 msg_print(Ind, "log_u is now on");
5392 cfg.log_u = TRUE;
5393 return;
5394 } else if (!strcmp(token[1], "off")) {
5395 msg_print(Ind, "log_u is now off");
5396 cfg.log_u = FALSE;
5397 return;
5398 } else {
5399 msg_print(Ind, "valid parameters are 'on' or 'off'");
5400 return;
5401 }
5402 }
5403 if (cfg.log_u) msg_print(Ind, "log_u is on");
5404 else msg_print(Ind, "log_u is off");
5405 return;
5406 }
5407 else if (prefix(message, "/noarts")) {
5408 if (tk) {
5409 if(!strcmp(token[1], "on")) {
5410 msg_print(Ind, "artifact generation is now supressed");
5411 cfg.arts_disabled = TRUE;
5412 return;
5413 } else if(!strcmp(token[1], "off")) {
5414 msg_print(Ind, "artifact generation is now back to normal");
5415 cfg.arts_disabled = FALSE;
5416 return;
5417 } else {
5418 msg_print(Ind, "valid parameters are 'on' or 'off'");
5419 return;
5420 }
5421 }
5422 if (cfg.arts_disabled) msg_print(Ind, "artifact generation is currently supressed");
5423 else msg_print(Ind, "artifact generation is currently allowed");
5424 return;
5425 }
5426 #if 0 //not implemented
5427 /* C. Blue's mad debug code to swap Minas Anor and Khazad-Dum on the worldmap :) */
5428 else if (prefix(message, "/swap-towns")) {
5429 int a = tk, b = atoi(token[2]);
5430 int x, y;
5431 struct worldpos wpos1, wpos2;
5432
5433 if (tk < 2) {
5434 msg_print(Ind, "Usage: /swap-towns <town1> <town2>");
5435 return;
5436 }
5437 if (a < 0 || a >= numtowns || b < 0 || b >= numtowns) {
5438 msg_format(Ind, "Town numbers may range from 0 to %d.", numtowns - 1);
5439 return;
5440 }
5441
5442 wpos1.wx = town[a].x;
5443 wpos1.wy = town[a].y;
5444 wpos1.wz = 0;
5445 wpos2.wx = town[b].x;
5446 wpos2.wy = town[b].y;
5447 wpos2.wz = 0;
5448
5449 #if 0
5450 for (x = wpos1.wx - wild_info[wpos1.wy][wpos1.wx].radius;
5451 x <= wpos1.wx + wild_info[wpos1.wy][wpos1.wx].radius; x++)
5452 for (y = wpos1.wy - wild_info[wpos1.wy][wpos1.wx].radius;
5453 y <= wpos1.wy + wild_info[wpos1.wy][wpos1.wx].radius; y++)
5454 if (in_bounds_wild(y, x) && (towndist(x, y) <= abs(wpos1.wx - x) + abs(wpos1.wy - y))) {
5455 wild_info[wpos1.wy][wpos1.wx].radius = towndist(wpos1.wy, wpos1.wx);
5456 wild_info[wpos1.wy][wpos1.wx].town_idx = wild_gettown(wpos1.wx, wpos1.wy);
5457 }
5458 #endif
5459
5460 wild_info[wpos1.wy][wpos1.wx].type = WILD_UNDEFINED; /* re-generate */
5461 wild_info[wpos1.wy][wpos1.wx].radius = towndist(wpos1.wy, wpos1.wx);
5462 wild_info[wpos1.wy][wpos1.wx].town_idx = wild_gettown(wpos1.wx, wpos1.wy);
5463
5464 wild_info[wpos2.wy][wpos2.wx].type = WILD_UNDEFINED; /* re-generate */
5465 wild_info[wpos2.wy][wpos2.wx].radius = towndist(wpos2.wy, wpos2.wx);
5466 wild_info[wpos2.wy][wpos2.wx].town_idx = wild_gettown(wpos2.wx, wpos2.wy);
5467
5468 // wilderness_gen(&wpos1);
5469 // wilderness_gen(&wpos2);
5470
5471 town[numtowns].x = x;
5472 town[numtowns].y = y;
5473 town[numtowns].baselevel = base;
5474 town[numtowns].flags = flags;
5475 town[numtowns].type = type;
5476 wild_info[y][x].type = WILD_TOWN;
5477 wild_info[y][x].town_idx = numtowns;
5478 wild_info[y][x].radius = base;
5479
5480 addtown(y1, x1, town_profile[b + 1].dun_base, 0, b + 1);
5481 addtown(y2, x2, town_profile[a + 1].dun_base, 0, a + 1);
5482 return;
5483 }
5484 #endif
5485 else if (prefix(message, "/debug-towns")){
5486 msg_format(Ind, "numtowns = %d", numtowns);
5487 for (i = 0; i < numtowns; i++) {
5488 msg_format(Ind, "%d: type = %d, x = %d, y = %d",
5489 i, town[i].type, town[i].x, town[i].y);
5490 }
5491 return;
5492 }
5493 /* manually reposition dungeon/tower stairs - C. Blue */
5494 else if (prefix(message, "/move-stair")){
5495 int scx, scy;
5496 worldpos *tpos = &p_ptr->wpos;
5497 cave_type **zcave = getcave(tpos);
5498 if (!(zcave = getcave(tpos))) return;
5499
5500 if (!tk) {
5501 msg_print(Ind, "Usage: /move-stair dun|tow");
5502 }
5503
5504 for (scx = 0; scx < MAX_WID; scx++) {
5505 for (scy = 0;scy < MAX_HGT; scy++) {
5506 if (zcave[scy][scx].feat == FEAT_MORE && !strcmp(token[1], "dun")) {
5507 if (wild_info[tpos->wy][tpos->wx].dungeon) {
5508 zcave[scy][scx].feat = FEAT_FLOOR;
5509 new_level_up_y(tpos, p_ptr->py);
5510 new_level_up_x(tpos, p_ptr->px);
5511 zcave[p_ptr->py][p_ptr->px].feat = FEAT_MORE;
5512 return;
5513 }
5514 }
5515 if (zcave[scy][scx].feat == FEAT_LESS && !strcmp(token[1], "tow")) {
5516 if (wild_info[tpos->wy][tpos->wx].tower) {
5517 zcave[scy][scx].feat = FEAT_FLOOR;
5518 new_level_down_y(tpos, p_ptr->py);
5519 new_level_down_x(tpos, p_ptr->px);
5520 zcave[p_ptr->py][p_ptr->px].feat = FEAT_LESS;
5521 return;
5522 }
5523 }
5524 }
5525 }
5526 msg_print(Ind, "No staircase downwards found.");
5527 return;
5528 }
5529 /* catch problematic stair coords everywhere */
5530 else if (prefix(message, "/debug-stairs")) {
5531 int wx, wy, x, y, xo, yo;
5532 struct worldpos tpos;
5533 bool always_relocate_x = FALSE, always_relocate_y = FALSE, personal_relocate = FALSE;
5534
5535 if (tk) personal_relocate = TRUE;
5536 if (tk && token[0][0] != 'y') always_relocate_x = TRUE;
5537 if (tk && token[0][0] != 'x') always_relocate_y = TRUE;
5538
5539 tpos.wz = 0;
5540 for (wx = 0; wx < MAX_WILD_X; wx++) {
5541 for (wy = 0; wy < MAX_WILD_Y; wy++) {
5542 if (personal_relocate && (wx != p_ptr->wpos.wx || wy != p_ptr->wpos.wy)) continue;
5543
5544 tpos.wx = wx;
5545 tpos.wy = wy;
5546 if (wild_info[wy][wx].dungeon) {
5547 xo = wild_info[wy][wx].up_x;
5548 yo = wild_info[wy][wx].up_y;
5549 if (xo < 2 || xo >= MAX_WID - 2 || always_relocate_x) {
5550 x = personal_relocate ? p_ptr->px : 2 + rand_int(MAX_WID - 4);
5551 new_level_up_x(&tpos, x);
5552 msg_format(Ind, "Changed '>' x in (%d,%d) from %d to %d.", wx, wy, xo, x);
5553 }
5554 if (yo < 2 || yo >= MAX_HGT - 2 || always_relocate_y) {
5555 y = personal_relocate ? p_ptr->py : 2 + rand_int(MAX_HGT - 4);
5556 new_level_up_y(&tpos, y);
5557 msg_format(Ind, "Changed '>' y in (%d,%d) from %d to %d.", wx, wy, yo, y);
5558 }
5559 }
5560 if (wild_info[wy][wx].tower) {
5561 xo = wild_info[wy][wx].dn_x;
5562 yo = wild_info[wy][wx].dn_y;
5563 if (xo < 2 || xo >= MAX_WID - 2 || always_relocate_x) {
5564 x = personal_relocate ? p_ptr->px : 2 + rand_int(MAX_WID - 4);
5565 new_level_down_x(&tpos, x);
5566 msg_format(Ind, "Changed '<' x in (%d,%d) from %d to %d.", wx, wy, xo, x);
5567 }
5568 if (yo < 2 || yo >= MAX_HGT - 2 || always_relocate_y) {
5569 y = personal_relocate ? p_ptr->py : 2 + rand_int(MAX_HGT - 4);
5570 new_level_down_y(&tpos, y);
5571 msg_format(Ind, "Changed '<' y in (%d,%d) from %d to %d.", wx, wy, yo, y);
5572 }
5573 }
5574
5575 if (personal_relocate) return;
5576 }
5577 }
5578 return;
5579 }
5580 else if (prefix(message, "/debug-dun")){
5581 struct dungeon_type *d_ptr;
5582 worldpos *tpos = &p_ptr->wpos;
5583 wilderness_type *wild = &wild_info[tpos->wy][tpos->wx];
5584 cave_type **zcave, *c_ptr;
5585
5586 if (!(zcave = getcave(tpos))) {
5587 msg_print(Ind, "Fatal: Couldn't acquire zcave!");
5588 return;
5589 }
5590 c_ptr = &zcave[p_ptr->py][p_ptr->px];
5591 if (c_ptr->feat != FEAT_LESS && c_ptr->feat != FEAT_MORE) {
5592 msg_print(Ind, "Error: Not standing on a staircase grid.");
5593 return;
5594 }
5595
5596 if (c_ptr->feat == FEAT_LESS) d_ptr = wild->tower;
5597 else d_ptr = wild->dungeon;
5598
5599 msg_print(Ind, "Dungeon stats:");
5600 msg_format(Ind, " type %d, baselevel %d, maxdepth %d (endlevel %d)", d_ptr->type, d_ptr->baselevel, d_ptr->maxdepth, d_ptr->baselevel + d_ptr->maxdepth - 1);
5601 msg_format(Ind, " flags1 %08x, flags2 %08x, flags3 %08x", d_ptr->flags1, d_ptr->flags2, d_ptr->flags3);
5602
5603 return;
5604 }
5605 else if (prefix(message, "/update-dun")){
5606 /* Reloads dungeon flags from d_info.txt, updating existing
5607 dungeons. Note that you have to call this after you made changes
5608 to d_info.txt, since dungeons will NOT update automatically.
5609 Syntax: /debug-dun updates dungeon on current worldmap sector.
5610 /debug-dun * updates ALL dungeons. - C. Blue */
5611 int type, x, y, pos_tmp;
5612 #ifdef RPG_SERVER
5613 bool found_town = FALSE;
5614 #endif
5615 struct dungeon_type *d_ptr, dun_tmp;
5616 struct worldpos *tpos = &p_ptr->wpos;
5617 wilderness_type *wild = &wild_info[tpos->wy][tpos->wx];
5618
5619 /* more mad code to change RPG_SERVER dungeon flags.. */
5620 for(x = 0; x < (tk ? 64 : 1); x++)
5621 for(y = 0; y < (tk ? 64 : 1); y++) {
5622 if (!tk) {tpos = &p_ptr->wpos;}
5623 else {tpos->wx = x; tpos->wy = y; tpos->wz = 0;}
5624 wild = &wild_info[tpos->wy][tpos->wx];
5625
5626 if ((d_ptr = wild->tower)) {
5627 type = d_ptr->type;
5628
5629 if (type) {
5630 d_ptr->flags1 = d_info[type].flags1;
5631 d_ptr->flags2 = d_info[type].flags2 | DF2_RANDOM;
5632 d_ptr->flags3 = d_info[type].flags3;
5633 d_ptr->baselevel = d_info[type].mindepth;
5634 d_ptr->maxdepth = d_info[type].maxdepth - d_ptr->baselevel + 1;
5635
5636 /* check for TOWER flag change! */
5637 if (!(d_ptr->flags1 & DF1_TOWER)) {
5638 /* also a dungeon here? need to swap them, so it isn't lost.
5639 (We assume that likewise that dungeon was actually changed to be a tower,
5640 since it'd be illegal to have 2 dungeons or 2 towers on the same sector.) */
5641 if (wild->dungeon) {
5642 /* simply swap the contents */
5643 dun_tmp = *(wild->tower);
5644 *(wild->tower) = *(wild->dungeon);
5645 *(wild->dungeon) = dun_tmp;
5646
5647 pos_tmp = wild->dn_x;
5648 wild->dn_x = wild->up_x;
5649 wild->up_x = pos_tmp;
5650 pos_tmp = wild->dn_y;
5651 wild->dn_y = wild->up_y;
5652 wild->up_y = pos_tmp;
5653 } else {
5654 /* change tower to dungeon */
5655 wild->dungeon = wild->tower;
5656 wild->tower = NULL;
5657 wild->flags |= WILD_F_DOWN;
5658 wild->flags &= ~WILD_F_UP;
5659
5660 wild->dn_x = wild->up_x;
5661 wild->dn_y = wild->up_y;
5662 wild->up_x = 0;//superfluous
5663 wild->up_y = 0;//superfluous
5664 }
5665 }
5666 } else {
5667 #if 0 /* don't touch custom dungeons, that might have flags such as ironman or no-entry etc! their flags would get zero'ed here! */
5668 d_ptr->flags1 = d_info[type].flags1;
5669 d_ptr->flags2 = d_info[type].flags2;
5670 d_ptr->flags3 = d_info[type].flags3;
5671 #else
5672 continue;
5673 #endif
5674 }
5675 //d_ptr->r_char = d_info[type].r_char;
5676 //d_ptr->nr_char = d_info[type].nr_char;
5677
5678 #ifdef RPG_SERVER /* Make towers harder */
5679 // d_ptr->flags2 &= ~(DF2_IRON | DF2_IRONFIX1 | DF2_IRONFIX2 | DF2_IRONFIX3 | DF2_IRONFIX4 |
5680 // DF2_IRONRND1 | DF2_IRONRND2 | DF2_IRONRND3 | DF2_IRONRND4) ; /* Reset flags first */
5681 // if (!(d_info[type].flags1 & DF1_NO_UP)) d_ptr->flags1 &= ~DF1_NO_UP;
5682
5683 if (
5684 #if 0
5685 !(d_ptr->flags2 & DF2_NO_DEATH) &&
5686 #endif
5687 !(d_ptr->flags2 & DF2_IRON)) { /* already Ironman? Don't change it */
5688 found_town = FALSE;
5689 for(i = 0; i < numtowns; i++) {
5690 if(town[i].x == tpos->wx && town[i].y == tpos->wy) {
5691 found_town = TRUE;
5692 if (in_bree(tpos)) {
5693 /* exempt training tower since it might be needed for global events */
5694 continue;
5695
5696 d_ptr->flags2 |= DF2_IRON; /* Barrow-downs only */
5697 } else {
5698 d_ptr->flags2 |= DF2_IRON | DF2_IRONFIX2; /* Other towns */
5699 }
5700 }
5701 }
5702 if (!found_town) {
5703 /* hack - exempt the Shores of Valinor! */
5704 if (d_ptr->baselevel != 200)
5705 d_ptr->flags2 |= DF2_IRON | DF2_IRONRND1; /* Wilderness dungeons */
5706 // d_ptr->flags1 |= DF1_NO_UP; /* Wilderness dungeons */
5707 }
5708 }
5709 #endif
5710 if(tk) msg_print(Ind, "Tower flags updated.");
5711 }
5712
5713 if ((d_ptr = wild->dungeon)) {
5714 type = d_ptr->type;
5715
5716 if (type) {
5717 d_ptr->flags1 = d_info[type].flags1;
5718 d_ptr->flags2 = d_info[type].flags2 | DF2_RANDOM;
5719 d_ptr->flags3 = d_info[type].flags3;
5720 d_ptr->baselevel = d_info[type].mindepth;
5721 d_ptr->maxdepth = d_info[type].maxdepth - d_ptr->baselevel + 1;
5722
5723 /* check for TOWER flag change! */
5724 if ((d_ptr->flags1 & DF1_TOWER)) {
5725 /* also a dungeon here? need to swap them, so it isn't lost.
5726 (We assume that likewise that dungeon was actually changed to be a tower,
5727 since it'd be illegal to have 2 dungeons or 2 towers on the same sector.) */
5728 if (wild->tower) {
5729 /* simply swap the contents */
5730 dun_tmp = *(wild->tower);
5731 *(wild->tower) = *(wild->dungeon);
5732 *(wild->dungeon) = dun_tmp;
5733
5734 pos_tmp = wild->dn_x;
5735 wild->dn_x = wild->up_x;
5736 wild->up_x = pos_tmp;
5737 pos_tmp = wild->dn_y;
5738 wild->dn_y = wild->up_y;
5739 wild->up_y = pos_tmp;
5740 } else {
5741 /* change dungeon to tower */
5742 wild->tower = wild->dungeon;
5743 wild->dungeon = NULL;
5744 wild->flags |= WILD_F_UP;
5745 wild->flags &= ~WILD_F_DOWN;
5746
5747 wild->up_x = wild->dn_x;
5748 wild->up_y = wild->dn_y;
5749 wild->dn_x = 0;//superfluous
5750 wild->dn_y = 0;//superfluous
5751 }
5752 }
5753 } else {
5754 #if 0 /* don't touch custom dungeons, that might have flags such as ironman or no-entry etc! their flags would get zero'ed here! */
5755 d_ptr->flags1 = d_info[type].flags1;
5756 d_ptr->flags2 = d_info[type].flags2;
5757 d_ptr->flags3 = d_info[type].flags3;
5758 #else
5759 continue;
5760 #endif
5761 }
5762
5763 #ifdef RPG_SERVER /* Make dungeons harder */
5764 // d_ptr->flags2 &= ~(DF2_IRON | DF2_IRONFIX1 | DF2_IRONFIX2 | DF2_IRONFIX3 | DF2_IRONFIX4 |
5765 // DF2_IRONRND1 | DF2_IRONRND2 | DF2_IRONRND3 | DF2_IRONRND4) ; /* Reset flags first */
5766 // if (!(d_info[type].flags1 & DF1_NO_UP)) d_ptr->flags1 &= ~DF1_NO_UP;
5767 if (
5768 #if 0
5769 !(d_ptr->flags2 & DF2_NO_DEATH) &&
5770 #endif
5771 !(d_ptr->flags2 & DF2_IRON)) { /* already Ironman? Don't change it */
5772 found_town = FALSE;
5773 for(i = 0; i < numtowns; i++) {
5774 if(town[i].x == tpos->wx && town[i].y == tpos->wy) {
5775 found_town = TRUE;
5776 if (in_bree(tpos)) {
5777 d_ptr->flags2 |= DF2_IRON; /* Barrow-downs only */
5778 } else {
5779 d_ptr->flags2 |= DF2_IRON | DF2_IRONFIX2; /* Other towns */
5780 }
5781 }
5782 }
5783 if (!found_town) {
5784 /* hack - exempt the Shores of Valinor! */
5785 if (d_ptr->baselevel != 200)
5786 d_ptr->flags2 |= DF2_IRON | DF2_IRONRND1; /* Wilderness dungeons */
5787 // d_ptr->flags1 |= DF1_NO_UP; /* Wilderness dungeons */
5788 }
5789 }
5790 #endif
5791 if (tk) msg_print(Ind, "Dungeon flags updated.");
5792 }
5793 }
5794 if(!tk) msg_print(Ind, "Dungeon/tower flags updated.");
5795 return;
5796 }
5797 else if (prefix(message, "/swap-dun")) {
5798 /* Move a predefined dungeon (in d_info.txt) to our worldmap sector - C. Blue */
5799 int type, x, y;
5800 struct dungeon_type *d_ptr, *d_ptr_tmp;
5801 wilderness_type *wild, *wild_new;
5802 u32b flags;
5803 bool done = FALSE;
5804 cave_type **zcave;
5805
5806 if (!(zcave = getcave(&p_ptr->wpos))) {
5807 msg_print(Ind, "Fatal: Couldn't acquire zcave!");
5808 return;
5809 }
5810
5811 if (!tk) {
5812 msg_print(Ind, "Usage: /swap-dun <index>");
5813 return;
5814 }
5815 if (!k) {
5816 msg_print(Ind, "Dungeon index cannot be 0.");
5817 return;
5818 }
5819
5820 wild_new = &wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx];
5821
5822 for(x = 0; x < MAX_WILD_X; x++) {
5823 for(y = 0; y < MAX_WILD_Y; y++) {
5824 wild = &wild_info[y][x];
5825
5826 if ((d_ptr = wild->tower)) {
5827 type = d_ptr->type;
5828 if (type == k) {
5829 /* simply swap the tower */
5830 d_ptr_tmp = wild_new->dungeon;
5831 wild_new->dungeon = wild->dungeon;
5832 wild->dungeon = d_ptr_tmp;
5833
5834 flags = (wild_new->flags & WILD_F_UP);
5835 wild->flags &= (~WILD_F_UP);
5836 wild->flags |= (flags & WILD_F_UP);
5837 wild_new->flags |= WILD_F_UP;
5838
5839 wild->dn_x = wild_new->dn_x;
5840 wild->dn_y = wild_new->dn_y;
5841 wild_new->dn_x = p_ptr->px;
5842 wild_new->dn_y = p_ptr->py;
5843 zcave[p_ptr->py][p_ptr->px].feat = FEAT_LESS;
5844
5845 if (d_ptr->id != 0) {
5846 dungeon_x[d_ptr->id] = x;
5847 dungeon_y[d_ptr->id] = y;
5848 }
5849 if (d_ptr->type == DI_NETHER_REALM) {
5850 netherrealm_wpos_x = x;
5851 netherrealm_wpos_y = y;
5852 }
5853 else if (d_ptr->type == DI_VALINOR) {
5854 valinor_wpos_x = x;
5855 valinor_wpos_y = y;
5856 }
5857 else if (d_ptr->type == DI_HALLS_OF_MANDOS) {
5858 hallsofmandos_wpos_x = x;
5859 hallsofmandos_wpos_y = y;
5860 }
5861
5862 msg_format(Ind, "Tower states swapped (%d,%d).", x, y);
5863 done = TRUE;
5864 break;
5865 }
5866 }
5867
5868 if ((d_ptr = wild->dungeon)) {
5869 type = d_ptr->type;
5870 if (type == k) {
5871 /* simply swap the dungeon */
5872 d_ptr_tmp = wild_new->dungeon;
5873 wild_new->dungeon = wild->dungeon;
5874 wild->dungeon = d_ptr_tmp;
5875
5876 flags = (wild_new->flags & WILD_F_DOWN);
5877 wild->flags &= (~WILD_F_DOWN);
5878 wild->flags |= (flags & WILD_F_DOWN);
5879 wild_new->flags |= WILD_F_DOWN;
5880
5881 wild->up_x = wild_new->up_x;
5882 wild->up_y = wild_new->up_y;
5883 wild_new->up_x = p_ptr->px;
5884 wild_new->up_y = p_ptr->py;
5885 zcave[p_ptr->py][p_ptr->px].feat = FEAT_MORE;
5886
5887 if (d_ptr->id != 0) {
5888 dungeon_x[d_ptr->id] = x;
5889 dungeon_y[d_ptr->id] = y;
5890 }
5891 if (d_ptr->type == DI_NETHER_REALM) {
5892 netherrealm_wpos_x = x;
5893 netherrealm_wpos_y = y;
5894 }
5895 else if (d_ptr->type == DI_VALINOR) {
5896 valinor_wpos_x = x;
5897 valinor_wpos_y = y;
5898 }
5899 else if (d_ptr->type == DI_HALLS_OF_MANDOS) {
5900 hallsofmandos_wpos_x = x;
5901 hallsofmandos_wpos_y = y;
5902 }
5903
5904 msg_format(Ind, "Dungeon states swapped (%d,%d).", x, y);
5905 done = TRUE;
5906 break;
5907 }
5908 }
5909 }
5910 if (done) break;
5911 }
5912 msg_print(Ind, "Done.");
5913 return;
5914 }
5915 else if (prefix(message, "/debug-pos")) {
5916 /* C. Blue's mad debug code to change player @
5917 startup positions in Bree (px, py) */
5918 new_level_rand_x(&p_ptr->wpos, atoi(token[1]));
5919 new_level_rand_y(&p_ptr->wpos, atoi(token[2]));
5920 msg_format(Ind, "Set x=%d, y=%d for this wpos.", atoi(token[1]), atoi(token[2]));
5921 return;
5922 }
5923 else if (prefix(message, "/anotes")) {
5924 int notes = 0;
5925 for (i = 0; i < MAX_ADMINNOTES; i++) {
5926 /* search for pending notes of this player */
5927 if (strcmp(admin_note[i], "")) {
5928 /* found a matching note */
5929 notes++;
5930 }
5931 }
5932 if (notes > 0) msg_format(Ind, "\377oAdmins wrote %d currently pending notes:", notes);
5933 else msg_print(Ind, "\377oNo admin wrote any pending note.");
5934 for (i = 0; i < MAX_ADMINNOTES; i++) {
5935 /* search for pending admin notes */
5936 if (strcmp(admin_note[i], "")) {
5937 /* found a matching note */
5938 msg_format(Ind, "\377o(#%d)- %s", i, admin_note[i]);
5939 }
5940 }
5941 return;
5942 }
5943 else if (prefix(message, "/danote")) { /* Delete a global admin note to everyone */
5944 int notes = 0;
5945 if ((tk < 1) || (strlen(message2) < 8)) { /* Explain command usage */
5946 msg_print(Ind, "\377oUse /danote <message index> to delete a message.");
5947 msg_print(Ind, "\377oTo clear all pending notes of yours, type: /danote *");
5948 return;
5949 }
5950 if (message2[8] == '*') {
5951 for (i = 0; i < MAX_ADMINNOTES; i++)
5952 if (strcmp(admin_note[i], "")) {
5953 notes++;
5954 strcpy(admin_note[i], "");
5955 }
5956 msg_format(Ind, "\377oDeleted %d notes.", notes);
5957 } else {
5958 notes = atoi(message2 + 8);
5959 if ((notes > 0) && (notes < MAX_ADMINNOTES)) {
5960 strcpy(admin_note[notes], "");
5961 msg_format(Ind, "\377oDeleted note %d.", notes);
5962 }
5963 }
5964 return;
5965 }
5966 else if (prefix(message, "/anote")) { /* Send a global admin note to everyone */
5967 j = 0;
5968 if (tk < 1) { /* Explain command usage */
5969 msg_print(Ind, "\377oUsage: /anote <text>");
5970 msg_print(Ind, "\377oUse /danote <message index> to delete a message.");
5971 msg_print(Ind, "\377oTo clear all pending notes of yours, type: /danote *");
5972 return;
5973 }
5974 /* Search for begin of parms ( == text of the note) */
5975 for (i = 6; i < (int)strlen(message2); i++)
5976 if (message2[i] == ' ')
5977 for (j = i; j < (int)strlen(message2); j++)
5978 if (message2[j] != ' ') {
5979 /* save start pos in j for latter use */
5980 i = strlen(message2);
5981 break;
5982 }
5983
5984 /* search for free admin note */
5985 for (i = 0; i < MAX_ADMINNOTES; i++) {
5986 if (!strcmp(admin_note[i], "")) {
5987 /* found a free memory spot */
5988 break;
5989 }
5990 }
5991 if (i < MAX_ADMINNOTES) {
5992 /* Add admin note */
5993 strcpy(admin_note[i], &message2[j]);
5994 msg_print(Ind, "\377yNote has been stored.");
5995 } else {
5996 msg_format(Ind, "\377oSorry, the server reached the maximum of %d pending admin notes.", MAX_ADMINNOTES);
5997 }
5998 return;
5999 }
6000 else if (prefix(message, "/broadcast-anotes")) { /* Display all admin notes to all players NOW! :) */
6001 for (i = 0; i < MAX_ADMINNOTES; i++)
6002 if (strcmp(admin_note[i], ""))
6003 msg_broadcast_format(0, "\377sGlobal Admin Note: %s", admin_note[i]);
6004 return;
6005 }
6006 else if (prefix(message, "/swarn")) { /* Send a global server warning everyone */
6007 j = 0;
6008 if (tk < 1) {
6009 strcpy(server_warning, "");
6010 msg_print(Ind, "Server warning has been cleared.");
6011 return;
6012 }
6013 /* Search for begin of parms ( == text of the note) */
6014 for (i = 6; i < (int)strlen(message2); i++)
6015 if (message2[i] == ' ')
6016 for (j = i; j < (int)strlen(message2); j++)
6017 if (message2[j] != ' ') {
6018 /* save start pos in j for latter use */
6019 i = strlen(message2);
6020 break;
6021 }
6022
6023 strcpy(server_warning, &message2[j]);
6024 if (server_warning[0]) msg_broadcast_format(0, "\374\377R*** Note: %s ***", server_warning);
6025 return;
6026 }
6027 else if (prefix(message, "/reart")) /* re-roll a random artifact */
6028 {
6029 object_type *o_ptr;
6030 u32b f1, f2, f3, f4, f5, f6, esp;
6031 int min_pval = -999, min_ap = -999, tries = 10000, min_todam = -999;
6032 bool no_am = FALSE, no_aggr = FALSE;
6033 int th ,td ,ta; //for retaining jewelry properties in case they get inverted by cursing
6034 if (tk < 1 || tk > 6) {
6035 msg_print(Ind, "\377oUsage: /reart <inventory-slot> [+<min pval>] [<min artifact power>] [D<dam>] [A] [R]");
6036 return;
6037 }
6038
6039 if (atoi(token[1]) < 0 || atoi(token[1]) >= INVEN_TOTAL) {
6040 msg_print(Ind, "\377oInvalid inventory slot.");
6041 return;
6042 }
6043
6044 o_ptr = &p_ptr->inventory[atoi(token[1])];
6045 if (o_ptr->name1 != ART_RANDART) {
6046 if (o_ptr->name1) {
6047 msg_print(Ind, "\377oIt's a static art. Aborting.");
6048 return;
6049 } else {
6050 msg_print(Ind, "\377oNot a randart - turning it into one.");
6051 o_ptr->name1 = ART_RANDART;
6052 }
6053 }
6054
6055 for (i = tk; i > 1; i--) {
6056 if (token[i][0] == '+') min_pval = atoi(token[i]);
6057 else if (token[i][0] == 'D') min_todam = atoi(token[i] + 1);
6058 else if (token[i][0] == 'A') no_am = TRUE;
6059 else if (token[i][0] == 'R') no_aggr = TRUE;
6060 else min_ap = atoi(token[i]);
6061 }
6062
6063 if (min_ap > -999 || min_pval > -999 || min_todam > -999 || no_am || no_aggr)
6064 msg_print(Ind, "\377wrerolling for at least..");
6065 if (min_pval > -999)
6066 msg_format(Ind, "\377w +%d pval.", min_pval);
6067 if (min_ap > -999)
6068 msg_format(Ind, "\377w %d ap.", min_ap);
6069 if (min_todam > -999)
6070 msg_format(Ind, "\377w +%d todam.", min_todam);
6071 if (no_am)
6072 msg_print(Ind, "\377w no Anti-Magic Shell.");
6073 if (no_aggr)
6074 msg_print(Ind, "\377w no AGGRAVATE.");
6075
6076
6077 th = o_ptr->to_h; td = o_ptr->to_d; ta = o_ptr->to_a; //for jewelry
6078 #if 0/*no good because on cursing, the stats aren't just inverted but also modified!*/
6079 //hacking around old curses
6080 if (th < 0) th = -th;
6081 if (td < 0) td = -td;
6082 if (ta < 0) ta = -ta;
6083 #endif
6084
6085 while (tries) {
6086 /* Piece together a 32-bit random seed */
6087 o_ptr->name3 = rand_int(0xFFFF) << 16;
6088 o_ptr->name3 += rand_int(0xFFFF);
6089 /* Check the tval is allowed */
6090 if (randart_make(o_ptr) == NULL) {
6091 /* If not, wipe seed. No randart today */
6092 o_ptr->name1 = 0;
6093 o_ptr->name3 = 0L;
6094 msg_print(Ind, "Randart creation failed..");
6095 return;
6096 }
6097 o_ptr->timeout = 0;
6098 apply_magic(&p_ptr->wpos, o_ptr, p_ptr->lev, FALSE, FALSE, FALSE, FALSE, RESF_FORCERANDART | RESF_NOTRUEART | RESF_LIFE);
6099
6100 /* restrictions? */
6101 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
6102 if (FALSE
6103 //|| !(f1 & TR1_VAMPIRIC) || !(f1 & TR1_BLOWS)
6104 //|| !(f3 & TR3_XTRA_MIGHT) || !(f3 & TR3_XTRA_SHOTS)
6105 ) {
6106 tries--;
6107 continue;
6108 }
6109
6110 if (o_ptr->pval >= min_pval &&
6111 artifact_power(randart_make(o_ptr)) >= min_ap &&
6112 o_ptr->to_d >= min_todam &&
6113 (!no_aggr || !(f3 & TR3_AGGRAVATE)) &&
6114 (!no_am || !(f3 & TR3_NO_MAGIC))) break;
6115 tries--;
6116 }
6117 if (!tries) msg_format(Ind, "Re-rolling failed (out of tries (10000))!");
6118 else msg_format(Ind, "Re-rolled randart in inventory slot %d (Tries: %d).", atoi(token[1]), 10000 + 1 - tries);
6119 if (o_ptr->tval == TV_RING || o_ptr->tval == TV_AMULET) {
6120 o_ptr->to_a = ta; o_ptr->to_d = td; o_ptr->to_h = th;
6121 }
6122
6123 o_ptr->ident |= ID_MENTAL; /* *id*ed */
6124 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
6125 return;
6126 }
6127 else if (prefix(message, "/debugart")) /* re-roll a random artifact */
6128 {
6129 object_type *o_ptr;
6130 int tries = 1;
6131
6132 if (atoi(token[1]) < 1 || atoi(token[1]) >= INVEN_TOTAL) {
6133 msg_print(Ind, "\377oInvalid inventory slot.");
6134 return;
6135 }
6136
6137 o_ptr = &p_ptr->inventory[atoi(token[1]) - 1];
6138 if (o_ptr->name1 != ART_RANDART) {
6139 if (o_ptr->name1) {
6140 msg_print(Ind, "\377oIt's a static art. Aborting.");
6141 return;
6142 } else {
6143 msg_print(Ind, "\377oNot a randart - turning it into one.");
6144 o_ptr->name1 = ART_RANDART;
6145 }
6146 }
6147
6148 while (tries < 1000000) {
6149 if (!(tries % 10000)) s_printf("%d, ", tries);
6150 /* Piece together a 32-bit random seed */
6151 o_ptr->name3 = rand_int(0xFFFF) << 16;
6152 o_ptr->name3 += rand_int(0xFFFF);
6153 /* Check the tval is allowed */
6154 if (randart_make(o_ptr) == NULL) {
6155 /* If not, wipe seed. No randart today */
6156 o_ptr->name1 = 0;
6157 o_ptr->name3 = 0L;
6158 msg_print(Ind, "Randart creation failed..");
6159 return;
6160 }
6161 o_ptr->timeout = 0;
6162 apply_magic(&p_ptr->wpos, o_ptr, p_ptr->lev, FALSE, FALSE, FALSE, FALSE, RESF_FORCERANDART | RESF_NOTRUEART);
6163
6164 #ifndef TO_AC_CAP_30
6165 if (o_ptr->to_a > 35) break;
6166 #else
6167 if (o_ptr->to_a > 30) break;
6168 #endif
6169 tries++;
6170 }
6171 if (!tries) msg_format(Ind, "Re-rolling failed, %d tries.", tries);
6172 else msg_format(Ind, "Re-rolled randart in inventory slot %d (Tries: %d).", atoi(token[1]), tries);
6173
6174 o_ptr->ident |= ID_MENTAL; /* *id*ed */
6175 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
6176 return;
6177 }
6178 else if (prefix(message, "/reego")) /* re-roll an ego item */
6179 {
6180 object_type *o_ptr;
6181 if (tk < 1) {
6182 msg_print(Ind, "\377oUsage: /reego <inventory-slot>");
6183 return;
6184 }
6185 if (atoi(token[1]) < 1 || atoi(token[1]) >= INVEN_TOTAL) {
6186 msg_print(Ind, "\377oInvalid inventory slot.");
6187 return;
6188 }
6189 o_ptr = &p_ptr->inventory[atoi(token[1]) - 1];
6190 if (!o_ptr->name2) {
6191 msg_print(Ind, "\377oNot an ego item.");
6192 return;
6193 }
6194
6195 o_ptr->timeout = 0;
6196 return;/* see create_reward for proper loop */
6197 apply_magic(&p_ptr->wpos, o_ptr, p_ptr->lev, TRUE, TRUE, TRUE, FALSE, RESF_NOART);
6198
6199 msg_format(Ind, "Re-rolled ego in inventory slot %d!", atoi(token[1]));
6200 /* Window stuff */
6201 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
6202 return;
6203 }
6204 /* very dangerous if player is poisoned, very weak, or has hp draining */
6205 else if (prefix(message, "/threaten") || prefix(message, "/thr")) { /* Nearly kill someone, as threat >:) */
6206 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6207 if (!tk) {
6208 msg_print(Ind, "Usage: /threaten <player name>");
6209 return;
6210 }
6211 if (!j) return;
6212 msg_format(Ind, "\377yThreatening %s.", Players[j]->name);
6213 msg_format_near(j, "\377y%s is hit by a bolt from the blue!", Players[j]->name);
6214 msg_print(j, "\377rYou are hit by a bolt from the blue!");
6215 bypass_invuln = TRUE;
6216 take_hit(j, Players[j]->chp - 1, "", 0);
6217 bypass_invuln = FALSE;
6218 msg_print(j, "\377rThat was close huh?!");
6219 return;
6220 }
6221 else if (prefix(message, "/aslap")) { /* Slap someone around, as threat :-o */
6222 if (!tk) {
6223 msg_print(Ind, "Usage: /aslap <player name>");
6224 return;
6225 }
6226 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6227 if (!j) return;
6228 #ifdef USE_SOUND_2010
6229 sound_near_site(Players[j]->py, Players[j]->px, &p_ptr->wpos, 0, "slap", "", SFX_TYPE_COMMAND, TRUE);
6230 #endif
6231 msg_format(Ind, "\377ySlapping %s.", Players[j]->name);
6232 msg_print(j, "\377rYou are slapped by something invisible!");
6233 msg_format_near(j, "\377y%s is slapped by something invisible!", Players[j]->name);
6234 bypass_invuln = TRUE;
6235 take_hit(j, Players[j]->chp / 2, "", 0);
6236 bypass_invuln = FALSE;
6237 return;
6238 }
6239 else if (prefix(message, "/apat")) { /* Counterpart to /slap :-p */
6240 if (!tk) {
6241 msg_print(Ind, "Usage: /apat <player name>");
6242 return;
6243 }
6244 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6245 if (!j) return;
6246 msg_format(Ind, "\377yPatting %s.", Players[j]->name);
6247 msg_print(j, "\377yYou are patted by something invisible.");
6248 msg_format_near(j, "\377y%s is patted by something invisible.", Players[j]->name);
6249 return;
6250 }
6251 else if (prefix(message, "/ahug")) { /* Counterpart to /slap :-p */
6252 if (!tk) {
6253 msg_print(Ind, "Usage: /ahug <player name>");
6254 return;
6255 }
6256 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6257 if (!j) return;
6258 msg_format(Ind, "\377yHugging %s.", Players[j]->name);
6259 msg_print(j, "\377yYou are hugged by something invisible.");
6260 msg_format_near(j, "\377y%s is hugged by something invisible.", Players[j]->name);
6261 return;
6262 }
6263 else if (prefix(message, "/apoke")) {
6264 if (!tk) {
6265 msg_print(Ind, "Usage: /apoke <player name>");
6266 return;
6267 }
6268 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6269 if (!j) return;
6270 msg_format(Ind, "\377yPoking %s.", Players[j]->name);
6271 msg_print(j, "\377yYou are poked by something invisible.");
6272 msg_format_near(j, "\377y%s is being poked by something invisible.", Players[j]->name);
6273 return;
6274 }
6275 else if (prefix(message, "/strangle")) {/* oO */
6276 if (!tk) {
6277 msg_print(Ind, "Usage: /strangle <player name>");
6278 return;
6279 }
6280 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6281 if (!j) return;
6282 msg_format(Ind, "\377yPoking %s.", Players[j]->name);
6283 msg_print(j, "\377yYou are being strangled by something invisible!");
6284 msg_format_near(j, "\377y%s is being strangled by something invisible!", Players[j]->name);
6285 bypass_invuln = TRUE;
6286 take_hit(j, Players[j]->chp / 4, "", 0);
6287 set_stun(j, Players[j]->stun + 5);
6288 bypass_invuln = FALSE;
6289 return;
6290 }
6291 else if (prefix(message, "/cheer")) {
6292 if (!tk) {
6293 msg_print(Ind, "Usage: /cheer <player name>");
6294 return;
6295 }
6296 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6297 if (!j) return;
6298 msg_print(j, "\377ySomething invisible is cheering for you!");
6299 msg_format_near(j, "\377yYou hear something invisible cheering for %s!", Players[j]->name);
6300 Players[j]->blessed_power = 10;
6301 set_blessed(j, randint(5) + 15);
6302 return;
6303 }
6304 else if (prefix(message, "/applaud")) {
6305 if (!tk) {
6306 msg_print(Ind, "Usage: /applaud <player name>");
6307 return;
6308 }
6309 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6310 if (!j) return;
6311 msg_format(Ind, "\377yApplauding %s.", Players[j]->name);
6312 msg_print(j, "\377ySomeone invisible is applauding for you!");
6313 msg_format_near(j, "\377yYou hear someone invisible applauding for %s!", Players[j]->name);
6314 set_hero(j, randint(5) + 15);
6315 return;
6316 }
6317 else if (prefix(message, "/presence")) {
6318 if (!tk) {
6319 msg_print(Ind, "Usage: /presence <player name>");
6320 return;
6321 }
6322 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6323 if (!j) return;
6324 msg_print(j, "\377yYou feel an invisible presence watching you!");
6325 msg_format_near(j, "\377yYou feel an invisible presence near %s!", Players[j]->name);
6326 return;
6327 }
6328 else if (prefix(message, "/snicker")) {
6329 if (!tk) {
6330 msg_print(Ind, "Usage: /snicker <player name>");
6331 return;
6332 }
6333 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6334 if (!j) return;
6335 msg_format(Ind, "\377ySnickering at %s.", Players[j]->name);
6336 msg_print(j, "\377yYou hear someone invisible snickering evilly!");
6337 msg_format_near(j, "\377yYou hear someone invisible snickering evilly near %s!", Players[j]->name);
6338 set_afraid(j, Players[j]->afraid + 6);
6339 return;
6340 }
6341 else if (prefix(message, "/deltown")){
6342 deltown(Ind);
6343 return;
6344 }
6345 else if (prefix(message, "/chouse")) { //count houses/castles
6346 if (!tk) {
6347 msg_print(Ind, "Usage: /chouse <character name>");
6348 return;
6349 }
6350 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
6351 if (!j) return;
6352 lua_count_houses(j);
6353 msg_format(Ind, "Counted houses/castles for %s.", Players[j]->name);
6354 return;
6355 }
6356 /* fix insane hit dice of a golem manually - gotta solve the bug really */
6357 else if (prefix(message, "/mblowdice") || prefix(message, "/mbd")) {
6358 cave_type *c_ptr, **zcave = getcave(&p_ptr->wpos);
6359 monster_type *m_ptr;
6360 int x, y, i;
6361 if (tk < 2) {
6362 msg_print(Ind, "\377oUsage: /mblowdice <dice> <sides>");
6363 return;
6364 }
6365 y = p_ptr->py + ddy[p_ptr->last_dir];
6366 x = p_ptr->px + ddx[p_ptr->last_dir];
6367 c_ptr = &zcave[y][x];
6368 if (c_ptr->m_idx) {
6369 m_ptr = &m_list[c_ptr->m_idx];
6370 for (i = 0; i < 4; i++) {
6371 m_ptr->blow[i].d_dice = atoi(token[1]);
6372 m_ptr->blow[i].d_side = atoi(token[2]);
6373 }
6374 }
6375 return;
6376 }
6377 /* Umm, well I added this for testing purpose =) - C. Blue */
6378 else if (prefix(message, "/crash")) {
6379 msg_print(Ind, "\377RCRASHING");
6380 s_printf("$CRASHING$\n");
6381 s_printf("%d %s", "game over man", 666);
6382 return; /* ^^ */
6383 }
6384 /* Assign all houses of a <party> or <guild> to a <player> instead (chown) - C. BLue */
6385 else if (prefix(message, "/citychown")) {
6386 int c = 0;
6387 #if 0
6388 int p; - after 'return': p = name_lookup_loose(Ind, token[2], FALSE, FALSE);
6389 if (tk < 2) {
6390 msg_print(Ind, "\377oUsage: /citychown <party|guild> <player>");
6391 msg_print(Ind, "\377oExample: /citychown Housekeepers Janitor");
6392 #else /* improved version */
6393 if (tk < 3) {
6394 msg_print(Ind, "\377oUsage: /citychown p|g <party-id|guild-id> <player-Index>");
6395 msg_print(Ind, "\377oExample: /citychown g 127 5");
6396 #endif
6397 return;
6398 }
6399 msg_format(Ind, "Changing house owner of all %s to %s...", token[1], token[2]);
6400 for (i = 0; i < num_houses; i++) {
6401 struct dna_type *dna = houses[i].dna;
6402 #if 0
6403 if (((dna->owner_type == OT_PARTY) && (!strcmp(parties[dna->owner].name, token[1]))) ||
6404 ((dna->owner_type == OT_GUILD) && (!strcmp(guilds[dna->owner].name, token[1]))))
6405 if (((dna->owner_type == OT_PARTY) || (dna->owner_type == OT_GUILD)) &&
6406 (dna->owner == atoi(token[1])))
6407 {
6408 dna->creator = Players[p]->dna;
6409 dna->owner = lookup_player_id_messy(token[2]);
6410 dna->owner_type = OT_PLAYER; /* Single player (code 1) is new owner */
6411 c++; /* :) */
6412 }
6413 #else /* improved version: */
6414 if ((((token[1][0] == 'p') && (dna->owner_type == OT_PARTY)) ||
6415 ((token[1][0] == 'g') && (dna->owner_type == OT_GUILD))) &&
6416 (dna->owner == atoi(token[2])))
6417 {
6418 dna->creator = Players[atoi(token[3])]->dna;
6419 dna->owner = Players[atoi(token[3])]->id;
6420 dna->owner_type = OT_PLAYER; /* Single player (code 1) is new owner */
6421 c++; /* :) */
6422 }
6423 #endif
6424 }
6425 msg_format(Ind, "%d houses have been changed.", c);
6426 lua_count_houses(atoi(token[3]));
6427 return;
6428 }
6429 /* This one is to fix houses which were changed by an outdated version of /citychown =p */
6430 else if (prefix(message, "/fixchown")) {
6431 int c = 0;
6432 int p;
6433 if (tk < 1) {
6434 msg_print(Ind, "\377oUsage: /fixchown <player>");
6435 return;
6436 }
6437 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6438 msg_format(Ind, "Fixing house owner %s...", token[1]);
6439 for (i = 0; i < num_houses; i++) {
6440 struct dna_type *dna = houses[i].dna;
6441 // if ((dna->owner_type == OT_PLAYER) && (!strcmp(lookup_player_name(dna->owner), token[1])))
6442 if ((dna->owner_type == OT_PLAYER) && (dna->owner == lookup_player_id_messy(message3)))
6443 {
6444 dna->creator = Players[p]->dna;
6445 c++; /* :) */
6446 }
6447 }
6448 msg_format(Ind, "%d houses have been changed.", c);
6449 lua_count_houses(p);
6450 return;
6451 }
6452 /* Check house number */
6453 else if (prefix(message, "/listhouses")) {
6454 int cp = 0, cy = 0, cg = 0;
6455 if (tk < 1) {
6456 msg_print(Ind, "\377oUsage: /listhouses <owner-name>");
6457 return;
6458 }
6459 for (i = 0; i < num_houses; i++) {
6460 struct dna_type *dna = houses[i].dna;
6461 if (!dna->owner) ;
6462 /* not owned */
6463 else if ((dna->owner_type == OT_PLAYER) && (dna->owner == lookup_player_id(message2 + 12)))
6464 cp++;
6465 else if ((dna->owner_type == OT_PARTY) && (!strcmp(parties[dna->owner].name, message2 + 12)))
6466 cy++;
6467 else if ((dna->owner_type == OT_GUILD) && (!strcmp(guilds[dna->owner].name, message2 + 12)))
6468 cg++;
6469 }
6470 msg_format(Ind, "%s has houses: Player %d, Party %d, Guild %d.", message2 + 12, cp, cy, cg);
6471 return;
6472 }
6473 /* List all specially created houses */
6474 else if (prefix(message, "/polyhouses")) {
6475 for (i = 0; i < num_houses; i++) {
6476 if (houses[i].flags & HF_RECT) continue;
6477 msg_format(Ind, "Poly-house %d at %d,%d,%d.", i, houses[i].wpos.wx, houses[i].wpos.wy, houses[i].wpos.wz);
6478 }
6479 msg_print(Ind, "Done.");
6480 return;
6481 }
6482 /* display a player's hit dice dna */
6483 else if (prefix(message, "/pyhpdbg")) {
6484 char buf[MSG_LEN];
6485 int p;
6486 if (tk < 1) {
6487 msg_print(Ind, "\377oUsage: /pyhpdbg <player name>");
6488 return;
6489 }
6490 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6491 if (!p) return;
6492 for (i = 1; i <= 100; i += 10) {
6493 sprintf(buf, "Lv %d-%d:", i, i + 10 - 1);
6494 for (j = 0; j < 10; j++) {
6495 if (i + j >= 100) strcat(buf, " -");
6496 else strcat(buf, format(" %d", p_ptr->player_hp[i + j]));
6497 }
6498 msg_print(Ind, buf);
6499 }
6500 return;
6501 }
6502 /* Reroll a player's birth hitdice to test major changes - C. Blue */
6503 else if (prefix(message, "/rollchar")) {
6504 int p;
6505 if (tk < 1) {
6506 msg_print(Ind, "\377oUsage: /rollchar <player name>");
6507 return;
6508 }
6509 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6510 if (!p) return;
6511 lua_recalc_char(p);
6512 msg_format(Ind, "Rerolled HP for %s.", Players[p]->name);
6513 return;
6514 }
6515 /* Reroll a player's HP a lot and measure */
6516 else if (prefix(message, "/roll!char")) {
6517 int p, min = 9999, max = 0;
6518 long avg = 0;
6519 if (tk < 1) {
6520 msg_print(Ind, "\377oUsage: /roll!char <player name>");
6521 return;
6522 }
6523 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6524 if (!p) return;
6525 for (i = 0; i < 10000; i++) {
6526 lua_recalc_char(p);
6527 if (Players[p]->mhp > max) max = Players[p]->mhp;
6528 if (Players[p]->mhp < min) min = Players[p]->mhp;
6529 avg += Players[p]->mhp;
6530 }
6531 avg /= 10000;
6532 msg_format(Ind, "Rerolled HP for %s 10000 times:", Players[p]->name);
6533 msg_format(Ind, " Min: %d, Max: %d, Avg: %d.", min, max, avg);
6534 return;
6535 }
6536 /* Reroll a player's background history text (for d-elves/vampires/draconians, maybe ents) */
6537 else if (prefix(message, "/rollhistory")) {
6538 int p;
6539 if (tk < 1) {
6540 msg_print(Ind, "\377oUsage: /rollhistory <player name>");
6541 return;
6542 }
6543 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6544 if (!p) return;
6545 get_history(p);
6546 Players[p]->redraw |= PR_HISTORY; //update the client's history text
6547 msg_format(Ind, "Rerolled history for %s.", Players[p]->name);
6548 return;
6549 }
6550 else if (prefix(message, "/checkhistory")) {
6551 int p;
6552 if (tk < 1) {
6553 msg_print(Ind, "\377oUsage: /checkhistory <player name>");
6554 return;
6555 }
6556 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6557 if (!p) return;
6558 for (i = 0; i < 4; i++) msg_format(Ind, "[%d]: %s", i, Players[p]->history[i]);
6559 return;
6560 }
6561 /* Turn all non-everlasting items inside a house to everlasting items if the owner is everlasting */
6562 else if (prefix(message, "/everhouse")) {
6563 /* house_contents_chmod .. (scan_obj style) */
6564 }
6565 /* Blink a player */
6566 else if (prefix(message, "/blink")) {
6567 int p;
6568 if (tk < 1) {
6569 msg_print(Ind, "\377oUsage: /blink <player name>");
6570 return;
6571 }
6572 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6573 if (!p) {
6574 msg_print(Ind, "Player not found.");
6575 return;
6576 }
6577 teleport_player_force(p, 10);
6578 msg_print(Ind, "Phased that player.");
6579 return;
6580 }
6581 /* Teleport a player */
6582 else if (prefix(message, "/tport")) {
6583 int p;
6584 if (tk < 1) {
6585 msg_print(Ind, "\377oUsage: /tport <player name>");
6586 return;
6587 }
6588 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6589 if (!p) {
6590 msg_print(Ind, "Player not found.");
6591 return;
6592 }
6593 teleport_player_force(p, 100);
6594 msg_print(Ind, "Teleported that player.");
6595 return;
6596 }
6597 /* Teleport a player to a target */
6598 else if (prefix(message, "/tptar")) {
6599 int p, x, y, ox, oy;
6600 player_type *q_ptr;
6601 cave_type **zcave;
6602
6603 if (tk < 3) {
6604 msg_print(Ind, "\377oUsage: /tptar <x> <y> <player name>");
6605 return;
6606 }
6607
6608 x = atoi(token[1]);
6609 y = atoi(token[2]);
6610 p = name_lookup_loose(Ind, token[3], FALSE, FALSE);
6611 if (!p) {
6612 msg_print(Ind, "Player not found.");
6613 return;
6614 }
6615
6616 q_ptr = Players[p];
6617 if (!in_bounds4(getfloor(&q_ptr->wpos), y, x)) {
6618 msg_print(Ind, "Error: Location not in_bounds.");
6619 return;
6620 }
6621 if (!(zcave = getcave(&q_ptr->wpos))) {
6622 msg_print(Ind, "Error: Cannot getcave().");
6623 return;
6624 }
6625
6626 /* Save the old location */
6627 oy = q_ptr->py;
6628 ox = q_ptr->px;
6629
6630 /* Move the player */
6631 q_ptr->py = y;
6632 q_ptr->px = x;
6633
6634 /* The player isn't here anymore */
6635 zcave[oy][ox].m_idx = 0;
6636
6637 /* The player is now here */
6638 zcave[y][x].m_idx = 0 - p;
6639 cave_midx_debug(&q_ptr->wpos, y, x, -p);
6640
6641 /* Redraw the old spot */
6642 everyone_lite_spot(&q_ptr->wpos, oy, ox);
6643
6644 /* Redraw the new spot */
6645 everyone_lite_spot(&q_ptr->wpos, p_ptr->py, p_ptr->px);
6646
6647 /* Check for new panel (redraw map) */
6648 verify_panel(p);
6649
6650 /* Update stuff */
6651 q_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW);
6652
6653 /* Update the monsters */
6654 q_ptr->update |= (PU_DISTANCE);
6655
6656 /* Window stuff */
6657 q_ptr->window |= (PW_OVERHEAD);
6658
6659 handle_stuff(p);
6660
6661 msg_print(Ind, "Teleported that player.");
6662 return;
6663 }
6664 /* Teleport a player to us - even if in different world sector */
6665 else if (prefix(message, "/tpto") ||
6666 /* Teleport us to a player - even if in different world sector */
6667 prefix(message, "/tpat")) {
6668 int p;
6669 player_type *q_ptr;
6670 cave_type **zcave;
6671
6672 if (tk < 1) {
6673 msg_print(Ind, "\377oUsage: /tpXX <player name>");
6674 return;
6675 }
6676
6677 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6678 if (!p) {
6679 msg_print(Ind, "Player not found.");
6680 return;
6681 }
6682
6683 q_ptr = Players[p];
6684 if (!(zcave = getcave(&q_ptr->wpos))) {
6685 msg_print(Ind, "Error: Cannot getcave().");
6686 return;
6687 }
6688
6689 if (prefix(message, "/tpto")) {
6690 if (!inarea(&q_ptr->wpos, &p_ptr->wpos)) {
6691 q_ptr->recall_pos.wx = p_ptr->wpos.wx;
6692 q_ptr->recall_pos.wy = p_ptr->wpos.wy;
6693 q_ptr->recall_pos.wz = p_ptr->wpos.wz;
6694 q_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
6695 recall_player(p, "\377yA magical gust of wind lifts you up and carries you away!");
6696 process_player_change_wpos(p);
6697 }
6698
6699 teleport_player_to_force(p, p_ptr->py, p_ptr->px);
6700
6701 msg_print(Ind, "Teleported that player.");
6702 } else {
6703 if (!inarea(&q_ptr->wpos, &p_ptr->wpos)) {
6704 p_ptr->recall_pos.wx = q_ptr->wpos.wx;
6705 p_ptr->recall_pos.wy = q_ptr->wpos.wy;
6706 p_ptr->recall_pos.wz = q_ptr->wpos.wz;
6707 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
6708 recall_player(Ind, "\377yA magical gust of wind lifts you up and carries you away!");
6709 process_player_change_wpos(Ind);
6710 }
6711
6712 teleport_player_to_force(Ind, q_ptr->py, q_ptr->px);
6713
6714 msg_print(Ind, "Teleported to that player.");
6715 }
6716 return;
6717 }
6718 /* STRIP ALL TRUE ARTIFACTS FROM ALL PLAYERS (!) */
6719 else if (prefix(message, "/strathash")) {
6720 msg_print(Ind, "Stripping all players.");
6721 lua_strip_true_arts_from_absent_players();
6722 return;
6723 }
6724 /* STRIP ALL TRUE ARTIFACTS FROM ALL FLOORS */
6725 else if (prefix(message, "/stratmap")) {
6726 msg_print(Ind, "Stripping all floors.");
6727 lua_strip_true_arts_from_floors();
6728 return;
6729 }
6730 /* STRIP ALL TRUE ARTIFACTS FROM A PLAYER */
6731 else if (prefix(message, "/strat")) {
6732 int p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6733 if (!p) return;
6734 lua_strip_true_arts_from_present_player(Ind, 0);
6735 msg_format(Ind, "Stripped arts from player %s.", Players[Ind]->name);
6736 return;
6737 }
6738 /* wipe wilderness map of tournament players - mikaelh */
6739 else if (prefix(message, "/wipewild")) {
6740 if (!tk) {
6741 msg_print(Ind, "\377oUsage: /wipewild <player name>");
6742 return;
6743 }
6744 int p = name_lookup_loose(Ind, message3, FALSE, FALSE);
6745 if (!p) return;
6746 for (i = 0; i < MAX_WILD_8; i++)
6747 Players[p]->wild_map[i] = 0;
6748 msg_format(Ind, "Wiped wilderness map of player %s.", Players[p]->name);
6749 return;
6750 }
6751 /* Find all true arts in o_list an tell where they are - mikaelh */
6752 else if (prefix(message, "/findarts")) {
6753 msg_print(Ind, "finding arts..");
6754 object_type *o_ptr;
6755 char o_name[ONAME_LEN];
6756 for(i = 0; i < o_max; i++){
6757 o_ptr = &o_list[i];
6758 if (o_ptr->k_idx) {
6759 if (true_artifact_p(o_ptr))
6760 {
6761 object_desc(Ind, o_name, o_ptr, FALSE, 0);
6762 msg_format(Ind, "%s is at (%d, %d, %d) (x=%d,y=%d)", o_name, o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz, o_ptr->ix, o_ptr->iy);
6763 }
6764 }
6765 }
6766 msg_print(Ind, "done.");
6767 return;
6768 }
6769 else if (prefix(message, "/debug-store")){
6770 /* Debug store size - C. Blue */
6771 store_type *st_ptr;
6772 store_info_type *sti_ptr;
6773 if (tk < 1) {
6774 msg_print(Ind, "Usage: /debug-store <store#>");
6775 return;
6776 }
6777 i = atoi(token[1]);
6778 st_ptr = &town[0].townstore[i];
6779 sti_ptr = &st_info[i];
6780 msg_format(Ind, "Store %d '%s' has size %d (expected %d).",
6781 i, st_name + sti_ptr->name, st_ptr->stock_size, sti_ptr->max_obj);
6782 return;
6783 }
6784 else if (prefix(message, "/acclist")) { /* list all living characters of a specified account name - C. Blue */
6785 int *id_list, i, n;
6786 struct account *l_acc;
6787 byte tmpm;
6788 char colour_sequence[3 + 1]; /* colour + dedicated slot marker */
6789 if (tk < 1) {
6790 msg_print(Ind, "Usage: /acclist <account name>");
6791 return;
6792 }
6793 msg_format(Ind, "Looking up account %s.", message3);
6794 l_acc = Admin_GetAccount(message3);
6795 if (l_acc) {
6796 msg_format(Ind, " (Normalised name is <%s>)", l_acc->name_normalised);
6797 n = player_id_list(&id_list, l_acc->id);
6798 /* Display all account characters here */
6799 for (i = 0; i < n; i++) {
6800 //unused huh u16b ptype = lookup_player_type(id_list[i]);
6801 /* do not change protocol here */
6802 tmpm = lookup_player_mode(id_list[i]);
6803 if (tmpm & MODE_EVERLASTING) strcpy(colour_sequence, "\377B");
6804 else if (tmpm & MODE_PVP) strcpy(colour_sequence, format("\377%c", COLOUR_MODE_PVP));
6805 else if (tmpm & MODE_NO_GHOST) strcpy(colour_sequence, "\377D");
6806 else if (tmpm & MODE_HARD) strcpy(colour_sequence, "\377s");
6807 else strcpy(colour_sequence, "\377W");
6808 if (tmpm & MODE_DED_IDDC) strcat(colour_sequence, "*");
6809 if (tmpm & MODE_DED_PVP) strcat(colour_sequence, "*");
6810 msg_format(Ind, "Character #%d: %s%s (%d) (ID: %d)", i+1, colour_sequence, lookup_player_name(id_list[i]), lookup_player_level(id_list[i]), id_list[i]);
6811 }
6812 if (n) C_KILL(id_list, n, int);
6813 KILL(l_acc, struct account);
6814 } else {
6815 msg_print(Ind, "Account not found.");
6816 }
6817 return;
6818 }
6819 else if (prefix(message, "/characc")) { /* and /characcl; returns account name to which the given character name belongs -- extended version of /who */
6820 u32b p_id;
6821 cptr acc;
6822 struct account *l_acc;
6823 if (tk < 1) {
6824 msg_print(Ind, "Usage: /characc <character name>");
6825 return;
6826 }
6827 if (!(p_id = lookup_player_id(message3))) {
6828 msg_print(Ind, "That character name does not exist.");
6829 return;
6830 }
6831 acc = lookup_accountname(p_id);
6832 if (!acc) {
6833 msg_print(Ind, "***ERROR: No account found.");
6834 return;
6835 }
6836 msg_format(Ind, "Account name: \377s'%s'", acc);
6837 if (!(l_acc = Admin_GetAccount(acc))) {
6838 msg_print(Ind, "***ERROR: Account does not exist.");
6839 return;
6840 }
6841 /* maybe do /acclist here? */
6842 if (prefix(message, "/characcl")) {
6843 int *id_list, i, n;
6844 byte tmpm;
6845 char colour_sequence[3 + 1]; /* colour + dedicated slot marker */
6846
6847 n = player_id_list(&id_list, l_acc->id);
6848 /* Display all account characters here */
6849 for(i = 0; i < n; i++) {
6850 //unused huh u16b ptype = lookup_player_type(id_list[i]);
6851 /* do not change protocol here */
6852 tmpm = lookup_player_mode(id_list[i]);
6853 if (tmpm & MODE_EVERLASTING) strcpy(colour_sequence, "\377B");
6854 else if (tmpm & MODE_PVP) strcpy(colour_sequence, format("\377%c", COLOUR_MODE_PVP));
6855 else if (tmpm & MODE_NO_GHOST) strcpy(colour_sequence, "\377D");
6856 else if (tmpm & MODE_HARD) strcpy(colour_sequence, "\377s");
6857 else strcpy(colour_sequence, "\377W");
6858 if (tmpm & MODE_DED_IDDC) strcat(colour_sequence, "*");
6859 if (tmpm & MODE_DED_PVP) strcat(colour_sequence, "*");
6860 msg_format(Ind, "Character #%d: %s%s (%d) (ID: %d)", i+1, colour_sequence, lookup_player_name(id_list[i]), lookup_player_level(id_list[i]), id_list[i]);
6861 }
6862 if (n) C_KILL(id_list, n, int);
6863 }
6864 KILL(l_acc, struct account);
6865 return;
6866
6867 }
6868 else if (prefix(message, "/addnewdun")) {
6869 msg_print(Ind, "Trying to add new dungeons..");
6870 wild_add_new_dungeons(tk ? Ind : 0);
6871 msg_print(Ind, "done.");
6872 return;
6873 }
6874 /* for now only loads Valinor */
6875 else if (prefix(message, "/loadmap")) {
6876 int xstart = 0, ystart = 0;
6877 if (tk < 1) {
6878 msg_print(Ind, "Usage: /loadmap t_<mapname>.txt");
6879 return;
6880 }
6881 msg_print(Ind, "Trying to load map..");
6882 // process_dungeon_file(format("t_%s.txt", message3), &p_ptr->wpos, &ystart, &xstart, 20+1, 32+34, TRUE);
6883 process_dungeon_file(format("t_%s.txt", message3), &p_ptr->wpos, &ystart, &xstart, MAX_HGT, MAX_WID, TRUE);
6884 wpos_apply_season_daytime(&p_ptr->wpos, getcave(&p_ptr->wpos));
6885 msg_print(Ind, "done.");
6886 return;
6887 }
6888 else if (prefix(message, "/lqm")) { //load quest map
6889 int xstart = p_ptr->px, ystart = p_ptr->py;
6890 if (tk < 1) {
6891 msg_print(Ind, "Usage: /lqm tq_<mapname>.txt");
6892 return;
6893 }
6894 msg_print(Ind, "Trying to load map..");
6895 // process_dungeon_file(format("tq_%s.txt", message3), &p_ptr->wpos, &ystart, &xstart, 20+1, 32+34, TRUE);
6896 process_dungeon_file(format("tq_%s.txt", message3), &p_ptr->wpos, &ystart, &xstart, MAX_HGT, MAX_WID, TRUE);
6897 wpos_apply_season_daytime(&p_ptr->wpos, getcave(&p_ptr->wpos));
6898 msg_print(Ind, "done.");
6899 return;
6900 }
6901 /* check monster inventories for (nothing)s - mikaelh */
6902 else if (prefix(message, "/minvcheck"))
6903 {
6904 monster_type *m_ptr;
6905 object_type *o_ptr;
6906 int this_o_idx, next_o_idx;
6907 msg_print(Ind, "Checking monster inventories...");
6908 for (i = 1; i < m_max; i++)
6909 {
6910 m_ptr = &m_list[i];
6911 for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) {
6912 o_ptr = &o_list[this_o_idx];
6913
6914 if (!o_ptr->k_idx || o_ptr->k_idx == 1)
6915 {
6916 msg_format(Ind, "Monster #%d is holding an invalid item (o_idx=%d) (k_idx=%d)!", i, m_ptr->hold_o_idx, o_ptr->k_idx);
6917 }
6918
6919 if (o_ptr->held_m_idx != i)
6920 {
6921 msg_format(Ind, "Item (o_idx=%d) has wrong held_m_idx! (is %d, should be %d)", this_o_idx, i);
6922 }
6923
6924 next_o_idx = o_ptr->next_o_idx;
6925 }
6926 }
6927 msg_print(Ind, "Check complete.");
6928 return;
6929 }
6930 /* remove a (nothing) the admin is standing on - C. Blue */
6931 else if (prefix(message, "/rmnothing")) {
6932 cave_type **zcave = getcave(&p_ptr->wpos);
6933 object_type *o_ptr;
6934
6935 if (!zcave) return; /* paranoia */
6936 if (!zcave[p_ptr->py][p_ptr->px].o_idx) {
6937 msg_print(Ind, "\377oNo object found here.");
6938 return;
6939 }
6940 o_ptr = &o_list[zcave[p_ptr->py][p_ptr->px].o_idx];
6941 if (!nothing_test(o_ptr, p_ptr, &p_ptr->wpos, p_ptr->px, p_ptr->py, 0)) {
6942 msg_print(Ind, "\377yObject here is not a (nothing).");
6943 return;
6944 }
6945
6946 zcave[p_ptr->py][p_ptr->px].o_idx = 0;
6947 /* Redraw the old grid */
6948 everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);
6949
6950 s_printf("Erased (nothing) via slash-command: %s\n.", p_ptr->name);
6951 msg_print(Ind, "\377RErased (nothing).");
6952 return;
6953 }
6954 #ifdef BACKTRACE_NOTHINGS
6955 else if (prefix(message, "/backtrace")) { /* backtrace test */
6956
6957 int size, i;
6958 void *buf[1000];
6959 char **fnames;
6960
6961 size = backtrace(buf, 1000);
6962 s_printf("size = %d\n", size);
6963
6964 fnames = backtrace_symbols(buf, size);
6965 for (i = 0; i < size; i++)
6966 s_printf("%s\n", fnames[i]);
6967
6968 msg_print(Ind, "Backtrace written to log.");
6969 return;
6970 }
6971 #endif
6972 /* erase a certain player character file */
6973 else if (prefix(message, "/erasechar"))
6974 {
6975 if (tk < 1) {
6976 msg_print(Ind, "Usage: /erasechar <character name>");
6977 return;
6978 }
6979 msg_format(Ind, "Erasing character %s.", message3);
6980 erase_player_name(message3);
6981 return;
6982 }
6983 /* rename a certain player character file */
6984 else if (prefix(message, "/renamechar"))
6985 {
6986 if (tk < 1) {
6987 msg_print(Ind, "Usage: /renamechar <character name>:<new name>");
6988 return;
6989 }
6990 msg_format(Ind, "Renaming character %s.", message3);
6991 rename_character(message3);
6992 return;
6993 }
6994 /* list of players about to expire - mikaelh */
6995 else if (prefix(message, "/checkexpir"))
6996 {
6997 int days;
6998 if (tk < 1) {
6999 msg_print(Ind, "Usage: /checkexpiry <number of days>");
7000 return;
7001 }
7002 days = atoi(token[1]);
7003 checkexpiry(Ind, days);
7004 return;
7005 }
7006 /* start a predefined global_event (quest, highlander tournament..),
7007 see process_events() in xtra1.c for details - C. Blue */
7008 else if (prefix(message, "/gestart"))
7009 {
7010 int err, msgpos = 0;
7011 if (tk < 1) {
7012 msg_print(Ind, "Usage: /gestart <predefined type> [parameters...]");
7013 return;
7014 }
7015 while(message3[msgpos] && message3[msgpos] != 32) msgpos++;
7016 if (message3[msgpos] && message3[++msgpos]) strcpy(message4, message3 + msgpos);
7017 else strcpy(message4, "");
7018 err = start_global_event(Ind, atoi(token[1]), message4);
7019 if (err) msg_print(Ind, "Error: no more global events.");
7020 return;
7021 }
7022 else if (prefix(message, "/gestop"))
7023 {
7024 if (tk < 1 || k < 1 || k > MAX_GLOBAL_EVENTS) {
7025 msg_format(Ind, "Usage: /gestop 1..%d", MAX_GLOBAL_EVENTS);
7026 return;
7027 }
7028 if (global_event[k-1].getype == GE_NONE) {
7029 msg_print(Ind, "No such event.");
7030 return;
7031 }
7032 stop_global_event(Ind, k-1);
7033 return;
7034 }
7035 else if (prefix(message, "/gepause"))
7036 {
7037 if (tk < 1 || k < 1 || k > MAX_GLOBAL_EVENTS) {
7038 msg_format(Ind, "Usage: /gepause 1..%d", MAX_GLOBAL_EVENTS);
7039 return;
7040 }
7041 if (global_event[k-1].getype == GE_NONE) {
7042 msg_print(Ind, "No such event.");
7043 return;
7044 }
7045 if (global_event[k-1].paused == FALSE) {
7046 global_event[k-1].paused = TRUE;
7047 msg_format(Ind, "Global event #%d of type %d is now paused.", k, global_event[k-1].getype);
7048 } else {
7049 global_event[k-1].paused = FALSE;
7050 msg_format(Ind, "Global event #%d of type %d has been resumed.", k, global_event[k-1].getype);
7051 }
7052 return;
7053 }
7054 else if (prefix(message, "/geretime")) /* skip the announcements, start NOW */
7055 /* (or optionally specfiy new remaining announce time in seconds) */
7056 {
7057 int t = 10;
7058 if (tk < 1 || k < 1 || k > MAX_GLOBAL_EVENTS) {
7059 msg_format(Ind, "Usage: /geretime 1..%d [<new T-x>]", MAX_GLOBAL_EVENTS);
7060 return;
7061 }
7062 if (global_event[k-1].getype == GE_NONE) {
7063 msg_print(Ind, "No such event.");
7064 return;
7065 }
7066 if (tk == 2) t = atoi(token[2]);
7067 /* only if announcement phase isn't over yet, we don't want to mess up a running event */
7068 if ((turn - global_event[k-1].start_turn) / cfg.fps < global_event[k-1].announcement_time) {
7069 global_event[k-1].announcement_time = (turn - global_event[k-1].start_turn) / cfg.fps + t;
7070 announce_global_event(k-1);
7071 }
7072 return;
7073 }
7074 else if (prefix(message, "/gefforward")) /* skip some running time - C. Blue */
7075 /* (use negative parameter to go back in time) (in seconds) */
7076 {
7077 int t = 60;
7078 if (tk < 1 || k < 1 || k > MAX_GLOBAL_EVENTS) {
7079 msg_format(Ind, "Usage: /gefforward 1..%d [<new T-x>]", MAX_GLOBAL_EVENTS);
7080 return;
7081 }
7082 if (global_event[k-1].getype == GE_NONE) {
7083 msg_print(Ind, "No such event.");
7084 return;
7085 }
7086 if (tk == 2) t = atoi(token[2]);
7087
7088 /* fix time overflow if set beyond actual end time */
7089 if (global_event[k-1].end_turn &&
7090 (turn + t * cfg.fps >= global_event[k-1].end_turn)) { /* end at 1 turn before actual end for safety */
7091 t = global_event[k-1].end_turn - turn - 1;
7092 }
7093
7094 /* dance the timewarp */
7095 global_event[k-1].start_turn = global_event[k-1].start_turn - cfg.fps * t;
7096 if (global_event[k-1].end_turn)
7097 global_event[k-1].end_turn = global_event[k-1].end_turn - cfg.fps * t;
7098 return;
7099 }
7100 else if (prefix(message, "/gesign")) { /* admin debug command - sign up for a global event and start it right the next turn */
7101 global_event_type *ge;
7102 for (i = 0; i < MAX_GLOBAL_EVENTS; i++) {
7103 ge = &global_event[i];
7104 if (ge->getype == GE_NONE) continue;
7105 if (ge->signup_time == -1) continue;
7106 if (ge->signup_time &&
7107 (!ge->announcement_time ||
7108 (ge->announcement_time - (turn - ge->start_turn) / cfg.fps <= 0)))
7109 continue;
7110 if (ge->signup_time &&
7111 (ge->signup_time - (turn - ge->start_turn) / cfg.fps <= 0))
7112 continue;
7113 break;
7114 }
7115 if (i == MAX_GLOBAL_EVENTS) {
7116 msg_print(Ind, "no eligible events running");
7117 return;
7118 }
7119
7120 if (tk < 1) global_event_signup(Ind, i, NULL);
7121 else global_event_signup(Ind, i, message3 + 1 + strlen(format("%d", k)));
7122
7123 if (ge->announcement_time) {
7124 s32b elapsed_time = turn - ge->start_turn - ge->paused_turns;
7125 s32b diff = ge->announcement_time * cfg.fps - elapsed_time - 1;
7126 msg_format(Ind, "forwarding %d turns", diff);
7127 global_event[i].start_turn -= diff;
7128 if (ge->end_turn) global_event[i].end_turn -= diff;
7129 }
7130 return;
7131 }
7132 else if (prefix(message, "/partydebug"))
7133 {
7134 FILE *fp;
7135 fp = fopen("tomenet_parties", "wb");
7136 if (!fp) {
7137 msg_print(Ind, "\377rError! Couldn't open tomenet_parties");
7138 return;
7139 }
7140 for (i = 1; i < MAX_PARTIES; i++) {
7141 fprintf(fp, "Party: %s Owner: %s Members: %d Created: %d\n", parties[i].name, parties[i].owner, (int)parties[i].members, (int)parties[i].created);
7142 }
7143 fclose(fp);
7144 msg_print(Ind, "Party data dumped to tomenet_parties");
7145 return;
7146 }
7147 else if (prefix(message, "/partyclean")) /* reset the creation times of empty parties - THIS MUST BE RUN WHEN THE TURN COUNTER IS RESET - mikaelh */
7148 {
7149 for (i = 1; i < MAX_PARTIES; i++) {
7150 if (parties[i].members == 0) parties[i].created = 0;
7151 }
7152 msg_print(Ind, "Creation times of empty parties reseted!");
7153 return;
7154 }
7155 else if (prefix(message, "/partymodefix")) {
7156 u32b p_id;
7157 s_printf("Fixing party modes..\n");
7158 for (i = 1; i < MAX_PARTIES; i++) {
7159 if (!parties[i].members) continue;
7160 p_id = lookup_player_id(parties[i].owner);
7161 if (p_id) {
7162 parties[i].cmode = lookup_player_mode(p_id);
7163 s_printf("Party '%s' (%d): Mode has been fixed to %d ('%s',%d).\n",
7164 parties[i].name, i, parties[i].cmode, parties[i].owner, p_id);
7165 }
7166 /* paranoia - a party without owner shouldn't exist */
7167 else s_printf("Party '%s' (%d): Mode couldn't be fixed ('%s',%d).\n",
7168 parties[i].name, i, parties[i].owner, p_id);
7169 }
7170 s_printf("done.\n");
7171 return;
7172 }
7173 else if (prefix(message, "/guildmodefix")) {
7174 cptr name = NULL;
7175 s_printf("Fixing guild modes..\n");
7176 for (i = 1; i < MAX_GUILDS; i++) {
7177 if (!guilds[i].members) continue;
7178 if (guilds[i].master && (name = lookup_player_name(guilds[i].master)) != NULL) {
7179 guilds[i].cmode = lookup_player_mode(guilds[i].master);
7180 s_printf("Guild '%s' (%d): Mode has been fixed to master's ('%s',%d) mode %d.\n",
7181 guilds[i].name, i, name, guilds[i].master, guilds[i].cmode);
7182 } else { /* leaderless guild, ow */
7183 s_printf("Guild '%s' (%d): Fixing lost guild, master (%d) is '%s'.\n",
7184 guilds[i].name, i, guilds[i].master, name ? name : "(null)");
7185 fix_lost_guild_mode(i);
7186 }
7187 }
7188 s_printf("done.\n");
7189 return;
7190 }
7191 else if (prefix(message, "/guildmemberfix")) {
7192 int slot, members;
7193 hash_entry *ptr;
7194 /* fix wrongly too high # of guild members, caused by (now fixed) guild_dna bug */
7195 s_printf("GUILDMEMBERFIX:\n");
7196 for (i = 1; i < MAX_GUILDS; i++) {
7197 if (!guilds[i].members) continue;
7198 members = 0;
7199 for (slot = 0; slot < NUM_HASH_ENTRIES; slot++) {
7200 ptr = hash_table[slot];
7201 while (ptr) {
7202 if (ptr->guild == i) members++;
7203 ptr = ptr->next;
7204 }
7205 }
7206 if (members != guilds[i].members) s_printf(" Fixed guild %d '%s': %d -> %d\n", i, guilds[i].name, guilds[i].members, members);
7207 else s_printf(" (Guild %d '%s': %d is correct)\n", i, guilds[i].name, members);
7208 guilds[i].members = members;
7209 if (!members) del_guild(i);
7210 }
7211 s_printf("Done.\n");
7212 return;
7213 }
7214 else if (prefix(message, "/guildrename")) {
7215 int i, g;
7216 char old_name[MAX_CHARS], new_name[MAX_CHARS];
7217
7218 if (tk < 1 || !strchr(message3, ':')) {
7219 msg_print(Ind, "Usage: /guildrename <old name>:<new name>");
7220 return;
7221 }
7222
7223 strcpy(old_name, message3);
7224 *(strchr(old_name, ':')) = 0;
7225 strcpy(new_name, strchr(message3, ':') + 1);
7226
7227 if ((g = guild_lookup(old_name)) == -1) {
7228 msg_format(Ind, "\377yGuild '%s' does not exist.", old_name);
7229 return;
7230 }
7231
7232 #if 0
7233 i = p_ptr->guild;
7234 p_ptr->guild = g; /* quick hack for admin */
7235 (void)guild_rename(Ind, new_name);
7236 p_ptr->guild = i;
7237 #else
7238 for (i = 0; i < MAX_GUILDNOTES; i++)
7239 if (!strcmp(guild_note_target[i], guilds[g].name))
7240 strcpy(guild_note_target[i], new_name);
7241
7242 strcpy(guilds[g].name, new_name);
7243 msg_broadcast_format(0, "\377U(Server-Administration) Guild '%s' has been renamed to '%s'.", old_name, new_name);
7244 #endif
7245 return;
7246 }
7247 else if (prefix(message, "/meta")) {
7248 if (!strcmp(message3, "update")) {
7249 msg_print(Ind, "Sending updated info to the metaserver");
7250 Report_to_meta(META_UPDATE);
7251 }
7252 else if (!strcmp(message3, "die")) {
7253 msg_print(Ind, "Reporting to the metaserver that we are dead");
7254 Report_to_meta(META_DIE);
7255 }
7256 else if (!strcmp(message3, "start")) {
7257 msg_print(Ind, "Starting to report to the metaserver");
7258 Report_to_meta(META_START);
7259 }
7260 else {
7261 msg_print(Ind, "Usage: /meta <update|die|start>");
7262 }
7263 return;
7264 }
7265 /* delete current highscore completely */
7266 else if (prefix(message, "/highscorereset")) {
7267 (void)highscore_reset(Ind);
7268 return;
7269 }
7270 /*
7271 * remove an entry from the high score file
7272 * required for restored chars that were lost to bugs - C. Blue :/
7273 */
7274 else if (prefix(message, "/highscorerm")) {
7275 if (tk < 1 || k < 1 || k > MAX_HISCORES) {
7276 msg_format(Ind, "Usage: /hiscorerm 1..%d", MAX_HISCORES);
7277 return;
7278 }
7279 (void)highscore_remove(Ind, k - 1);
7280 return;
7281 }
7282 /* convert current highscore file to new format */
7283 else if (prefix(message, "/highscorecv")) {
7284 (void)highscore_file_convert(Ind);
7285 return;
7286 }
7287 else if (prefix(message, "/rem")) { /* write a remark (comment) to log file, for bookmarking - C. Blue */
7288 char *rem = "-";
7289 if (tk) rem = message3;
7290 s_printf("%s ADMIN_REMARK by %s: %s\n", showtime(), p_ptr->name, rem);
7291 return;
7292 }
7293 else if (prefix(message, "/mcarry")) { /* give a designated item to the monster currently looked at (NOT the one targetted) - C. Blue */
7294 #ifdef MONSTER_INVENTORY
7295 s16b o_idx, m_idx;
7296 object_type *o_ptr;
7297 monster_type *m_ptr;
7298 if (!tk) {
7299 msg_print(Ind, "No inventory slot specified.");
7300 return; /* no inventory slot specified */
7301 }
7302 if (k < 1 || k > INVEN_TOTAL) {
7303 msg_format(Ind, "Inventory slot must be between 1 and %d", INVEN_TOTAL);
7304 return; /* invalid inventory slot index */
7305 }
7306 k--; /* start at index 1, easier for user */
7307 if (!p_ptr->inventory[k].tval) {
7308 msg_print(Ind, "Specified inventory slot is empty.");
7309 return; /* inventory slot empty */
7310 }
7311 if (p_ptr->health_who <= 0) {//target_who
7312 msg_print(Ind, "No monster looked at.");
7313 return; /* no monster targetted */
7314 }
7315 m_idx = p_ptr->health_who;
7316 m_ptr = &m_list[m_idx];
7317 o_ptr = &p_ptr->inventory[k];
7318 o_idx = o_pop();
7319 if (o_idx) {
7320 object_type *j_ptr;
7321 j_ptr = &o_list[o_idx];
7322 object_copy(j_ptr, o_ptr);
7323 j_ptr->owner = 0;
7324 j_ptr->mode = 0;
7325 j_ptr->held_m_idx = m_idx;
7326 j_ptr->next_o_idx = m_ptr->hold_o_idx;
7327 m_ptr->hold_o_idx = o_idx;
7328 #if 1 /* only transfer 1 item instead of a whole stack? */
7329 j_ptr->number = 1;
7330 inven_item_increase(Ind, k, -1);
7331 #else
7332 inven_item_increase(Ind, k, -j_ptr->number);
7333 #endif
7334 inven_item_optimize(Ind, k);
7335 msg_print(Ind, "Monster-carry successfully completed.");
7336 } else {
7337 msg_print(Ind, "No more objects available.");
7338 }
7339 #else
7340 msg_print(Ind, "MONSTER_INVENTORY not defined.");
7341 #endif // MONSTER_INVENTORY
7342 return;
7343 }
7344 else if (prefix(message, "/unown")) { /* clear owner of an item - C. Blue */
7345 object_type *o_ptr;
7346 if (!tk) {
7347 msg_print(Ind, "No inventory slot specified.");
7348 return; /* no inventory slot specified */
7349 }
7350 if (k < 1 || k > INVEN_TOTAL) {
7351 msg_format(Ind, "Inventory slot must be between 1 and %d", INVEN_TOTAL);
7352 return; /* invalid inventory slot index */
7353 }
7354 k--; /* start at index 1, easier for user */
7355 if (!p_ptr->inventory[k].tval) {
7356 msg_print(Ind, "Specified inventory slot is empty.");
7357 return; /* inventory slot empty */
7358 }
7359 o_ptr = &p_ptr->inventory[k];
7360 o_ptr->owner = 0;
7361 o_ptr->mode = 0;
7362 p_ptr->window |= PW_INVEN;
7363 return;
7364 }
7365 else if (prefix(message, "/erasehashtableid")) { /* erase a player id in case there's a duplicate entry in the hash table - mikaelh */
7366 int id;
7367 if (tk < 1) {
7368 msg_print(Ind, "Usage: /erasehashtableid <player id>");
7369 return;
7370 }
7371 id = atoi(message3);
7372 if (!id) {
7373 msg_print(Ind, "Invalid ID");
7374 return;
7375 }
7376 msg_format(Ind, "Erasing player id %d from hash table.", id);
7377 delete_player_id(id);
7378 return;
7379 }
7380 /* check o_list for invalid items - mikaelh */
7381 else if (prefix(message, "/olistcheck")) {
7382 object_type *o_ptr;
7383 msg_print(Ind, "Check o_list for invalid items...");
7384 for (i = 0; i < o_max; i++) {
7385 o_ptr = &o_list[i];
7386
7387 if (!o_ptr->k_idx || o_ptr->k_idx == 1) {
7388 if (o_ptr->held_m_idx) {
7389 msg_format(Ind, "Invalid item (o_idx=%d) (k_idx=%d) held by monster %d", i, o_ptr->k_idx, o_ptr->held_m_idx);
7390 }
7391 else {
7392 msg_format(Ind, "Invalid item (o_idx=%d) (k_idx=%d) found at (%d,%d,%d) (x=%d,y=%d)", i, o_ptr->k_idx, o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz, o_ptr->ix, o_ptr->iy);
7393 }
7394 }
7395 }
7396 msg_print(Ind, "Check complete.");
7397 return;
7398 }
7399 /* check for anomalous items somewhere - mikaelh */
7400 else if (prefix(message, "/floorcheck")) {
7401 struct worldpos wpos;
7402 cave_type **zcave, *c_ptr;
7403 object_type *o_ptr;
7404 int y, x, o_idx;
7405 if (tk > 1) {
7406 wpos.wx = atoi(token[1]);
7407 wpos.wy = atoi(token[2]);
7408 if (tk > 2) wpos.wz = atoi(token[3]);
7409 else wpos.wz = 0;
7410 }
7411 else {
7412 wpcopy(&wpos, &p_ptr->wpos);
7413 }
7414 msg_format(Ind, "Checking (%d,%d,%d)...", wpos.wx, wpos.wy, wpos.wz);
7415 zcave = getcave(&wpos);
7416 if (!zcave) {
7417 msg_print(Ind, "Couldn't getcave().");
7418 return;
7419 }
7420 for (y = 1; y < MAX_HGT - 1; y++) {
7421 for (x = 1; x < MAX_WID - 1; x++) {
7422 c_ptr = &zcave[y][x];
7423 o_idx = c_ptr->o_idx;
7424 if (o_idx) {
7425 if (o_idx > o_max) {
7426 msg_format(Ind, "Non-existent object (o_idx > o_max) (o_idx=%d, o_max=%d) found at (x=%d,y=%d)", c_ptr->o_idx, o_max, x, y);
7427 continue;
7428 }
7429 o_ptr = &o_list[o_idx];
7430 if (memcmp(&o_ptr->wpos, &wpos, sizeof(struct worldpos)) != 0 || x != o_ptr->ix || y != o_ptr->iy) {
7431 msg_format(Ind, "Invalid reference found! Item (o_idx=%d) that should be at (%d, %d, %d) (x=%d, y=%d)", o_idx, o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz, o_ptr->ix, o_ptr->iy);
7432 msg_format(Ind, "Invalid reference is located at (%d, %d, %d) (x=%d, y=%d)", wpos.wx, wpos.wy, wpos.wz, x, y);
7433 }
7434 /* k_idx = 1 is something weird... */
7435 if (!o_ptr->k_idx || o_ptr->k_idx == 1) {
7436 msg_format(Ind, "Invalid item (o_idx=%d) (k_idx=%d) found at (x=%d,y=%d)", o_idx, o_ptr->k_idx, x, y);
7437 }
7438 /* more objects on this grid? */
7439 while (o_ptr->next_o_idx) {
7440 o_idx = o_ptr->next_o_idx;
7441 if (o_idx > o_max) {
7442 msg_format(Ind, "Non-existent object (o_idx > o_max) (o_idx=%d) found under a pile at (x=%d,y=%d)", c_ptr->o_idx, x, y);
7443 break;
7444 }
7445 o_ptr = &o_list[o_idx];
7446 if (memcmp(&o_ptr->wpos, &wpos, sizeof(struct worldpos)) != 0 || x != o_ptr->ix || y != o_ptr->iy) {
7447 msg_format(Ind, "Invalid reference found! Item (o_idx=%d) that should be at (%d, %d, %d) (x=%d, y=%d)", o_idx, o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz, o_ptr->ix, o_ptr->iy);
7448 msg_format(Ind, "Invalid reference is located under a pile at (%d, %d, %d) (x=%d, y=%d)", wpos.wx, wpos.wy, wpos.wz, x, y);
7449 }
7450 if (!o_ptr->k_idx || o_ptr->k_idx == 1) {
7451 msg_format(Ind, "Invalid item (o_idx=%d) (k_idx=%d) found under a pile at (x=%d,y=%d)", o_idx, o_ptr->k_idx, x, y);
7452 }
7453 }
7454 }
7455 }
7456 }
7457 msg_print(Ind, "Check complete.");
7458 return;
7459 }
7460 /* attempt to remove problematic items - mikaelh */
7461 else if (prefix(message, "/floorfix")) {
7462 struct worldpos wpos;
7463 cave_type **zcave, *c_ptr;
7464 object_type *o_ptr, *prev_o_ptr;
7465 int y, x, o_idx;
7466 if (tk > 1) {
7467 wpos.wx = atoi(token[1]);
7468 wpos.wy = atoi(token[2]);
7469 if (tk > 2) wpos.wz = atoi(token[3]);
7470 else wpos.wz = 0;
7471 }
7472 else {
7473 wpcopy(&wpos, &p_ptr->wpos);
7474 }
7475 msg_format(Ind, "Fixing (%d,%d,%d)...", wpos.wx, wpos.wy, wpos.wz);
7476 zcave = getcave(&wpos);
7477 if (!zcave) {
7478 msg_print(Ind, "Couldn't getcave().");
7479 return;
7480 }
7481 for (y = 1; y < MAX_HGT - 1; y++) {
7482 for (x = 1; x < MAX_WID - 1; x++) {
7483 c_ptr = &zcave[y][x];
7484 o_idx = c_ptr->o_idx;
7485 if (o_idx) {
7486 if (o_idx > o_max) {
7487 msg_format(Ind, "Erased reference to a non-existent (o_idx > o_max) object (o_idx=%d, o_max=%d) found at (x=%d,y=%d)", c_ptr->o_idx, o_max, x, y);
7488 c_ptr->o_idx = 0;
7489 continue;
7490 }
7491 o_ptr = &o_list[o_idx];
7492 if (memcmp(&o_ptr->wpos, &wpos, sizeof(struct worldpos)) != 0 || x != o_ptr->ix || y != o_ptr->iy) {
7493 msg_format(Ind, "Invalid reference erased! Found item (o_idx=%d) that should be at (%d, %d, %d) (x=%d, y=%d)", o_idx, o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz, o_ptr->ix, o_ptr->iy);
7494 msg_format(Ind, "Invalid reference was located at (%d, %d, %d) (x=%d, y=%d)", wpos.wx, wpos.wy, wpos.wz, x, y);
7495 c_ptr->o_idx = 0;
7496 }
7497 /* k_idx = 1 is something weird... */
7498 else if (!o_ptr->k_idx || o_ptr->k_idx == 1) {
7499 msg_format(Ind, "Removed an invalid item (o_idx=%d) (k_idx=%d) found at (x=%d,y=%d)", o_idx, o_ptr->k_idx, x, y);
7500 delete_object_idx(o_idx, FALSE);
7501 }
7502 prev_o_ptr = NULL;
7503 /* more objects on this grid? */
7504 while (o_ptr->next_o_idx) {
7505 o_idx = o_ptr->next_o_idx;
7506 if (o_idx > o_max) {
7507 msg_format(Ind, "Erased an invalid reference (o_idx > o_max) (o_idx=%d) from a pile at (x=%d,y=%d)", c_ptr->o_idx, x, y);
7508 o_ptr->next_o_idx = 0;
7509 break;
7510 }
7511 prev_o_ptr = o_ptr;
7512 o_ptr = &o_list[o_idx];
7513 if (memcmp(&o_ptr->wpos, &wpos, sizeof(struct worldpos)) != 0 || x != o_ptr->ix || y != o_ptr->iy) {
7514 msg_format(Ind, "Invalid reference erased! Found item (o_idx=%d) that should be at (%d, %d, %d) (x=%d, y=%d)", o_idx, o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz, o_ptr->ix, o_ptr->iy);
7515 msg_format(Ind, "Invalid reference was located under a pile at (%d, %d, %d) (x=%d, y=%d)", wpos.wx, wpos.wy, wpos.wz, x, y);
7516 if (prev_o_ptr) prev_o_ptr->next_o_idx = o_ptr->next_o_idx;
7517 }
7518 else if (!o_ptr->k_idx || o_ptr->k_idx == 1) {
7519 msg_format(Ind, "Removed an invalid item (o_idx=%d) (k_idx=%d) from a pile at (x=%d,y=%d)", o_idx, o_ptr->k_idx, x, y);
7520 delete_object_idx(o_idx, FALSE);
7521 }
7522 }
7523 }
7524 }
7525 }
7526 msg_print(Ind, "Everything fixed.");
7527 return;
7528 }
7529 /* delete a line from bbs */
7530 else if (prefix(message, "/dbbs")) {
7531 if (tk != 1) {
7532 msg_print(Ind, "Usage: /dbbs <line number>");
7533 return;
7534 }
7535 bbs_del_line(k);
7536 return;
7537 }
7538 /* erase all bbs lines */
7539 else if (prefix(message, "/ebbs")) {
7540 bbs_erase();
7541 return;
7542 }
7543 else if (prefix(message, "/reward")) { /* for testing purpose - C. Blue */
7544 if (!tk) {
7545 msg_print(Ind, "Usage: /reward <player name>");
7546 return;
7547 }
7548 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
7549 if (!j) return;
7550 msg_print(j, "\377GYou have been rewarded by the gods!");
7551
7552 // create_reward(j, o_ptr, 1, 100, TRUE, TRUE, make_resf(Players[j]) | RESF_NOHIDSM, 5000);
7553 give_reward(j, RESF_LOW2, NULL, 0, 100);
7554 return;
7555 }
7556 else if (prefix(message, "/debug1")) { /* debug an issue at hand */
7557 for (j = INVEN_TOTAL; j >= 0; j--)
7558 if (p_ptr->inventory[j].tval == TV_AMULET && p_ptr->inventory[j].sval == SV_AMULET_HIGHLANDS)
7559 invcopy(&p_ptr->inventory[j], lookup_kind(TV_AMULET, SV_AMULET_HIGHLANDS2));
7560 p_ptr->update |= (PU_BONUS | PU_VIEW);
7561 handle_stuff(Ind);
7562 msg_print(Ind, "debug1");
7563 return;
7564 }
7565 else if (prefix(message, "/debug2")) { /* debug an issue at hand */
7566 for (j = INVEN_TOTAL - 1; j >= 0; j--)
7567 if (p_ptr->inventory[j].tval == TV_AMULET && p_ptr->inventory[j].sval == SV_AMULET_HIGHLANDS) {
7568 invcopy(&p_ptr->inventory[j], lookup_kind(TV_AMULET, SV_AMULET_HIGHLANDS2));
7569 p_ptr->inventory[j].number = 1;
7570 p_ptr->inventory[j].level = 0;
7571 p_ptr->inventory[j].discount = 0;
7572 p_ptr->inventory[j].ident |= ID_MENTAL;
7573 p_ptr->inventory[j].owner = p_ptr->id;
7574 p_ptr->inventory[j].mode = p_ptr->mode;
7575 object_aware(Ind, &p_ptr->inventory[j]);
7576 object_known(&p_ptr->inventory[j]);
7577 }
7578 p_ptr->update |= (PU_BONUS | PU_VIEW);
7579 p_ptr->window |= (PW_INVEN | PW_EQUIP);
7580 handle_stuff(Ind);
7581 msg_print(Ind, "debug2");
7582 return;
7583 }
7584 else if (prefix(message, "/daynight")) { /* switch between day and night - use carefully! */
7585 int h = (turn % DAY) / HOUR;
7586 turn -= (turn % DAY) % HOUR;
7587 if (h < SUNRISE) turn += (SUNRISE - h) * HOUR - 1;
7588 else if (h < NIGHTFALL) turn += (NIGHTFALL - h) * HOUR - 1;
7589 else turn += (24 + SUNRISE - h) * HOUR - 1;
7590 return;
7591 }
7592 else if (prefix(message, "/season")) { /* switch through 4 seasons */
7593 if (tk >= 1) {
7594 if (k < 0 || k > 3) {
7595 msg_print(Ind, "Usage: /season [0..3]");
7596 return;
7597 }
7598 season_change(k, FALSE);
7599 }
7600 else season_change((season + 1) % 4, FALSE);
7601 return;
7602 }
7603 else if (prefix(message, "/weather")) { /* toggle snowfall during WINTER_SEASON */
7604 #ifdef CLIENT_SIDE_WEATHER
7605 if (tk) {
7606 if (k) weather = 0;
7607 else if (season == SEASON_WINTER) weather = 2;
7608 else weather = 1;
7609 }
7610 weather_duration = 0;
7611 #else
7612 if (tk >= 1) weather = k;
7613 else if (weather == 1) weather = 0;
7614 else {
7615 weather = 1;
7616 weather_duration = 60 * 4; /* 4 minutes */
7617 }
7618 #endif
7619 return;
7620 }
7621 /* toggle own client-side weather for testing purpose:
7622 This overrides regular weather, to reenable use
7623 /cweather -1 x x x.
7624 Syntax: Type, Wind, WEATHER_GEN_TICKS, Intensity, Speed.
7625 To turn on rain: 1 0 3 8 3 */
7626 else if (prefix(message, "/cweather") || prefix(message, "/cw")) {
7627 if (k == -1) p_ptr->custom_weather = FALSE;
7628 else p_ptr->custom_weather = TRUE;
7629 /* Note: 'cloud'-shaped restrictions don't apply
7630 if there are no clouds in the current sector.
7631 In that case, the weather will simply fill the
7632 whole worldmap sector.
7633 revoke_clouds is TRUE here, so it'll be all-sector. */
7634 Send_weather(Ind,
7635 atoi(token[1]), atoi(token[2]), atoi(token[3]), atoi(token[4]), atoi(token[5]),
7636 FALSE, TRUE);
7637 return;
7638 }
7639 else if (prefix(message, "/jokeweather")) {//unfinished
7640 if (!k || k > NumPlayers) return;
7641 if (Players[k]->joke_weather == 0) {
7642 /* check clouds from first to last (so it has a good chance of
7643 getting into the 10 that will actually be transmitted) */
7644 for (i = 0; i < MAX_CLOUDS; i++) {
7645 /* assume that 'permanent' clouds are set only by us (might change)
7646 and don't abuse those, since they are already reserved for a player ;) */
7647 if (cloud_dur[i] != -1) {
7648 Players[k]->joke_weather = i + 1; /* 0 is reserved for 'disabled' */
7649 cloud_dur[i] = -1;
7650
7651 /* set cloud parameters */
7652 cloud_x1[i] = Players[k]->px - 1;
7653 cloud_y1[i] = Players[k]->py;
7654 cloud_x2[i] = Players[k]->px + 1;
7655 cloud_y2[i] = Players[k]->py;
7656 cloud_state[i] = 1;
7657 cloud_dsum[i] = 7;
7658 cloud_xm100[i] = 0;
7659 cloud_ym100[i] = 0;
7660 cloud_mdur[i] = 200;
7661
7662 /* send new situation to everyone */
7663 #if 0
7664 wild_info[Players[k]->wpos.wy][Players[k]->wpos.wx].weather_type = (season == SEASON_WINTER ? 2 : 1);
7665 wild_info[Players[k]->wpos.wy][Players[k]->wpos.wx].weather_updated = TRUE;
7666 #else
7667 Send_weather(Ind,
7668 1, 0, 3, 8, 3,
7669 TRUE, FALSE);
7670 #endif
7671 break;
7672 }
7673 }
7674 } else {
7675 /* run out (and thereby get freed) next turn */
7676 cloud_dur[Players[k]->joke_weather - 1] = 1;
7677 Players[k]->joke_weather = 0;
7678 }
7679 return;
7680 }
7681 else if (prefix(message, "/fireworks")) { /* toggle fireworks during NEW_YEARS_EVE */
7682 if (tk >= 1) {
7683 fireworks = k;
7684 }
7685 else if (fireworks) fireworks = 0;
7686 else fireworks = 1;
7687 return;
7688 }
7689 else if (prefix(message, "/lightning")) {
7690 cast_lightning(&p_ptr->wpos, p_ptr->px, p_ptr->py);
7691 return;
7692 }
7693 else if (prefix(message, "/hostilities")) {
7694 player_list_type *ptr;
7695
7696 for (i = 1; i <= NumPlayers; i++) {
7697 ptr = Players[i]->hostile;
7698
7699 while (ptr) {
7700 if (player_list_find(Players[i]->blood_bond, ptr->id)) {
7701 msg_format(Ind, "%s is hostile towards %s. (blood bond)", p_ptr->name, lookup_player_name(ptr->id));
7702 }
7703 else {
7704 msg_format(Ind, "%s is hostile towards %s.", p_ptr->name, lookup_player_name(ptr->id));
7705 }
7706 }
7707
7708 ptr = ptr->next;
7709 }
7710
7711 msg_print(Ind, "\377sEnd of hostility list.");
7712 return;
7713 }
7714 else if (prefix(message, "/debugstore")) { /* parameter is # of maintenance runs to perform at once (1..10) */
7715 if (tk > 0) {
7716 if (!store_debug_mode) store_debug_startturn = turn;
7717
7718 /* reset maintenance-timer for cleanness */
7719 for (i = 0; i < numtowns; i++)
7720 for (j = 0; j < max_st_idx; j++)
7721 town[i].townstore[j].last_visit = turn;
7722
7723 store_debug_mode = k;
7724
7725 if (tk > 1) store_debug_quickmotion = atoi(token[2]);
7726 else store_debug_quickmotion = 10;
7727
7728 s_printf("STORE_DEBUG_MODE: freq %d, time x%d at %s (%d).\n", store_debug_mode, store_debug_quickmotion, showtime(), turn - store_debug_startturn);
7729 }
7730 msg_format(Ind, "store_debug_mode: freq %d, time x%d.", store_debug_mode, store_debug_quickmotion);
7731 return;
7732 }
7733 else if (prefix(message, "/costs")) { /* shows monetary details about an object */
7734 object_type *o_ptr;
7735 char o_name[ONAME_LEN];
7736 if (tk < 1)
7737 {
7738 msg_print(Ind, "\377oUsage: /costs <inventory-slot>");
7739 return;
7740 }
7741 if (atoi(token[1]) < 1 || atoi(token[1]) >= INVEN_TOTAL) {
7742 msg_print(Ind, "\377oInvalid inventory slot.");
7743 return;
7744 }
7745 o_ptr = &p_ptr->inventory[atoi(token[1]) - 1];
7746 object_desc(Ind, o_name, o_ptr, FALSE, 0);
7747 msg_format(Ind, "Overview for item %s in slot %d:",
7748 o_name, atoi(token[1]));
7749 msg_format(Ind, "Flag cost: %d; for artifact: %d.",
7750 flag_cost(o_ptr, o_ptr->pval), artifact_flag_cost(o_ptr, o_ptr->pval));
7751 msg_format(Ind, "Your value: %d.", object_value(Ind, o_ptr));
7752 msg_format(Ind, "Your real value: %d; for artifact: %d.",
7753 object_value_real(Ind, o_ptr), artifact_value_real(Ind, o_ptr));
7754 msg_format(Ind, "Full real value: %d; for artifact: %d.",
7755 object_value_real(0, o_ptr), artifact_value_real(0, o_ptr));
7756 msg_format(Ind, "Discount %d; aware? %d; known? %d; broken? %d.",
7757 o_ptr->discount, object_aware_p(Ind, o_ptr), object_known_p(Ind, o_ptr), broken_p(o_ptr));
7758 return;
7759 }
7760 #if 0
7761 /* 'unbreak' all EDSMs in someone's inventory -- added to fix EDSMs after accidental seal-conversion
7762 when seals had 0 value and therefore obtained ID_BROKEN automatically on loading */
7763 else if (prefix(message, "/unbreak")) {
7764 if (!tk) {
7765 msg_print(Ind, "Usage: /unbreak <name>");
7766 return;
7767 }
7768
7769 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
7770 if (!j) {
7771 msg_print(Ind, "Name not found.");
7772 return;
7773 }
7774
7775 for (i = 0; i < INVEN_PACK; i++) {
7776 if (Players[j]->inventory[i].tval != TV_DRAG_ARMOR) continue;
7777 if (Players[j]->inventory[i].sval != SV_DRAGON_SHINING) continue;
7778 Players[j]->inventory[i].ident &= ~ID_BROKEN;
7779 msg_print(Ind, "<fixed>");
7780 }
7781
7782 msg_print(Ind, "Done.");
7783 return;
7784 }
7785 #endif
7786 /* just calls cron_24h as if it was time to do so */
7787 else if (prefix(message, "/debugdate")) {
7788 int dwd, dd, dm, dy;
7789 get_date(&dwd, &dd, &dm, &dy);
7790 exec_lua(0, format("cron_24h(\"%s\", %d, %d, %d, %d, %d, %d, %d)", showtime(), 0, 0, 0, dwd, dd, dm, dy));
7791 return;
7792 }
7793 /* copy an object from someone's inventory into own inventory */
7794 else if (prefix(message, "/ocopy")) {
7795 object_type forge, *o_ptr = &forge;
7796 if (tk < 2) {
7797 msg_print(Ind, "Usage: /ocopy <1..38> <name>");
7798 return;
7799 }
7800
7801 /* syntax: /ocopy <1..38> <name> */
7802 j = name_lookup_loose(Ind, strstr(message3, " ") + 1, FALSE, FALSE);
7803 if (!j) {
7804 msg_print(Ind, "Name not found.");
7805 return;
7806 }
7807 object_copy(o_ptr, &Players[j]->inventory[atoi(token[1]) - 1]);
7808
7809 /* skip true arts to prevent duplicates */
7810 if (true_artifact_p(o_ptr)) {
7811 if (!multiple_artifact_p(o_ptr)) {
7812 msg_print(Ind, "Skipping true artifact.");
7813 return;
7814 }
7815 handle_art_inum(o_ptr->name1);
7816 }
7817 inven_carry(Ind, o_ptr);
7818 msg_print(Ind, "Done.");
7819 return;
7820 }
7821 /* re-initialize the skill chart */
7822 else if (prefix(message, "/fixskills")) {
7823 if (tk < 1) return;
7824 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
7825 if (j < 1) return;
7826 lua_fix_skill_chart(j);
7827 return;
7828 }
7829 /* debug-hack: set all items within houses to ITEM_REMOVAL_HOUSE - C. Blue
7830 warning: can cause a pause of serious duration >:) */
7831 else if (prefix(message, "/debugitemremovalhouse")) {
7832 cave_type **zcave;
7833 object_type *o_ptr;
7834 j = 0;
7835 bool sj;
7836 /* go through all items (well except for player inventories
7837 or tradehouses, but that's not needed anyway) */
7838 for(i = 0; i < o_max; i++){
7839 o_ptr = &o_list[i];
7840 /* check unprotected items on the world's surface in CAVE_ICKY locations, ie houses */
7841 if(o_ptr->k_idx && o_ptr->marked2 == ITEM_REMOVAL_NORMAL && !o_ptr->wpos.wz) {
7842 /* make sure object's floor is currently allocated so we can test for CAVE_ICKY flag */
7843 h = 0;
7844 if (!getcave(&o_ptr->wpos)) {
7845 alloc_dungeon_level(&o_ptr->wpos);
7846 h = 1;
7847 /* relink c_ptr->o_idx with objects */
7848 wilderness_gen(&o_ptr->wpos);
7849 }
7850 if ((zcave = getcave(&o_ptr->wpos))) { /* paranoia? */
7851 /* monster traps hack */
7852 sj = FALSE;
7853 if (!in_bounds_array(o_ptr->iy, o_ptr->ix) &&
7854 in_bounds_array(255 - o_ptr->iy, o_ptr->ix)){
7855 sj = TRUE;
7856 o_ptr->iy = 255 - o_ptr->iy;
7857 }
7858 /* in a house (or vault, theoretically) */
7859 if (zcave[o_ptr->iy][o_ptr->ix].info & CAVE_ICKY) {
7860 /* mark item as 'inside house' */
7861 o_ptr->marked2 = ITEM_REMOVAL_HOUSE;
7862 /* count for fun */
7863 j++;
7864 }
7865 /* restore monster traps hack */
7866 if(sj) o_ptr->iy = 255 - o_ptr->iy;
7867 /* remove our exclusively allocated level again */
7868 if (h) dealloc_dungeon_level(&o_ptr->wpos);
7869 } else {
7870 /* display warning! */
7871 msg_format(Ind, "WARNING: Couldn't allocate %d,%d,%d.",
7872 o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz);
7873 s_printf("Debugging ITEM_REMOVAL_HOUSE couldn't allocate %d,%d,%d.\n",
7874 o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz);
7875 }
7876 }
7877 }
7878 /* give msg and quit */
7879 msg_format(Ind, "Set %d items to ITEM_REMOVAL_HOUSE.", j);
7880 s_printf("Set %d items to ITEM_REMOVAL_HOUSE.\n", j);
7881 return;
7882 }
7883 /* debug-hack: un-perma all death loot or other ITEM_REMOVAL_NEVER
7884 items in wilderness, to clean 'lost items' off the object list - C. Blue
7885 warning: can cause a pause of serious duration >:)
7886 note: also un-permas 'game pieces' and generated items such as
7887 cabbage etc. :/ */
7888 else if (prefix(message, "/purgeitemremovalnever")) {
7889 cave_type **zcave;
7890 object_type *o_ptr;
7891 j = 0;
7892 bool sj;
7893 /* go through all items (well except for player inventories
7894 or tradehouses, but that's not needed anyway) */
7895 for(i = 0; i < o_max; i++){
7896 o_ptr = &o_list[i];
7897 /* check ITEM_REMOVAL_NEVER items on the world's surface that aren't inside houses */
7898 if(o_ptr->k_idx && o_ptr->marked2 == ITEM_REMOVAL_NEVER && !o_ptr->wpos.wz) {
7899 /* make sure object's floor is currently allocated so we can test for CAVE_ICKY flag;
7900 this is neccessary for server-generated public house contents for example */
7901 h = 0;
7902 if (!getcave(&o_ptr->wpos)) {
7903 alloc_dungeon_level(&o_ptr->wpos);
7904 h = 1;
7905 /* relink c_ptr->o_idx with objects */
7906 wilderness_gen(&o_ptr->wpos);
7907 }
7908 if ((zcave = getcave(&o_ptr->wpos))) { /* paranoia? */
7909 /* monster traps hack */
7910 sj = FALSE;
7911 if (!in_bounds_array(o_ptr->iy, o_ptr->ix) &&
7912 in_bounds_array(255 - o_ptr->iy, o_ptr->ix)){
7913 sj = TRUE;
7914 o_ptr->iy = 255 - o_ptr->iy;
7915 }
7916 /* not in a house (or vault, theoretically) */
7917 if (!(zcave[o_ptr->iy][o_ptr->ix].info & CAVE_ICKY)) {
7918 /* remove permanence */
7919 o_ptr->marked2 = ITEM_REMOVAL_NORMAL;
7920 /* count for fun */
7921 j++;
7922 }
7923 /* restore monster traps hack */
7924 if(sj) o_ptr->iy = 255 - o_ptr->iy;
7925 /* remove our exclusively allocated level again */
7926 if (h) dealloc_dungeon_level(&o_ptr->wpos);
7927 } else {
7928 /* display warning! */
7929 msg_format(Ind, "WARNING: Couldn't allocate %d,%d,%d.",
7930 o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz);
7931 s_printf("Purging ITEM_REMOVAL_NEVER couldn't allocate %d,%d%d.\n",
7932 o_ptr->wpos.wx, o_ptr->wpos.wy, o_ptr->wpos.wz);
7933 }
7934 }
7935 }
7936 /* give msg and quit */
7937 msg_format(Ind, "Set %d items to ITEM_REMOVAL_NORMAL.", j);
7938 s_printf("Purged ITEM_REMOVAL_NEVER off %d items.\n", j);
7939 return;
7940 }
7941 /* fire up all available status tags in the display to see
7942 which space is actually occupied and which is free */
7943 else if (prefix(message, "/testdisplay")) {
7944 struct worldpos wpos;
7945 wpos.wx = 0; wpos.wy = 0; wpos.wz = 200;
7946 Send_extra_status(Ind, "ABCDEFGHIJKL");
7947 // Send_depth(Ind, &wpos);
7948 Send_depth_hack(Ind, &wpos, TRUE, "TOONTOWNoO");
7949 Send_food(Ind, PY_FOOD_MAX);
7950 Send_blind(Ind, TRUE);
7951 Send_confused(Ind, TRUE);
7952 Send_fear(Ind, TRUE);
7953 Send_poison(Ind, TRUE);
7954 Send_state(Ind, TRUE, TRUE, TRUE);
7955 Send_speed(Ind, 210);
7956 if (is_older_than(&p_ptr->version, 4, 4, 8, 5, 0, 0))
7957 Send_study(Ind, TRUE);
7958 else Send_bpr(Ind, 99, TERM_L_RED);
7959 Send_cut(Ind, 1001);
7960 Send_stun(Ind, 101);
7961 Send_AFK(Ind, 1);
7962 Send_encumberment(Ind, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
7963 Send_monster_health(Ind, 10, TERM_VIOLET);
7964 return;
7965 }
7966 /* test new \376, \375, \374 chat line prefixes */
7967 else if (prefix(message, "/testchat")) {
7968 msg_print(Ind, "No code.");
7969 msg_print(Ind, "\376376 code.");
7970 msg_print(Ind, "No code.");
7971 msg_print(Ind, "\375375 code.");
7972 msg_print(Ind, "No code.");
7973 msg_print(Ind, "\374374 code.");
7974 msg_print(Ind, "No code.");
7975 msg_print(Ind, "[Chat-style].");
7976 msg_print(Ind, "No code.");
7977 msg_print(Ind, "[Chat-style].");
7978 msg_print(Ind, "~'~' follow-up.");
7979 msg_print(Ind, "No code.");
7980 return;
7981 }
7982 else if (prefix(message, "/initlua")) {
7983 msg_print(Ind, "Reinitializing Lua");
7984 reinit_lua();
7985 return;
7986 }
7987 /* hazardous/incomplete */
7988 else if (prefix(message, "/reinitarrays")) {
7989 msg_print(Ind, "Reinitializing some arrays");
7990 reinit_some_arrays();
7991 return;
7992 }
7993 else if (prefix(message, "/bench")) {
7994 if (tk < 1) {
7995 msg_print(Ind, "Usage: /bench <something>");
7996 msg_print(Ind, "Use on an empty server!");
7997 return;
7998 }
7999 do_benchmark(Ind);
8000 return;
8001 }
8002 else if (prefix(message, "/pings")) {
8003 struct timeval now;
8004 player_type *q_ptr;
8005
8006 if (tk < 1) {
8007 msg_print(Ind, "Usage: /pings <player>");
8008 return;
8009 }
8010
8011 j = name_lookup_loose(Ind, message3, FALSE, TRUE);
8012 if (!j) {
8013 msg_format(Ind, "Couldn't find player %s.", token[1]);
8014 return;
8015 }
8016 q_ptr = Players[j];
8017
8018 gettimeofday(&now, NULL);
8019
8020 msg_format(Ind, "Last pings for player %s:", q_ptr->name);
8021
8022 /* Starting from latest */
8023 for (i = 0; i < MAX_PING_RECVS_LOGGED; i++) {
8024 j = (q_ptr->pings_received_head - i + MAX_PING_RECVS_LOGGED) % MAX_PING_RECVS_LOGGED;
8025 if (q_ptr->pings_received[j].tv_sec) {
8026 msg_format(Ind, " - %s", timediff(&q_ptr->pings_received[j], &now));
8027 }
8028 }
8029
8030 return;
8031 }
8032 else if (prefix(message, "/dmpriv")) {
8033 if (!p_ptr->admin_dm) { // || !cfg.secret_dungeon_master) {
8034 msg_print(Ind, "Command only available to hidden dungeon masters.");
8035 return;
8036 }
8037 if (p_ptr->admin_dm_chat)
8038 msg_print(Ind, "You can no longer receive direct private chat from players.");
8039 else
8040 msg_print(Ind, "You can now receive direct private chat from players.");
8041 p_ptr->admin_dm_chat = ~p_ptr->admin_dm_chat;
8042 return;
8043 }
8044 /* unidentifies an item */
8045 else if (prefix(message, "/unid")) {
8046 object_type *o_ptr;
8047 char note2[80], noteid[10];
8048
8049 if (!tk) {
8050 msg_print(Ind, "No inventory slot specified.");
8051 return; /* no inventory slot specified */
8052 }
8053 if (k < 1 || k > INVEN_TOTAL) {
8054 msg_format(Ind, "Inventory slot must be between 1 and %d", INVEN_TOTAL);
8055 return; /* invalid inventory slot index */
8056 }
8057 k--; /* start at index 1, easier for user */
8058 if (!p_ptr->inventory[k].tval) {
8059 msg_print(Ind, "Specified inventory slot is empty.");
8060 return; /* inventory slot empty */
8061 }
8062 o_ptr = &p_ptr->inventory[k];
8063 /* Hack -- Clear the "empty" flag */
8064 o_ptr->ident &= ~ID_EMPTY;
8065 /* Hack -- Clear the "known" flag */
8066 o_ptr->ident &= ~ID_KNOWN;
8067 /* Hack -- Clear the "felt" flag */
8068 o_ptr->ident &= ~(ID_SENSE | ID_SENSED_ONCE | ID_MENTAL | ID_SENSE_HEAVY);
8069 p_ptr->window |= PW_INVEN;
8070
8071 /* remove pseudo-id tags too */
8072 if (o_ptr->note) {
8073 note_crop_pseudoid(note2, noteid, quark_str(o_ptr->note));
8074 if (!note2[0]) o_ptr->note = 0;
8075 else o_ptr->note = quark_add(note2);
8076 }
8077 return;
8078 }
8079 else if (prefix(message, "/ai")) { /* returns/resets all AI flags and states of monster currently looked at (NOT the one targetted) - C. Blue */
8080 monster_type *m_ptr;
8081 int m_idx;
8082 if (p_ptr->health_who <= 0) {//target_who
8083 msg_print(Ind, "No monster looked at.");
8084 return; /* no monster targetted */
8085 }
8086 m_idx = p_ptr->health_who;
8087 m_ptr = &m_list[m_idx];
8088 if (!tk) msg_print(Ind, "Current Monster AI state:");
8089 else msg_print(Ind, "Former monster AI state (RESETTING NOW):");
8090 #ifdef ANTI_SEVEN_EXPLOIT
8091 msg_format(Ind, " ANTI_SEVEN_EXPLOIT (PD %d, X %d, Y %d, CD %d, DD %d, PX %d, PY %d).",
8092 m_ptr->previous_direction, m_ptr->damage_tx, m_ptr->damage_ty, m_ptr->cdis_on_damage, m_ptr->damage_dis, m_ptr->p_tx, m_ptr->p_ty);
8093 if (tk) {
8094 m_ptr->previous_direction = 0;
8095 m_ptr->damage_tx = 0;
8096 m_ptr->damage_ty = 0;
8097 m_ptr->cdis_on_damage = 0;
8098 m_ptr->damage_dis = 0;
8099 m_ptr->p_tx = 0;
8100 m_ptr->p_ty = 0;
8101 }
8102 #endif
8103 return;
8104 }
8105 #ifdef USE_SOUND_2010
8106 else if (prefix(message, "/hmus")) { /* set own music according to the location of someone else */
8107 u32b f;
8108 if (tk < 1) {
8109 msg_print(Ind, "Usage: /hmus <player>");
8110 return;
8111 }
8112 j = name_lookup_loose(Ind, message3, FALSE, FALSE);
8113 if (!j) {
8114 msg_format(Ind, "Couldn't find player %s.", message3);
8115 return;
8116 }
8117
8118 msg_format(Ind, "Using music of player %s.", Players[j]->name);
8119 f = Players[Ind]->esp_link_flags;
8120 Players[Ind]->esp_link_flags &= ~LINKF_VIEW_DEDICATED;
8121 Send_music(Ind, Players[j]->music_current, -1);
8122 Players[Ind]->esp_link_flags = f;
8123 return;
8124 }
8125 else if (prefix(message, "/psfx")) { /* play specific sound */
8126 int vol = 100;
8127 if (tk < 1) {
8128 msg_print(Ind, "Usage: /psfx <sound name> [vol]");
8129 return;
8130 }
8131 if (tk == 2) {
8132 vol = atoi(token[2]);
8133 msg_format(Ind, "Playing <%s> at volume %d%%.", token[1], vol);
8134 sound_vol(Ind, token[1], NULL, SFX_TYPE_COMMAND, FALSE, vol);
8135 } else {
8136 msg_format(Ind, "Playing <%s>.", token[1]);
8137 sound(Ind, token[1], NULL, SFX_TYPE_COMMAND, FALSE);
8138 }
8139 return;
8140 }
8141 else if (prefix(message, "/pmus")) { /* play specific music */
8142 if (tk < 1) {
8143 msg_print(Ind, "Usage: /pmus <music number>");
8144 return;
8145 }
8146 msg_format(Ind, "Playing <%d>.", k);
8147 Send_music(Ind, k, -1);
8148 return;
8149 }
8150 #endif
8151 else if (prefix(message, "/towea")) { /* teleport player to a sector with weather going */
8152 int x, y;
8153 for (x = 0; x < 64; x++)
8154 for (y = 0; y < 64; y++)
8155 if (wild_info[y][x].weather_type > 0 &&
8156 (wild_info[y][x].weather_type == 1 || //rain
8157 wild_info[y][x].weather_type == 2) && //snow
8158 wild_info[y][x].cloud_idx[0] > 0 &&
8159 wild_info[y][x].cloud_x1[0] > 0) {
8160 /* skip sectors 'before' us? (counting from bottom left corner) */
8161 if (tk && (y < p_ptr->wpos.wy || (y == p_ptr->wpos.wy && x <= p_ptr->wpos.wx))) continue;
8162 /* we're already here? pick a different sector */
8163 if (p_ptr->wpos.wx == x && p_ptr->wpos.wy == y) continue;
8164
8165 p_ptr->recall_pos.wx = x;
8166 p_ptr->recall_pos.wy = y;
8167 p_ptr->recall_pos.wz = 0;
8168 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
8169 recall_player(Ind, "");
8170 return;
8171 }
8172 return;
8173 }
8174 else if (prefix(message, "/madart")) { /* try to create a very specific randart - C. Blue */
8175 /* added this to create a new matching uber bow for Andur, after his old one fell victim to randart code changes. */
8176 object_type *o_ptr;
8177 artifact_type *a_ptr;
8178 int tries = 0; //keep track xD
8179
8180 if (!tk) {
8181 msg_print(Ind, "\377oUsage: /madart <slot>");
8182 return;
8183 }
8184 o_ptr = &p_ptr->inventory[k];
8185 if (!o_ptr->tval) {
8186 msg_print(Ind, "\377oInventory slot empty.");
8187 return;
8188 }
8189 if (o_ptr->name1 != ART_RANDART) {
8190 msg_print(Ind, "\377oNot a randart. Aborting.");
8191 return;
8192 }
8193
8194 msg_print(Ind, "\377yMadness in progress..searching 4E9 combinations :-p");
8195 handle_stuff(Ind);
8196 do {
8197 tries++;
8198 /* Piece together a 32-bit random seed */
8199 o_ptr->name3 = rand_int(0xFFFF) << 16;
8200 o_ptr->name3 += rand_int(0xFFFF);
8201 /* Check the tval is allowed */
8202 if ((a_ptr = randart_make(o_ptr)) == NULL) {
8203 /* If not, wipe seed. No randart today */
8204 o_ptr->name1 = 0;
8205 o_ptr->name3 = 0L;
8206 msg_print(Ind, "Randart creation failed.");
8207 return;
8208 }
8209 o_ptr->timeout = 0;
8210 apply_magic(&p_ptr->wpos, o_ptr, p_ptr->lev, FALSE, FALSE, FALSE, FALSE, RESF_FORCERANDART | RESF_NOTRUEART);
8211
8212 i = 0;
8213 if ((a_ptr->flags2 & TR2_IM_FIRE)) i++;
8214 if ((a_ptr->flags2 & TR2_IM_COLD)) i++;
8215 if ((a_ptr->flags2 & TR2_IM_ELEC)) i++;
8216 if ((a_ptr->flags2 & TR2_IM_ACID)) i++;
8217 if ((a_ptr->flags5 & TR5_IM_POISON)) i++;
8218 } while (
8219 //i < 2 ||
8220 //o_ptr->to_h < 30 ||
8221 //o_ptr->to_d < 30 ||
8222 //o_ptr->to_a < 30 ||
8223 o_ptr->pval < 9 ||
8224
8225 //o_ptr->dd < 3 ||
8226 //!((a_ptr->flags1 & TR1_SLAY_DRAGON) || (a_ptr->flags1 & TR1_KILL_DRAGON)) ||
8227 //!((a_ptr->flags1 & TR1_SLAY_DEMON) || (a_ptr->flags1 & TR1_KILL_DEMON)) ||
8228 //!((a_ptr->flags1 & TR1_SLAY_UNDEAD) || (a_ptr->flags1 & TR1_KILL_UNDEAD)) ||
8229 !(a_ptr->flags1 & TR1_BRAND_ELEC) ||
8230
8231 !(a_ptr->flags3 & TR3_SEE_INVIS) ||
8232
8233 //!(a_ptr->flags3 & TR3_SH_ELEC) ||
8234
8235 //!(a_ptr->flags1 & TR1_CON) ||
8236 //!(a_ptr->flags1 & TR1_STEALTH) ||
8237 //!(a_ptr->flags1 & TR1_SPEED) ||
8238 //!(a_ptr->flags2 & TR2_FREE_ACT) ||
8239 //!(a_ptr->flags2 & TR2_RES_BLIND) ||
8240 //!(a_ptr->flags2 & TR2_RES_POIS) ||
8241 //!(a_ptr->flags2 & TR2_RES_FIRE) ||
8242 //!(a_ptr->flags2 & TR2_RES_COLD) ||
8243 //!(a_ptr->flags2 & TR2_RES_ACID) ||
8244 //!(a_ptr->flags2 & TR2_RES_ELEC) ||
8245 //!(a_ptr->flags2 & TR2_IM_FIRE) ||
8246 //!(a_ptr->flags2 & TR2_IM_COLD) ||
8247 //!(a_ptr->flags2 & TR2_RES_SHARDS) ||
8248 //!(a_ptr->flags2 & TR2_RES_NEXUS) ||
8249
8250 //!(a_ptr->flags3 & TR3_XTRA_MIGHT) ||
8251 //!(a_ptr->flags3 & TR3_XTRA_SHOTS) ||
8252 //!(a_ptr->flags1 & TR1_BLOWS) ||
8253 !(a_ptr->flags1 & TR1_VAMPIRIC) ||
8254 !(a_ptr->flags5 & TR5_CRIT) ||
8255
8256 //!(a_ptr->esp & ESP_ALL) ||
8257
8258 (a_ptr->flags3 & TR3_NO_MAGIC) ||
8259 (a_ptr->flags3 & TR3_AGGRAVATE)
8260 );
8261 msg_format(Ind, "Re-rolled randart %d times.", tries);
8262 s_printf("MADART: Re-rolled randart %d times.\n", tries);
8263
8264 o_ptr->ident |= ID_MENTAL; /* *id*ed */
8265 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
8266 return;
8267 }
8268 /* Display all information about the grid an admin-char is currently standing on - C. Blue */
8269 else if (prefix(message, "/debug-grid")){
8270 worldpos *tpos = &p_ptr->wpos;
8271 cave_type **zcave, *c_ptr;
8272 struct c_special *cs_ptr;
8273 if (!(zcave = getcave(tpos))) {
8274 msg_print(Ind, "Fatal: Couldn't acquire zcave!");
8275 return;
8276 }
8277 c_ptr = &zcave[p_ptr->py][p_ptr->px];
8278 cs_ptr = c_ptr->special;
8279 msg_format(Ind, "Feature / org : %d / %d", c_ptr->feat, c_ptr->feat_org);
8280 msg_format(Ind, "Info flags : %d", c_ptr->info);
8281 if (cs_ptr) msg_format(Ind, "1st Special->Type: %d", cs_ptr->type);
8282 else msg_print(Ind, "1st Special->Type: NONE");
8283 return;
8284 }
8285 /* Display various gameplay-related or rather global server status
8286 like seasons and (seasonal) events (for debugging) - C. Blue */
8287 else if (prefix(message, "/vars")) {
8288 msg_format(Ind, "season (0..3): %d.", season);
8289 msg_format(Ind, "season_halloween: %d, season_xmas: %d, season_newyearseve: %d.", season_halloween, season_xmas, season_newyearseve);
8290 msg_format(Ind, "sector weather: %d, sector wind: %d, sector w-speed: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_type, wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_wind, wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_speed);
8291 msg_format(Ind, "server time: %s", showtime());
8292 msg_format(Ind, "lua-seen current date: %d-%d-%d", exec_lua(0, "return cur_year"), exec_lua(0, "return cur_month"), exec_lua(0, "return cur_day"));
8293 return;
8294 }
8295 else if (prefix(message, "/debug-wild")) {
8296 // cptr wf = flags_str(wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags);
8297 msg_format(Ind, "wild_info[%d][%d]:", p_ptr->wpos.wy, p_ptr->wpos.wx);
8298 msg_format(Ind, " terrain: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].type);
8299 msg_format(Ind, " terr-bled: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].bled);
8300 // msg_format(Ind, " flags: %s (%d)", wf, wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags);
8301 // free(wf);
8302 msg_format(Ind, " flags: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags);
8303 msg_format(Ind, " tower: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].tower != NULL ? 1 : 0);
8304 msg_format(Ind, " dungeon: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].dungeon != NULL ? 1 : 0);
8305 msg_format(Ind, " town_idx: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].town_idx);
8306 msg_format(Ind, " townrad: %d", wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].radius);
8307 return;
8308 }
8309 else if (prefix(message, "/fix-wildflock")) {
8310 /* erase WILD_F_..LOCK flags from when the server crashed during dungeon removal (??) */
8311 if (wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags & WILD_F_LOCKDOWN) {
8312 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags &= ~WILD_F_LOCKDOWN;
8313 msg_print(Ind, "WILD_F_LOCKDOWN was set and is now cleared.");
8314 }
8315 if (wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags & WILD_F_LOCKUP) {
8316 wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags &= ~WILD_F_LOCKUP;
8317 msg_print(Ind, "WILD_F_LOCKUP was set and is now cleared.");
8318 }
8319 return;
8320 }
8321 else if (prefix(message, "/fix-house-modes")) {
8322 /* if house doesn't have its mode set yet, search
8323 hash for player who owns it and set mode to his. */
8324 byte m = 0x0;
8325 k = 0;
8326 tk = 0;
8327 for (i = 0; i < num_houses; i++) {
8328 if (houses[i].dna->owner &&
8329 (houses[i].dna->owner_type == OT_PLAYER)) {
8330 m = lookup_player_mode(houses[i].dna->owner);
8331 if (m != houses[i].dna->mode) {
8332 s_printf("hmode %d; ", i);
8333 houses[i].dna->mode = m;
8334 k++;
8335 }
8336 if (houses[i].colour && (m & MODE_EVERLASTING) && houses[i].colour < 100) {
8337 houses[i].colour += 100;
8338 tk++;
8339 }
8340 }
8341 }
8342 s_printf("done (chown %d, chcol %d)\n.", k, tk);
8343 msg_format(Ind, "Houses that had their ownership changed: %d. Colour-mode changed: %d", k, tk);
8344 return;
8345 }
8346 #ifdef TEST_SERVER
8347 else if (prefix(message, "/testreqs")) {
8348 msg_print(Ind, "Sending request(s)...");
8349 switch (k) {
8350 case 0: Send_request_key(Ind, 0, "Key: "); break;
8351 case 1: Send_request_num(Ind, 0, "Num: ", 9); break;
8352 case 2: Send_request_str(Ind, 0, "Str: ", "mh"); break;
8353 case 3: Send_request_cfr(Ind, 0, "Y/n: ", TRUE); break;
8354 }
8355 // Send_request_abort(Ind);
8356 msg_print(Ind, "...done.");
8357 return;
8358 }
8359 #endif
8360 /* Update 'noteworthy occurances' aka legends.log display, for debugging purposes */
8361 else if (prefix(message,"/update-leg")) {
8362 char path[MAX_PATH_LENGTH];
8363 char path_rev[MAX_PATH_LENGTH];
8364 path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_DATA, "legends.log");
8365 path_build(path_rev, MAX_PATH_LENGTH, ANGBAND_DIR_DATA, "legends-rev.log");
8366 /* create reverse version of the log for viewing,
8367 so the latest entries are displayed top first! */
8368 reverse_lines(path, path_rev);
8369 msg_print(Ind, "updated legends-rev.log");
8370 return;
8371 }
8372 /* Test values of deep_dive..[] deep dive record saving array */
8373 else if (prefix(message, "/deepdivestats")) {
8374 for (i = 0; i < IDDC_HIGHSCORE_SIZE; i++) {
8375 //msg_format(Ind, "#%2d. %20s %3d", i + 1, deep_dive_name[i], deep_dive_level[i]);//NAME_LEN
8376 msg_format(Ind, "#%2d. %65s %3d", i, deep_dive_name[i], deep_dive_level[i]);//MAX_CHARS - 15 to fit on screen
8377 msg_format(Ind, " (char '%s', acc '%s', class %d)", deep_dive_char[i], deep_dive_account[i], deep_dive_class[i]);
8378 }
8379 return;
8380 }
8381 else if (prefix(message, "/deepdivefix")) {
8382 #if 0
8383 /* Fix erroneous colour codes in deep_dive_name[] */
8384 char *p, *q, buf[256];
8385 for (i = 0; i < IDDC_HIGHSCORE_SIZE; i++) {
8386 //msg_format(Ind, "#%2d. %20s %3d", i + 1, deep_dive_name[i], deep_dive_level[i]);//NAME_LEN
8387 msg_format(Ind, "#%2d. %65s %3d", i + 1, deep_dive_name[i], deep_dive_level[i]);//MAX_CHARS - 15 to fit on screen
8388 q = NULL;
8389 while ((p = strchr(deep_dive_name[i], '\377'))) {
8390 strcpy(buf, deep_dive_name[i]);
8391 q = strchr(buf, '\377');
8392 strcpy(q + 2, p + 1);
8393 *q = '\\';
8394 *(q + 1) = '{';
8395 strcpy(deep_dive_name[i], buf);
8396 }
8397 if (q) msg_format(Ind, " has been fixed to: <%s>", deep_dive_name[i]);
8398 else msg_print(Ind, " Ok.");
8399 }
8400 #endif
8401 #if 1
8402 char buf[256], *b;
8403
8404 /* delete or complete an entry (to fix duplicate entries, account+class wise) */
8405 if (!tk || (tk > 1 && !strchr(message2, ':'))) {//almost -_-
8406 msg_print(Ind, "usage: /deepdivefix <#entry to delete>");
8407 msg_print(Ind, "usage: /deepdivefix <#entry to modify> <class> <account>:<char>");
8408 msg_print(Ind, "usage: /deepdivefix +<#entry to insert> <class> <account>:<char>");
8409 msg_print(Ind, "usage: /deepdivefix =<#entry to insert> <level>:<name>");
8410 return;
8411 }
8412 //k++;
8413
8414 /* delete mode? */
8415 if (tk == 1) {
8416 msg_print(Ind, "Delete.");
8417 /* pull up all succeeding entries by 1 */
8418 for (i = k; i < IDDC_HIGHSCORE_SIZE - 1; i++) {
8419 deep_dive_level[i] = deep_dive_level[i + 1];
8420 strcpy(deep_dive_name[i], deep_dive_name[i + 1]);
8421 strcpy(deep_dive_char[i], deep_dive_char[i + 1]);
8422 strcpy(deep_dive_account[i], deep_dive_account[i + 1]);
8423 deep_dive_class[i] = deep_dive_class[i + 1];
8424 }
8425 return;
8426 }
8427
8428 /* insert mode? */
8429 if (message3[0] == '+') {
8430 k = atoi(message3 + 1);
8431 msg_print(Ind, "Insert.");
8432 /* push down all succeeding entries by 1 */
8433 for (i = IDDC_HIGHSCORE_SIZE; i > k; i--) {
8434 deep_dive_level[i] = deep_dive_level[i - 1];
8435 strcpy(deep_dive_name[i], deep_dive_name[i - 1]);
8436 strcpy(deep_dive_char[i], deep_dive_char[i - 1]);
8437 strcpy(deep_dive_account[i], deep_dive_account[i - 1]);
8438 deep_dive_class[i] = deep_dive_class[i - 1];
8439 }
8440 /* insert */
8441 strcpy(buf, message3 + strlen(token[1]) + strlen(token[2]) + 2);
8442 b = strchr(buf, ':');
8443 if (!b) {
8444 msg_print(Ind, "failed!");
8445 return;
8446 }
8447 *b = 0;
8448 strcpy(deep_dive_account[k], buf);
8449 b++;
8450 strcpy(deep_dive_char[k], b);
8451 deep_dive_class[k] = atoi(token[2]);
8452 return;
8453 }
8454 /* complete-inserted mode? */
8455 if (message3[0] == '=') {
8456 char *bp;
8457 k = atoi(message3 + 1);
8458 msg_print(Ind, "Complete inserted.");
8459 deep_dive_level[k] = atoi(token[2]);
8460 strcpy(buf, message3 + strlen(token[1]) + 1);
8461 b = strchr(message3, ':');
8462 if (!b) {
8463 msg_print(Ind, "failed!");
8464 return;
8465 }
8466
8467 //convert colour code chars
8468 bp = b + 1;
8469 while (*++b) {
8470 if (*b == '\377') *b = '{';
8471 }
8472
8473 strcpy(deep_dive_name[k], bp);
8474 return;
8475 }
8476
8477 /* complete mode */
8478 msg_print(Ind, "Complete.");
8479 strcpy(buf, message3 + strlen(token[1]) + strlen(token[2]) + 2);
8480 b = strchr(buf, ':');
8481 if (!b) {
8482 msg_print(Ind, "failed!");
8483 return;
8484 }
8485 *b = 0;
8486 strcpy(deep_dive_account[k], buf);
8487 b++;
8488 strcpy(deep_dive_char[k], b);
8489 deep_dive_class[k] = atoi(token[2]);
8490 #endif
8491 return;
8492 }
8493 /* Reset Ironman Deep Dive Challenge records */
8494 else if (prefix(message, "/deepdivereset")) {
8495 char path[MAX_PATH_LENGTH];
8496 char path_rev[MAX_PATH_LENGTH];
8497 path_build(path, MAX_PATH_LENGTH, ANGBAND_DIR_DATA, "legends.log");
8498 path_build(path_rev, MAX_PATH_LENGTH, ANGBAND_DIR_DATA, "legends-rev.log");
8499 /* Reset stats */
8500 for (i = 0; i < IDDC_HIGHSCORE_SIZE; i++) {
8501 strcpy(deep_dive_name[i], "");
8502 deep_dive_level[i] = 0;
8503 strcpy(deep_dive_char[i], "");
8504 strcpy(deep_dive_account[i], "");
8505 deep_dive_class[i] = 0;
8506 }
8507 /* Rebuild legends log file */
8508 reverse_lines(path, path_rev);
8509 msg_print(Ind, "Ironman Deep Dive Challenge records have been reset!");
8510 return;
8511 }
8512 /* list statics; unstatic all empty, static (not stale) floors if parm is given */
8513 else if (prefix(message, "/lsl") || prefix(message, "/lsls") || prefix(message, "/lslsu")) {
8514 int x, y;
8515 struct dungeon_type *d_ptr;
8516 worldpos tpos;
8517 bool stale = FALSE, used = FALSE, unstat = FALSE;
8518
8519 if (prefix(message, "/lsls")) stale = TRUE;
8520 if (prefix(message, "/lslsu")) used = TRUE;
8521 if (tk) unstat = TRUE;
8522
8523 for (x = 0; x < 64; x++) for (y = 0; y < 64; y++) {
8524 /* check surface */
8525 k = 0; tpos.wx = x; tpos.wy = y; tpos.wz = 0;
8526 for (j = 1; j < NumPlayers + 1; j++) if (inarea(&Players[j]->wpos, &tpos)) k++;
8527 if (used && k) msg_format(Ind, "\377g %2d,%2d", x, y);
8528 else if (wild_info[y][x].ondepth > k) {
8529 msg_format(Ind, " %2d,%2d", x, y);
8530 if (unstat) master_level_specific(Ind, &tpos, "u");
8531 }
8532 else if (stale && getcave(&tpos) && stale_level(&tpos, cfg.anti_scum)) msg_format(Ind, "\377D %2d,%2d", x, y);
8533 /* check tower */
8534 if ((d_ptr = wild_info[y][x].tower)) {
8535 //msg_format(Ind, "T max,base = %d,%d", d_ptr->maxdepth, d_ptr->baselevel);
8536 for (i = 0; i < d_ptr->maxdepth; i++) {
8537 k = 0; tpos.wx = x; tpos.wy = y; tpos.wz = i + 1;
8538 for (j = 1; j < NumPlayers + 1; j++) if (inarea(&Players[j]->wpos, &tpos)) k++;
8539 if (used && k) msg_format(Ind, "\377gT %2d,%2d,%2d", x, y, i + 1);
8540 else if (d_ptr->level[i].ondepth > k) {
8541 msg_format(Ind, "T %2d,%2d,%2d", x, y, i + 1);
8542 if (unstat) master_level_specific(Ind, &tpos, "u");
8543 }
8544 else if (stale && getcave(&tpos) && stale_level(&tpos, cfg.anti_scum)) msg_format(Ind, "\377DT %2d,%2d,%2d", x, y, i + 1);
8545 }
8546 }
8547 /* check dungeon */
8548 if ((d_ptr = wild_info[y][x].dungeon)) {
8549 //msg_format(Ind, "D max,base = %d,%d", d_ptr->maxdepth, d_ptr->baselevel);
8550 for (i = 0; i < d_ptr->maxdepth; i++) {
8551 k = 0; tpos.wx = x; tpos.wy = y; tpos.wz = -(i + 1);
8552 for (j = 1; j < NumPlayers + 1; j++) if (inarea(&Players[j]->wpos, &tpos)) k++;
8553 if (used && k) msg_format(Ind, "\377gD %2d,%2d,%2d", x, y, -(i + 1));
8554 else if (d_ptr->level[i].ondepth > k) {
8555 msg_format(Ind, "D %2d,%2d,%2d", x, y, -(i + 1));
8556 if (unstat) master_level_specific(Ind, &tpos, "u");
8557 }
8558 else if (stale && getcave(&tpos) && stale_level(&tpos, cfg.anti_scum)) msg_format(Ind, "\377DD %2d,%2d,%2d", x, y, -(i + 1));
8559 }
8560 }
8561 }
8562 msg_print(Ind, "done.");
8563 return;
8564 }
8565 else if (prefix(message, "/fixguild")) { /* Set a guild to GFLG_EVERLASTING */
8566 if (!tk) {
8567 msg_print(Ind, "Usage: /fixguild <guild_id>");
8568 return;
8569 }
8570 guilds[k].flags |= GFLG_EVERLASTING;
8571 msg_print(Ind, "Guild was set to GFLG_EVERLASTING.");
8572 return;
8573 }
8574 #ifdef DUNGEON_VISIT_BONUS
8575 else if (prefix(message, "/debugdvb")) { /* debug DUNGEON_VISIT_BONUS */
8576 msg_print(Ind, "Experience bonus list for dungeons/towers:");
8577 /* pre-process data for colourization */
8578 j = VISIT_TIME_CAP - 1;
8579 for (i = 1; i <= dungeon_id_max; i++)
8580 if (dungeon_visit_frequency[i] < j) j = dungeon_visit_frequency[i];
8581 /* output the actual list */
8582 for (i = 1; i <= dungeon_id_max; i++) {
8583 msg_format(Ind, " \377%c%s %2d at (%2d,%2d): visit \377%c%3d\377%c -> bonus \377%c%d \377%c- %-28.28s",
8584 (i % 2) == 0 ? 'W' : 'U',
8585 dungeon_tower[i] ? "tower " : "dungeon", i,
8586 dungeon_x[i], dungeon_y[i],
8587 (dungeon_visit_frequency[i] == j) ? 'D' : 'w',
8588 dungeon_visit_frequency[i], (i % 2) == 0 ? 'W' : 'U',
8589 (dungeon_bonus[i] == 0) ? 'w' : ((dungeon_bonus[i] == 1) ? 'y' : ((dungeon_bonus[i] == 2) ? 'o' : 'r')),
8590 dungeon_bonus[i],
8591 (i % 2) == 0 ? 'W' : 'U',
8592 get_dun_name(dungeon_x[i], dungeon_y[i], dungeon_tower[i],
8593 getdungeon(&((struct worldpos){dungeon_x[i], dungeon_y[i], dungeon_tower[i] ? 1 : -1})), 0, FALSE)
8594 // d_name + d_info[dungeon_tower[i] ? wild_info[dungeon_y[i]][dungeon_x[i]].tower->type : wild_info[dungeon_y[i]][dungeon_x[i]].dungeon->type].name
8595 );
8596 }
8597 return;
8598 }
8599 else if (prefix(message, "/reindexdvb")) { /* debug DUNGEON_VISIT_BONUS */
8600 s_printf("Reindexing dungeons:\n");
8601 reindex_dungeons();
8602 msg_print(Ind, "dungeons reindexed.");
8603 return;
8604 }
8605 #endif
8606 else if (prefix(message, "/debug-house")) {
8607 int h_idx;
8608 house_type *h_ptr;
8609
8610 h_idx = pick_house(&p_ptr->wpos, p_ptr->py, p_ptr->px);
8611 if (h_idx == -1) return;
8612 h_ptr = &houses[h_idx];
8613
8614 j = -1;
8615 if (h_ptr->dna->owner &&
8616 (h_ptr->dna->owner_type == OT_PLAYER)) {
8617 j = lookup_player_mode(h_ptr->dna->owner);
8618 }
8619
8620 msg_format(Ind, "house #%d, mode %d, owner-mode %d, colour %d.", h_idx, h_ptr->dna->mode, j, h_ptr->colour);
8621 return;
8622 }
8623 else if (prefix(message, "/debugmd")) {//debug p_ptr->max_depth[]
8624 int p;
8625 if (tk < 1) {
8626 msg_print(Ind, "\377oUsage: /debugmd <player name>");
8627 return;
8628 }
8629 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
8630 if (!p) return;
8631 msg_format(Ind, "max_depth[] for player '%s':", Players[p]->name);
8632 for (i = 0; i < MAX_D_IDX; i++) {
8633 msg_format(Ind, " %d,%d %s %d",
8634 Players[p]->max_depth_wx[i],
8635 Players[p]->max_depth_wy[i],
8636 Players[p]->max_depth_tower[i] ? "t" : "D",
8637 Players[p]->max_depth[i]);
8638 }
8639 return;
8640 }
8641 else if (prefix(message, "/fixmd")) {//debug p_ptr->max_depth[]
8642 int p;
8643 if (tk < 1) {
8644 msg_print(Ind, "\377oUsage: /fixmd <player name>");
8645 return;
8646 }
8647 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
8648 if (!p) return;
8649
8650 fix_max_depth(Players[p]);
8651
8652 msg_format(Ind, "max_depth[] fixed for '%s':", Players[p]->name);
8653 return;
8654 }
8655 else if (prefix(message, "/wipemd")) {
8656 int p;
8657 if (tk < 1) {
8658 msg_print(Ind, "\377oUsage: /wipemd <player name>");
8659 return;
8660 }
8661 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
8662 if (!p) return;
8663
8664 for (i = 0; i < MAX_D_IDX * 2; i++) {
8665 Players[p]->max_depth_wx[i] = 0;
8666 Players[p]->max_depth_wy[i] = 0;
8667 Players[p]->max_depth[i] = 0;
8668 Players[p]->max_depth_tower[i] = FALSE;
8669 }
8670
8671 msg_format(Ind, "max_depth[] wiped for '%s':", Players[p]->name);
8672 return;
8673 }
8674 /* new unfortunately: remove all non-existing dungeons that got added due
8675 to a bug that adds a 'dungeon' everytime on world-surface recall, ew */
8676 else if (prefix(message, "/fix!md")) {
8677 int p;
8678 if (tk < 1) {
8679 msg_print(Ind, "\377oUsage: /fix!md <player name>");
8680 return;
8681 }
8682 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
8683 if (!p) return;
8684
8685 fix_max_depth_bug(Players[p]);
8686
8687 msg_format(Ind, "max_depth[] bug-fixed for '%s':", Players[p]->name);
8688 return;
8689 }
8690 else if (prefix(message, "/fixcondmd")) {
8691 int p;
8692 if (tk < 1) {
8693 msg_print(Ind, "\377oUsage: /fixcondmd <player name>");
8694 return;
8695 }
8696 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
8697 if (!p) return;
8698
8699 condense_max_depth(Players[p]);
8700
8701 msg_format(Ind, "max_depth[] condensation-bug-fixed for '%s':", Players[p]->name);
8702 return;
8703 }
8704 else if (prefix(message, "/fixjaildun")) {//adds DF3_JAIL_DUNGEON flag to a dungeon if on a jail grid
8705 worldpos *tpos = &p_ptr->wpos;
8706 cave_type **zcave, *c_ptr;
8707 wilderness_type *wild = &wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx];
8708 struct dungeon_type *d_ptr;
8709
8710 if (!(zcave = getcave(tpos))) {
8711 msg_print(Ind, "Fatal: Couldn't acquire zcave!");
8712 return;
8713 }
8714 c_ptr = &zcave[p_ptr->py][p_ptr->px];
8715 if (c_ptr->feat != FEAT_LESS && c_ptr->feat != FEAT_MORE) {
8716 msg_print(Ind, "Error: Not standing on a staircase grid.");
8717 return;
8718 }
8719 if (!(c_ptr->info & CAVE_JAIL)) {
8720 msg_print(Ind, "Error: Not standing on a CAVE_JAIL grid.");
8721 return;
8722 }
8723
8724 if (c_ptr->feat == FEAT_LESS) d_ptr = wild->tower;
8725 else d_ptr = wild->dungeon;
8726
8727 d_ptr->flags3 = DF3_JAIL_DUNGEON;
8728 msg_print(Ind, "DF3_JAIL_DUNGEON added.");
8729 return;
8730 }
8731 else if (prefix(message, "/fixiddc")) {//adds DF3_NO_DUNGEON_BONUS to ironman deep dive challenge dungeon
8732 worldpos *tpos = &p_ptr->wpos;
8733 cave_type **zcave, *c_ptr;
8734 wilderness_type *wild = &wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx];
8735 struct dungeon_type *d_ptr;
8736
8737 if (!(zcave = getcave(tpos))) {
8738 msg_print(Ind, "Fatal: Couldn't acquire zcave!");
8739 return;
8740 }
8741 c_ptr = &zcave[p_ptr->py][p_ptr->px];
8742 if (c_ptr->feat != FEAT_LESS && c_ptr->feat != FEAT_MORE) {
8743 msg_print(Ind, "Error: Not standing on a staircase grid.");
8744 return;
8745 }
8746 if (p_ptr->wpos.wx != WPOS_IRONDEEPDIVE_X || p_ptr->wpos.wy != WPOS_IRONDEEPDIVE_Y ||
8747 !(c_ptr->feat == FEAT_LESS ? (WPOS_IRONDEEPDIVE_Z > 0) : (WPOS_IRONDEEPDIVE_Z < 0))) {
8748 msg_print(Ind, "Error: Not standing on IRONDEEDIVE staircase.");
8749 return;
8750 }
8751
8752 if (c_ptr->feat == FEAT_LESS) d_ptr = wild->tower;
8753 else d_ptr = wild->dungeon;
8754
8755 d_ptr->flags3 |= DF3_NO_DUNGEON_BONUS | DF3_EXP_20;
8756 msg_print(Ind, "DF3_NO_DUNGEON_BONUS | DF3_EXP_20 added.");
8757 return;
8758 }
8759 /* adjust iddc flags */
8760 else if (prefix(message, "/fix2iddc")) {
8761 struct dungeon_type *d_ptr;
8762 wilderness_type *wild = &wild_info[WPOS_IRONDEEPDIVE_Y][WPOS_IRONDEEPDIVE_X];
8763
8764 if (WPOS_IRONDEEPDIVE_Z > 0) d_ptr = wild->tower;
8765 else d_ptr = wild->dungeon;
8766
8767 if (!d_ptr) {
8768 msg_print(Ind, "weird error.");
8769 return;
8770 }
8771
8772 //d_ptr->flags1 = d_ptr->flags1;
8773 //d_ptr->flags2 = d_ptr->flags2;
8774 d_ptr->flags3 = d_ptr->flags3 | DF3_DEEPSUPPLY;
8775 //d_ptr->baselevel = 1;
8776 //d_ptr->maxdepth = 127;
8777 return;
8778 }
8779 /* add experimental dungeon flags */
8780 else if (prefix(message, "/dunmkexp")) {
8781 struct dungeon_type *d_ptr;
8782 cave_type **zcave = getcave(&p_ptr->wpos);
8783
8784 switch(zcave[p_ptr->py][p_ptr->px].feat){
8785 case FEAT_MORE:
8786 d_ptr = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].dungeon;
8787 break;
8788 case FEAT_LESS:
8789 d_ptr = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].tower;
8790 break;
8791 default:
8792 msg_print(Ind, "There is no dungeon here");
8793 return;
8794 }
8795
8796 /* already has these flags? then remove them again */
8797 if (!(d_ptr->flags3 & DF3_NO_TELE)) {
8798 if (tk) {
8799 if (k == 0) {
8800 d_ptr->flags3 |= DF3_NO_TELE | DF3_NO_SUMMON | DF3_NO_ESP;
8801 msg_print(Ind, "Flags NT/NS/NE added.");
8802 } else {
8803 d_ptr->flags3 &= ~DF3_NO_ESP;
8804 d_ptr->flags3 |= DF3_NO_TELE | DF3_NO_SUMMON | DF3_LIMIT_ESP;
8805 msg_print(Ind, "Flags NT/NS/LE added.");
8806 }
8807 } else {
8808 d_ptr->flags3 |= DF3_NO_TELE | DF3_NO_SUMMON;
8809 msg_print(Ind, "Flags NT/NS added.");
8810 }
8811 } else {
8812 d_ptr->flags3 &= ~(DF3_NO_TELE | DF3_NO_SUMMON | DF3_NO_ESP | DF3_LIMIT_ESP);
8813 msg_print(Ind, "Flags removed.");
8814 }
8815 return;
8816 }
8817 if (prefix(message, "/terminate")) {
8818 /* same as /shutdown 0, except server will return -2 instead of -1.
8819 can be used by scripts to initiate maintenance downtime etc. */
8820 set_runlevel(-1);
8821
8822 /* paranoia - set_runlevel() will call exit() */
8823 time(&cfg.closetime);
8824 return;
8825 }
8826 /* back up all house prices and items/gold inside houses for all
8827 characters to lib/save/estate/ and invoke /terminate right
8828 afterwards if the parameter "term" is given. - C. Blue */
8829 if (prefix(message, "/backup_estate")) {
8830 msg_print(Ind, "Backing up all real estate...");
8831 if (!backup_estate()) {
8832 msg_print(Ind, "...failed.");
8833 return;
8834 }
8835 msg_print(Ind, "...done.");
8836
8837 /* terminate the server? */
8838 if (tk && !strcmp(token[1], "term"))
8839 set_runlevel(-1);
8840 return;
8841 }
8842 /* backup all account<-character relations from 'server' savefile,
8843 so it could be deleted without everyone having to remember their
8844 char names because they get confronted with 'empty' character lists.
8845 -> To be used with /backup_estate mechanism. - C. Blue */
8846 else if (prefix(message, "/backup_acclists")) {
8847 backup_acclists();
8848 msg_print(Ind, "Backed up all account<-character relations.");
8849 return;
8850 }
8851 /* restore all account<-character relations saved by /backup_acclists */
8852 else if (prefix(message, "/restore_acclists")) {
8853 restore_acclists();
8854 msg_print(Ind, "Restored all account<-character relations.");
8855 return;
8856 }
8857 #ifdef CLIENT_SIDE_WEATHER
8858 #ifndef CLIENT_WEATHER_GLOBAL
8859 /* weather: generate a cloud at current worldmap sector */
8860 else if (prefix(message, "/mkcloud")) {
8861 if (clouds == MAX_CLOUDS) {
8862 msg_print(Ind, "Error: Cloud number already at maximum.");
8863 return;
8864 }
8865 for (i = 0; i < MAX_CLOUDS; i++)
8866 if (!cloud_dur[i]) break;
8867 if (i == MAX_CLOUDS) {
8868 msg_print(Ind, "Error: Cloud array already full.");
8869 return;
8870 }
8871
8872 //around our current worldmap sector
8873 cloud_create(i, p_ptr->wpos.wx * MAX_WID, p_ptr->wpos.wy * MAX_HGT);
8874
8875 /* update players' local client-side weather if required */
8876 local_weather_update();
8877
8878 msg_format(Ind, "Cloud (%d) has been created around this worldmap sector.", i);
8879 return;
8880 }
8881 /* weather: remove a cloud at current worldmap sector */
8882 else if (prefix(message, "/rmcloud")) {
8883 wilderness_type *w_ptr = &wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx];
8884 for (i = 0; i < 10; i++) {
8885 if (w_ptr->cloud_idx[i] == -1) continue;
8886 break;
8887 }
8888 if (i == 10) {
8889 msg_print(Ind, "Error: No cloud found here.");
8890 return;
8891 }
8892
8893 /* near-dissolve */
8894 cloud_dur[w_ptr->cloud_idx[i]] = 1;
8895
8896 msg_format(Ind, "A cloud (%d) touching this worldmap sector has been drained.", w_ptr->cloud_idx[i]);
8897
8898 /* update players' local client-side weather if required */
8899 local_weather_update();
8900
8901 return;
8902 }
8903 /* weather: list all clouds at current worldmap sector */
8904 else if (prefix(message, "/lscloud")) {
8905 wilderness_type *w_ptr = &wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx];
8906 msg_print(Ind, "Local wild_info cloud array:");
8907 for (i = 0; i < 10; i++) {
8908 if (w_ptr->cloud_idx[i] == -1) continue;
8909 msg_format(Ind, " cloud_idx[%02d] = %d", i, w_ptr->cloud_idx[i]);
8910 }
8911 msg_print(Ind, "Done.");
8912 return;
8913 }
8914 #endif
8915 #endif
8916 /* transport admin to Valinor */
8917 else if (prefix(message, "/tovalinor")) {
8918 msg_print(Ind, "Initiating passage to Valinor.");
8919 p_ptr->auto_transport = AT_VALINOR;
8920 return;
8921 }
8922 #ifdef IRONDEEPDIVE_MIXED_TYPES
8923 /* Re-roll IDDC */
8924 else if (prefix(message, "/riddc") || prefix(message, "/liddc")) {
8925 int ft = -1, last = 1;
8926
8927 if (prefix(message, "/riddc")) {
8928 if (scan_iddc()) msg_print(Ind, "scan_iddc() FAILED!");
8929 else msg_print(Ind, "scan_iddc() succeeded.");
8930 }
8931
8932 /* list declared IDDC themes for current IDDC layout */
8933 for (i = 1; i <= 127; i++) {
8934 if (ft != iddc[i].type
8935 && i != 40 && i != 80
8936 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
8937 && i != 20 && i != 60
8938 #endif
8939 ) { /* added to fix the list visuals for the reverse approach (127..1) theme generation */
8940 if (ft != -1) {
8941 msg_format(Ind, "%c%4d ft (%2d floors): %s %s", WPOS_IRONDEEPDIVE_Z < 0 ? '-' : ' ',
8942 last * 50, i - last, d_name + d_info[ft].name, !(last <= d_info[ft].maxdepth && i > d_info[ft].maxdepth) ? "" :
8943 (d_info[ft].final_guardian ? "\377o(Boss)" : "\377D(Boss)"));
8944
8945 if (last < 40 && i >= 40)
8946 msg_format(Ind, "%c2000 ft: \377yMenegroth", WPOS_IRONDEEPDIVE_Z < 0 ? '-' : ' ');
8947 else if (last < 80 && i >= 80)
8948 msg_format(Ind, "%c4000 ft: \377yNargothrond", WPOS_IRONDEEPDIVE_Z < 0 ? '-' : ' ');
8949 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
8950 if (last < 20 && i >= 20)
8951 msg_format(Ind, "%c1000 ft: \377y<town>", WPOS_IRONDEEPDIVE_Z < 0 ? '-' : ' ');
8952 else if (last < 60 && i >= 60)
8953 msg_format(Ind, "%c3000 ft: \377y<town>", WPOS_IRONDEEPDIVE_Z < 0 ? '-' : ' ');
8954 #endif
8955
8956 last = i;
8957 }
8958 ft = iddc[i].type;
8959 }
8960 }
8961 msg_format(Ind, "%c%4d ft (%2d floors): %s %s", WPOS_IRONDEEPDIVE_Z < 0 ? '-' : ' ',
8962 last * 50, i - last, d_name + d_info[ft].name, !(last <= d_info[ft].maxdepth && i > d_info[ft].maxdepth) ? "" :
8963 (d_info[ft].final_guardian ? "\377o(Boss)" : "\377D(Boss)"));
8964 return;
8965 }
8966 #endif
8967 /* Recall all players out of the dungeons, kick those who aren't eligible */
8968 else if (prefix(message, "/allrec")) {
8969 struct worldpos pwpos;
8970 player_type *p_ptr;
8971
8972 for (i = 1; i <= NumPlayers; i++) {
8973 p_ptr = Players[i];
8974 pwpos = Players[i]->wpos;
8975
8976 if (!pwpos.wz) continue;
8977 if (is_admin(p_ptr)) continue;
8978
8979 if (in_irondeepdive(&pwpos)) {
8980 msg_print(i, "\377OServer is restarting...");
8981 Destroy_connection(p_ptr->conn, "Server is restarting");
8982 i--;
8983 continue;
8984 }
8985 if (pwpos.wz > 0) {
8986 if ((wild_info[pwpos.wy][pwpos.wx].tower->flags2 & DF2_IRON) ||
8987 (wild_info[pwpos.wy][pwpos.wx].tower->flags1 & DF1_FORCE_DOWN)) {
8988 msg_print(i, "\377OServer is restarting...");
8989 Destroy_connection(p_ptr->conn, "Server is restarting");
8990 i--;
8991 continue;
8992 }
8993 } else {
8994 if ((wild_info[pwpos.wy][pwpos.wx].dungeon->flags2 & DF2_IRON) ||
8995 (wild_info[pwpos.wy][pwpos.wx].dungeon->flags1 & DF1_FORCE_DOWN)) {
8996 msg_print(i, "\377OServer is restarting...");
8997 Destroy_connection(p_ptr->conn, "Server is restarting");
8998 i--;
8999 continue;
9000 }
9001 }
9002
9003 p_ptr->recall_pos.wx = p_ptr->wpos.wx;
9004 p_ptr->recall_pos.wy = p_ptr->wpos.wy;
9005 p_ptr->recall_pos.wz = 0;
9006 p_ptr->new_level_method = (p_ptr->wpos.wz > 0 ? LEVEL_RECALL_DOWN : LEVEL_RECALL_UP);
9007 recall_player(i, "");
9008 }
9009 return;
9010 }
9011 /* sets current true artifact holders to players who own them */
9012 else if (prefix(message, "/fixartowners1")) {
9013 object_type *o_ptr;
9014 int a_idx;
9015 for (i = 0; i < o_max; i++) {
9016 o_ptr = &o_list[i];
9017 a_idx = o_ptr->name1;
9018 if (a_idx == 0 || a_idx == ART_RANDART) continue;
9019 if (a_info[a_idx].carrier) continue;
9020 a_info[a_idx].carrier = o_ptr->owner;
9021 }
9022 return;
9023 }
9024 /* sets current true artifact holders to players who own them */
9025 else if (prefix(message, "/fixartowners2")) {
9026 object_type *o_ptr;
9027 int a_idx;
9028 for (j = 1; j <= NumPlayers; j++) {
9029 for (i = 0; i < INVEN_TOTAL; i++) {
9030 o_ptr = &Players[j]->inventory[i];
9031 if (!o_ptr->k_idx) continue;
9032 a_idx = o_ptr->name1;
9033 if (a_idx == 0 || a_idx == ART_RANDART) continue;
9034 if (a_info[a_idx].carrier) continue;
9035 a_info[a_idx].carrier = o_ptr->owner;
9036 }
9037 }
9038 return;
9039 }
9040 else if (prefix(message, "/mtrack")) { /* track monster health of someone's current target */
9041 char m_name[MNAME_LEN];
9042 int p;
9043
9044 if (!tk) {
9045 msg_print(Ind, "No player specified.");
9046 return;
9047 }
9048 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
9049 if (!p) return;
9050 if (Players[p]->health_who <= 0) {//target_who
9051 msg_print(Ind, "No monster looked at.");
9052 return;
9053 }
9054
9055 p_ptr->health_who = Players[p]->health_who;
9056 monster_desc(0, m_name, p_ptr->health_who, 0);
9057 msg_format(Ind, "Tracking %s.", m_name);
9058 p_ptr->redraw |= PR_HEALTH;
9059 return;
9060 }
9061 /* fix hash table entry in particular aspect(s) */
9062 else if (prefix(message, "/fixhash")) {
9063 int p;
9064 if (!tk) {
9065 msg_print(Ind, "No player specified.");
9066 return;
9067 }
9068 p = name_lookup_loose(Ind, message3, FALSE, FALSE);
9069 if (!p) return;
9070 clockin(p, 6);
9071 return;
9072 }
9073 else if (prefix(message, "/charlaston")) {
9074 unsigned long int s, sl;
9075 time_t now;
9076 u32b p_id;
9077
9078 if (!tk) {
9079 msg_print(Ind, "No player specified.");
9080 return;
9081 }
9082 if (!(p_id = lookup_player_id(message3))) {
9083 msg_format(Ind, "Player <%s> not found.", message3);
9084 return;
9085 }
9086
9087 now = time(&now);
9088 sl = lookup_player_laston(p_id);
9089 if (!sl) {
9090 msg_format(Ind, "laston is zero for player <%s>!", message3);
9091 return;
9092 }
9093 s = now - sl;
9094 if (s >= 60 * 60 * 24 * 3) msg_format(Ind, "Player <%s> was seen ~%d days ago.", message3, s / (60 * 60 * 24));
9095 else if (s >= 60 * 60 * 3) msg_format(Ind, "Player <%s> was seen ~%d hours ago.", message3, s / (60 * 60));
9096 else if (s >= 60 * 3) msg_format(Ind, "Player <%s> was seen ~%d minutes ago.", message3, s / 60);
9097 else msg_format(Ind, "Player <%s> was seen %d seconds ago.", message3, s);
9098 return;
9099 }
9100 else if (prefix(message, "/testrandart")) { /* test how often randarts get AM shell '>_> */
9101 object_type *o_ptr;
9102 u32b f1, f2, f3, f4, f5, f6, esp;
9103 int tries = 100000, found = 0;
9104
9105 if (tk != 1) {
9106 msg_print(Ind, "\377oUsage: /testrandart <inventory-slot>");
9107 return;
9108 }
9109
9110 if (atoi(token[1]) < 1 || atoi(token[1]) >= INVEN_TOTAL) {
9111 msg_print(Ind, "\377oInvalid inventory slot.");
9112 return;
9113 }
9114
9115 o_ptr = &p_ptr->inventory[atoi(token[1]) - 1];
9116 if (o_ptr->name1 != ART_RANDART) {
9117 if (o_ptr->name1) {
9118 msg_print(Ind, "\377oIt's a static art. Aborting.");
9119 return;
9120 } else {
9121 msg_print(Ind, "\377oNot a randart - turning it into one.");
9122 o_ptr->name1 = ART_RANDART;
9123 }
9124 }
9125
9126 do {
9127 /* Piece together a 32-bit random seed */
9128 o_ptr->name3 = rand_int(0xFFFF) << 16;
9129 o_ptr->name3 += rand_int(0xFFFF);
9130 /* Check the tval is allowed */
9131 if (randart_make(o_ptr) == NULL) {
9132 /* If not, wipe seed. No randart today */
9133 o_ptr->name1 = 0;
9134 o_ptr->name3 = 0L;
9135 msg_print(Ind, "Randart creation failed.");
9136 return;
9137 }
9138 apply_magic(&p_ptr->wpos, o_ptr, p_ptr->lev, FALSE, FALSE, FALSE, FALSE, RESF_FORCERANDART | RESF_NOTRUEART);
9139
9140 /* check it for AM shell */
9141 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
9142 if ((f3 & TR3_NO_MAGIC)) found++;
9143 } while (--tries);
9144
9145 msg_format(Ind, "%d were positive: %d.%d%%", found, 100 * found / 100000, (found % 1000) / 100);//wtb correct rounding >.> o laziness
9146 return;
9147 }
9148 else if (prefix(message, "/moditem")) { /* modify a particular existing item type (added for LL drop sky dsm of imm -> randart sky dsm) */
9149 hack_particular_item();
9150 return;
9151 }
9152 else if (prefix(message, "/qinf")) { /* debug new quest_info stuff - C. Blue */
9153 /* display hard info about a specific quest? */
9154 if (tk) {
9155 int l;
9156 quest_info *q_ptr = &q_info[k];
9157 char tmp[MAX_CHARS];
9158 tmp[0] = 0;
9159
9160 msg_format(Ind, "\377UQuest '%s' (%d,%s) - oreg %d:", q_name + q_ptr->name, k, q_ptr->codename, q_ptr->objects_registered);
9161 for (i = 0; i < QI_PASSWORDS; i++) {
9162 strcat(tmp, q_ptr->password[i]);
9163 if (i < QI_PASSWORDS - 1) strcat(tmp, ",");
9164 }
9165 msg_format(Ind, "Passwords: %s", tmp);
9166
9167 for (i = 0; i < q_ptr->stages; i++) {
9168 msg_format(Ind, "stage %d (qinfo:?): actq %d, autoac %d, cstage %d", i, q_ptr->stage[i].activate_quest, q_ptr->stage[i].auto_accept, q_ptr->stage[i].change_stage);
9169 }
9170
9171 /* ok, attempt to get the whole full frigging allocated mem size >_> */
9172 j = sizeof(quest_info);
9173 for (i = 0; i < q_ptr->questors; i++) {
9174 j += sizeof(qi_questor);
9175 if (q_ptr->questor[i].q_loc.tpref) j += strlen(q_ptr->questor[i].q_loc.tpref) + 1;
9176 }
9177 for (i = 0; i < q_ptr->stages; i++) {
9178 j += sizeof(qi_stage);
9179 for (k = 0; k < QI_QUESTORS; k++) {
9180 if (q_ptr->stage[i].questor_morph[k]) j += sizeof(qi_questor_morph);
9181 if (q_ptr->stage[i].questor_hostility[k]) j += sizeof(qi_questor_hostility);
9182 if (q_ptr->stage[i].questor_act[k]) j += sizeof(qi_questor_act);
9183 }
9184 for (l = 0; l < QI_QUESTORS; l++) {
9185 j += sizeof(cptr*) * q_ptr->stage[i].talk_lines[l];//talk[]
9186 j += sizeof(u16b*) * q_ptr->stage[i].talk_lines[l];//talk_flags[]
9187 }
9188 for (k = 0; k < QI_TALK_LINES; k++) {
9189 for (l = 0; l < q_ptr->questors; l++) {
9190 if (q_ptr->stage[i].talk_lines[l] <= k) continue;
9191 if (q_ptr->stage[i].talk[l][k]) j+= strlen(q_ptr->stage[i].talk[l][k]) + 1;
9192 }
9193 if (q_ptr->stage[i].narration[k]) j+= strlen(q_ptr->stage[i].narration[k]) + 1;
9194 }
9195 for (k = 0; k < q_ptr->stage[i].rewards; k++) {
9196 j += sizeof(qi_reward);
9197 }
9198 for (k = 0; k < q_ptr->stage[i].goals; k++) {
9199 j += sizeof(qi_goal);
9200 if (q_ptr->stage[i].goal[k].target_tpref) j += strlen(q_ptr->stage[i].goal[k].target_tpref) + 1;
9201 if (q_ptr->stage[i].goal[k].kill) j += sizeof(qi_kill);
9202 if (q_ptr->stage[i].goal[k].retrieve) j += sizeof(qi_retrieve);
9203 if (q_ptr->stage[i].goal[k].deliver) j += sizeof(qi_deliver);
9204 }
9205 }
9206 for (i = 0; i < q_ptr->keywords; i++) {
9207 j += sizeof(qi_keyword);
9208 }
9209 for (i = 0; i < q_ptr->kwreplies; i++) {
9210 j += sizeof(qi_kwreply);
9211 for (k = 0; k < QI_TALK_LINES; k++)
9212 if (q_ptr->kwreply[i].reply[k]) j+= strlen(q_ptr->kwreply[i].reply[k]) + 1;
9213 }
9214 msg_format(Ind, "\377oTotal allocated memory for q_info[%d]: %d", k, j);
9215 }
9216
9217 /* display basic quests info */
9218 msg_format(Ind, "\377UQuests (max_q_idx/MAX_Q_IDX %d/%d):", max_q_idx, MAX_Q_IDX);
9219 for (i = 0; i < max_q_idx; i++) {
9220 msg_format(Ind, " %3d %10s %c S%02d%s %s%s %4d %4d, Or:%d Q:%d '%s'",
9221 i, q_info[i].codename, q_info[i].individual ? (q_info[i].individual == 2 ? 'I' : 'i') : 'g',
9222 quest_get_stage(Ind, i), q_info[i].individual ? format("/%02d", q_info[i].cur_stage) : " ",
9223 !q_info[i].defined ? "\377rU\377w" : (q_info[i].active ? "A" : " "),
9224 !q_info[i].defined ? " " : (q_info[i].disabled ? "D" : " "),
9225 quest_get_cooldown(Ind, i), q_info[i].cooldown,
9226 q_info[i].objects_registered, q_info[i].questors
9227 , q_name + q_info[i].name
9228 //, q_info[i].creator
9229 );
9230 }
9231 /* display extra info? */
9232 //pointless.. msg_format(Ind, " \377wSize of quest_info*max_q_idx=total (real): %d*%d=\377U%d (%d)", sizeof(quest_info), max_q_idx, sizeof(quest_info) * max_q_idx, sizeof(quest_info) * MAX_Q_IDX);
9233 return;
9234 }
9235 else if (prefix(message, "/qsize")) { /* try to calc full q_info[] mem usage - C. Blue */
9236 int l, q, t, td;
9237 quest_info *q_ptr;
9238
9239 t = td = j = 0;
9240 for (q = 0; q < MAX_Q_IDX; q++) {
9241 q_ptr = &q_info[q];
9242
9243 j = sizeof(quest_info);
9244 for (i = 0; i < q_ptr->questors; i++) {
9245 j += sizeof(qi_questor);
9246 if (q_ptr->questor[i].q_loc.tpref) j += strlen(q_ptr->questor[i].q_loc.tpref) + 1;
9247 }
9248 for (i = 0; i < q_ptr->stages; i++) {
9249 j += sizeof(qi_stage);
9250 for (k = 0; k < QI_QUESTORS; k++) {
9251 if (q_ptr->stage[i].questor_morph[k]) j += sizeof(qi_questor_morph);
9252 if (q_ptr->stage[i].questor_hostility[k]) j += sizeof(qi_questor_hostility);
9253 if (q_ptr->stage[i].questor_act[k]) j += sizeof(qi_questor_act);
9254 }
9255 for (l = 0; l < QI_QUESTORS; l++) {
9256 j += sizeof(cptr*) * q_ptr->stage[i].talk_lines[l];//talk[]
9257 j += sizeof(u16b*) * q_ptr->stage[i].talk_lines[l];//talk_flags[]
9258 }
9259 for (k = 0; k < QI_TALK_LINES; k++) {
9260 for (l = 0; l < q_ptr->questors; l++) {
9261 if (q_ptr->stage[i].talk_lines[l] <= k) continue;
9262 if (q_ptr->stage[i].talk[l][k]) j+= strlen(q_ptr->stage[i].talk[l][k]) + 1;
9263 }
9264 if (q_ptr->stage[i].narration[k]) j+= strlen(q_ptr->stage[i].narration[k]) + 1;
9265 }
9266 for (k = 0; k < q_ptr->stage[i].rewards; k++) {
9267 j += sizeof(qi_reward);
9268 }
9269 for (k = 0; k < q_ptr->stage[i].goals; k++) {
9270 j += sizeof(qi_goal);
9271 if (q_ptr->stage[i].goal[k].target_tpref) j += strlen(q_ptr->stage[i].goal[k].target_tpref) + 1;
9272 if (q_ptr->stage[i].goal[k].kill) j += sizeof(qi_kill);
9273 if (q_ptr->stage[i].goal[k].retrieve) j += sizeof(qi_retrieve);
9274 if (q_ptr->stage[i].goal[k].deliver) j += sizeof(qi_deliver);
9275 }
9276 }
9277 for (i = 0; i < q_ptr->keywords; i++) {
9278 j += sizeof(qi_keyword);
9279 }
9280 for (i = 0; i < q_ptr->kwreplies; i++) {
9281 j += sizeof(qi_kwreply);
9282 for (k = 0; k < QI_TALK_LINES; k++)
9283 if (q_ptr->kwreply[i].reply[k]) j+= strlen(q_ptr->kwreply[i].reply[k]) + 1;
9284 }
9285 t += j;
9286 if (q_ptr->defined) {
9287 td += j;
9288 msg_format(Ind, "\377yTotal allocated memory for q_info[%d]: %d", q, j);
9289 }
9290 }
9291 msg_format(Ind, "\377oTotal allocated memory for q_info[0..%d]: %d", max_q_idx - 1, td);
9292 msg_format(Ind, "\377oTotal allocated memory for q_info[0..%d]: %d", MAX_Q_IDX - 1, t);
9293 return;
9294 }
9295 /* list quest items we carry */
9296 else if (prefix(message, "/qinv")) {
9297 object_type *o_ptr;
9298 char buf[MAX_CHARS];
9299
9300 if (!tk) k = Ind;
9301 else k = name_lookup_loose(Ind, message3, FALSE, FALSE);
9302 p_ptr = Players[k];
9303
9304 msg_format(Ind, "\377yQuest item info for player %s (%d):", p_ptr->name, k);
9305 for (i = 0; i < INVEN_PACK; i++) {
9306 o_ptr = &p_ptr->inventory[i];
9307 if (!o_ptr->k_idx) continue;
9308 if (!o_ptr->quest) continue;
9309 object_desc(0, buf, o_ptr, FALSE, 0);
9310 msg_format(Ind, " %c) Q%dS%d%c %s", 'a' + i, o_ptr->quest - 1, o_ptr->quest_stage, o_ptr->questor ? '*' : ' ', buf);
9311 }
9312 return;
9313 }
9314 else if (prefix(message, "/qaquest") || prefix(message, "/qaq")) { /* drop a quest a player is on */
9315 int q = -1, p;
9316 if (!tk) {
9317 msg_print(Ind, "Usage: /qaquest [<quest>] <character name>");
9318 return;
9319 }
9320
9321 /* hack- assume number = quest parm, not char name */
9322 if (message3[0] >= '0' && message3[0] <= '9') q = atoi(message3);
9323 else if (message3[0] == '*') q = -2; //drop all
9324
9325 if (q == -1) p = name_lookup_loose(Ind, message3, FALSE, FALSE);
9326 else p = name_lookup_loose(Ind, message3 + 2, FALSE, FALSE);
9327 if (!p) {
9328 msg_print(Ind, "Couldn't find that player.");
9329 return;
9330 }
9331 p_ptr = Players[p];
9332
9333 if (q == -1) {
9334 int qa = 0;
9335
9336 for (i = 0; i < MAX_CONCURRENT_QUESTS; i++)
9337 if (p_ptr->quest_idx[i] != -1) qa++;
9338
9339 msg_print(Ind, "");
9340 if (!qa) msg_format(Ind, "\377U%s is not currently pursuing any quests.", p_ptr->name);
9341 else {
9342 if (qa == 1) msg_format(Ind, "\377U%s is currently pursuing the following quest:", p_ptr->name);
9343 else msg_format(Ind, "\377U%s is currently pursuing the following quests:", p_ptr->name);
9344 for (i = 0; i < MAX_CONCURRENT_QUESTS; i++) {
9345 if (p_ptr->quest_idx[i] == -1) continue;
9346 msg_format(Ind, " %2d) %s (%d)", i + 1, q_name + q_info[p_ptr->quest_idx[i]].name, quest_get_stage(p, p_ptr->quest_idx[i]));
9347 }
9348 }
9349 return;
9350 }
9351 if (q == -2) {
9352 msg_format(Ind, "%s is no longer pursuing any quest!", p_ptr->name);
9353 for (i = 0; i < MAX_CONCURRENT_QUESTS; i++) {
9354 j = p_ptr->quest_idx[i];
9355 p_ptr->quest_idx[i] = -1;
9356 /* give him 'quest done' credit if he cancelled it too late (ie after rewards were handed out)? */
9357 if (q_info[j].quest_done_credit_stage <= quest_get_stage(Ind, j) && p_ptr->quest_done[j] < 10000) p_ptr->quest_done[j]++;
9358 }
9359 return;
9360 }
9361 k = q;
9362 if (k < 1 || k > MAX_CONCURRENT_QUESTS) {
9363 msg_print(Ind, "\377yThe quest number must be from 1 to 5!");
9364 return;
9365 }
9366 if (p_ptr->quest_idx[k - 1] == -1) {
9367 msg_format(Ind, "\377y%s is not pursing a quest numbered %d.", p_ptr->name, k);
9368 return;
9369 }
9370 msg_format(Ind, "%s is no longer pursuing the quest '%s'!", p_ptr->name, q_name + q_info[p_ptr->quest_idx[k - 1]].name);
9371 j = p_ptr->quest_idx[k - 1];
9372 p_ptr->quest_idx[k - 1] = -1;
9373 /* give him 'quest done' credit if he cancelled it too late (ie after rewards were handed out)? */
9374 if (q_info[j].quest_done_credit_stage <= quest_get_stage(Ind, j) && p_ptr->quest_done[j] < 10000) p_ptr->quest_done[j]++;
9375 return;
9376 }
9377 else if (prefix(message, "/qccd")) { /* clear a quest's cooldown */
9378 if (tk < 1) {
9379 msg_print(Ind, "Usage: /qccd <q_idx|*> [Ind]");
9380 return;
9381 }
9382 if (tk > 1) i = atoi(token[2]);
9383 else i = 0;
9384 if (token[1][0] == '*') {
9385 for (k = 0; k < max_q_idx; k++) {
9386 if (quest_get_cooldown(i, k)) {
9387 msg_format(Ind, "\377BCompleted cooldown of quest quest %d (%s).", k, q_info[k].codename);
9388 quest_set_cooldown(i, k, 0);
9389 }
9390 }
9391 return;
9392 }
9393 if (!quest_get_cooldown(i, k)) {
9394 msg_format(Ind, "Quest %d (%s) is not on cooldown.", k, q_info[k].codename);
9395 return;
9396 }
9397 msg_format(Ind, "\377BCompleted cooldown of quest %d (%s).", k, q_info[k].codename);
9398 quest_set_cooldown(i, k, 0);
9399 return;
9400 }
9401 else if (prefix(message, "/qpriv")) { /* change a quest's privilege level */
9402 if (tk < 1) {
9403 msg_print(Ind, "Usage: /qpriv <q_idx|*> [0..3]");
9404 return;
9405 }
9406 if (token[1][0] == '*') {
9407 if (tk == 1) return;
9408 i = atoi(token[2]);
9409 for (k = 0; k < max_q_idx; k++)
9410 q_info[k].privilege = i;
9411 msg_format(Ind, "All set to %d.", i);
9412 return;
9413 }
9414 msg_format(Ind, "Quest '%s' (%s,%d) - privileged %d.", q_name + q_info[k].name, q_info[k].codename, k, q_info[k].privilege);
9415 if (tk == 1) return;
9416 i = atoi(token[2]);
9417 q_info[k].privilege = i;
9418 msg_format(Ind, "Now set to %d.", i);
9419 return;
9420 }
9421 else if (prefix(message, "/qdis")) { /* disable a quest */
9422 if (tk != 1) {
9423 msg_print(Ind, "Usage: /qdis <q_idx|*>");
9424 return;
9425 }
9426 if (token[1][0] == '*') {
9427 for (i = 0; i < max_q_idx; i++) {
9428 if (!q_info[i].disabled) {
9429 msg_format(Ind, "\377rDisabling quest %d (%s).", i, q_info[i].codename);
9430 quest_deactivate(i);
9431 q_info[i].disabled = TRUE;
9432 }
9433 }
9434 return;
9435 }
9436 if (q_info[k].disabled) {
9437 msg_format(Ind, "Quest %d (%s) is already disabled.", k, q_info[k].codename);
9438 return;
9439 }
9440 msg_format(Ind, "\377rDisabling quest %d (%s).", k, q_info[k].codename);
9441 quest_deactivate(k);
9442 q_info[k].disabled = TRUE;
9443 return;
9444 }
9445 else if (prefix(message, "/qena")) { /* enable a quest */
9446 if (tk != 1) {
9447 msg_print(Ind, "Usage: /qena <q_idx|*>");
9448 return;
9449 }
9450 if (token[1][0] == '*') {
9451 for (i = 0; i < max_q_idx; i++) {
9452 if (q_info[i].disabled) {
9453 msg_format(Ind, "\377GEnabling quest %d (%s).", i, q_info[i].codename);
9454 q_info[i].disabled = FALSE;
9455 }
9456 }
9457 return;
9458 }
9459 if (!q_info[k].disabled) {
9460 msg_format(Ind, "Quest %d (%s) is already disabled.", k, q_info[k].codename);
9461 return;
9462 }
9463 msg_format(Ind, "\377GEnabling quest %d (%s).", k, q_info[k].codename);
9464 q_info[k].disabled = FALSE;
9465 return;
9466 }
9467 else if (prefix(message, "/qstart")) { /* activate a quest */
9468 if (tk != 1) {
9469 msg_print(Ind, "Usage: /qstart <q_idx|*>");
9470 return;
9471 }
9472 if (token[1][0] == '*') {
9473 for (i = 0; i < max_q_idx; i++) {
9474 if (!q_info[i].active) {
9475 msg_format(Ind, "\377GActivating quest %d (%s).", i, q_info[i].codename);
9476 quest_activate(i);
9477 }
9478 }
9479 return;
9480 }
9481 if (q_info[k].active) {
9482 msg_format(Ind, "Quest %d (%s) is already active.", k, q_info[k].codename);
9483 return;
9484 }
9485 msg_format(Ind, "\377GActivating quest %d (%s).", k, q_info[k].codename);
9486 if (!quest_activate(k)) msg_format(Ind, "\377oFailed!");
9487 else msg_print(Ind, "\377gOk.");
9488 return;
9489 }
9490 else if (prefix(message, "/qstop")) { /* cancel a quest */
9491 if (tk != 1) {
9492 msg_print(Ind, "Usage: /qstop <q_idx|*>");
9493 return;
9494 }
9495 if (token[1][0] == '*') {
9496 for (i = 0; i < max_q_idx; i++) {
9497 if (q_info[i].active) {
9498 msg_format(Ind, "\377rDeactivating quest %d (%s).", i, q_info[i].codename);
9499 quest_deactivate(i);
9500 }
9501 }
9502 return;
9503 }
9504 if (!q_info[k].active) {
9505 msg_format(Ind, "Quest %d (%s) is already inactive.", k, q_info[k].codename);
9506 return;
9507 }
9508 msg_format(Ind, "\377rDeactivating quest %d (%s).", k, q_info[k].codename);
9509 quest_deactivate(k);
9510 return;
9511 }
9512 else if (prefix(message, "/qstage")) { /* change a quest's stage */
9513 if (tk != 2) {
9514 msg_print(Ind, "Usage: /qstage <q_idx> <stage>");
9515 return;
9516 }
9517 msg_format(Ind, "\377BChanging quest %d (%s) to stage %d.", k, q_info[k].codename, atoi(token[2]));
9518 quest_set_stage(0, k, atoi(token[2]), FALSE, NULL);
9519 return;
9520 }
9521 else if (prefix(message, "/qfx")) { /* for testing/debugging status effects (for rewards) */
9522 quest_statuseffect(Ind, k);
9523 msg_print(Ind, "Applied.");
9524 return;
9525 }
9526 else if (prefix(message, "/debugfloor")) {
9527 struct dun_level *l_ptr;
9528 if (!p_ptr->wpos.wz) {
9529 msg_print(Ind, "Must be used in dungeon/tower.");
9530 return;
9531 }
9532 l_ptr = getfloor(&p_ptr->wpos);
9533 if (!l_ptr) { /* paranoia */
9534 msg_print(Ind, "PARANOIA - couldn't get floor.");
9535 return;
9536 }
9537 msg_format(Ind, "flags1 = %lu", l_ptr->flags1);
9538 msg_format(Ind, "flags2 = %lu", l_ptr->flags2);
9539 return;
9540 }
9541 else if (prefix(message, "/reservednames")) {
9542 for (i = 0; i < MAX_RESERVED_NAMES; i++) {
9543 if (!reserved_name_character[i][0]) break;
9544 msg_format(Ind, "%s by account %s for %d minutes",
9545 reserved_name_character[i], reserved_name_account[i], reserved_name_timeout[i]);
9546 }
9547 return;
9548 }
9549 else if (prefix(message, "/purgeaccountfile")) {
9550 purge_acc_file();
9551 msg_print(Ind, "done.");
9552 return;
9553 }
9554 else if (prefix(message, "/ap") && !prefix(message, "/apat")) { /* set optional parameter (too hacky..) */
9555 if (!tk) {
9556 msg_print(Ind, "Admin parm cleared.");
9557 p_ptr->admin_parm[0] = 0;
9558 return;
9559 }
9560 strncpy(p_ptr->admin_parm, message3, MAX_CHARS);
9561 p_ptr->admin_parm[MAX_CHARS - 1] = 0;
9562 msg_print(Ind, "Admin parm set.");
9563 return;
9564 }
9565 }
9566 }
9567
9568 do_slash_brief_help(Ind);
9569 return;
9570 }
9571 #endif
9572
9573 static void do_slash_brief_help(int Ind){
9574 #if 0 /* pretty outdated */
9575 player_type *p_ptr = Players[Ind];
9576
9577 msg_print(Ind, "Commands: afk at bed broadcast bug cast dis dress ex feel fill help ignore me"); // pet ?
9578 msg_print(Ind, " pk xorder rec ref rfe shout sip tag target untag;");
9579
9580 if (is_admin(p_ptr)) {
9581 msg_print(Ind, " art cfg cheeze clv cp en eq geno id kick lua purge respawn shutdown");
9582 msg_print(Ind, " sta store trap unc unst wish");
9583 } else {
9584 msg_print(Ind, " /dis \377rdestroys \377wall the uninscribed items in your inventory!");
9585 }
9586 #else
9587 #endif
9588 msg_print(Ind, "Common commands: afk page ex feel rec tag untag dis me fill ignore bug rfe");
9589 msg_print(Ind, " please type '/help' for detailed help.");
9590 }
9591
9592
9593 /* determine when character or account name was online the last time */
9594 void get_laston(char *name, char *response, bool admin) {
9595 unsigned long int s, sl = 0;
9596 time_t now;
9597 u32b p_id;
9598 bool acc = FALSE;
9599 int i;
9600 struct account *l_acc;
9601 char name_tmp[MAX_CHARS_WIDE], *nameproc = name_tmp;
9602
9603 /* trim name */
9604 strncpy(nameproc, name, MAX_CHARS_WIDE - 1);
9605 nameproc[MAX_CHARS_WIDE - 1] = 0;
9606 while (*nameproc == ' ') nameproc++;
9607 while (nameproc[strlen(nameproc) - 1] == ' ') nameproc[strlen(nameproc) - 1] = 0;
9608 if (!(*nameproc)) {
9609 strcpy(response, "You must specify a character or account name.");
9610 return;
9611 }
9612 *nameproc = toupper(*nameproc);
9613
9614 /* catch silliness of target actually being online right now */
9615 for (i = 1; i <= NumPlayers; i++) {
9616 if (Players[i]->conn == NOT_CONNECTED) continue;
9617 if (admin_p(i) && !admin) continue;
9618 if (streq(Players[i]->name, nameproc)) {
9619 strcpy(response, "A character of that name is online right now!");
9620 return;
9621 } else if (streq(Players[i]->accountname, nameproc)) {
9622 strcpy(response, "The player using that account name is online right now!");
9623 return;
9624 }
9625 }
9626
9627 /* check if it's an acount name */
9628 l_acc = Admin_GetAccount(nameproc);
9629 if (l_acc) {
9630 acc = TRUE;
9631 if (admin || !(l_acc->flags & ACC_ADMIN)) sl = l_acc->acc_laston_real;
9632 KILL(l_acc, struct account);
9633 }
9634
9635 /* check if it's a character name (not really necessary if we found an account already) */
9636 if ((p_id = lookup_player_id(nameproc))) {
9637 if (!lookup_player_admin(p_id) || admin) {
9638 if (!acc) sl = lookup_player_laston(p_id);
9639 else {
9640 s = lookup_player_laston(p_id);
9641 if (s >= sl) {
9642 sl = s;
9643 acc = FALSE; /* as I said, not necessary :-p */
9644 }
9645 }
9646 }
9647 /* neither char nor acc? */
9648 } else if (!acc) {
9649 sprintf(response, "Sorry, couldn't find anyone named %s.", nameproc);
9650 return;
9651 }
9652
9653 /* error or admin account? */
9654 if (!sl) {
9655 sprintf(response, "Sorry, unable to determine the last time %s was seen.", nameproc);
9656 return;
9657 }
9658
9659 now = time(&now);
9660 s = now - sl;
9661 if (s >= 60 * 60 * 24 * 3) sprintf(response, "%s %s was last seen %ld days ago.", acc ? "The player using account" : "The character", nameproc, s / (60 * 60 * 24));
9662 else if (s >= 60 * 60 * 3) sprintf(response, "%s %s was last seen %ld hours ago.", acc ? "The player using account" : "The character", nameproc, s / (60 * 60));
9663 else if (s >= 60 * 3) sprintf(response, "%s %s was last seen %ld minutes ago.", acc ? "The player using account" : "The character", nameproc, s / 60);
9664 else sprintf(response, "%s %s was last seen %ld seconds ago.", acc ? "The player using Account" : "The character", nameproc, s);
9665 }
9666