ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.8
Committed: Sun Sep 10 13:20:27 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +1546 -1332 lines
Log Message:
indent

File Contents

# Content
1
2 /*
3 * static char *rcsid_c_wiz_c =
4 * "$Id: c_wiz.C,v 1.7 2006-09-07 10:01:57 pippijn Exp $";
5 */
6
7 /*
8 CrossFire, A Multiplayer game for X-windows
9
10 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27 The authors can be reached via e-mail at crossfire-devel@real-time.com
28 */
29
30 #include <global.h>
31 #ifndef __CEXTRACT__
32 # include <sproto.h>
33 #endif
34 #include <spells.h>
35 #include <treasure.h>
36 #include <skills.h>
37
38 /** Defines for DM item stack **/
39 #define STACK_SIZE 50 /* Stack size, static */
40
41 /* Values for 'from' field of get_dm_object */
42 #define STACK_FROM_NONE 0 /* Item was not found */
43 #define STACK_FROM_TOP 1 /* Item is stack top */
44 #define STACK_FROM_STACK 2 /* Item is somewhere in stack */
45 #define STACK_FROM_NUMBER 3 /* Item is a number (may be top) */
46
47
48 /**
49 * Enough of the DM functions seem to need this that I broke
50 * it out to a seperate function. name is the person
51 * being saught, rq is who is looking for them. This
52 * prints diagnostics messages, and returns the
53 * other player, or NULL otherwise.
54 */
55 static player *
56 get_other_player_from_name (object *op, char *name)
57 {
58 player *pl;
59
60 if (!name)
61 return NULL;
62
63 for (pl = first_player; pl != NULL; pl = pl->next)
64 if (!strncmp (pl->ob->name, name, MAX_NAME))
65 break;
66
67 if (pl == NULL)
68 {
69 new_draw_info (NDI_UNIQUE, 0, op, "No such player.");
70 return NULL;
71 }
72
73 if (pl->ob == op)
74 {
75 new_draw_info (NDI_UNIQUE, 0, op, "You can't do that to yourself.");
76 return NULL;
77 }
78 if (pl->state != ST_PLAYING)
79 {
80 new_draw_info (NDI_UNIQUE, 0, op, "That player is in no state for that right now.");
81 return NULL;
82 }
83 return pl;
84 }
85
86 /**
87 * This command will stress server.
88 */
89 int
90 command_loadtest (object *op, char *params)
91 {
92 uint32 x, y;
93 char buf[1024];
94
95 new_draw_info (NDI_UNIQUE, 0, op, "loadtest will stress server through teleporting");
96 new_draw_info (NDI_UNIQUE, 0, op, "at different map places.");
97 new_draw_info (NDI_UNIQUE, 0, op, "use at your own risks.");
98 new_draw_info (NDI_UNIQUE, 0, op, "Very long loop used so server may have to be reset.");
99 new_draw_info (NDI_UNIQUE, 0, op, "type loadtest TRUE to run");
100 new_draw_info_format (NDI_UNIQUE, 0, op, "{%s}", params);
101 if (!params)
102 return 0;
103 if (strncmp (params, "TRUE", 4))
104 return 0;
105
106 new_draw_info_format (NDI_UNIQUE, 0, op, "gogogo");
107 for (x = 0; x < settings.worldmaptilesx; x++)
108 {
109 for (y = 0; y < settings.worldmaptilesy; y++)
110 {
111 sprintf (buf, "/world/world_%d_%d", x + settings.worldmapstartx, y + settings.worldmapstarty);
112 command_goto (op, buf);
113 }
114 }
115
116 return 0;
117 }
118
119 /**
120 * Actually hides specified player (obviously a DM).
121 * If 'silent_dm' is non zero, other players are informed of DM entering/leaving,
122 * else they just think someone left/entered.
123 */
124 void
125 do_wizard_hide (object *op, int silent_dm)
126 {
127 if (op->contr->hidden)
128 {
129 op->contr->hidden = 0;
130 op->invisible = 1;
131 new_draw_info (NDI_UNIQUE, 0, op, "You are no longer hidden from other players");
132 op->map->players++;
133 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s has entered the game.", &op->name);
134 if (!silent_dm)
135 {
136 new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master has arrived!");
137 }
138 }
139 else
140 {
141 op->contr->hidden = 1;
142 new_draw_info (NDI_UNIQUE, 0, op, "Other players will no longer see you.");
143 op->map->players--;
144 if (!silent_dm)
145 {
146 new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master is gone..");
147 }
148 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s leaves the game.", &op->name);
149 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s left the game.", &op->name);
150 }
151 }
152
153 int
154 command_hide (object *op, char *params)
155 {
156 do_wizard_hide (op, 0);
157 return 1;
158 }
159
160 /**
161 * This finds and returns the object which matches the name or
162 * object nubmer (specified via num #whatever).
163 */
164 static object *
165 find_object_both (char *params)
166 {
167 if (!params)
168 return NULL;
169 if (params[0] == '#')
170 return find_object (atol (params + 1));
171 else
172 return find_object_name (params);
173 }
174
175 /**
176 * Sets the god for some objects. params should contain two values -
177 * first the object to change, followed by the god to change it to.
178 */
179 int
180 command_setgod (object *op, char *params)
181 {
182 object *ob, *god;
183 char *str;
184
185 if (!params || !(str = strchr (params, ' ')))
186 {
187 new_draw_info (NDI_UNIQUE, 0, op, "Usage: setgod object god");
188 return 0;
189 }
190
191 /* kill the space, and set string to the next param */
192 *str++ = '\0';
193 if (!(ob = find_object_both (params)))
194 {
195 new_draw_info_format (NDI_UNIQUE, 0, op, "Set whose god - can not find object %s?", params);
196 return 1;
197 }
198
199 /*
200 * Perhaps this is overly restrictive? Should we perhaps be able
201 * to rebless altars and the like?
202 */
203 if (ob->type != PLAYER)
204 {
205 new_draw_info_format (NDI_UNIQUE, 0, op, "%s is not a player - can not change its god", &ob->name);
206 return 1;
207 }
208
209 god = find_god (str);
210 if (god == NULL)
211 {
212 new_draw_info_format (NDI_UNIQUE, 0, op, "No such god %s.", str);
213 return 1;
214 }
215
216 become_follower (ob, god);
217 return 1;
218 }
219
220 /**
221 * Add player's IP to ban_file and kick them off the server
222 * I know most people have dynamic IPs but this is more of a short term
223 * solution if they have to get a new IP to play maybe they'll calm down.
224 * This uses the banish_file in the local directory *not* the ban_file
225 * The action is logged with a ! for easy searching. -tm
226 */
227 int
228 command_banish (object *op, char *params)
229 {
230 player *pl;
231 FILE *banishfile;
232 char buf[MAX_BUF];
233 time_t now;
234
235 if (!params)
236 {
237 new_draw_info (NDI_UNIQUE, 0, op, "Usage: banish <player>.");
238 return 1;
239 }
240
241 pl = get_other_player_from_name (op, params);
242 if (!pl)
243 return 1;
244
245 sprintf (buf, "%s/%s", settings.localdir, BANISHFILE);
246
247 if ((banishfile = fopen (buf, "a")) == NULL)
248 {
249 LOG (llevDebug, "Could not find file banish_file.\n");
250 new_draw_info (NDI_UNIQUE, 0, op, "Could not find banish_file.");
251 return 0;
252 }
253
254 now = time (NULL);
255 /*
256 * Record this as a comment - then we don't have to worry about changing
257 * the parsing code.
258 */
259 fprintf (banishfile, "# %s (%s) banned by %s at %s\n", &pl->ob->name, pl->socket.host, &op->name, ctime (&now));
260 fprintf (banishfile, "*@%s\n", pl->socket.host);
261 fclose (banishfile);
262
263 LOG (llevDebug, "! %s banned %s from IP: %s.\n", &op->name, &pl->ob->name, pl->socket.host);
264 new_draw_info_format (NDI_UNIQUE | NDI_RED, 0, op, "You banish %s", &pl->ob->name);
265 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 5, op, "%s banishes %s from the land!", &op->name, &pl->ob->name);
266 command_kick (op, (char *) &pl->ob->name);
267 return 1;
268 }
269
270 int
271 command_kick (object *op, char *params)
272 {
273 struct pl *pl;
274
275 for (pl = first_player; pl != NULL; pl = pl->next)
276 if ((params == NULL || !strcmp (&pl->ob->name, params)) && !INVOKE_PLAYER (KICK, pl, ARG_STRING (params)))
277 {
278 object *op = pl->ob;
279
280 if (!QUERY_FLAG (op, FLAG_REMOVED) && !QUERY_FLAG (op, FLAG_FREED))
281 {
282 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 5, op, "%s is kicked out of the game.", &op->name);
283 strcpy (op->contr->killer, "kicked");
284 }
285
286 pl->socket.status = Ns_Dead;
287 }
288
289 return 1;
290 }
291
292 int
293 command_save_overlay (object *op, char *params)
294 {
295 if (!op)
296 return 0;
297
298 if (op != NULL && !QUERY_FLAG (op, FLAG_WIZ))
299 {
300 new_draw_info (NDI_UNIQUE, 0, op, "Sorry, you can't force an overlay save.");
301 return 1;
302 }
303
304 new_save_map (op->map, 2);
305 new_save_map (op->map, 0);
306 new_draw_info (NDI_UNIQUE, 0, op, "Current map has been saved as an" " overlay.");
307
308 ready_map_name (op->map->path, 0);
309
310 return 1;
311 }
312
313 int
314 command_shutdown (object *op, char *params)
315 {
316 struct pl *pl;
317
318 if (op != NULL && !QUERY_FLAG (op, FLAG_WIZ))
319 {
320 new_draw_info (NDI_UNIQUE, 0, op, "Sorry, you can't shutdown the server.");
321 return 1;
322 }
323
324 for (pl = first_player; pl != NULL; pl = pl->next)
325 save_player (pl->ob, 0);
326
327 for (pl = first_player; pl != NULL; pl = pl->next)
328 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
329 leave_map (pl->ob);
330
331 cleanup ();
332 /* not reached */
333 return 1;
334 }
335
336 int
337 command_goto (object *op, char *params)
338 {
339 char *name;
340 object *dummy;
341
342 if (!op)
343 return 0;
344
345 if (params == NULL)
346 {
347 new_draw_info (NDI_UNIQUE, 0, op, "Go to what level?");
348 return 1;
349 }
350
351 name = params;
352 dummy = get_object ();
353 dummy->map = op->map;
354 EXIT_PATH (dummy) = name;
355 dummy->name = name;
356
357 enter_exit (op, dummy);
358 free_object (dummy);
359 if (op->contr->loading == NULL)
360 {
361 new_draw_info_format (NDI_UNIQUE, 0, op, "Difficulty: %d.", op->map->difficulty);
362 }
363
364 return 1;
365 }
366
367 /* is this function called from somewhere ? -Tero */
368 int
369 command_generate (object *op, char *params)
370 {
371 object *tmp;
372 int nr = 1, i, retry;
373
374 if (!op)
375 return 0;
376
377 if (params != NULL)
378 sscanf (params, "%d", &nr);
379 for (i = 0; i < nr; i++)
380 {
381 retry = 50;
382 while ((tmp = generate_treasure (0, op->map->difficulty)) == NULL && --retry)
383 ;
384 if (tmp != NULL)
385 {
386 tmp = insert_ob_in_ob (tmp, op);
387 if (op->type == PLAYER)
388 esrv_send_item (op, tmp);
389 }
390 }
391
392 return 1;
393 }
394
395 int
396 command_freeze (object *op, char *params)
397 {
398 int ticks;
399 player *pl;
400
401 if (!params)
402 {
403 new_draw_info (NDI_UNIQUE, 0, op, "Usage: freeze [ticks] <player>.");
404 return 1;
405 }
406
407 ticks = atoi (params);
408 if (ticks)
409 {
410 while ((isdigit (*params) || isspace (*params)) && *params != 0)
411 params++;
412 if (*params == 0)
413 {
414 new_draw_info (NDI_UNIQUE, 0, op, "Usage: freeze [ticks] <player>.");
415 return 1;
416 }
417 }
418 else
419 ticks = 100;
420
421 pl = get_other_player_from_name (op, params);
422 if (!pl)
423 return 1;
424
425 new_draw_info (NDI_UNIQUE | NDI_RED, 0, pl->ob, "You have been frozen by the DM!");
426 new_draw_info_format (NDI_UNIQUE, 0, op, "You freeze %s for %d ticks", &pl->ob->name, ticks);
427 pl->ob->speed_left = -(pl->ob->speed * ticks);
428 return 0;
429 }
430
431 int
432 command_arrest (object *op, char *params)
433 {
434 object *dummy;
435 player *pl;
436
437 if (!op)
438 return 0;
439 if (params == NULL)
440 {
441 new_draw_info (NDI_UNIQUE, 0, op, "Usage: arrest <player>.");
442 return 1;
443 }
444 pl = get_other_player_from_name (op, params);
445 if (!pl)
446 return 1;
447 dummy = get_jail_exit (pl->ob);
448 if (!dummy)
449 {
450 /* we have nowhere to send the prisoner.... */
451 new_draw_info (NDI_UNIQUE, 0, op, "can't jail player, there is no map to hold them");
452 return 0;
453 }
454 enter_exit (pl->ob, dummy);
455 free_object (dummy);
456 new_draw_info (NDI_UNIQUE, 0, pl->ob, "You have been arrested.");
457 new_draw_info (NDI_UNIQUE, 0, op, "OK.");
458 LOG (llevInfo, "Player %s arrested by %s\n", &pl->ob->name, &op->name);
459 return 1;
460 }
461
462 int
463 command_summon (object *op, char *params)
464 {
465 int i;
466 object *dummy;
467 player *pl;
468
469 if (!op)
470 return 0;
471
472 if (params == NULL)
473 {
474 new_draw_info (NDI_UNIQUE, 0, op, "Usage: summon <player>.");
475 return 1;
476 }
477
478 pl = get_other_player_from_name (op, params);
479 if (!pl)
480 return 1;
481
482 i = find_free_spot (op, op->map, op->x, op->y, 1, 9);
483 if (i == -1)
484 {
485 new_draw_info (NDI_UNIQUE, 0, op, "Can not find a free spot to place summoned player.");
486 return 1;
487 }
488
489 dummy = get_object ();
490 EXIT_PATH (dummy) = op->map->path;
491 EXIT_X (dummy) = op->x + freearr_x[i];
492 EXIT_Y (dummy) = op->y + freearr_y[i];
493 enter_exit (pl->ob, dummy);
494 free_object (dummy);
495 new_draw_info (NDI_UNIQUE, 0, pl->ob, "You are summoned.");
496 new_draw_info (NDI_UNIQUE, 0, op, "OK.");
497
498 return 1;
499 }
500
501 /**
502 * Teleport next to target player.
503 */
504
505 /* mids 01/16/2002 */
506 int
507 command_teleport (object *op, char *params)
508 {
509 int i;
510 object *dummy;
511 player *pl;
512
513 if (!op)
514 return 0;
515
516 if (params == NULL)
517 {
518 new_draw_info (NDI_UNIQUE, 0, op, "Usage: teleport <player>.");
519 return 1;
520 }
521
522 pl = get_other_player_from_name (op, params);
523 if (!pl)
524 return 1;
525
526 i = find_free_spot (pl->ob, pl->ob->map, pl->ob->x, pl->ob->y, 1, 9);
527 if (i == -1)
528 {
529 new_draw_info (NDI_UNIQUE, 0, op, "Can not find a free spot to teleport to.");
530 return 1;
531 }
532
533 dummy = get_object ();
534 EXIT_PATH (dummy) = pl->ob->map->path;
535 EXIT_X (dummy) = pl->ob->x + freearr_x[i];
536 EXIT_Y (dummy) = pl->ob->y + freearr_y[i];
537 enter_exit (op, dummy);
538 free_object (dummy);
539 if (!op->contr->hidden)
540 new_draw_info (NDI_UNIQUE, 0, pl->ob, "You see a portal open.");
541 new_draw_info (NDI_UNIQUE, 0, op, "OK.");
542 return 1;
543 }
544
545 /**
546 * This function is a real mess, because we're stucking getting
547 * the entire item description in one block of text, so we just
548 * can't simply parse it - we need to look for double quotes
549 * for example. This could actually get much simpler with just a
550 * little help from the client - if we could get line breaks, it
551 * makes parsing much easier, eg, something like:
552 * arch dragon
553 * name big nasty creature
554 * hp 5
555 * sp 30
556 * Is much easier to parse than
557 * dragon name "big nasty creature" hp 5 sp 30
558 * for example.
559 */
560 int
561 command_create (object *op, char *params)
562 {
563 object *tmp = NULL;
564 int nrof, i, magic, set_magic = 0, set_nrof = 0, gotquote, gotspace;
565 char buf[MAX_BUF], *cp, *bp = buf, *bp2, *bp3, *bp4, *endline;
566 archetype *at, *at_spell = NULL;
567 artifact *art = NULL;
568
569 if (!op)
570 return 0;
571
572 if (params == NULL)
573 {
574 new_draw_info (NDI_UNIQUE, 0, op, "Usage: create [nr] [magic] <archetype> [ of <artifact>]" " [variable_to_patch setting]");
575 return 1;
576 }
577 bp = params;
578
579 /* We need to know where the line ends */
580 endline = bp + strlen (bp);
581
582 if (sscanf (bp, "%d ", &nrof))
583 {
584 if ((bp = strchr (params, ' ')) == NULL)
585 {
586 new_draw_info (NDI_UNIQUE, 0, op, "Usage: create [nr] [magic] <archetype> [ of <artifact>]" " [variable_to_patch setting]");
587 return 1;
588 }
589 bp++;
590 set_nrof = 1;
591 LOG (llevDebug, "%s creates: (%d) %s\n", &op->name, nrof, bp);
592 }
593 if (sscanf (bp, "%d ", &magic))
594 {
595 if ((bp = strchr (bp, ' ')) == NULL)
596 {
597 new_draw_info (NDI_UNIQUE, 0, op, "Usage: create [nr] [magic] <archetype> [ of <artifact>]" " [variable_to_patch setting]");
598 return 1;
599 }
600 bp++;
601 set_magic = 1;
602 LOG (llevDebug, "%s creates: (%d) (%d) %s\n", &op->name, nrof, magic, bp);
603 }
604 if ((cp = strstr (bp, " of ")) != NULL)
605 {
606 *cp = '\0';
607 cp += 4;
608 }
609 for (bp2 = bp; *bp2; bp2++)
610 {
611 if (*bp2 == ' ')
612 {
613 *bp2 = '\0';
614 bp2++;
615 break;
616 }
617 }
618
619 if ((at = find_archetype (bp)) == NULL)
620 {
621 new_draw_info (NDI_UNIQUE, 0, op, "No such archetype.");
622 return 1;
623 }
624
625 if (cp)
626 {
627 char spell_name[MAX_BUF], *fsp = NULL;
628
629 /*
630 * Try to find a spell object for this. Note that
631 * we also set up spell_name which is only
632 * the first word.
633 */
634
635 at_spell = find_archetype (cp);
636 if (!at_spell || at_spell->clone.type != SPELL)
637 at_spell = find_archetype_by_object_name (cp);
638 if (!at_spell || at_spell->clone.type != SPELL)
639 {
640 strcpy (spell_name, cp);
641 fsp = strchr (spell_name, ' ');
642 if (fsp)
643 {
644 *fsp = 0;
645 fsp++;
646 at_spell = find_archetype (spell_name);
647
648 /* Got a spell, update the first string pointer */
649 if (at_spell && at_spell->clone.type == SPELL)
650 bp2 = cp + strlen (spell_name) + 1;
651 else
652 at_spell = NULL;
653 }
654 }
655
656 /* OK - we didn't find a spell - presume the 'of'
657 * in this case means its an artifact.
658 */
659 if (!at_spell)
660 {
661 if (find_artifactlist (at->clone.type) == NULL)
662 {
663 new_draw_info_format (NDI_UNIQUE, 0, op, "No artifact list for type %d\n", at->clone.type);
664 }
665 else
666 {
667 art = find_artifactlist (at->clone.type)->items;
668
669 do
670 {
671 if (!strcmp (art->item->name, cp))
672 break;
673 art = art->next;
674 }
675 while (art != NULL);
676 if (!art)
677 {
678 new_draw_info_format (NDI_UNIQUE, 0, op, "No such artifact ([%d] of %s)", at->clone.type, cp);
679 }
680 }
681 LOG (llevDebug, "%s creates: (%d) (%d) (%s) of (%s)\n", &op->name, set_nrof ? nrof : 0, set_magic ? magic : 0, bp, cp);
682 }
683 } /* if cp */
684
685 if ((at->clone.type == ROD || at->clone.type == WAND || at->clone.type == SCROLL ||
686 at->clone.type == HORN || at->clone.type == SPELLBOOK) && !at_spell)
687 {
688 new_draw_info_format (NDI_UNIQUE, 0, op, "Unable to find spell %s for object that needs it, or it is of wrong type", cp);
689 return 1;
690 }
691
692 /*
693 * Rather than have two different blocks with a lot of similar code,
694 * just create one object, do all the processing, and then determine
695 * if that one object should be inserted or if we need to make copies.
696 */
697 tmp = arch_to_object (at);
698 if (settings.real_wiz == FALSE)
699 SET_FLAG (tmp, FLAG_WAS_WIZ);
700 if (set_magic)
701 set_abs_magic (tmp, magic);
702 if (art)
703 give_artifact_abilities (tmp, art->item);
704 if (need_identify (tmp))
705 {
706 SET_FLAG (tmp, FLAG_IDENTIFIED);
707 CLEAR_FLAG (tmp, FLAG_KNOWN_MAGICAL);
708 }
709
710 /*
711 * This entire block here tries to find variable pairings,
712 * eg, 'hp 4' or the like. The mess here is that values
713 * can be quoted (eg "my cool sword"); So the basic logic
714 * is we want to find two spaces, but if we got a quote,
715 * any spaces there don't count.
716 */
717 while (*bp2 && bp2 <= endline)
718 {
719 bp4 = NULL;
720 gotspace = 0;
721 gotquote = 0;
722 /* find the first quote */
723 for (bp3 = bp2; *bp3 && gotspace < 2 && gotquote < 2; bp3++)
724 {
725
726 /* Found a quote - now lets find the second one */
727 if (*bp3 == '"')
728 {
729 *bp3 = ' ';
730 bp2 = bp3 + 1; /* Update start of string */
731 bp3++;
732 gotquote++;
733 while (*bp3)
734 {
735 if (*bp3 == '"')
736 {
737 *bp3 = '\0';
738 gotquote++;
739 }
740 else
741 bp3++;
742 }
743 }
744 else if (*bp3 == ' ')
745 {
746 gotspace++;
747 }
748 }
749
750 /*
751 * If we got two spaces, send the second one to null.
752 * if we've reached the end of the line, increase gotspace -
753 * this is perfectly valid for the list entry listed.
754 */
755 if (gotspace == 2 || gotquote == 2)
756 {
757 bp3--; /* Undo the extra increment */
758 *bp3 = '\0';
759 }
760 else if (*bp3 == '\0')
761 gotspace++;
762
763 if ((gotquote && gotquote != 2) || (gotspace != 2 && gotquote != 2))
764 {
765 /*
766 * Unfortunately, we've clobbered lots of values, so printing
767 * out what we have probably isn't useful. Break out, because
768 * trying to recover is probably won't get anything useful
769 * anyways, and we'd be confused about end of line pointers
770 * anyways.
771 */
772 new_draw_info_format (NDI_UNIQUE, 0, op, "Malformed create line: %s", bp2);
773 break;
774 }
775 /* bp2 should still point to the start of this line,
776 * with bp3 pointing to the end
777 */
778 if (set_variable (tmp, bp2) == -1)
779 new_draw_info_format (NDI_UNIQUE, 0, op, "Unknown variable %s", bp2);
780 else
781 new_draw_info_format (NDI_UNIQUE, 0, op, "(%s#%d)->%s", &tmp->name, tmp->count, bp2);
782 bp2 = bp3 + 1;
783 }
784
785 if (at->clone.nrof)
786 {
787 if (at_spell)
788 insert_ob_in_ob (arch_to_object (at_spell), tmp);
789
790 tmp->x = op->x;
791 tmp->y = op->y;
792 if (set_nrof)
793 tmp->nrof = nrof;
794 tmp->map = op->map;
795
796 tmp = insert_ob_in_ob (tmp, op);
797 esrv_send_item (op, tmp);
798
799 /* Let's put this created item on stack so dm can access it easily. */
800 dm_stack_push (op->contr, tmp->count);
801
802 return 1;
803 }
804 else
805 {
806 for (i = 0; i < (set_nrof ? nrof : 1); i++)
807 {
808 archetype *atmp;
809 object *prev = NULL, *head = NULL, *dup;
810
811 for (atmp = at; atmp != NULL; atmp = atmp->more)
812 {
813 dup = arch_to_object (atmp);
814
815 if (at_spell)
816 insert_ob_in_ob (arch_to_object (at_spell), dup);
817
818 /*
819 * The head is what contains all the important bits,
820 * so just copying it over should be fine.
821 */
822 if (head == NULL)
823 {
824 head = dup;
825 copy_object (tmp, dup);
826 }
827 if (settings.real_wiz == FALSE)
828 SET_FLAG (dup, FLAG_WAS_WIZ);
829 dup->x = op->x + dup->arch->clone.x;
830 dup->y = op->y + dup->arch->clone.y;
831 dup->map = op->map;
832
833 if (head != dup)
834 {
835 dup->head = head;
836 prev->more = dup;
837 }
838 prev = dup;
839 }
840
841 if (QUERY_FLAG (head, FLAG_ALIVE))
842 {
843 object *check = head;
844 int size_x = 0;
845 int size_y = 0;
846
847 while (check)
848 {
849 size_x = MAX (size_x, check->arch->clone.x);
850 size_y = MAX (size_y, check->arch->clone.y);
851 check = check->more;
852 }
853
854 if (out_of_map (op->map, head->x + size_x, head->y + size_y))
855 {
856 if (head->x < size_x || head->y < size_y)
857 {
858 dm_stack_pop (op->contr);
859 free_object (head);
860 new_draw_info (NDI_UNIQUE, 0, op, "Object too big to insert in map, or wrong position.");
861 free_object (tmp);
862 return 1;
863 }
864
865 check = head;
866 while (check)
867 {
868 check->x -= size_x;
869 check->y -= size_y;
870 check = check->more;
871 }
872 }
873
874 insert_ob_in_map (head, op->map, op, 0);
875 }
876 else
877 head = insert_ob_in_ob (head, op);
878
879 /* Let's put this created item on stack so dm can access it easily. */
880 /* Wonder if we really want to push all of these, but since
881 * things like rods have nrof 0, we want to cover those.
882 */
883 dm_stack_push (op->contr, head->count);
884
885 if (at->clone.randomitems != NULL && !at_spell)
886 create_treasure (at->clone.randomitems, head, GT_APPLY, op->map->difficulty, 0);
887 esrv_send_item (op, head);
888 }
889
890 /* free the one we used to copy */
891 free_object (tmp);
892 }
893
894 return 1;
895 }
896
897 /*
898 * Now follows dm-commands which are also acceptable from sockets
899 */
900
901 int
902 command_inventory (object *op, char *params)
903 {
904 object *tmp;
905 int i;
906
907 if (!params)
908 {
909 inventory (op, NULL);
910 return 0;
911 }
912
913 if (!sscanf (params, "%d", &i) || (tmp = find_object (i)) == NULL)
914 {
915 new_draw_info (NDI_UNIQUE, 0, op, "Inventory of what object (nr)?");
916 return 1;
917 }
918
919 inventory (op, tmp);
920 return 1;
921 }
922
923 /* just show player's their skills for now. Dm's can
924 * already see skills w/ inventory command - b.t.
925 */
926
927 int
928 command_skills (object *op, char *params)
929 {
930 show_skills (op, params);
931 return 0;
932 }
933
934 int
935 command_dump (object *op, char *params)
936 {
937 object *tmp;
938
939 tmp = get_dm_object (op->contr, &params, NULL);
940 if (!tmp)
941 return 1;
942
943 dump_object (tmp);
944 new_draw_info (NDI_UNIQUE, 0, op, errmsg);
945 if (QUERY_FLAG (tmp, FLAG_OBJ_ORIGINAL))
946 new_draw_info (NDI_UNIQUE, 0, op, "Object is marked original");
947 return 1;
948 }
949
950 /**
951 * When DM is possessing a monster, flip aggression on and off, to allow
952 * better motion.
953 */
954 int
955 command_mon_aggr (object *op, char *params)
956 {
957 if (op->enemy || !QUERY_FLAG (op, FLAG_UNAGGRESSIVE))
958 {
959 op->enemy = NULL;
960 SET_FLAG (op, FLAG_UNAGGRESSIVE);
961 new_draw_info (NDI_UNIQUE, 0, op, "Aggression turned OFF");
962 }
963 else
964 {
965 CLEAR_FLAG (op, FLAG_FRIENDLY);
966 CLEAR_FLAG (op, FLAG_UNAGGRESSIVE);
967 new_draw_info (NDI_UNIQUE, 0, op, "Aggression turned ON");
968 }
969
970 return 1;
971 }
972
973 /** DM can possess a monster. Basically, this tricks the client into thinking
974 * a given monster, is actually the player it controls. This allows a DM
975 * to inhabit a monster's body, and run around the game with it.
976 * This function is severely broken - it has tons of hardcoded values,
977 */
978 int
979 command_possess (object *op, char *params)
980 {
981 object *victim, *curinv, *nextinv;
982 player *pl;
983 int i;
984 char buf[MAX_BUF];
985
986 victim = NULL;
987 if (params != NULL)
988 {
989 if (sscanf (params, "%d", &i))
990 victim = find_object (i);
991 else if (sscanf (params, "%s", buf))
992 victim = find_object_name (buf);
993 }
994 if (victim == NULL)
995 {
996 new_draw_info (NDI_UNIQUE, 0, op, "Patch what object (nr)?");
997 return 1;
998 }
999
1000 if (victim == op)
1001 {
1002 new_draw_info (NDI_UNIQUE, 0, op, "As insane as you are, I cannot " "allow you to possess yourself.");
1003 return 1;
1004 }
1005
1006 /* clear out the old inventory */
1007 curinv = op->inv;
1008 while (curinv != NULL)
1009 {
1010 nextinv = curinv->below;
1011 esrv_del_item (op->contr, curinv->count);
1012 curinv = nextinv;
1013 }
1014
1015 /* make the switch */
1016 pl = op->contr;
1017 victim->contr = pl;
1018 pl->ob = victim;
1019 victim->type = PLAYER;
1020 SET_FLAG (victim, FLAG_WIZ);
1021
1022 /* send the inventory to the client */
1023 curinv = victim->inv;
1024 while (curinv != NULL)
1025 {
1026 nextinv = curinv->below;
1027 esrv_send_item (victim, curinv);
1028 curinv = nextinv;
1029 }
1030 /* basic patchup */
1031 /* The use of hard coded values is terrible. Note
1032 * that really, to be fair, this shouldn't get changed at
1033 * all - if you are possessing a kobold, you should have the
1034 * same limitations. As it is, as more body locations are added,
1035 * this will give this player more locations than perhaps
1036 * they should be allowed.
1037 */
1038 for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1039 if (i == 1 || i == 6 || i == 8 || i == 9)
1040 victim->body_info[i] = 2;
1041 else
1042 victim->body_info[i] = 1;
1043
1044 esrv_new_player (pl, 80); /* just pick a wieght, we don't care */
1045 esrv_send_inventory (victim, victim);
1046
1047 fix_player (victim);
1048
1049 do_some_living (victim);
1050 return 1;
1051 }
1052
1053 int
1054 command_patch (object *op, char *params)
1055 {
1056 char *arg, *arg2;
1057 object *tmp;
1058
1059 tmp = get_dm_object (op->contr, &params, NULL);
1060 if (!tmp)
1061 /* Player already informed of failure */
1062 return 1;
1063
1064 /* params set to first value by get_dm_default */
1065 arg = params;
1066 if (arg == NULL)
1067 {
1068 new_draw_info (NDI_UNIQUE, 0, op, "Patch what values?");
1069 return 1;
1070 }
1071
1072 if ((arg2 = strchr (arg, ' ')))
1073 arg2++;
1074 if (settings.real_wiz == FALSE)
1075 SET_FLAG (tmp, FLAG_WAS_WIZ); /* To avoid cheating */
1076 if (set_variable (tmp, arg) == -1)
1077 new_draw_info_format (NDI_UNIQUE, 0, op, "Unknown variable %s", arg);
1078 else
1079 {
1080 new_draw_info_format (NDI_UNIQUE, 0, op, "(%s#%d)->%s=%s", &tmp->name, tmp->count, arg, arg2);
1081 }
1082
1083 return 1;
1084 }
1085
1086 int
1087 command_remove (object *op, char *params)
1088 {
1089 object *tmp;
1090 int from;
1091
1092 tmp = get_dm_object (op->contr, &params, &from);
1093 if (!tmp)
1094 {
1095 new_draw_info (NDI_UNIQUE, 0, op, "Remove what object (nr)?");
1096 return 1;
1097 }
1098
1099 if (tmp->type == PLAYER)
1100 {
1101 new_draw_info (NDI_UNIQUE, 0, op, "Unable to remove a player!");
1102 return 1;
1103 }
1104
1105 if (QUERY_FLAG (tmp, FLAG_REMOVED))
1106 {
1107 new_draw_info_format (NDI_UNIQUE, 0, op, "%s is already removed!", query_name (tmp));
1108 return 1;
1109 }
1110
1111 if (from != STACK_FROM_STACK)
1112 /* Item is either stack top, or is a number thus is now stack top, let's remove it */
1113 dm_stack_pop (op->contr);
1114
1115 /* Always work on the head - otherwise object will get in odd state */
1116 if (tmp->head)
1117 tmp = tmp->head;
1118 remove_ob (tmp);
1119 return 1;
1120 }
1121
1122 int
1123 command_free (object *op, char *params)
1124 {
1125 object *tmp;
1126 int from;
1127
1128 tmp = get_dm_object (op->contr, &params, &from);
1129
1130 if (!tmp)
1131 {
1132 new_draw_info (NDI_UNIQUE, 0, op, "Free what object (nr)?");
1133 return 1;
1134 }
1135
1136 if (from != STACK_FROM_STACK)
1137 /* Item is either stack top, or is a number thus is now stack top, let's remove it */
1138 dm_stack_pop (op->contr);
1139
1140 if (!QUERY_FLAG (tmp, FLAG_REMOVED))
1141 {
1142 new_draw_info (NDI_UNIQUE, 0, op, "Warning, item wasn't removed.");
1143 remove_ob (tmp);
1144 }
1145
1146 if (tmp->head)
1147 tmp = tmp->head;
1148 free_object (tmp);
1149 return 1;
1150 }
1151
1152 /**
1153 * This adds exp to a player. We now allow adding to a specific skill.
1154 */
1155 int
1156 command_addexp (object *op, char *params)
1157 {
1158 char buf[MAX_BUF], skill[MAX_BUF];
1159 int i, q;
1160 object *skillob = NULL;
1161 player *pl;
1162
1163 skill[0] = '\0';
1164 if ((params == NULL) || (strlen (params) > MAX_BUF) || ((q = sscanf (params, "%s %d %s", buf, &i, skill)) < 2))
1165 {
1166 new_draw_info (NDI_UNIQUE, 0, op, "Usage: addexp <who> <how much> [<skill>].");
1167 return 1;
1168 }
1169
1170 for (pl = first_player; pl != NULL; pl = pl->next)
1171 if (!strncmp (pl->ob->name, buf, MAX_NAME))
1172 break;
1173
1174 if (pl == NULL)
1175 {
1176 new_draw_info (NDI_UNIQUE, 0, op, "No such player.");
1177 return 1;
1178 }
1179
1180 if (q >= 3)
1181 {
1182 skillob = find_skill_by_name (pl->ob, skill);
1183 if (!skillob)
1184 {
1185 new_draw_info_format (NDI_UNIQUE, 0, op, "Unable to find skill %s in %s", skill, buf);
1186 return 1;
1187 }
1188
1189 i = check_exp_adjust (skillob, i);
1190 skillob->stats.exp += i;
1191 calc_perm_exp (skillob);
1192 player_lvl_adj (pl->ob, skillob);
1193 }
1194
1195 pl->ob->stats.exp += i;
1196 calc_perm_exp (pl->ob);
1197 player_lvl_adj (pl->ob, NULL);
1198
1199 if (settings.real_wiz == FALSE)
1200 SET_FLAG (pl->ob, FLAG_WAS_WIZ);
1201 return 1;
1202 }
1203
1204 /**************************************************************************/
1205
1206 /* Mods made by Tyler Van Gorder, May 10-13, 1992. */
1207
1208 /* CSUChico : tvangod@cscihp.ecst.csuchico.edu */
1209
1210 /**************************************************************************/
1211
1212 int
1213 command_stats (object *op, char *params)
1214 {
1215 char thing[20];
1216 player *pl;
1217 char buf[MAX_BUF];
1218
1219 thing[0] = '\0';
1220 if (params == NULL || !sscanf (params, "%s", thing) || thing == NULL)
1221 {
1222 new_draw_info (NDI_UNIQUE, 0, op, "Who?");
1223 return 1;
1224 }
1225
1226 for (pl = first_player; pl != NULL; pl = pl->next)
1227 if (!strcmp (pl->ob->name, thing))
1228 {
1229 sprintf (buf, "Str : %-2d H.P. : %-4d MAX : %d", pl->ob->stats.Str, pl->ob->stats.hp, pl->ob->stats.maxhp);
1230 new_draw_info (NDI_UNIQUE, 0, op, buf);
1231 sprintf (buf, "Dex : %-2d S.P. : %-4d MAX : %d", pl->ob->stats.Dex, pl->ob->stats.sp, pl->ob->stats.maxsp);
1232 new_draw_info (NDI_UNIQUE, 0, op, buf);
1233 sprintf (buf, "Con : %-2d AC : %-4d WC : %d", pl->ob->stats.Con, pl->ob->stats.ac, pl->ob->stats.wc);
1234 new_draw_info (NDI_UNIQUE, 0, op, buf);
1235 sprintf (buf, "Int : %-2d Damage : %d", pl->ob->stats.Int, pl->ob->stats.dam);
1236 new_draw_info (NDI_UNIQUE, 0, op, buf);
1237 sprintf (buf, "Wis : %-2d EXP : %lld", pl->ob->stats.Wis, (long long) pl->ob->stats.exp);
1238 new_draw_info (NDI_UNIQUE, 0, op, buf);
1239 sprintf (buf, "Pow : %-2d Grace : %d", pl->ob->stats.Pow, pl->ob->stats.grace);
1240 new_draw_info (NDI_UNIQUE, 0, op, buf);
1241 sprintf (buf, "Cha : %-2d Food : %d", pl->ob->stats.Cha, pl->ob->stats.food);
1242 new_draw_info (NDI_UNIQUE, 0, op, buf);
1243 break;
1244 }
1245 if (pl == NULL)
1246 new_draw_info (NDI_UNIQUE, 0, op, "No such player.");
1247 return 1;
1248 }
1249
1250 int
1251 command_abil (object *op, char *params)
1252 {
1253 char thing[20], thing2[20];
1254 int iii;
1255 player *pl;
1256 char buf[MAX_BUF];
1257
1258 iii = 0;
1259 thing[0] = '\0';
1260 thing2[0] = '\0';
1261 if (params == NULL || !sscanf (params, "%s %s %d", thing, thing2, &iii) || thing == NULL)
1262 {
1263 new_draw_info (NDI_UNIQUE, 0, op, "Who?");
1264 return 1;
1265 }
1266
1267 if (thing2 == NULL)
1268 {
1269 new_draw_info (NDI_UNIQUE, 0, op, "You can't change that.");
1270 return 1;
1271 }
1272
1273 if (iii < MIN_STAT || iii > MAX_STAT)
1274 {
1275 new_draw_info (NDI_UNIQUE, 0, op, "Illegal range of stat.\n");
1276 return 1;
1277 }
1278
1279 for (pl = first_player; pl != NULL; pl = pl->next)
1280 {
1281 if (!strcmp (pl->ob->name, thing))
1282 {
1283 if (settings.real_wiz == FALSE)
1284 SET_FLAG (pl->ob, FLAG_WAS_WIZ);
1285 if (!strcmp ("str", thing2))
1286 pl->ob->stats.Str = iii, pl->orig_stats.Str = iii;
1287 if (!strcmp ("dex", thing2))
1288 pl->ob->stats.Dex = iii, pl->orig_stats.Dex = iii;
1289 if (!strcmp ("con", thing2))
1290 pl->ob->stats.Con = iii, pl->orig_stats.Con = iii;
1291 if (!strcmp ("wis", thing2))
1292 pl->ob->stats.Wis = iii, pl->orig_stats.Wis = iii;
1293 if (!strcmp ("cha", thing2))
1294 pl->ob->stats.Cha = iii, pl->orig_stats.Cha = iii;
1295 if (!strcmp ("int", thing2))
1296 pl->ob->stats.Int = iii, pl->orig_stats.Int = iii;
1297 if (!strcmp ("pow", thing2))
1298 pl->ob->stats.Pow = iii, pl->orig_stats.Pow = iii;
1299 sprintf (buf, "%s has been altered.", &pl->ob->name);
1300 new_draw_info (NDI_UNIQUE, 0, op, buf);
1301 fix_player (pl->ob);
1302 return 1;
1303 }
1304 }
1305
1306 new_draw_info (NDI_UNIQUE, 0, op, "No such player.");
1307 return 1;
1308 }
1309
1310 int
1311 command_reset (object *op, char *params)
1312 {
1313 mapstruct *m;
1314 object *dummy = NULL, *tmp = NULL;
1315
1316 if (params == NULL)
1317 {
1318 new_draw_info (NDI_UNIQUE, 0, op, "Reset what map [name]?");
1319 return 1;
1320 }
1321
1322 if (strcmp (params, ".") == 0)
1323 params = op->map->path;
1324 m = has_been_loaded (params);
1325 if (m == NULL)
1326 {
1327 new_draw_info (NDI_UNIQUE, 0, op, "No such map.");
1328 return 1;
1329 }
1330
1331 if (m->in_memory != MAP_SWAPPED)
1332 {
1333 if (m->in_memory != MAP_IN_MEMORY)
1334 {
1335 LOG (llevError, "Tried to swap out map which was not in memory.\n");
1336 return 0;
1337 }
1338
1339 /*
1340 * Only attempt to remove the player that is doing the reset, and not other
1341 * players or wiz's.
1342 */
1343 if (op->map == m)
1344 {
1345 dummy = get_object ();
1346 dummy->map = NULL;
1347 EXIT_X (dummy) = op->x;
1348 EXIT_Y (dummy) = op->y;
1349 EXIT_PATH (dummy) = op->map->path;
1350 remove_ob (op);
1351 op->map = NULL;
1352 tmp = op;
1353 }
1354 swap_map (m);
1355 }
1356
1357 if (m->in_memory == MAP_SWAPPED)
1358 {
1359 LOG (llevDebug, "Resetting map %s.\n", m->path);
1360
1361 /* setting this effectively causes an immediate reload */
1362 m->reset_time = 1;
1363 flush_old_maps ();
1364 new_draw_info (NDI_UNIQUE, 0, op, "OK.");
1365 if (tmp)
1366 {
1367 enter_exit (tmp, dummy);
1368 free_object (dummy);
1369 }
1370 return 1;
1371 }
1372 else
1373 {
1374 player *pl;
1375 int playercount = 0;
1376
1377 /* Need to re-insert player if swap failed for some reason */
1378 if (tmp)
1379 {
1380 insert_ob_in_map (op, m, NULL, 0);
1381 free_object (dummy);
1382 }
1383
1384 new_draw_info (NDI_UNIQUE, 0, op, "Reset failed, couldn't swap map, the following players are on it:");
1385 for (pl = first_player; pl != NULL; pl = pl->next)
1386 {
1387 if (pl->ob->map == m && pl->ob != op)
1388 {
1389 new_draw_info_format (NDI_UNIQUE, 0, op, "%s", &pl->ob->name);
1390 playercount++;
1391 }
1392 }
1393 if (!playercount)
1394 new_draw_info (NDI_UNIQUE, 0, op, "hmm, I don't see any other players on this map, something else is the problem.");
1395 return 1;
1396 }
1397 }
1398
1399 int
1400 command_nowiz (object *op, char *params)
1401 { /* 'noadm' is alias */
1402 CLEAR_FLAG (op, FLAG_WIZ);
1403 CLEAR_FLAG (op, FLAG_WIZPASS);
1404 CLEAR_FLAG (op, FLAG_WIZCAST);
1405
1406 if (settings.real_wiz == TRUE)
1407 CLEAR_FLAG (op, FLAG_WAS_WIZ);
1408 if (op->contr->hidden)
1409 {
1410 new_draw_info (NDI_UNIQUE, 0, op, "You are no longer hidden from other players");
1411 op->map->players++;
1412 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s has entered the game.", &op->name);
1413 op->contr->hidden = 0;
1414 op->invisible = 1;
1415 }
1416 else
1417 new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master is gone..");
1418 return 1;
1419 }
1420
1421 /**
1422 * object *op is trying to become dm.
1423 * pl_name is name supplied by player. Restrictive DM will make it harder
1424 * for socket users to become DM - in that case, it will check for the players
1425 * character name.
1426 */
1427 static int
1428 checkdm (object *op, const char *pl_name, const char *pl_passwd, const char *pl_host)
1429 {
1430 FILE *dmfile;
1431 char buf[MAX_BUF];
1432 char line_buf[160], name[160], passwd[160], host[160];
1433
1434 #ifdef RESTRICTIVE_DM
1435 *pl_name = op->name ? op->name : "*";
1436 #endif
1437
1438 sprintf (buf, "%s/%s", settings.confdir, DMFILE);
1439 if ((dmfile = fopen (buf, "r")) == NULL)
1440 {
1441 LOG (llevDebug, "Could not find DM file.\n");
1442 return 0;
1443 }
1444
1445 while (fgets (line_buf, 160, dmfile) != NULL)
1446 {
1447 if (line_buf[0] == '#')
1448 continue;
1449 if (sscanf (line_buf, "%[^:]:%[^:]:%s\n", name, passwd, host) != 3)
1450 {
1451 LOG (llevError, "Warning - malformed dm file entry: %s\n", line_buf);
1452 }
1453 else if ((!strcmp (name, "*") || (pl_name && !strcmp (pl_name, name)))
1454 && (!strcmp (passwd, "*") || !strcmp (passwd, pl_passwd)) && (!strcmp (host, "*") || !strcmp (host, pl_host)))
1455 {
1456 fclose (dmfile);
1457 return (1);
1458 }
1459 }
1460 fclose (dmfile);
1461 return (0);
1462 }
1463
1464 int
1465 do_wizard_dm (object *op, char *params, int silent)
1466 {
1467 if (!op->contr)
1468 return 0;
1469
1470 if (QUERY_FLAG (op, FLAG_WIZ))
1471 {
1472 new_draw_info (NDI_UNIQUE, 0, op, "You are already the Dungeon Master!");
1473 return 0;
1474 }
1475
1476 if (checkdm (op, op->name, (params ? params : "*"), op->contr->socket.host))
1477 {
1478 SET_FLAG (op, FLAG_WIZ);
1479 SET_FLAG (op, FLAG_WAS_WIZ);
1480 SET_FLAG (op, FLAG_WIZPASS);
1481 SET_FLAG (op, FLAG_WIZCAST);
1482 new_draw_info (NDI_UNIQUE, 0, op, "Ok, you are the Dungeon Master!");
1483 /*
1484 * Remove setting flying here - that won't work, because next
1485 * fix_player() is called that will get cleared - proper solution
1486 * is probably something like a wiz_force which gives that and any
1487 * other desired abilities.
1488 */
1489 clear_los (op);
1490 op->contr->write_buf[0] = '\0';
1491
1492 if (!silent)
1493 new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master has arrived!");
1494
1495 return 1;
1496 }
1497 else
1498 {
1499 new_draw_info (NDI_UNIQUE, 0, op, "Sorry Pal, I don't think so.");
1500 op->contr->write_buf[0] = '\0';
1501 return 0;
1502 }
1503 }
1504
1505 /*
1506 * Actual command to perhaps become dm. Changed aroun a bit in version 0.92.2
1507 * - allow people on sockets to become dm, and allow better dm file
1508 */
1509 int
1510 command_dm (object *op, char *params)
1511 {
1512 if (!op->contr)
1513 return 0;
1514
1515 do_wizard_dm (op, params, 0);
1516
1517 return 1;
1518 }
1519
1520 int
1521 command_invisible (object *op, char *params)
1522 {
1523 if (op)
1524 {
1525 op->invisible += 100;
1526 update_object (op, UP_OBJ_FACE);
1527 new_draw_info (NDI_UNIQUE, 0, op, "You turn invisible.");
1528 }
1529
1530 return 0;
1531 }
1532
1533 /**
1534 * Returns spell object (from archetypes) by name.
1535 * Returns NULL if 0 or more than one spell matches.
1536 * Used for wizard's learn spell/prayer.
1537 *
1538 * op is the player issuing the command.
1539 *
1540 * Ignores archetypes "spelldirect_xxx" since these archetypes are not used
1541 * anymore (but may still be present in some player's inventories and thus
1542 * cannot be removed). We have to ignore them here since they have the same
1543 * name than other "spell_xxx" archetypes and would always conflict.
1544 */
1545 static object *
1546 get_spell_by_name (object *op, const char *spell_name)
1547 {
1548 archetype *ar;
1549 archetype *found;
1550 int conflict_found;
1551 size_t spell_name_length;
1552
1553 /* First check for full name matches. */
1554 conflict_found = 0;
1555 found = NULL;
1556 for (ar = first_archetype; ar != NULL; ar = ar->next)
1557 {
1558 if (ar->clone.type != SPELL)
1559 continue;
1560
1561 if (strncmp (ar->name, "spelldirect_", 12) == 0)
1562 continue;
1563
1564 if (strcmp (ar->clone.name, spell_name) != 0)
1565 continue;
1566
1567 if (found != NULL)
1568 {
1569 if (!conflict_found)
1570 {
1571 conflict_found = 1;
1572 new_draw_info_format (NDI_UNIQUE, 0, op, "More than one archetype matches the spell name %s:", spell_name);
1573 new_draw_info_format (NDI_UNIQUE, 0, op, "- %s", &found->name);
1574 }
1575 new_draw_info_format (NDI_UNIQUE, 0, op, "- %s", &ar->name);
1576 continue;
1577 }
1578
1579 found = ar;
1580 }
1581
1582 /* No match if more more than one archetype matches. */
1583 if (conflict_found)
1584 return NULL;
1585
1586 /* Return if exactly one archetype matches. */
1587 if (found != NULL)
1588 return arch_to_object (found);
1589
1590 /* No full match found: now check for partial matches. */
1591 spell_name_length = strlen (spell_name);
1592 conflict_found = 0;
1593 found = NULL;
1594 for (ar = first_archetype; ar != NULL; ar = ar->next)
1595 {
1596 if (ar->clone.type != SPELL)
1597 continue;
1598
1599 if (strncmp (ar->name, "spelldirect_", 12) == 0)
1600 continue;
1601
1602 if (strncmp (ar->clone.name, spell_name, spell_name_length) != 0)
1603 continue;
1604
1605 if (found != NULL)
1606 {
1607 if (!conflict_found)
1608 {
1609 conflict_found = 1;
1610 new_draw_info_format (NDI_UNIQUE, 0, op, "More than one spell matches %s:", spell_name);
1611 new_draw_info_format (NDI_UNIQUE, 0, op, "- %s", &found->clone.name);
1612 }
1613 new_draw_info_format (NDI_UNIQUE, 0, op, "- %s", &ar->clone.name);
1614 continue;
1615 }
1616
1617 found = ar;
1618 }
1619
1620 /* No match if more more than one archetype matches. */
1621 if (conflict_found)
1622 return NULL;
1623
1624 /* Return if exactly one archetype matches. */
1625 if (found != NULL)
1626 return arch_to_object (found);
1627
1628 /* No spell found: just print an error message. */
1629 new_draw_info_format (NDI_UNIQUE, 0, op, "The spell %s does not exist.", spell_name);
1630 return NULL;
1631 }
1632
1633 static int
1634 command_learn_spell_or_prayer (object *op, char *params, int special_prayer)
1635 {
1636 object *tmp;
1637
1638 if (op->contr == NULL || params == NULL)
1639 {
1640 new_draw_info (NDI_UNIQUE, 0, op, "Which spell do you want to learn?");
1641 return 0;
1642 }
1643
1644 tmp = get_spell_by_name (op, params);
1645 if (tmp == NULL)
1646 {
1647 return 0;
1648 }
1649
1650 if (check_spell_known (op, tmp->name))
1651 {
1652 new_draw_info_format (NDI_UNIQUE, 0, op, "You already know the spell %s.", &tmp->name);
1653 return 0;
1654 }
1655
1656 do_learn_spell (op, tmp, special_prayer);
1657 free_object (tmp);
1658 return 1;
1659 }
1660
1661 int
1662 command_learn_spell (object *op, char *params)
1663 {
1664 return command_learn_spell_or_prayer (op, params, 0);
1665 }
1666
1667 int
1668 command_learn_special_prayer (object *op, char *params)
1669 {
1670 return command_learn_spell_or_prayer (op, params, 1);
1671 }
1672
1673 int
1674 command_forget_spell (object *op, char *params)
1675 {
1676 object *spell;
1677
1678 if (op->contr == NULL || params == NULL)
1679 {
1680 new_draw_info (NDI_UNIQUE, 0, op, "Which spell do you want to forget?");
1681 return 0;
1682 }
1683
1684 spell = lookup_spell_by_name (op, params);
1685 if (spell == NULL)
1686 {
1687 new_draw_info_format (NDI_UNIQUE, 0, op, "You do not know the spell %s.", params);
1688 return 0;
1689 }
1690
1691 do_forget_spell (op, spell->name);
1692 return 1;
1693 }
1694
1695 /**
1696 * Lists all plugins currently loaded with their IDs and full names.
1697 */
1698 int
1699 command_listplugins (object *op, char *params)
1700 {
1701 plugins_display_list (op);
1702 return 1;
1703 }
1704
1705 /**
1706 * Loads the given plugin. The DM specifies the name of the library to load (no
1707 * pathname is needed). Do not ever attempt to load the same plugin more than
1708 * once at a time, or bad things could happen.
1709 */
1710 int
1711 command_loadplugin (object *op, char *params)
1712 {
1713 char buf[MAX_BUF];
1714
1715 if (params == NULL)
1716 {
1717 new_draw_info (NDI_UNIQUE, 0, op, "Load which plugin?");
1718 return 1;
1719 }
1720
1721 strcpy (buf, LIBDIR);
1722 strcat (buf, "/plugins/");
1723 strcat (buf, params);
1724 LOG (llevDebug, "Requested plugin file is %s\n", buf);
1725 if (plugins_init_plugin (buf) == 0)
1726 new_draw_info (NDI_UNIQUE, 0, op, "Plugin successfully loaded.");
1727 else
1728 new_draw_info (NDI_UNIQUE, 0, op, "Could not load plugin.");
1729 return 1;
1730 }
1731
1732 /**
1733 * Unloads the given plugin. The DM specified the ID of the library to unload.
1734 * Note that some things may behave strangely if the correct plugins are not
1735 * loaded.
1736 */
1737 int
1738 command_unloadplugin (object *op, char *params)
1739 {
1740 if (params == NULL)
1741 {
1742 new_draw_info (NDI_UNIQUE, 0, op, "Remove which plugin?");
1743 return 1;
1744 }
1745
1746 if (plugins_remove_plugin (params) == 0)
1747 new_draw_info (NDI_UNIQUE, 0, op, "Plugin successfully removed.");
1748 else
1749 new_draw_info (NDI_UNIQUE, 0, op, "Could not remove plugin.");
1750 return 1;
1751 }
1752
1753 /**
1754 * A players wants to become DM and hide.
1755 * Let's see if that's authorized.
1756 * Make sure to not tell anything to anyone.
1757 */
1758 int
1759 command_dmhide (object *op, char *params)
1760 {
1761 if (!do_wizard_dm (op, params, 1))
1762 return 0;
1763
1764 do_wizard_hide (op, 1);
1765
1766 return 1;
1767 }
1768
1769 void
1770 dm_stack_pop (player *pl)
1771 {
1772 if (!pl->stack_items || !pl->stack_position)
1773 {
1774 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Empty stack!");
1775 return;
1776 }
1777
1778 pl->stack_position--;
1779 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "Popped item from stack, %d left.", pl->stack_position);
1780 }
1781
1782 /**
1783 * Get current stack top item for player.
1784 * Returns NULL if no stacked item.
1785 * If stacked item disappeared (freed), remove it.
1786 *
1787 * Ryo, august 2004
1788 */
1789 object *
1790 dm_stack_peek (player *pl)
1791 {
1792 object *ob;
1793
1794 if (!pl->stack_position)
1795 {
1796 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Empty stack!");
1797 return NULL;
1798 }
1799
1800 ob = find_object (pl->stack_items[pl->stack_position - 1]);
1801 if (!ob)
1802 {
1803 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Stacked item was removed!");
1804 dm_stack_pop (pl);
1805 return NULL;
1806 }
1807
1808 return ob;
1809 }
1810
1811 /**
1812 * Push specified item on player stack.
1813 * Inform player of position.
1814 * Initializes variables if needed.
1815 */
1816 void
1817 dm_stack_push (player *pl, tag_t item)
1818 {
1819 if (!pl->stack_items)
1820 {
1821 pl->stack_items = (tag_t *) malloc (sizeof (tag_t) * STACK_SIZE);
1822 memset (pl->stack_items, 0, sizeof (tag_t) * STACK_SIZE);
1823 }
1824
1825 if (pl->stack_position == STACK_SIZE)
1826 {
1827 new_draw_info (NDI_UNIQUE, 0, pl->ob, "Item stack full!");
1828 return;
1829 }
1830
1831 pl->stack_items[pl->stack_position] = item;
1832 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "Item stacked as %d.", pl->stack_position);
1833 pl->stack_position++;
1834 }
1835
1836 /**
1837 * Checks 'params' for object code.
1838 *
1839 * Can be:
1840 * * empty => get current object stack top for player
1841 * * number => get item with that tag, stack it for future use
1842 * * $number => get specified stack item
1843 * * "me" => player himself
1844 *
1845 * At function exit, params points to first non-object char
1846 *
1847 * 'from', if not NULL, contains at exit:
1848 * * STACK_FROM_NONE => object not found
1849 * * STACK_FROM_TOP => top item stack, may be NULL if stack was empty
1850 * * STACK_FROM_STACK => item from somewhere in the stack
1851 * * STACK_FROM_NUMBER => item by number, pushed on stack
1852 *
1853 * Ryo, august 2004
1854 */
1855 object *
1856 get_dm_object (player *pl, char **params, int *from)
1857 {
1858 int item_tag, item_position;
1859 object *ob;
1860
1861 if (!pl)
1862 return NULL;
1863
1864 if (!params || !*params || **params == '\0')
1865 {
1866 if (from)
1867 *from = STACK_FROM_TOP;
1868 /* No parameter => get stack item */
1869 return dm_stack_peek (pl);
1870 }
1871
1872 /* Let's clean white spaces */
1873 while (**params == ' ')
1874 (*params)++;
1875
1876 /* Next case: number => item tag */
1877 if (sscanf (*params, "%d", &item_tag))
1878 {
1879 /* Move parameter to next item */
1880 while (isdigit (**params))
1881 (*params)++;
1882
1883 /* And skip blanks, too */
1884 while (**params == ' ')
1885 (*params)++;
1886
1887 /* Get item */
1888 ob = find_object (item_tag);
1889 if (!ob)
1890 {
1891 if (from)
1892 *from = STACK_FROM_NONE;
1893 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "No such item %d!", item_tag);
1894 return NULL;
1895 }
1896
1897 /* Got one, let's push it on stack */
1898 dm_stack_push (pl, item_tag);
1899 if (from)
1900 *from = STACK_FROM_NUMBER;
1901 return ob;
1902 }
1903
1904 /* Next case: $number => stack item */
1905 if (sscanf (*params, "$%d", &item_position))
1906 {
1907 /* Move parameter to next item */
1908 (*params)++;
1909
1910 while (isdigit (**params))
1911 (*params)++;
1912 while (**params == ' ')
1913 (*params)++;
1914
1915 if (item_position >= pl->stack_position)
1916 {
1917 if (from)
1918 *from = STACK_FROM_NONE;
1919 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "No such stack item %d!", item_position);
1920 return NULL;
1921 }
1922
1923 ob = find_object (pl->stack_items[item_position]);
1924 if (!ob)
1925 {
1926 if (from)
1927 *from = STACK_FROM_NONE;
1928 new_draw_info_format (NDI_UNIQUE, 0, pl->ob, "Stack item %d was removed.", item_position);
1929 return NULL;
1930 }
1931
1932 if (from)
1933 *from = item_position < pl->stack_position - 1 ? STACK_FROM_STACK : STACK_FROM_TOP;
1934 return ob;
1935 }
1936
1937 /* Next case: 'me' => return pl->ob */
1938 if (!strncmp (*params, "me", 2))
1939 {
1940 if (from)
1941 *from = STACK_FROM_NUMBER;
1942 dm_stack_push (pl, pl->ob->count);
1943
1944 /* Skip to next token */
1945 (*params) += 2;
1946 while (**params == ' ')
1947 (*params)++;
1948
1949 return pl->ob;
1950 }
1951
1952 /* Last case: get stack top */
1953 if (from)
1954 *from = STACK_FROM_TOP;
1955 return dm_stack_peek (pl);
1956 }
1957
1958 /**
1959 * Pop the stack top.
1960 */
1961 int
1962 command_stack_pop (object *op, char *params)
1963 {
1964 dm_stack_pop (op->contr);
1965 return 0;
1966 }
1967
1968 /**
1969 * Push specified item on stack.
1970 */
1971 int
1972 command_stack_push (object *op, char *params)
1973 {
1974 object *ob;
1975 int from;
1976
1977 ob = get_dm_object (op->contr, &params, &from);
1978
1979 if (ob && from != STACK_FROM_NUMBER)
1980 /* Object was from stack, need to push it again */
1981 dm_stack_push (op->contr, ob->count);
1982
1983 return 0;
1984 }
1985
1986 /**
1987 * Displays stack contents.
1988 */
1989 int
1990 command_stack_list (object *op, char *params)
1991 {
1992 int item;
1993 object *display;
1994 player *pl = op->contr;
1995
1996 new_draw_info (NDI_UNIQUE, 0, op, "Item stack contents:");
1997
1998 for (item = 0; item < pl->stack_position; item++)
1999 {
2000 display = find_object (pl->stack_items[item]);
2001 if (display)
2002 new_draw_info_format (NDI_UNIQUE, 0, op, " %d : %s [%d]", item, &display->name, display->count);
2003 else
2004 /* Item was freed */
2005 new_draw_info_format (NDI_UNIQUE, 0, op, " %d : (lost item: %d)", item, pl->stack_items[item]);
2006 }
2007
2008 return 0;
2009 }
2010
2011 /**
2012 * Empty DM item stack.
2013 */
2014 int
2015 command_stack_clear (object *op, char *params)
2016 {
2017 op->contr->stack_position = 0;
2018 new_draw_info (NDI_UNIQUE, 0, op, "Item stack cleared.");
2019 return 0;
2020 }
2021
2022 int
2023 command_insert_into (object *op, char *params)
2024 {
2025 object *left, *right, *inserted;
2026 int left_from, right_from;
2027
2028 left = get_dm_object (op->contr, &params, &left_from);
2029 if (!left)
2030 {
2031 new_draw_info (NDI_UNIQUE, 0, op, "Insert into what object?");
2032 return 0;
2033 }
2034
2035 if (left_from == STACK_FROM_NUMBER)
2036 /* Item was stacked, remove it else right will be the same... */
2037 dm_stack_pop (op->contr);
2038
2039 right = get_dm_object (op->contr, &params, &right_from);
2040
2041 if (!right)
2042 {
2043 new_draw_info (NDI_UNIQUE, 0, op, "Insert what item?");
2044 return 0;
2045 }
2046
2047 if (left_from == STACK_FROM_TOP && right_from == STACK_FROM_TOP)
2048 {
2049 /*
2050 * Special case: both items were taken from stack top.
2051 * Override the behaviour, taking left as item just below top, if exists.
2052 * See function description for why.
2053 * Besides, can't insert an item into itself.
2054 */
2055 if (op->contr->stack_position > 1)
2056 {
2057 left = find_object (op->contr->stack_items[op->contr->stack_position - 2]);
2058 if (left)
2059 new_draw_info (NDI_UNIQUE, 0, op, "(Note: item to insert into taken from undertop)");
2060 else
2061 /* Stupid case: item under top was freed, fallback to stack top */
2062 left = right;
2063 }
2064 }
2065
2066 if (left == right)
2067 {
2068 new_draw_info (NDI_UNIQUE, 0, op, "Can't insert an object into itself!");
2069 return 0;
2070 }
2071
2072 if (right->type == PLAYER)
2073 {
2074 new_draw_info (NDI_UNIQUE, 0, op, "Can't insert a player into something!");
2075 return 0;
2076 }
2077
2078 if (!QUERY_FLAG (right, FLAG_REMOVED))
2079 remove_ob (right);
2080 inserted = insert_ob_in_ob (right, left);
2081 if (left->type == PLAYER)
2082 if (inserted == right)
2083 esrv_send_item (left, right);
2084 else
2085 esrv_update_item (UPD_WEIGHT | UPD_NAME | UPD_NROF, left, inserted);
2086
2087 new_draw_info_format (NDI_UNIQUE, 0, op, "Inserted %s in %s", query_name (inserted), query_name (left));
2088
2089 return 0;
2090
2091 }