ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.C
Revision: 1.41
Committed: Wed Mar 14 04:12:29 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.40: +1 -1 lines
Log Message:
- rewrote more face handling code
- automatically send smooth faces, as the client will need them anyways
  and it makes little sense to wait for the client to axk for it. of course,
  gcfclient suffers from weird ordering problems again.
- UP_OBJ_FACE was often abused in situations where other things changed,
  updated lots of spaces, probably more to be done.
- update_smooth became so small that inlining it actually clarified
  the code. similar for update_space, which is not inlined for other reasons.
- faces were not initialised properly
- add versioncheck for face data
- rewrite invisibility handling a bit: god finger etc. now makes you blink,
  blinking routine has changed to be less annoying and more useful while
  still indicating invisibleness.

File Contents

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