ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.12
Committed: Thu Sep 14 22:34:03 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +1 -7 lines
Log Message:
indent

File Contents

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