ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.49
Committed: Sun Jul 1 05:00:19 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.48: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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