ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_wiz.c
Revision: 1.3
Committed: Fri May 12 22:29:15 2006 UTC (18 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +17 -18 lines
Log Message:
rewrite the logic inside command_kick so hopefully players won't lose all their items on kick anymore (untested)

File Contents

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