ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.30
Committed: Sat Jan 6 14:42:30 2007 UTC (17 years, 5 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.29: +1 -0 lines
Log Message:
added some copyrights

File Contents

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