Atrinik Server 2.5
commands/wiz.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 #undef SS_STATISTICS
00032 #include <shstr.h>
00033 
00039 static player *get_other_player_from_name(object *op, char *name)
00040 {
00041     player *pl;
00042 
00043     if (!name)
00044     {
00045         return NULL;
00046     }
00047 
00048     adjust_player_name(name);
00049 
00050     for (pl = first_player; pl; pl = pl->next)
00051     {
00052         if (!strncasecmp(pl->ob->name, name, MAX_NAME))
00053         {
00054             break;
00055         }
00056     }
00057 
00058     if (pl == NULL)
00059     {
00060         new_draw_info(0, COLOR_WHITE, op, "No such player.");
00061         return NULL;
00062     }
00063 
00064     if (pl->ob == op)
00065     {
00066         new_draw_info(0, COLOR_WHITE, op, "You can't do that to yourself.");
00067         return NULL;
00068     }
00069 
00070     if (pl->state != ST_PLAYING)
00071     {
00072         new_draw_info(0, COLOR_WHITE, op, "That player is in no state for that right now.");
00073         return NULL;
00074     }
00075 
00076     return pl;
00077 }
00078 
00085 static object *find_object_rec(object *ob, const char *name, tag_t count)
00086 {
00087     object *tmp;
00088 
00089     for (tmp = ob; tmp; tmp = tmp->below)
00090     {
00091         if ((name && tmp->name == name) || (count && tmp->count == count))
00092         {
00093             return tmp;
00094         }
00095         else if (tmp->inv)
00096         {
00097             object *tmp2 = find_object_rec(tmp->inv, name, count);
00098 
00099             if (tmp2)
00100             {
00101                 return tmp2;
00102             }
00103         }
00104     }
00105 
00106     return NULL;
00107 }
00108 
00115 static object *find_object_both(object *op, char *params)
00116 {
00117     tag_t count = 0;
00118     const char *name = NULL;
00119     player *pl;
00120     object *tmp, *tmp2;
00121     int x, y;
00122 
00123     if (!params)
00124     {
00125         return NULL;
00126     }
00127 
00128     if (params[0] == '#')
00129     {
00130         count = atol(params + 1);
00131     }
00132     else
00133     {
00134         name = find_string(params);
00135     }
00136 
00137     /* If find_string() can't find the string, then it's impossible that
00138      * op->name will match. */
00139     if (!name && !count)
00140     {
00141         return NULL;
00142     }
00143 
00144     /* First search through the players */
00145     for (pl = first_player; pl; pl = pl->next)
00146     {
00147         if ((name && pl->ob->name == name) || (count && pl->ob->count == count))
00148         {
00149             return pl->ob;
00150         }
00151     }
00152 
00153     /* Otherwise search below the DM */
00154     for (tmp = get_map_ob(op->map, op->x, op->y); tmp; tmp = tmp->above)
00155     {
00156         tmp2 = find_object_rec(tmp, name, count);
00157 
00158         if (tmp2)
00159         {
00160             return tmp2;
00161         }
00162     }
00163 
00164     /* No match? Search through the entire map... */
00165     for (x = 0; x < MAP_WIDTH(op->map); x++)
00166     {
00167         for (y = 0; y < MAP_HEIGHT(op->map); y++)
00168         {
00169             for (tmp = get_map_ob(op->map, x, y); tmp; tmp = tmp->above)
00170             {
00171                 tmp2 = find_object_rec(tmp, name, count);
00172 
00173                 if (tmp2)
00174                 {
00175                     return tmp2;
00176                 }
00177             }
00178         }
00179     }
00180 
00181     return NULL;
00182 }
00183 
00189 static int dm_map_remove_players(mapstruct *m)
00190 {
00191     int count = 0;
00192     player *pl;
00193 
00194     for (pl = first_player; pl; pl = pl->next)
00195     {
00196         if (pl->ob->map == m)
00197         {
00198             count++;
00199             remove_ob(pl->ob);
00200             pl->dm_removed_from_map = 1;
00201             pl->ob->map = NULL;
00202         }
00203     }
00204 
00205     return count;
00206 }
00207 
00212 static void dm_map_reinsert_players(mapstruct *m, object *op)
00213 {
00214     player *pl;
00215 
00216     for (pl = first_player; pl; pl = pl->next)
00217     {
00218         if (pl->dm_removed_from_map)
00219         {
00220             pl->dm_removed_from_map = 0;
00221             insert_ob_in_map(pl->ob, m, NULL, INS_NO_MERGE);
00222             /* So that we don't access invalid values of old player's last_update map
00223              * pointer when sending map to the client. */
00224             pl->last_update = NULL;
00225 
00226             if (pl->ob != op)
00227             {
00228                 if (QUERY_FLAG(pl->ob, FLAG_WIZ))
00229                 {
00230                     new_draw_info_format(0, COLOR_WHITE, pl->ob, "Map reset by %s.", op->name);
00231                 }
00232                 /* Write a nice little confusing message to the players */
00233                 else
00234                 {
00235                     new_draw_info(0, COLOR_WHITE, pl->ob, "Your surroundings seem different but still familiar. Haven't you been here before?");
00236                 }
00237             }
00238         }
00239     }
00240 }
00241 
00248 int command_setgod(object *op, char *params)
00249 {
00250     object *ob, *god;
00251     char *str;
00252 
00253     if (!params || !(str = strchr(params, ' ')))
00254     {
00255         new_draw_info(0, COLOR_WHITE, op, "Usage: /setgod object god");
00256         return 0;
00257     }
00258 
00259     /* Kill the space, and set string to the next param */
00260     *str++ = '\0';
00261 
00262     if (!(ob = find_object_both(op, params)))
00263     {
00264         new_draw_info_format(0, COLOR_WHITE, op, "Set whose god - can not find object %s?", params);
00265         return 1;
00266     }
00267 
00268     /* Perhaps this is overly restrictive? Should we perhaps be able to
00269      * re-bless altars and the like? */
00270     if (ob->type != PLAYER)
00271     {
00272         new_draw_info_format(0, COLOR_WHITE, op, "%s is not a player - can not change its god", ob->name);
00273         return 1;
00274     }
00275 
00276     change_skill(ob, SK_PRAYING);
00277 
00278     if (!ob->chosen_skill || ob->chosen_skill->stats.sp != SK_PRAYING)
00279     {
00280         new_draw_info_format(0, COLOR_WHITE, op, "%s doesn't have praying skill.", ob->name);
00281         return 1;
00282     }
00283 
00284     god = find_god(str);
00285 
00286     if (god == NULL)
00287     {
00288         new_draw_info_format(0, COLOR_WHITE, op, "No such god %s.", str);
00289         return 1;
00290     }
00291 
00292     become_follower(ob, god);
00293 
00294     return 1;
00295 }
00296 
00304 int command_kick(object *ob, char *params)
00305 {
00306     player *pl, *pl_next;
00307 
00308     if (ob && params == NULL)
00309     {
00310         new_draw_info_format(0, COLOR_WHITE, ob, "Use: /kick <name>");
00311         return 1;
00312     }
00313 
00314     if (ob && ob->name && !strncasecmp(ob->name, params, MAX_NAME))
00315     {
00316         new_draw_info_format(0, COLOR_WHITE, ob, "You can't /kick yourself!");
00317         return 1;
00318     }
00319 
00320     for (pl = first_player; pl; pl = pl_next)
00321     {
00322         pl_next = pl->next;
00323 
00324         /* Ignore players not playing. */
00325         if (pl->state != ST_PLAYING)
00326         {
00327             continue;
00328         }
00329 
00330         if (!ob || (pl->ob != ob && pl->ob->name && !strncasecmp(pl->ob->name, params, MAX_NAME)))
00331         {
00332             object *op = pl->ob;
00333 
00334             remove_ob(op);
00335             check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
00336 
00337             if (params)
00338             {
00339                 new_draw_info_format(NDI_ALL, COLOR_WHITE, ob, "%s was kicked out of the game.", op->name);
00340             }
00341 
00342             LOG(llevChat, "Kick: %s was kicked out of the game by %s.\n", op->name, ob ? ob->name : "a shutdown");
00343 
00344             CONTR(op)->socket.status = Ns_Dead;
00345             remove_ns_dead_player(CONTR(op));
00346         }
00347     }
00348 
00349     return 1;
00350 }
00351 
00357 int command_shutdown_now(object *op, char *params)
00358 {
00359     (void) params;
00360 
00361     LOG(llevSystem, "Server shutdown started by %s\n", op->name);
00362     command_kick(NULL, NULL);
00363     cleanup();
00364     exit(0);
00365 
00366     /* Not reached */
00367     return 1;
00368 }
00369 
00375 int command_goto(object *op, char *params)
00376 {
00377     char name[MAX_BUF] = {"\0"};
00378     int x = -1, y = -1;
00379     object *dummy;
00380 
00381     if (!op)
00382     {
00383         return 0;
00384     }
00385 
00386     if (params == NULL)
00387     {
00388         new_draw_info(0, COLOR_WHITE, op, "Go to what map?\nUsage: /goto <map> x y");
00389         return 1;
00390     }
00391 
00392     sscanf(params, "%s %d %d", name, &x, &y);
00393 
00394     dummy = get_object();
00395     dummy->map = op->map;
00396     dummy->stats.hp = x;
00397     dummy->stats.sp = y;
00398     FREE_AND_COPY_HASH(EXIT_PATH(dummy), name);
00399     FREE_AND_COPY_HASH(dummy->name, name);
00400 
00401     enter_exit(op, dummy);
00402 
00403     new_draw_info_format(0, COLOR_WHITE, op, "Difficulty: %d.", op->map->difficulty);
00404 
00405     return 1;
00406 }
00407 
00413 int command_freeze(object *op, char *params)
00414 {
00415     int ticks;
00416     player *pl;
00417 
00418     if (!params)
00419     {
00420         new_draw_info(0, COLOR_WHITE, op, "Usage: /freeze [ticks] <player>");
00421         return 1;
00422     }
00423 
00424     ticks = atoi(params);
00425 
00426     if (ticks)
00427     {
00428         while ((isdigit(*params) || isspace(*params)) && *params != 0)
00429         {
00430             params++;
00431         }
00432 
00433         if (*params == 0)
00434         {
00435             new_draw_info(0, COLOR_WHITE, op, "Usage: /freeze [ticks] <player>");
00436             return 1;
00437         }
00438     }
00439     else
00440     {
00441         ticks = 100;
00442     }
00443 
00444     pl = get_other_player_from_name(op, params);
00445 
00446     if (!pl)
00447     {
00448         return 1;
00449     }
00450 
00451     new_draw_info(0, COLOR_RED, pl->ob, "You have been frozen by the DM!");
00452 
00453     new_draw_info_format(0, COLOR_WHITE, op, "You freeze %s for %d ticks.", pl->ob->name, ticks);
00454 
00455     pl->ob->speed_left = -(pl->ob->speed * ticks);
00456     return 1;
00457 }
00458 
00464 int command_summon(object *op, char *params)
00465 {
00466     int i;
00467     player *pl;
00468 
00469     if (!op)
00470     {
00471         return 0;
00472     }
00473 
00474     if (params == NULL)
00475     {
00476         new_draw_info(0, COLOR_WHITE, op, "Usage: /summon <player>.");
00477         return 1;
00478     }
00479 
00480     pl = get_other_player_from_name(op, params);
00481 
00482     if (!pl)
00483     {
00484         return 1;
00485     }
00486 
00487     i = find_free_spot(op->arch, op, op->map, op->x, op->y, 1, SIZEOFFREE1 + 1);
00488 
00489     if (i == -1 || op->x + freearr_x[i] < 0 || op->y + freearr_y[i] < 0 || op->x + freearr_x[i] >= MAP_WIDTH(op->map) || op->y + freearr_y[i] >= MAP_HEIGHT(op->map))
00490     {
00491         new_draw_info(0, COLOR_WHITE, op, "Can not find a free spot to place summoned player.");
00492         return 1;
00493     }
00494 
00495     remove_ob(pl->ob);
00496     pl->ob->x = op->x + freearr_x[i];
00497     pl->ob->y = op->y + freearr_y[i];
00498     insert_ob_in_map(pl->ob, op->map, NULL, INS_NO_MERGE);
00499     new_draw_info(0, COLOR_WHITE, pl->ob, "You are summoned.");
00500     new_draw_info_format(0, COLOR_WHITE, op, "You summon %s.", pl->ob->name);
00501     return 1;
00502 }
00503 
00509 int command_teleport(object *op, char *params)
00510 {
00511     int i;
00512     player *pl;
00513 
00514     if (!op)
00515     {
00516         return 0;
00517     }
00518 
00519     if (params == NULL)
00520     {
00521         new_draw_info(0, COLOR_WHITE, op, "Usage: /teleport <player>.");
00522         return 1;
00523     }
00524 
00525     pl = get_other_player_from_name(op, params);
00526 
00527     if (!pl)
00528     {
00529         return 1;
00530     }
00531 
00532     i = find_free_spot(pl->ob->arch, pl->ob, pl->ob->map, pl->ob->x, pl->ob->y, 1, SIZEOFFREE1 + 1);
00533 
00534     if (i == -1 || pl->ob->x + freearr_x[i] < 0 || pl->ob->y + freearr_y[i] < 0 || pl->ob->x + freearr_x[i] >= MAP_WIDTH(pl->ob->map) || pl->ob->y + freearr_y[i] >= MAP_HEIGHT(pl->ob->map))
00535     {
00536         new_draw_info(0, COLOR_WHITE, op, "Can not find a free spot to teleport to.");
00537         return 1;
00538     }
00539 
00540     remove_ob(op);
00541     op->x = pl->ob->x + freearr_x[i];
00542     op->y = pl->ob->y + freearr_y[i];
00543     insert_ob_in_map(op, pl->ob->map, NULL, INS_NO_MERGE);
00544 
00545     if (!CONTR(op)->dm_stealth)
00546     {
00547         new_draw_info(0, COLOR_WHITE, pl->ob, "You see a portal open.");
00548     }
00549 
00550     new_draw_info_format(0, COLOR_WHITE, op, "You teleport to %s.", pl->ob->name);
00551 
00552     return 1;
00553 }
00554 
00560 int command_create(object *op, char *params)
00561 {
00562     object *tmp = NULL;
00563     int magic, set_magic = 0, set_nrof = 0, gotquote, gotspace;
00564     sint32 i, nrof;
00565     char *cp, *bp, *bp2, *bp3, *bp4, *endline;
00566     archetype *at;
00567     artifact *art = NULL;
00568 
00569     if (params == NULL)
00570     {
00571         new_draw_info(0, COLOR_WHITE, op, "Usage: /create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]");
00572         return 1;
00573     }
00574 
00575     bp = params;
00576 
00577     /* We need to know where the line ends */
00578     endline = bp + strlen(bp);
00579 
00580     if (sscanf(bp, "%d ", &nrof))
00581     {
00582         if (!(bp = strchr(params, ' ')))
00583         {
00584             new_draw_info(0, COLOR_WHITE, op, "Usage: /create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]");
00585             return 1;
00586         }
00587 
00588         nrof = MAX(1, MIN(nrof, 1000));
00589 
00590         bp++;
00591         set_nrof = 1;
00592     }
00593 
00594     if (sscanf(bp, "%d ", &magic))
00595     {
00596         if (!(bp = strchr(bp, ' ')))
00597         {
00598             new_draw_info(0, COLOR_WHITE, op, "Usage: /create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]");
00599             return 1;
00600         }
00601 
00602         bp++;
00603         set_magic = 1;
00604     }
00605 
00606     if ((cp = strstr(bp, " of ")))
00607     {
00608         *cp = '\0';
00609         cp += 4;
00610     }
00611 
00612     for (bp2 = bp; *bp2; bp2++)
00613     {
00614         if (*bp2 == ' ')
00615         {
00616             *bp2 = '\0';
00617             bp2++;
00618             break;
00619         }
00620     }
00621 
00622     /* First step: browse the archetypes for the name. */
00623     if (!(at = find_archetype(bp)))
00624     {
00625         new_draw_info(0, COLOR_WHITE, op, "No such archetype or artifact name.");
00626         return 1;
00627     }
00628 
00629     if (cp)
00630     {
00631         if (find_artifactlist(at->clone.type) == NULL)
00632         {
00633             new_draw_info_format(0, COLOR_WHITE, op, "No artifact list for type %d\n", at->clone.type);
00634         }
00635         else
00636         {
00637             art = find_artifactlist(at->clone.type)->items;
00638 
00639             do
00640             {
00641                 if (!strcmp(art->name, cp))
00642                 {
00643                     break;
00644                 }
00645 
00646                 art = art->next;
00647             } while (art);
00648 
00649             if (!art)
00650             {
00651                 new_draw_info_format(0, COLOR_WHITE, op, "No such artifact ([%d] of %s)", at->clone.type, cp);
00652             }
00653         }
00654     }
00655 
00656     /* Rather than have two different blocks with a lot of similar code,
00657      * just create one object, do all the processing, and then determine
00658      * if that one object should be inserted or if we need to make copies. */
00659     tmp = arch_to_object(at);
00660 
00661     if (set_magic)
00662     {
00663         set_abs_magic(tmp, magic);
00664     }
00665 
00666     if (art)
00667     {
00668         give_artifact_abilities(tmp, art);
00669     }
00670 
00671     if (need_identify(tmp))
00672     {
00673         SET_FLAG(tmp, FLAG_IDENTIFIED);
00674     }
00675 
00676     /* This entire block here tries to find variable pairings,
00677      * eg, 'hp 4' or the like. The mess here is that values
00678      * can be quoted (eg "my cool sword"); So the basic logic
00679      * is we want to find two spaces, but if we got a quote,
00680      * any spaces there don't count. */
00681     while (*bp2 && bp2 <= endline)
00682     {
00683         bp4 = NULL;
00684         gotspace = 0;
00685         gotquote = 0;
00686 
00687         /* Find the first quote. */
00688         for (bp3 = bp2; *bp3 && gotspace < 2; bp3++)
00689         {
00690             /* Found a quote. */
00691             if (*bp3 == '"')
00692             {
00693                 *bp3 = ' ';
00694                 gotquote++;
00695                 bp3++;
00696 
00697                 for (bp4 = bp3; *bp4; bp4++)
00698                 {
00699                     if (*bp4 == '"')
00700                     {
00701                         *bp4 = '\0';
00702                         break;
00703                     }
00704                 }
00705             }
00706             else if (*bp3 == ' ')
00707             {
00708                 gotspace++;
00709             }
00710         }
00711 
00712         if (!gotquote)
00713         {
00714             /* Then find the second space. */
00715             for (bp3 = bp2; *bp3; bp3++)
00716             {
00717                 if (*bp3 == ' ')
00718                 {
00719                     bp3++;
00720 
00721                     for (bp4 = bp3; *bp4; bp4++)
00722                     {
00723                         if (*bp4 == ' ')
00724                         {
00725                             *bp4 = '\0';
00726                             break;
00727                         }
00728                     }
00729 
00730                     break;
00731                 }
00732             }
00733         }
00734 
00735         if (!bp4)
00736         {
00737             /* Unfortunately, we've clobbered lots of values, so printing
00738              * out what we have probably isn't useful. Break out, because
00739              * trying to recover is probably won't get anything useful
00740              * anyways, and we'd be confused about end of line pointers
00741              * anyways. */
00742             new_draw_info_format(0, COLOR_WHITE, op, "Malformed create line: %s", bp2);
00743             break;
00744         }
00745 
00746         /* bp2 should still point to the start of this line,
00747          * with bp3 pointing to the end. */
00748         if (set_variable(tmp, bp2) == -1)
00749         {
00750             new_draw_info_format(0, COLOR_WHITE, op, "Unknown variable %s", bp2);
00751         }
00752         else
00753         {
00754             new_draw_info_format(0, COLOR_WHITE, op, "(%s)->%s", tmp->name, bp2);
00755         }
00756 
00757         if (gotquote)
00758         {
00759             bp2 = bp4 + 2;
00760         }
00761         else
00762         {
00763             bp2 = bp4 + 1;
00764         }
00765     }
00766 
00767     if (at->clone.nrof)
00768     {
00769         if (set_nrof)
00770         {
00771             tmp->nrof = nrof;
00772         }
00773 
00774         if (tmp->randomitems)
00775         {
00776             create_treasure(tmp->randomitems, tmp, GT_APPLY, tmp->type == MONSTER ? tmp->level : get_environment_level(tmp), T_STYLE_UNSET, ART_CHANCE_UNSET, 0, NULL);
00777         }
00778 
00779         /* If the created object is alive or is multi arch, insert it on
00780          * the map. */
00781         if (IS_LIVE(tmp) || tmp->more)
00782         {
00783             if (tmp->type == MONSTER)
00784             {
00785                 fix_monster(tmp);
00786             }
00787 
00788             insert_ob_in_map(tmp, op->map, op, INS_NO_MERGE | INS_NO_WALK_ON);
00789         }
00790         /* Into the DM's inventory otherwise. */
00791         else
00792         {
00793             tmp = insert_ob_in_ob(tmp, op);
00794             esrv_send_item(op, tmp);
00795         }
00796 
00797         return 1;
00798     }
00799 
00800     for (i = 0; i < (set_nrof ? nrof : 1); i++)
00801     {
00802         archetype *atmp;
00803         object *prev = NULL, *head = NULL, *ob_dup;
00804 
00805         for (atmp = at; atmp; atmp = atmp->more)
00806         {
00807             ob_dup = arch_to_object(atmp);
00808 
00809             /* The head is what contains all the important bits,
00810              * so just copying it over should be fine. */
00811             if (head == NULL)
00812             {
00813                 head = ob_dup;
00814                 copy_object(tmp, ob_dup, 0);
00815             }
00816 
00817             ob_dup->x = op->x + ob_dup->arch->clone.x;
00818             ob_dup->y = op->y + ob_dup->arch->clone.y;
00819             ob_dup->map = op->map;
00820 
00821             if (head != ob_dup)
00822             {
00823                 ob_dup->head = head;
00824                 prev->more = ob_dup;
00825             }
00826 
00827             prev = ob_dup;
00828         }
00829 
00830         if (head->randomitems)
00831         {
00832             create_treasure(head->randomitems, head, GT_APPLY, head->type == MONSTER ? head->level : get_environment_level(head), T_STYLE_UNSET, ART_CHANCE_UNSET, 0, NULL);
00833         }
00834 
00835         /* If the created object is alive or is multi arch, insert it on
00836          * the map. */
00837         if (IS_LIVE(head) || head->more)
00838         {
00839             if (head->type == MONSTER)
00840             {
00841                 fix_monster(head);
00842             }
00843 
00844             head = insert_ob_in_map(head, op->map, op, INS_NO_MERGE | INS_NO_WALK_ON);
00845         }
00846         /* Into the DM's inventory otherwise. */
00847         else
00848         {
00849             head = insert_ob_in_ob(head, op);
00850             esrv_send_item(op, head);
00851         }
00852 
00853         if (!set_nrof || nrof == 1)
00854         {
00855             new_draw_info_format(0, COLOR_WHITE, op, "Created %s (#%d)", query_name(head, NULL), head->count);
00856         }
00857     }
00858 
00859     return 1;
00860 }
00861 
00868 int command_inventory(object *op, char *params)
00869 {
00870     object *ob = NULL, *tmp;
00871     char *cp;
00872 
00873     if (!params)
00874     {
00875         new_draw_info(0, COLOR_WHITE, op, "Inventory of what object?");
00876         return 0;
00877     }
00878 
00879     params = strtok(params, "$");
00880     cp = strtok(NULL, "$");
00881 
00882     if (!strncmp(params, "me", 2))
00883     {
00884         ob = op;
00885     }
00886     else
00887     {
00888         ob = find_object_both(op, params);
00889 
00890         if (!ob)
00891         {
00892             new_draw_info(0, COLOR_WHITE, op, "No such object.");
00893             return 0;
00894         }
00895     }
00896 
00897     new_draw_info_format(0, COLOR_WHITE, op, "\nInventory of '%s':\n", query_name(ob, op));
00898 
00899     for (tmp = ob->inv; tmp; tmp = tmp->below)
00900     {
00901         if (cp && !item_matched_string(op, tmp, cp))
00902         {
00903             continue;
00904         }
00905 
00906         new_draw_info_format(0, COLOR_WHITE, op, "#<green>%d</green>: %s", tmp->count, query_name(tmp, op));
00907     }
00908 
00909     return 1;
00910 }
00911 
00917 int command_dump(object *op, char *params)
00918 {
00919     object *tmp;
00920     StringBuffer *sb;
00921     char *diff;
00922 
00923     if (params != NULL && !strcmp(params, "me"))
00924     {
00925         tmp = op;
00926     }
00927     else if (params == NULL || !(tmp = find_object_both(op, params)))
00928     {
00929         new_draw_info(0, COLOR_WHITE, op, "Dump what object?");
00930         return 1;
00931     }
00932 
00933     sb = stringbuffer_new();
00934     stringbuffer_append_printf(sb, "count %d\n", tmp->count);
00935     dump_object(tmp, sb);
00936     diff = stringbuffer_finish(sb);
00937     new_draw_info(0, COLOR_WHITE, op, diff);
00938     free(diff);
00939     return 1;
00940 }
00941 
00947 int command_patch(object *op, char *params)
00948 {
00949     char *arg, *arg2;
00950     object *tmp = NULL;
00951 
00952     if (params != NULL)
00953     {
00954         if (!strncmp(params, "me", 2))
00955         {
00956             tmp = op;
00957         }
00958         else
00959         {
00960             char name[MAX_BUF];
00961 
00962             if (sscanf(params, "%s", name) == 1)
00963             {
00964                 tmp = find_object_both(op, name);
00965             }
00966         }
00967     }
00968 
00969     if (tmp == NULL)
00970     {
00971         new_draw_info(0, COLOR_WHITE, op, "Patch what object?");
00972         return 1;
00973     }
00974 
00975     arg = strchr(params, ' ');
00976 
00977     if (arg == NULL)
00978     {
00979         new_draw_info(0, COLOR_WHITE, op, "Patch what values?");
00980         return 1;
00981     }
00982 
00983     if ((arg2 = strchr(++arg, ' ')))
00984     {
00985         arg2++;
00986     }
00987 
00988     if (!strncmp(arg, "msg", 3))
00989     {
00990         char buf[HUGE_BUF / 2];
00991 
00992         arg += 4;
00993 
00994         if (!arg || *arg == '\0')
00995         {
00996             FREE_AND_CLEAR_HASH(tmp->msg);
00997             new_draw_info_format(0, COLOR_WHITE, op, "(%s#%d)->msg=", tmp->name, tmp->count);
00998             return 1;
00999         }
01000 
01001         buf[0] = '\0';
01002 
01003         if (tmp->msg)
01004         {
01005             strncpy(buf, tmp->msg, sizeof(buf) - 1);
01006         }
01007 
01008         convert_newline(arg);
01009 
01010         if (buf_overflow(buf, arg, sizeof(buf) - 1))
01011         {
01012             new_draw_info(0, COLOR_RED, op, "Message string would overflow.");
01013             return 1;
01014         }
01015 
01016         strncat(buf, arg, sizeof(buf) - strlen(buf) - 1);
01017         FREE_AND_COPY_HASH(tmp->msg, buf);
01018         new_draw_info_format(0, COLOR_WHITE, op, "(%s#%d)->msg=%s", tmp->name, tmp->count, buf);
01019     }
01020     else if (set_variable(tmp, arg) == -1)
01021     {
01022         new_draw_info_format(0, COLOR_WHITE, op, "Unknown variable %s", arg);
01023     }
01024     else
01025     {
01026         new_draw_info_format(0, COLOR_WHITE, op, "(%s#%d)->%s=%s", tmp->name, tmp->count, arg, arg2);
01027     }
01028 
01029     return 1;
01030 }
01031 
01037 int command_remove(object *op, char *params)
01038 {
01039     object *tmp;
01040 
01041     if (params == NULL || !(tmp = find_object_both(op, params)))
01042     {
01043         new_draw_info(0, COLOR_WHITE, op, "Remove what object?");
01044         return 1;
01045     }
01046 
01047     if (tmp->type == PLAYER)
01048     {
01049         new_draw_info(0, COLOR_WHITE, op, "Cannot remove a player!");
01050         return 1;
01051     }
01052 
01053     if (QUERY_FLAG(tmp, FLAG_REMOVED))
01054     {
01055         new_draw_info_format(0, COLOR_WHITE, op, "%s is already removed!", query_name(tmp, NULL));
01056         return 1;
01057     }
01058 
01059     /* Ensure we have head. */
01060     if (tmp->head)
01061     {
01062         tmp = tmp->head;
01063     }
01064 
01065     if (tmp->speed != 0)
01066     {
01067         tmp->speed = 0;
01068         update_ob_speed(tmp);
01069     }
01070 
01071     remove_ob(tmp);
01072     check_walk_off(tmp, NULL, MOVE_APPLY_VANISHED);
01073     return 1;
01074 }
01075 
01081 int command_addexp(object *op, char *params)
01082 {
01083     char buf[MAX_BUF];
01084     int snr;
01085     sint64 exp;
01086     object *exp_skill, *exp_ob;
01087     player *pl;
01088 
01089     if (params == NULL || sscanf(params, "%s %d %"FMT64, buf, &snr, &exp) != 3)
01090     {
01091         int i;
01092 
01093         new_draw_info(0, COLOR_WHITE, op, "Usage: /addexp <who> <skill nr> <exp>\nSkills/Nr: ");
01094 
01095         for (i = 0; i < NROFSKILLS; i++)
01096         {
01097             new_draw_info_format(0, COLOR_WHITE, op, "%d: %s", i, skills[i].name);
01098         }
01099 
01100         return 1;
01101     }
01102 
01103     for (pl = first_player; pl != NULL; pl = pl->next)
01104     {
01105         if (!strncasecmp(pl->ob->name, buf, MAX_NAME))
01106         {
01107             break;
01108         }
01109     }
01110 
01111     if (pl == NULL)
01112     {
01113         new_draw_info(0, COLOR_WHITE, op, "No such player.");
01114         return 1;
01115     }
01116 
01117     /* Safety check */
01118     if (snr < 0 || snr >= NROFSKILLS)
01119     {
01120         new_draw_info(0, COLOR_WHITE, op, "No such skill.");
01121         return 1;
01122     }
01123 
01124     exp_skill = pl->skill_ptr[snr];
01125 
01126     /* Our player doesn't have this skill? */
01127     if (!exp_skill)
01128     {
01129         new_draw_info_format(0, COLOR_WHITE, op, "Player %s does not know the skill '%s'.", pl->ob->name, skills[snr].name);
01130         return 0;
01131     }
01132 
01133     /* If we are full in this skill, there is nothing to do */
01134     if (exp_skill->level >= MAXLEVEL && exp > 0)
01135     {
01136         return 0;
01137     }
01138 
01139     /* We will sure change skill exp, mark for update */
01140     pl->update_skills = 1;
01141     exp_ob = exp_skill->exp_obj;
01142 
01143     if (!exp_ob)
01144     {
01145         LOG(llevBug, "add_exp() skill:%s - no exp_ob found!\n", query_name(exp_skill, NULL));
01146         return 0;
01147     }
01148 
01149     /* First we see what we can add to our skill */
01150     exp = adjust_exp(pl->ob, exp_skill, exp);
01151 
01152     /* adjust_exp has adjust the skill and all exp_obj and player exp */
01153     /* now lets check for level up in all categories */
01154     player_lvl_adj(pl->ob, exp_skill);
01155     player_lvl_adj(pl->ob, exp_ob);
01156     player_lvl_adj(pl->ob, NULL);
01157 
01158     return 1;
01159 }
01160 
01166 int command_speed(object *op, char *params)
01167 {
01168     int i;
01169 
01170     if (params == NULL || !sscanf(params, "%d", &i))
01171     {
01172         new_draw_info_format(0, COLOR_WHITE, op, "Current speed is %ld.", max_time);
01173         return 1;
01174     }
01175 
01176     set_max_time(i);
01177     reset_sleep();
01178     new_draw_info(0, COLOR_WHITE, op, "The speed has changed.");
01179     return 1;
01180 }
01181 
01187 int command_stats(object *op, char *params)
01188 {
01189     player *pl;
01190 
01191     if (params == NULL)
01192     {
01193         new_draw_info(0, COLOR_WHITE, op, "Who?");
01194         return 1;
01195     }
01196 
01197     for (pl = first_player; pl != NULL; pl = pl->next)
01198     {
01199         if (!strcmp(pl->ob->name, params))
01200         {
01201             new_draw_info_format(0, COLOR_WHITE, op, "Str : %-2d      H.P.   : %-4d  MAX : %d", pl->ob->stats.Str, pl->ob->stats.hp, pl->ob->stats.maxhp);
01202             new_draw_info_format(0, COLOR_WHITE, op, "Dex : %-2d      S.P.   : %-4d  MAX : %d", pl->ob->stats.Dex, pl->ob->stats.sp, pl->ob->stats.maxsp);
01203             new_draw_info_format(0, COLOR_WHITE, op, "Con : %-2d      AC     : %-4d  WC  : %d", pl->ob->stats.Con, pl->ob->stats.ac, pl->ob->stats.wc);
01204             new_draw_info_format(0, COLOR_WHITE, op, "Wis : %-2d      EXP    : %"FMT64, pl->ob->stats.Wis, pl->ob->stats.exp);
01205             new_draw_info_format(0, COLOR_WHITE, op, "Cha : %-2d      Food   : %d", pl->ob->stats.Cha, pl->ob->stats.food);
01206             new_draw_info_format(0, COLOR_WHITE, op, "Int : %-2d      Damage : %d", pl->ob->stats.Int, pl->ob->stats.dam);
01207             new_draw_info_format(0, COLOR_WHITE, op, "Pow : %-2d      Grace  : %d", pl->ob->stats.Pow, pl->ob->stats.grace);
01208             return 1;
01209         }
01210     }
01211 
01212     if (pl == NULL)
01213     {
01214         new_draw_info(0, COLOR_WHITE, op, "No such player.");
01215     }
01216 
01217     return 1;
01218 }
01219 
01226 int command_resetmap(object *op, char *params)
01227 {
01228     mapstruct *m;
01229     shstr *path;
01230     int flags;
01231 
01232     if (params == NULL)
01233     {
01234         m = has_been_loaded_sh(op->map->path);
01235     }
01236     else
01237     {
01238         shstr *mapfile_sh = add_string(params);
01239 
01240         m = has_been_loaded_sh(mapfile_sh);
01241         free_string_shared(mapfile_sh);
01242     }
01243 
01244     if (m == NULL)
01245     {
01246         new_draw_info(0, COLOR_WHITE, op, "No such map.");
01247         return 1;
01248     }
01249 
01250     if (MAP_UNIQUE(m) && MAP_NOSAVE(m))
01251     {
01252         new_draw_info(0, COLOR_WHITE, op, "Cannot reset unique no-save map.");
01253         return 1;
01254     }
01255 
01256     if (!strncmp(m->path, "/random/", 8))
01257     {
01258         new_draw_info(0, COLOR_WHITE, op, "You cannot reset a random map.");
01259         return 1;
01260     }
01261 
01262     if (m->in_memory != MAP_IN_MEMORY)
01263     {
01264         LOG(llevBug, "Tried to swap out map which was not in memory.\n");
01265         return 0;
01266     }
01267 
01268     new_draw_info_format(0, COLOR_WHITE, op, "Start resetting map %s.", m->path);
01269     new_draw_info_format(0, COLOR_WHITE, op, "Removed %d players from map. Reset map.", dm_map_remove_players(m));
01270     m->reset_time = seconds();
01271     m->map_flags |= MAP_FLAG_FIXED_RTIME;
01272     /* Store the path, so we can load it after swapping is done. */
01273     path = add_refcount(m->path);
01274     flags = MAP_NAME_SHARED | (MAP_UNIQUE(m) ? MAP_PLAYER_UNIQUE : 0);
01275     swap_map(m, 1);
01276 
01277     m = ready_map_name(path, flags);
01278     free_string_shared(path);
01279     new_draw_info(0, COLOR_WHITE, op, "Resetmap done.");
01280     dm_map_reinsert_players(m, op);
01281 
01282     return 1;
01283 }
01284 
01290 int command_nowiz(object *op, char *params)
01291 {
01292     (void) params;
01293 
01294     CLEAR_FLAG(op, FLAG_WIZ);
01295     CONTR(op)->followed_player[0] = '\0';
01296     CLEAR_FLAG(op, FLAG_WIZPASS);
01297     CLEAR_MULTI_FLAG(op, FLAG_FLYING);
01298     fix_player(op);
01299     CONTR(op)->socket.update_tile = 0;
01300     esrv_send_inventory(op, op);
01301     CONTR(op)->update_los = 1;
01302     new_draw_info(0, COLOR_WHITE, op, "DM mode deactivated.");
01303 
01304     return 1;
01305 }
01306 
01314 static int checkdm(object *op, char *pl_passwd)
01315 {
01316     char name[MAX_BUF], passwd[MAX_BUF], host[MAX_BUF], buf[MAX_BUF], filename[MAX_BUF];
01317     FILE *fp;
01318 
01319     snprintf(filename, sizeof(filename), "%s/%s", settings.localdir, DMFILE);
01320 
01321     if ((fp = fopen(filename, "r")) == NULL)
01322     {
01323         LOG(llevBug, "Could not read DM file.\n");
01324         return 0;
01325     }
01326 
01327     while(fgets(buf, sizeof(buf), fp) != NULL)
01328     {
01329         if (buf[0] == '#' || buf[0] == '\n')
01330         {
01331             continue;
01332         }
01333 
01334         if (sscanf(buf, "%[^:]:%[^:]:%s\n", name, passwd, host) != 3)
01335         {
01336             LOG(llevBug, "Malformed dm file entry: %s", buf);
01337         }
01338         else if ((!strcmp(name, "*") || (op->name && !strcmp(op->name, name))) && (!strcmp(passwd, "*") || !strcmp(passwd, pl_passwd)) && (!strcmp(host, "*") || !strcmp(host, CONTR(op)->socket.host)))
01339         {
01340             fclose(fp);
01341             return 1;
01342         }
01343     }
01344 
01345     fclose(fp);
01346 
01347     return 0;
01348 }
01349 
01355 int command_dm(object *op, char *params)
01356 {
01357     CONTR(op)->socket.ext_title_flag = 1;
01358 
01359     /* IF we are DM, then turn mode off */
01360     if (QUERY_FLAG(op, FLAG_WIZ) && op->type == PLAYER)
01361     {
01362         /* First remove all the spells */
01363         send_spelllist_cmd(op, NULL, SPLIST_MODE_REMOVE);
01364         command_nowiz(op, params);
01365         /* Now that we are out of DM mode, add the known ones back */
01366         send_spelllist_cmd(op, NULL, SPLIST_MODE_ADD);
01367         return 1;
01368     }
01369 
01370     if (op->type != PLAYER || !CONTR(op))
01371     {
01372         return 0;
01373     }
01374 
01375     if (checkdm(op, (params ? params : "*")))
01376     {
01377         SET_FLAG(op, FLAG_WIZ);
01378         SET_FLAG(op, FLAG_WAS_WIZ);
01379         SET_FLAG(op, FLAG_WIZPASS);
01380 
01381         new_draw_info_format(0, COLOR_WHITE, op, "DM mode activated for %s!", op->name);
01382         SET_MULTI_FLAG(op, FLAG_FLYING);
01383 
01384         esrv_send_inventory(op, op);
01385 
01386         /* Send all the spells */
01387         send_spelllist_cmd(op, NULL, SPLIST_MODE_ADD);
01388 
01389         clear_los(op);
01390 
01391         /* force a draw_look() */
01392         CONTR(op)->socket.update_tile = 0;
01393         CONTR(op)->update_los = 1;
01394     }
01395 
01396     return 1;
01397 }
01398 
01406 static int command_learn_spell_or_prayer(object *op, char *params, int special_prayer)
01407 {
01408     int spell;
01409 
01410     if (op->type != PLAYER || CONTR(op) == NULL || params == NULL)
01411     {
01412         return 0;
01413     }
01414 
01415     if ((spell = look_up_spell_name(params)) < 0)
01416     {
01417         new_draw_info(0, COLOR_WHITE, op, "Unknown spell.");
01418         return 1;
01419     }
01420 
01421     if (check_spell_known(op, spell))
01422     {
01423         new_draw_info_format(0, COLOR_WHITE, op, "You already know the spell %s.", params);
01424         return 0;
01425     }
01426 
01427     do_learn_spell(op, spell, special_prayer);
01428     return 1;
01429 }
01430 
01436 int command_learn_spell(object *op, char *params)
01437 {
01438     return command_learn_spell_or_prayer(op, params, 0);
01439 }
01440 
01446 int command_learn_special_prayer(object *op, char *params)
01447 {
01448     return command_learn_spell_or_prayer(op, params, 1);
01449 }
01450 
01456 int command_forget_spell(object *op, char *params)
01457 {
01458     int spell;
01459 
01460     if (op->type != PLAYER || CONTR(op) == NULL || params == NULL)
01461     {
01462         return 0;
01463     }
01464 
01465     if ((spell = look_up_spell_name(params)) < 0)
01466     {
01467         new_draw_info(0, COLOR_WHITE, op, "Unknown spell.");
01468         return 1;
01469     }
01470 
01471     do_forget_spell(op, spell);
01472     return 1;
01473 }
01474 
01480 int command_listplugins(object *op, char *params)
01481 {
01482     (void) params;
01483 
01484     display_plugins_list(op);
01485     return 1;
01486 }
01487 
01495 int command_loadplugin(object *op, char *params)
01496 {
01497     char buf[MAX_BUF];
01498 
01499     if (!params)
01500     {
01501         new_draw_info(0, COLOR_WHITE, op, "Load what plugin?");
01502         return 1;
01503     }
01504 
01505     snprintf(buf, sizeof(buf), "%s/%s", PLUGINDIR, params);
01506     init_plugin(buf);
01507 
01508     return 1;
01509 }
01510 
01518 int command_unloadplugin(object *op, char *params)
01519 {
01520     if (!params)
01521     {
01522         new_draw_info(0, COLOR_WHITE, op, "Unload what plugin?");
01523         return 1;
01524     }
01525 
01526     remove_plugin(params);
01527 
01528     return 1;
01529 }
01530 
01536 void shutdown_agent(int timer, char *reason)
01537 {
01538     static int sd_timer = -1, m_count, real_count = -1;
01539     static struct timeval tv1, tv2;
01540 
01541     if (timer == -1 && sd_timer == -1)
01542     {
01543         if (real_count > 0)
01544         {
01545             if (--real_count <= 0)
01546             {
01547                 LOG(llevSystem, "Server shutdown started.\n");
01548                 command_kick(NULL, NULL);
01549                 cleanup();
01550                 exit(0);
01551             }
01552         }
01553 
01554         /* Nothing to do */
01555         return;
01556     }
01557 
01558     /* reset shutdown count */
01559     if (timer != -1)
01560     {
01561         int t_min = timer / 60, t_sec = timer - (int) (timer / 60) * 60;
01562 
01563         sd_timer = timer;
01564 
01565         new_draw_info(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: ** SERVER SHUTDOWN STARTED **");
01566 
01567         if (reason)
01568         {
01569             new_draw_info_format(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: %s", reason);
01570         }
01571 
01572         if (t_sec)
01573         {
01574             new_draw_info_format(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: SERVER REBOOT in %d minutes and %d seconds", t_min, t_sec);
01575         }
01576         else
01577         {
01578             new_draw_info_format(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: SERVER REBOOT in %d minutes", t_min);
01579         }
01580 
01581         GETTIMEOFDAY(&tv1);
01582         m_count = timer / 60 - 1;
01583         real_count = -1;
01584     }
01585     /* Count the shutdown timer */
01586     else
01587     {
01588         int t_min, t_sec = 0;
01589 
01590         GETTIMEOFDAY(&tv2);
01591 
01592         /* End countdown */
01593         if ((int) (tv2.tv_sec - tv1.tv_sec) >= sd_timer)
01594         {
01595             new_draw_info(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: ** SERVER GOES DOWN NOW!!! **");
01596 
01597             if (reason)
01598             {
01599                 new_draw_info_format(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: %s", reason);
01600             }
01601 
01602             sd_timer = -1;
01603             real_count = 30;
01604         }
01605 
01606         t_min = (sd_timer - (int) (tv2.tv_sec - tv1.tv_sec)) / 60;
01607         t_sec = (sd_timer - (int) (tv2.tv_sec - tv1.tv_sec)) - (int) ((sd_timer - (int) (tv2.tv_sec - tv1.tv_sec)) / 60) * 60;
01608 
01609         if ((t_min == m_count && !t_sec))
01610         {
01611             m_count = t_min - 1;
01612 
01613             if (t_sec)
01614             {
01615                 new_draw_info_format(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: SERVER REBOOT in %d minutes and %d seconds", t_min, t_sec);
01616             }
01617             else
01618             {
01619                 new_draw_info_format(NDI_PLAYER | NDI_ALL, COLOR_GREEN, NULL, "[Server]: SERVER REBOOT in %d minutes", t_min);
01620             }
01621         }
01622     }
01623 }
01624 
01631 int command_motd_set(object *op, char *params)
01632 {
01633     char filename[MAX_BUF];
01634 
01635     /* No params, show usage. */
01636     if (params == NULL)
01637     {
01638         new_draw_info(0, COLOR_WHITE, op, "Usage:\nRevert to original MotD: /motd_set original\nAppend to custom MotD: /motd_set message");
01639         return 0;
01640     }
01641 
01642     snprintf(filename, sizeof(filename), "%s/motd_custom", settings.localdir);
01643 
01644     /* If we are not reverting to original MotD */
01645     if (strcmp(params, "original"))
01646     {
01647         FILE *fp;
01648 
01649         if (!(fp = fopen(filename, "a")))
01650         {
01651             new_draw_info(0, COLOR_RED, op, "Could not open file for appending data.");
01652             return 0;
01653         }
01654 
01655         fprintf(fp, "%s\n", params);
01656         fclose(fp);
01657 
01658         new_draw_info(0, COLOR_GREEN, op, "Appended to custom Message of the Day.");
01659     }
01660     else
01661     {
01662         unlink(filename);
01663         new_draw_info(0, COLOR_GREEN, op, "Reverted original Message of the Day.");
01664     }
01665 
01666     return 1;
01667 }
01668 
01674 int command_ban(object *op, char *params)
01675 {
01676     if (params == NULL)
01677     {
01678         return 1;
01679     }
01680 
01681     /* Add a new ban */
01682     if (strncmp(params, "add ", 4) == 0)
01683     {
01684         if (add_ban(params + 4))
01685         {
01686             new_draw_info(0, COLOR_GREEN, op, "Added new ban successfully.");
01687         }
01688         else
01689         {
01690             new_draw_info(0, COLOR_RED, op, "Failed to add new ban!");
01691         }
01692     }
01693     /* Remove ban */
01694     else if (strncmp(params, "remove ", 7) == 0)
01695     {
01696         if (remove_ban(params + 7))
01697         {
01698             new_draw_info(0, COLOR_GREEN, op, "Removed ban successfully.");
01699         }
01700         else
01701         {
01702             new_draw_info(0, COLOR_RED, op, "Failed to remove ban!");
01703         }
01704     }
01705     /* List bans */
01706     else if (strncmp(params, "list", 4) == 0)
01707     {
01708         list_bans(op);
01709     }
01710 
01711     return 1;
01712 }
01713 
01719 int command_debug(object *op, char *params)
01720 {
01721     int i;
01722 
01723     if (params == NULL || !sscanf(params, "%d", &i))
01724     {
01725         new_draw_info_format(0, COLOR_WHITE, op, "Debug level is %d.", settings.debug);
01726         return 1;
01727     }
01728 
01729     settings.debug = (enum LogLevel) FABS(i);
01730     new_draw_info_format(0, COLOR_WHITE, op, "Set debug level to %d.", i);
01731     return 1;
01732 }
01733 
01739 int command_dumpbelowfull(object *op, char *params)
01740 {
01741     object *tmp;
01742     StringBuffer *sb;
01743     char *diff;
01744 
01745     (void) params;
01746 
01747     new_draw_info(0, COLOR_WHITE, op, "OBJECTS ON THIS TILE");
01748     new_draw_info(0, COLOR_WHITE, op, "-------------------");
01749 
01750     for (tmp = get_map_ob(op->map, op->x, op->y); tmp; tmp = tmp->above)
01751     {
01752         /* Exclude the DM player object */
01753         if (tmp == op)
01754         {
01755             continue;
01756         }
01757 
01758         sb = stringbuffer_new();
01759         stringbuffer_append_printf(sb, "count %d\n", tmp->count);
01760         dump_object(tmp, sb);
01761         diff = stringbuffer_finish(sb);
01762         new_draw_info(0, COLOR_WHITE, op, diff);
01763         free(diff);
01764 
01765         if (tmp->above && tmp->above != op)
01766         {
01767             new_draw_info(0, COLOR_WHITE, op, ">next object<");
01768         }
01769     }
01770 
01771     new_draw_info(0, COLOR_WHITE, op, "------------------");
01772 
01773     return 1;
01774 }
01775 
01781 int command_dumpbelow(object *op, char *params)
01782 {
01783     object *tmp;
01784     int i = 0;
01785 
01786     (void) params;
01787 
01788     new_draw_info(0, COLOR_WHITE, op, "OBJECTS ON THIS TILE");
01789     new_draw_info(0, COLOR_WHITE, op, "-------------------");
01790 
01791     for (tmp = get_map_ob(op->map, op->x, op->y); tmp; tmp = tmp->above, i++)
01792     {
01793         /* Exclude the DM player object */
01794         if (tmp == op)
01795         {
01796             continue;
01797         }
01798 
01799         new_draw_info_format(0, COLOR_WHITE, op, "#%d  >%s<  >%s<  >%s<", i, query_name(tmp, NULL), tmp->arch ? (tmp->arch->name ? tmp->arch->name : "no arch name") : "NO ARCH", tmp->env ? query_name(tmp->env, NULL) : "");
01800     }
01801 
01802     new_draw_info(0, COLOR_WHITE, op, "------------------");
01803 
01804     return 1;
01805 }
01806 
01812 int command_wizpass(object *op, char *params)
01813 {
01814     int i;
01815 
01816     if (!op)
01817     {
01818         return 0;
01819     }
01820 
01821     if (!params)
01822     {
01823         i = !QUERY_FLAG(op, FLAG_WIZPASS);
01824     }
01825     else
01826     {
01827         i = onoff_value(params);
01828     }
01829 
01830     if (i)
01831     {
01832         new_draw_info(0, COLOR_WHITE, op, "You will now walk through walls.");
01833         SET_FLAG(op, FLAG_WIZPASS);
01834     }
01835     else
01836     {
01837         new_draw_info(0, COLOR_WHITE, op, "You will now be stopped by walls.");
01838         CLEAR_FLAG(op, FLAG_WIZPASS);
01839     }
01840 
01841     return 1;
01842 }
01843 
01849 int command_dumpallarchetypes(object *op, char *params)
01850 {
01851     (void) params;
01852     (void) op;
01853     dump_all_archetypes();
01854     return 1;
01855 }
01856 
01864 int command_dm_stealth(object *op, char *params)
01865 {
01866     (void) params;
01867 
01868     if (op->type != PLAYER || !CONTR(op))
01869     {
01870         return 1;
01871     }
01872 
01873     if (CONTR(op)->dm_stealth)
01874     {
01875         CONTR(op)->dm_stealth = 0;
01876     }
01877     else
01878     {
01879         CONTR(op)->dm_stealth = 1;
01880     }
01881 
01882     new_draw_info_format(0, COLOR_WHITE, op, "Toggled dm_stealth to %d.", CONTR(op)->dm_stealth);
01883     return 1;
01884 }
01885 
01891 int command_dm_light(object *op, char *params)
01892 {
01893     (void) params;
01894 
01895     if (op->type != PLAYER || !CONTR(op))
01896     {
01897         return 1;
01898     }
01899 
01900     if (CONTR(op)->dm_light)
01901     {
01902         CONTR(op)->dm_light = 0;
01903     }
01904     else
01905     {
01906         CONTR(op)->dm_light = 1;
01907     }
01908 
01909     new_draw_info_format(0, COLOR_WHITE, op, "Toggled dm_light to %d.", CONTR(op)->dm_light);
01910     return 1;
01911 }
01912 
01918 int command_dm_password(object *op, char *params)
01919 {
01920     FILE *fp, *fpout;
01921     const char *name_hash;
01922     char filename[MAX_BUF], bufall[MAX_BUF], outfile[MAX_BUF];
01923     char name[MAX_BUF], password[MAX_BUF];
01924 
01925     if (!params || sscanf(params, "%s %s", name, password) != 2)
01926     {
01927         new_draw_info(0, COLOR_RED, op, "Usage: /dm_password <player name> <new password>");
01928         return 0;
01929     }
01930 
01931     adjust_player_name(name);
01932     snprintf(filename, sizeof(filename), "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, name, name);
01933 
01934     if (!player_exists(name))
01935     {
01936         new_draw_info_format(0, COLOR_WHITE, op, "Player %s doesn't exist.", name);
01937     }
01938 
01939     strncpy(outfile, filename, sizeof(outfile));
01940     strncat(outfile, ".tmp", sizeof(outfile) - strlen(outfile) - 1);
01941 
01942     if (!(fp = fopen(filename, "r")))
01943     {
01944         new_draw_info_format(0, COLOR_RED, op, "Error opening file %s.", filename);
01945         return 0;
01946     }
01947 
01948     if (!(fpout = fopen(outfile, "w")))
01949     {
01950         new_draw_info_format(0, COLOR_RED, op, "Error opening file %s.", outfile);
01951         return 0;
01952     }
01953 
01954     while (fgets(bufall, sizeof(bufall) - 1, fp))
01955     {
01956         if (!strncmp(bufall, "password ", 9))
01957         {
01958             fprintf(fpout, "password %s\n", crypt_string(password, NULL));
01959         }
01960         else
01961         {
01962             fputs(bufall, fpout);
01963         }
01964     }
01965 
01966     if ((name_hash = find_string(name)))
01967     {
01968         player *pl;
01969 
01970         for (pl = first_player; pl; pl = pl->next)
01971         {
01972             if (pl->ob && pl->ob->name == name_hash)
01973             {
01974                 strcpy(pl->password, crypt_string(password, NULL));
01975                 break;
01976             }
01977         }
01978     }
01979 
01980     fclose(fp);
01981     fclose(fpout);
01982     unlink(filename);
01983     rename(outfile, filename);
01984 
01985     new_draw_info_format(0, COLOR_GREEN, op, "Done. Changed password of %s to %s!", name, password);
01986     return 0;
01987 }
01988 
01994 int command_dumpactivelist(object *op, char *params)
01995 {
01996     int count = 0;
01997     object *tmp;
01998 
01999     (void) params;
02000 
02001     for (tmp = active_objects; tmp; tmp = tmp->active_next)
02002     {
02003         count++;
02004         LOG(llevSystem, "%08d %03d %f %s (%s)\n", tmp->count, tmp->type, tmp->speed, query_short_name(tmp, NULL), tmp->arch->name ? tmp->arch->name : "<NA>");
02005     }
02006 
02007     new_draw_info_format(0, COLOR_WHITE, op, "Active objects: %d (dumped to log)", count);
02008     LOG(llevSystem, "Active objects: %d\n", count);
02009 
02010     return 1;
02011 }
02012 
02018 int command_shutdown(object *op, char *params)
02019 {
02020     char *bp = NULL;
02021     int i = -2;
02022 
02023     if (params == NULL)
02024     {
02025         new_draw_info(0, COLOR_WHITE, op, "Usage: /shutdown <seconds> [reason]");
02026         return 1;
02027     }
02028 
02029     sscanf(params, "%d ", &i);
02030 
02031     if ((bp = strchr(params, ' ')) != NULL)
02032     {
02033         bp++;
02034     }
02035 
02036     if (bp && *bp == '\0')
02037     {
02038         bp = NULL;
02039     }
02040 
02041     if (i < -1)
02042     {
02043         new_draw_info(0, COLOR_WHITE, op, "Usage: /shutdown <seconds> [reason]");
02044         return 1;
02045     }
02046 
02047     LOG(llevSystem, "Shutdown agent started!\n");
02048     shutdown_agent(i, bp);
02049     new_draw_info_format(0, COLOR_GREEN, op, "Shutdown agent started! Timer set to %d seconds.", i);
02050 
02051     return 1;
02052 }
02053 
02059 int command_setmaplight(object *op, char *params)
02060 {
02061     int i;
02062 
02063     if (params == NULL || !sscanf(params, "%d", &i))
02064     {
02065         return 0;
02066     }
02067 
02068     set_map_darkness(op->map, i);
02069 
02070     new_draw_info_format(0, COLOR_WHITE, op, "WIZ: set map darkness: %d -> map:%s (%d)", i, op->map->path, MAP_OUTDOORS(op->map));
02071 
02072     return 1;
02073 }
02074 
02080 int command_dumpmap(object *op, char *params)
02081 {
02082     (void) params;
02083 
02084     if (op)
02085     {
02086         dump_map(op->map);
02087     }
02088 
02089     return 1;
02090 }
02091 
02097 int command_dumpallmaps(object *op, char *params)
02098 {
02099     (void) params;
02100     (void) op;
02101 
02102     dump_all_maps();
02103 
02104     return 1;
02105 }
02106 
02116 int command_malloc(object *op, char *params)
02117 {
02118 #ifdef MEMPOOL_TRACKING
02119     if (params)
02120     {
02121         int force_flag = 0, i;
02122 
02123         if (strcmp(params, "free") && strcmp(params, "force"))
02124         {
02125             new_draw_info(0, COLOR_WHITE, op, "Usage: /malloc [free | force]");
02126             return 1;
02127         }
02128 
02129         if (strcmp(params, "force") == 0)
02130         {
02131             force_flag = 1;
02132         }
02133 
02134         for (i = 0; i < nrof_mempools; i++)
02135         {
02136             if (force_flag == 1 || mempools[i]->flags & MEMPOOL_ALLOW_FREEING)
02137             {
02138 #if 0
02139                 free_empty_puddles(mempools[i]);
02140 #endif
02141             }
02142         }
02143     }
02144 #else
02145     (void) params;
02146 #endif
02147 
02148     malloc_info(op);
02149     return 1;
02150 }
02151 
02157 int command_maps(object *op, char *params)
02158 {
02159     (void) params;
02160 
02161     maps_info(op);
02162     return 1;
02163 }
02164 
02170 int command_strings(object *op, char *params)
02171 {
02172     char buf[HUGE_BUF];
02173 
02174     (void) params;
02175 
02176     LOG(llevSystem, "HASH TABLE DUMP\n");
02177 
02178     ss_dump_statistics(buf, sizeof(buf));
02179     new_draw_info(0, COLOR_WHITE, op, buf);
02180     LOG(llevSystem, "%s\n", buf);
02181 
02182     ss_dump_table(SS_DUMP_TOTALS, buf, sizeof(buf));
02183     new_draw_info(0, COLOR_WHITE, op, buf);
02184     LOG(llevSystem, "%s\n", buf);
02185 
02186     return 1;
02187 }
02188 
02194 int command_ssdumptable(object *op, char *params)
02195 {
02196     (void) params;
02197     (void) op;
02198 
02199     ss_dump_table(SS_DUMP_TABLE, NULL, 0);
02200     return 1;
02201 }
02202 
02208 int command_follow(object *op, char *params)
02209 {
02210     player *pl;
02211 
02212     if (!params)
02213     {
02214         if (CONTR(op)->followed_player[0])
02215         {
02216             new_draw_info_format(0, COLOR_WHITE, op, "You stop following %s.", CONTR(op)->followed_player);
02217             CONTR(op)->followed_player[0] = '\0';
02218         }
02219 
02220         return 0;
02221     }
02222 
02223     pl = get_other_player_from_name(op, params);
02224 
02225     if (!pl)
02226     {
02227         return 0;
02228     }
02229 
02230     CONTR(op)->followed_player[0] = '\0';
02231     strncpy(CONTR(op)->followed_player, params, sizeof(CONTR(op)->followed_player));
02232 
02233     new_draw_info_format(0, COLOR_GREEN, op, "Following %s.", params);
02234     return 0;
02235 }
02236 
02242 int command_insert_into(object *op, char *params)
02243 {
02244     object *ob, *marked;
02245 
02246     if (!params)
02247     {
02248         new_draw_info(0, COLOR_RED, op, "What object to insert something into?");
02249         return 0;
02250     }
02251 
02252     marked = find_marked_object(op);
02253 
02254     if (!marked)
02255     {
02256         new_draw_info(0, COLOR_RED, op, "You need to mark the object to insert.");
02257         return 0;
02258     }
02259 
02260     ob = find_object_both(op, params);
02261 
02262     if (!ob)
02263     {
02264         new_draw_info(0, COLOR_RED, op, "No such object.");
02265         return 0;
02266     }
02267 
02268     remove_ob(marked);
02269     insert_ob_in_ob(marked, ob);
02270     esrv_send_item(op, marked);
02271     fix_player(op);
02272     new_draw_info_format(0, COLOR_GREEN, op, "Successfully inserted '%s' into '%s'.", query_name(marked, NULL), ob->name);
02273     return 0;
02274 }
02275 
02281 int command_arrest(object *op, char *params)
02282 {
02283     object *dummy;
02284     player *pl;
02285 
02286     if (!params)
02287     {
02288         new_draw_info(0, COLOR_RED, op, "Usage: /arrest <player>.");
02289         return 1;
02290     }
02291 
02292     pl = get_other_player_from_name(op, params);
02293 
02294     if (!pl)
02295     {
02296         return 1;
02297     }
02298 
02299     dummy = get_jail_exit(pl->ob);
02300 
02301     if (!dummy)
02302     {
02303         /* We have nowhere to send the prisoner....*/
02304         new_draw_info(0, COLOR_RED, op, "Can't jail player, there is no map to hold them.");
02305         return 1;
02306     }
02307 
02308     enter_exit(pl->ob, dummy);
02309     new_draw_info_format(0, COLOR_GREEN, op, "Jailed %s.", pl->ob->name);
02310     LOG(llevChat, "Arrest: Player %s arrested by %s\n", pl->ob->name, op->name);
02311     return 1;
02312 }
02313 
02319 int command_cmd_permission(object *op, char *params)
02320 {
02321     char *cp;
02322     player *pl;
02323     int i;
02324 
02325     if (!params)
02326     {
02327         new_draw_info(0, COLOR_RED, op, "Usage: /cmd_permission <player> <add-remove-list> [command]");
02328         return 1;
02329     }
02330 
02331     cp = strchr(params, ' ');
02332 
02333     if (!cp)
02334     {
02335         return 1;
02336     }
02337 
02338     *(cp++) = '\0';
02339 
02340     pl = find_player(params);
02341 
02342     if (!pl)
02343     {
02344         new_draw_info(0, COLOR_WHITE, op, "No such player.");
02345         return 1;
02346     }
02347 
02348     if (!strncmp(cp, "add ", 4))
02349     {
02350         cp += 4;
02351 
02352         if (cp[0] == '/')
02353         {
02354             cp++;
02355         }
02356 
02357         for (i = 0; i < pl->num_cmd_permissions; i++)
02358         {
02359             if (pl->cmd_permissions[i] && !strcmp(pl->cmd_permissions[i], cp))
02360             {
02361                 new_draw_info_format(0, COLOR_RED, op, "%s already has permission for /%s.", pl->ob->name, cp);
02362                 return 1;
02363             }
02364         }
02365 
02366         pl->num_cmd_permissions++;
02367         pl->cmd_permissions = realloc(pl->cmd_permissions, sizeof(char *) * pl->num_cmd_permissions);
02368         pl->cmd_permissions[pl->num_cmd_permissions - 1] = strdup_local(cp);
02369         new_draw_info_format(0, COLOR_GREEN, op, "%s has been granted permission for /%s.", pl->ob->name, cp);
02370     }
02371     else if (!strncmp(cp, "remove ", 7))
02372     {
02373         cp += 7;
02374 
02375         if (cp[0] == '/')
02376         {
02377             cp++;
02378         }
02379 
02380         for (i = 0; i < pl->num_cmd_permissions; i++)
02381         {
02382             if (pl->cmd_permissions[i] && !strcmp(pl->cmd_permissions[i], cp))
02383             {
02384                 FREE_AND_NULL_PTR(pl->cmd_permissions[i]);
02385                 new_draw_info_format(0, COLOR_GREEN, op, "%s has had permission for /%s command removed.", pl->ob->name, cp);
02386                 return 1;
02387             }
02388         }
02389 
02390         new_draw_info_format(0, COLOR_RED, op, "%s does not have permission for /%s.", pl->ob->name, cp);
02391     }
02392     else if (!strncmp(cp, "list", 4))
02393     {
02394         if (pl->cmd_permissions)
02395         {
02396             new_draw_info_format(0, COLOR_WHITE, op, "%s has permissions for the following commands:\n", pl->ob->name);
02397 
02398             for (i = 0; i < pl->num_cmd_permissions; i++)
02399             {
02400                 if (pl->cmd_permissions[i])
02401                 {
02402                     new_draw_info_format(0, COLOR_WHITE, op, "/%s", pl->cmd_permissions[i]);
02403                 }
02404             }
02405         }
02406         else
02407         {
02408             new_draw_info_format(0, COLOR_WHITE, op, "%s has no command permissions.", pl->ob->name);
02409         }
02410     }
02411 
02412     return 1;
02413 }
02414 
02420 int command_map_save(object *op, char *params)
02421 {
02422     char buf[MAX_BUF], path[MAX_BUF], map_path[MAX_BUF];
02423     struct stat stats;
02424     mapstruct *m;
02425 
02426     (void) params;
02427 
02428     /* Don't allow doing this for unique or random maps. */
02429     if (MAP_UNIQUE(op->map) || !strncmp(op->map->path, "/random/", 8))
02430     {
02431         new_draw_info(0, COLOR_WHITE, op, "Cannot be used on unique or random maps.");
02432         return 1;
02433     }
02434 
02435     /* Store the map's path. */
02436     strncpy(map_path, op->map->path, sizeof(map_path));
02437     /* Create a path name to the actual map file. */
02438     strncpy(path, create_pathname(op->map->path), sizeof(path) - 1);
02439     /* Path to the original file. */
02440     snprintf(buf, sizeof(buf), "%s.map_old", path);
02441 
02442     /* No original file yet? Create one. */
02443     if (stat(buf, &stats))
02444     {
02445         FILE *fp = fopen(buf, "w");
02446 
02447         if (!fp)
02448         {
02449             LOG(llevBug, "command_map_save(): Could not open '%s' for writing.\n", buf);
02450             new_draw_info_format(0, COLOR_WHITE, op, "Could not open '%s' for writing.", buf);
02451             return 1;
02452         }
02453 
02454         copy_file(path, fp);
02455         fclose(fp);
02456     }
02457 
02458     /* Remove players from the map. */
02459     m = op->map;
02460     dm_map_remove_players(m);
02461 
02462     /* Try to save the map. */
02463     if (new_save_map(m, 1) == -1)
02464     {
02465         unlink(path);
02466         rename(buf, path);
02467         new_draw_info(0, COLOR_WHITE, op, "Map save error!");
02468     }
02469     else
02470     {
02471         new_draw_info(0, COLOR_WHITE, op, "Current map has been saved to the original map file.");
02472     }
02473 
02474     free_map(m, 1);
02475     /* Reload the map and re-insert players. */
02476     m = ready_map_name(map_path, 0);
02477     dm_map_reinsert_players(m, op);
02478     return 1;
02479 }
02480 
02486 int command_map_reset(object *op, char *params)
02487 {
02488     char buf[MAX_BUF], path[MAX_BUF];
02489     struct stat stats;
02490 
02491     (void) params;
02492 
02493     /* Create a path name to the actual map file. */
02494     strncpy(path, create_pathname(op->map->path), sizeof(path) - 1);
02495     /* Path to the original file. */
02496     snprintf(buf, sizeof(buf), "%s.map_old", path);
02497 
02498     /* Is there the original map file? */
02499     if (!stat(buf, &stats))
02500     {
02501         unlink(path);
02502         rename(buf, path);
02503         new_draw_info(0, COLOR_WHITE, op, "Current map reset.");
02504     }
02505     else
02506     {
02507         new_draw_info(0, COLOR_WHITE, op, "There is no original map to reset to.");
02508     }
02509 
02510     return 1;
02511 }
02512 
02518 int command_map_patch(object *op, char *params)
02519 {
02520     if (!params)
02521     {
02522         new_draw_info(0, COLOR_WHITE, op, "Patch what values?");
02523         return 1;
02524     }
02525 
02526     if (map_set_variable(op->map, params) == -1)
02527     {
02528         new_draw_info_format(0, COLOR_WHITE, op, "Unknown value for map header: %s", params);
02529     }
02530     else
02531     {
02532         new_draw_info_format(0, COLOR_WHITE, op, "(%s)->%s", op->map->name, params);
02533     }
02534 
02535     return 1;
02536 }
02537 
02543 int command_no_shout(object *op, char *params)
02544 {
02545     player *pl;
02546 
02547     if (!params)
02548     {
02549         new_draw_info(0, COLOR_RED, op, "Usage: /no_shout <player>");
02550         return 1;
02551     }
02552 
02553     pl = find_player(params);
02554 
02555     if (!pl)
02556     {
02557         new_draw_info(0, COLOR_WHITE, op, "No such player.");
02558         return 1;
02559     }
02560 
02561     if (pl->no_shout)
02562     {
02563         new_draw_info_format(0, COLOR_WHITE, op, "%s is able to shout again.", pl->ob->name);
02564         pl->no_shout = 0;
02565     }
02566     else
02567     {
02568         new_draw_info_format(0, COLOR_WHITE, op, "%s is now not able to shout.", pl->ob->name);
02569         pl->no_shout = 1;
02570     }
02571 
02572     return 1;
02573 }
02574 
02580 int command_dmtake(object *op, char *params)
02581 {
02582     object *tmp;
02583 
02584     if (!params)
02585     {
02586         new_draw_info(0, COLOR_WHITE, op, "Take what object?");
02587         return 1;
02588     }
02589 
02590     tmp = find_object_both(op, params);
02591 
02592     if (!tmp)
02593     {
02594         new_draw_info(0, COLOR_WHITE, op, "No such object.");
02595         return 1;
02596     }
02597 
02598     if (tmp->env == op)
02599     {
02600         return 1;
02601     }
02602 
02603     pick_up(op, tmp, 0);
02604     return 1;
02605 }
02606 
02614 int command_server_shout(object *op, char *params)
02615 {
02616     player *pl;
02617 
02618     params = cleanup_chat_string(params);
02619 
02620     if (!params || *params == '\0')
02621     {
02622         return 0;
02623     }
02624 
02625     LOG(llevChat, "Server shout: %s: %s\n", op->name, params);
02626 
02627     for (pl = first_player; pl; pl = pl->next)
02628     {
02629         if (can_do_wiz_command(pl, "server_shout"))
02630         {
02631             new_draw_info_format(NDI_PLAYER, COLOR_GREEN, pl->ob, "[Server] (%s): %s", op->name, params);
02632         }
02633         else
02634         {
02635             new_draw_info_format(NDI_PLAYER, COLOR_GREEN, pl->ob, "[Server]: %s", params);
02636         }
02637     }
02638 
02639     return 1;
02640 }
02641 
02649 int command_mod_shout(object *op, char *params)
02650 {
02651     player *pl;
02652 
02653     params = cleanup_chat_string(params);
02654 
02655     if (!params || *params == '\0')
02656     {
02657         return 0;
02658     }
02659 
02660     LOG(llevChat, "Mod shout: %s: %s\n", op->name, params);
02661 
02662     for (pl = first_player; pl; pl = pl->next)
02663     {
02664         if (can_do_wiz_command(pl, "mod_shout"))
02665         {
02666             new_draw_info_format(NDI_PLAYER, COLOR_BRIGHT_PURPLE, pl->ob, "[Moderator] (%s): %s", op->name, params);
02667         }
02668         else
02669         {
02670             new_draw_info_format(NDI_PLAYER, COLOR_BRIGHT_PURPLE, pl->ob, "[Moderator]: %s", params);
02671         }
02672     }
02673 
02674     return 1;
02675 }