ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.28
Committed: Sat Dec 30 10:16:11 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.27: +12 -96 lines
Log Message:
preliminary snapshot check-in, DO NOT USE IN PRODUCTION SYSTEMS
See the Changes file for details

File Contents

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