ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.9
Committed: Sun Sep 10 14:15:34 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.8: +29 -10 lines
Log Message:
*** empty log message ***

File Contents

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