ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.14
Committed: Sat Sep 16 22:24:13 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +2 -4 lines
Log Message:
mapstruct => maptile
removed many ytypedefs in favor of structure tags

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