Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_c_wiz_c = 00003 * "$Id: c_wiz.c 13939 2010-09-29 19:21:57Z ryo_saeba $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00035 #include <global.h> 00036 #ifndef __CEXTRACT__ 00037 #include <sproto.h> 00038 #endif 00039 #include <spells.h> 00040 #include <treasure.h> 00041 #include <skills.h> 00042 00043 /* Defines for DM item stack **/ 00044 #define STACK_SIZE 50 00046 enum { 00047 STACK_FROM_NONE = 0, 00048 STACK_FROM_TOP = 1, 00049 STACK_FROM_STACK = 2, 00050 STACK_FROM_NUMBER = 3 00051 }; 00052 00067 static player *get_other_player_from_name(object *op, const char *name) { 00068 player *pl; 00069 00070 if (!name) 00071 return NULL; 00072 00073 for (pl = first_player; pl != NULL; pl = pl->next) 00074 if (!strncmp(pl->ob->name, name, MAX_NAME)) 00075 break; 00076 00077 if (pl == NULL) { 00078 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00079 "No such player.", NULL); 00080 return NULL; 00081 } 00082 00083 if (pl->ob == op) { 00084 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00085 "You can't do that to yourself.", NULL); 00086 return NULL; 00087 } 00088 if (pl->state != ST_PLAYING) { 00089 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00090 "That player is in no state for that right now.", NULL); 00091 return NULL; 00092 } 00093 return pl; 00094 } 00095 00108 int command_loadtest(object *op, char *params) { 00109 uint32 x, y; 00110 char buf[1024]; 00111 00112 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00113 "loadtest will stress server through teleporting at different map places. " 00114 "Use at your own risk. Very long loop used so server may have to be reset. " 00115 "type loadtest TRUE to run", 00116 NULL); 00117 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00118 "{%s}", 00119 "{%s}", 00120 params); 00121 if (!params) 00122 return 0; 00123 if (strncmp(params, "TRUE", 4)) 00124 return 0; 00125 00126 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, 00127 "gogogo", NULL); 00128 00129 for (x = 0; x < settings.worldmaptilesx; x++) { 00130 for (y = 0; y < settings.worldmaptilesy; y++) { 00131 snprintf(buf, sizeof(buf), "/world/world_%u_%u", x+settings.worldmapstartx, y+settings.worldmapstarty); 00132 command_goto(op, buf); 00133 } 00134 } 00135 00136 return 0; 00137 } 00138 00147 void do_wizard_hide(object *op, int silent_dm) { 00148 if (op->contr->hidden) { 00149 op->contr->hidden = 0; 00150 op->invisible = 1; 00151 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00152 "You are no longer hidden from other players", NULL); 00153 op->map->players++; 00154 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_DK_ORANGE, 5, NULL, 00155 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_PLAYER, 00156 "%s has entered the game.", 00157 "%s has entered the game.", 00158 op->name); 00159 if (!silent_dm) { 00160 draw_ext_info(NDI_UNIQUE|NDI_ALL|NDI_LT_GREEN, 1, NULL, 00161 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00162 "The Dungeon Master has arrived!", NULL); 00163 } 00164 } else { 00165 op->contr->hidden = 1; 00166 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00167 "Other players will no longer see you.", NULL); 00168 op->map->players--; 00169 if (!silent_dm) { 00170 draw_ext_info(NDI_UNIQUE|NDI_ALL|NDI_LT_GREEN, 1, NULL, 00171 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00172 "The Dungeon Master is gone..", NULL); 00173 } 00174 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_DK_ORANGE, 5, NULL, 00175 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_PLAYER, 00176 "%s leaves the game.", 00177 "%s leaves the game.", 00178 op->name); 00179 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_DK_ORANGE, 5, NULL, 00180 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_PLAYER, 00181 "%s left the game.", 00182 "%s left the game.", 00183 op->name); 00184 } 00185 } 00186 00197 int command_hide(object *op, char *params) { 00198 do_wizard_hide(op, 0); 00199 return 1; 00200 } 00201 00211 static object *find_object_both(char *params) { 00212 if (!params) 00213 return NULL; 00214 if (params[0] == '#') 00215 return find_object(atol(params+1)); 00216 else 00217 return find_object_name(params); 00218 } 00219 00232 int command_setgod(object *op, char *params) { 00233 object *ob; 00234 const object *god; 00235 char *str; 00236 00237 if (!params || !(str = strchr(params, ' '))) { 00238 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00239 "Usage: setgod object god", NULL); 00240 return 0; 00241 } 00242 00243 /* kill the space, and set string to the next param */ 00244 *str++ = '\0'; 00245 if (!(ob = find_object_both(params))) { 00246 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00247 "Set whose god - can not find object %s?", 00248 "Set whose god - can not find object %s?", 00249 params); 00250 return 1; 00251 } 00252 00253 /* 00254 * Perhaps this is overly restrictive? Should we perhaps be able 00255 * to rebless altars and the like? 00256 */ 00257 if (ob->type != PLAYER) { 00258 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00259 "%s is not a player - can not change its god", 00260 "%s is not a player - can not change its god", 00261 ob->name); 00262 return 1; 00263 } 00264 00265 god = find_god(str); 00266 if (god == NULL) { 00267 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00268 "No such god %s.", 00269 "No such god %s.", 00270 str); 00271 return 1; 00272 } 00273 00274 become_follower(ob, god); 00275 return 1; 00276 } 00277 00293 int command_banish(object *op, char *params) { 00294 player *pl; 00295 FILE *banishfile; 00296 char buf[MAX_BUF]; 00297 time_t now; 00298 00299 if (!params) { 00300 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00301 "Usage: banish <player>.", NULL); 00302 return 1; 00303 } 00304 00305 pl = get_other_player_from_name(op, params); 00306 if (!pl) 00307 return 1; 00308 00309 snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, BANISHFILE); 00310 00311 if ((banishfile = fopen(buf, "a")) == NULL) { 00312 LOG(llevDebug, "Could not find file banish_file.\n"); 00313 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00314 "Could not find banish_file.", NULL); 00315 return 0; 00316 } 00317 00318 now = time(NULL); 00319 /* 00320 * Record this as a comment - then we don't have to worry about changing 00321 * the parsing code. 00322 */ 00323 fprintf(banishfile, "# %s (%s) banned by %s at %s\n", pl->ob->name, pl->socket.host, op->name, ctime(&now)); 00324 fprintf(banishfile, "*@%s\n", pl->socket.host); 00325 fclose(banishfile); 00326 00327 LOG(llevDebug, "! %s banned %s from IP: %s.\n", op->name, pl->ob->name, pl->socket.host); 00328 00329 draw_ext_info_format(NDI_UNIQUE|NDI_RED, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00330 "You banish %s", 00331 "You banish %s", 00332 pl->ob->name); 00333 00334 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_RED, 5, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00335 "%s banishes %s from the land!", 00336 "%s banishes %s from the land!", 00337 op->name, pl->ob->name); 00338 command_kick(op, pl->ob->name); 00339 return 1; 00340 } 00341 00352 int command_kick(object *op, const char *params) { 00353 struct pl *pl; 00354 00355 for (pl = first_player; pl != NULL; pl = pl->next) { 00356 if ((params == NULL || !strcmp(pl->ob->name, params)) && pl->ob != op) { 00357 object *op; 00358 int removed = 0; 00359 00360 op = pl->ob; 00361 if (!QUERY_FLAG(op, FLAG_REMOVED)) { 00362 /* Avion : Here we handle the KICK global event */ 00363 execute_global_event(EVENT_KICK, op, params); 00364 remove_ob(op); 00365 removed = 1; 00366 } 00367 op->direction = 0; 00368 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_RED, 5, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00369 "%s is kicked out of the game.", 00370 "%s is kicked out of the game.", 00371 op->name); 00372 strcpy(op->contr->killer, "left"); 00373 check_score(op, 0); /* Always check score */ 00374 00375 /* 00376 * not sure how the player would be freed, but did see 00377 * a crash here - if that is the case, don't save the 00378 * the player. 00379 */ 00380 if (!removed && !QUERY_FLAG(op, FLAG_FREED)) { 00381 (void)save_player(op, 0); 00382 if (op->map) 00383 op->map->players--; 00384 } 00385 #if MAP_MAXTIMEOUT 00386 if (op->map) 00387 op->map->timeout = MAP_TIMEOUT(op->map); 00388 #endif 00389 pl->socket.status = Ns_Dead; 00390 } 00391 } 00392 00393 return 1; 00394 } 00395 00406 int command_overlay_save(object *op, char *params) { 00407 if (!op) 00408 return 0; 00409 00410 if (save_map(op->map, SAVE_MODE_OVERLAY) < 0) 00411 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00412 "Overlay save error!", NULL); 00413 else 00414 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00415 "Current map has been saved as an overlay.", NULL); 00416 00417 return 1; 00418 } 00419 00430 int command_overlay_reset(object *op, char *params) { 00431 char filename[MAX_BUF]; 00432 struct stat stats; 00433 00434 create_overlay_pathname(op->map->path, filename, MAX_BUF); 00435 if (!stat(filename, &stats)) 00436 if (!unlink(filename)) 00437 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00438 "Overlay successfully removed.", NULL); 00439 else 00440 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00441 "Overlay couldn't be removed.", NULL); 00442 else 00443 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00444 "No overlay for current map.", NULL); 00445 00446 return 1; 00447 } 00448 00459 int command_toggle_shout(object *op, char *params) { 00460 player *pl; 00461 00462 if (!params) { 00463 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00464 "Usage: toggle_shout <player>.", NULL); 00465 return 1; 00466 } 00467 00468 pl = get_other_player_from_name(op, params); 00469 if (!pl) 00470 return 1; 00471 00472 if (pl->ob->contr->no_shout == 0) { 00473 pl->ob->contr->no_shout = 1; 00474 00475 draw_ext_info(NDI_UNIQUE|NDI_RED, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00476 "You have been muzzled by the DM!", NULL); 00477 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00478 "You muzzle %s.", 00479 "You muzzle %s.", 00480 pl->ob->name); 00481 00482 /* Avion : Here we handle the MUZZLE global event */ 00483 execute_global_event(EVENT_MUZZLE, pl->ob, params); 00484 00485 return 1; 00486 } else { 00487 pl->ob->contr->no_shout = 0; 00488 draw_ext_info(NDI_UNIQUE|NDI_ORANGE, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00489 "You are allowed to shout and chat again.", NULL); 00490 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00491 "You remove %s's muzzle.", 00492 "You remove %s's muzzle.", 00493 pl->ob->name); 00494 return 1; 00495 } 00496 } 00497 00508 int command_shutdown(object *op, char *params) { 00509 /* 00510 * We need to give op - command_kick expects it. however, this means 00511 * the op won't get kicked off, so we do it ourselves 00512 */ 00513 command_kick(op, NULL); 00514 check_score(op, 0); /* Always check score */ 00515 (void)save_player(op, 0); 00516 play_again(op); 00517 cleanup(); 00518 /* not reached */ 00519 return 1; 00520 } 00521 00532 int command_goto(object *op, char *params) { 00533 char *name; 00534 object *dummy; 00535 00536 if (!op) 00537 return 0; 00538 00539 if (params == NULL) { 00540 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00541 "Go to what level?", NULL); 00542 return 1; 00543 } 00544 00545 name = params; 00546 dummy = get_object(); 00547 dummy->map = op->map; 00548 EXIT_PATH(dummy) = add_string(name); 00549 dummy->name = add_string(name); 00550 00551 enter_exit(op, dummy); 00552 free_object(dummy); 00553 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00554 "Difficulty: %d.", 00555 "Difficulty: %d.", 00556 op->map->difficulty); 00557 00558 return 1; 00559 } 00560 00571 int command_freeze(object *op, char *params) { 00572 int ticks; 00573 player *pl; 00574 00575 if (!params) { 00576 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00577 "Usage: freeze [ticks] <player>.", NULL); 00578 return 1; 00579 } 00580 00581 ticks = atoi(params); 00582 if (ticks) { 00583 while ((isdigit(*params) || isspace(*params)) && *params != 0) 00584 params++; 00585 if (*params == 0) { 00586 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00587 "Usage: freeze [ticks] <player>.", NULL); 00588 return 1; 00589 } 00590 } else 00591 ticks = 100; 00592 00593 pl = get_other_player_from_name(op, params); 00594 if (!pl) 00595 return 1; 00596 00597 draw_ext_info(NDI_UNIQUE|NDI_RED, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00598 "You have been frozen by the DM!", NULL); 00599 00600 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00601 "You freeze %s for %d ticks", 00602 "You freeze %s for %d ticks", 00603 pl->ob->name, ticks); 00604 00605 pl->ob->speed_left = -(pl->ob->speed*ticks); 00606 return 0; 00607 } 00608 00619 int command_arrest(object *op, char *params) { 00620 object *dummy; 00621 player *pl; 00622 00623 if (!op) 00624 return 0; 00625 if (params == NULL) { 00626 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00627 "Usage: arrest <player>.", NULL); 00628 return 1; 00629 } 00630 pl = get_other_player_from_name(op, params); 00631 if (!pl) 00632 return 1; 00633 dummy = get_jail_exit(pl->ob); 00634 if (!dummy) { 00635 /* we have nowhere to send the prisoner....*/ 00636 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00637 "Can't jail player, there is no map to hold them", NULL); 00638 return 0; 00639 } 00640 enter_exit(pl->ob, dummy); 00641 free_object(dummy); 00642 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00643 "You have been arrested.", NULL); 00644 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00645 "Jailed %s", 00646 "Jailed %s", 00647 pl->ob->name); 00648 LOG(llevInfo, "Player %s arrested by %s\n", pl->ob->name, op->name); 00649 return 1; 00650 } 00651 00661 int command_summon(object *op, char *params) { 00662 int i; 00663 object *dummy; 00664 player *pl; 00665 00666 if (!op) 00667 return 0; 00668 00669 if (params == NULL) { 00670 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00671 "Usage: summon <player>.", NULL); 00672 return 1; 00673 } 00674 00675 pl = get_other_player_from_name(op, params); 00676 if (!pl) 00677 return 1; 00678 00679 i = find_free_spot(op, op->map, op->x, op->y, 1, 9); 00680 if (i == -1) { 00681 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00682 "Can not find a free spot to place summoned player.", NULL); 00683 return 1; 00684 } 00685 00686 dummy = get_object(); 00687 EXIT_PATH(dummy) = add_string(op->map->path); 00688 EXIT_X(dummy) = op->x+freearr_x[i]; 00689 EXIT_Y(dummy) = op->y+freearr_y[i]; 00690 enter_exit(pl->ob, dummy); 00691 free_object(dummy); 00692 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00693 "You are summoned.", NULL); 00694 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00695 "You summon %s", 00696 "You summon %s", 00697 pl->ob->name); 00698 return 1; 00699 } 00700 00711 /* mids 01/16/2002 */ 00712 int command_teleport(object *op, char *params) { 00713 int i; 00714 object *dummy; 00715 player *pl; 00716 00717 if (!op) 00718 return 0; 00719 00720 if (params == NULL) { 00721 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00722 "Usage: teleport <player>.", NULL); 00723 return 0; 00724 } 00725 00726 pl = find_player_partial_name(params); 00727 if (!pl) { 00728 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00729 "No such player or ambiguous name.", NULL); 00730 return 0; 00731 } 00732 00733 i = find_free_spot(pl->ob, pl->ob->map, pl->ob->x, pl->ob->y, 1, 9); 00734 if (i == -1) { 00735 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00736 "Can not find a free spot to teleport to.", NULL); 00737 return 0; 00738 } 00739 00740 dummy = get_object(); 00741 EXIT_PATH(dummy) = add_string(pl->ob->map->path); 00742 EXIT_X(dummy) = pl->ob->x+freearr_x[i]; 00743 EXIT_Y(dummy) = pl->ob->y+freearr_y[i]; 00744 enter_exit(op, dummy); 00745 free_object(dummy); 00746 if (!op->contr->hidden) 00747 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 00748 "You see a portal open.", NULL); 00749 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00750 "You teleport to %s", 00751 "You teleport to %s", 00752 pl->ob->name); 00753 00754 return 1; 00755 } 00756 00783 int command_create(object *op, char *params) { 00784 object *tmp = NULL; 00785 int i, magic, set_magic = 0, set_nrof = 0, gotquote, gotspace; 00786 uint32 nrof; 00787 char buf[MAX_BUF], *cp, *bp = buf, *bp2, *bp3, *bp4, *endline; 00788 archetype *at, *at_spell = NULL; 00789 artifact *art = NULL; 00790 00791 if (!op) 00792 return 0; 00793 00794 if (params == NULL) { 00795 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00796 "Usage: create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]", 00797 NULL); 00798 return 1; 00799 } 00800 bp = params; 00801 00802 /* We need to know where the line ends */ 00803 endline = bp+strlen(bp); 00804 00805 if (sscanf(bp, "%u ", &nrof)) { 00806 if ((bp = strchr(params, ' ')) == NULL) { 00807 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00808 "Usage: create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]", 00809 NULL); 00810 return 1; 00811 } 00812 bp++; 00813 set_nrof = 1; 00814 LOG(llevDebug, "%s creates: (%u) %s\n", op->name, nrof, bp); 00815 } 00816 if (sscanf(bp, "%d ", &magic)) { 00817 if ((bp = strchr(bp, ' ')) == NULL) { 00818 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00819 "Usage: create [nr] [magic] <archetype> [ of <artifact>] [variable_to_patch setting]", 00820 NULL); 00821 return 1; 00822 } 00823 bp++; 00824 set_magic = 1; 00825 LOG(llevDebug, "%s creates: (%d) (%d) %s\n", op->name, nrof, magic, bp); 00826 } 00827 if ((cp = strstr(bp, " of ")) != NULL) { 00828 *cp = '\0'; 00829 cp += 4; 00830 } 00831 for (bp2 = bp; *bp2; bp2++) { 00832 if (*bp2 == ' ') { 00833 *bp2 = '\0'; 00834 bp2++; 00835 break; 00836 } 00837 } 00838 00839 if ((at = find_archetype(bp)) == NULL) { 00840 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00841 "No such archetype.", NULL); 00842 return 1; 00843 } 00844 00845 if (cp) { 00846 char spell_name[MAX_BUF], *fsp = NULL; 00847 00848 /* 00849 * Try to find a spell object for this. Note that 00850 * we also set up spell_name which is only 00851 * the first word. 00852 */ 00853 00854 at_spell = find_archetype(cp); 00855 if (!at_spell || at_spell->clone.type != SPELL) 00856 at_spell = find_archetype_by_object_name(cp); 00857 if (!at_spell || at_spell->clone.type != SPELL) { 00858 strcpy(spell_name, cp); 00859 fsp = strchr(spell_name, ' '); 00860 if (fsp) { 00861 *fsp = 0; 00862 fsp++; 00863 at_spell = find_archetype(spell_name); 00864 00865 /* Got a spell, update the first string pointer */ 00866 if (at_spell && at_spell->clone.type == SPELL) 00867 bp2 = cp+strlen(spell_name)+1; 00868 else 00869 at_spell = NULL; 00870 } else 00871 at_spell = NULL; 00872 } 00873 00874 /* OK - we didn't find a spell - presume the 'of' 00875 * in this case means its an artifact. 00876 */ 00877 if (!at_spell) { 00878 if (find_artifactlist(at->clone.type) == NULL) { 00879 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00880 "No artifact list for type %d\n", 00881 "No artifact list for type %d\n", 00882 at->clone.type); 00883 } else { 00884 art = find_artifactlist(at->clone.type)->items; 00885 00886 do { 00887 if (!strcmp(art->item->name, cp)) 00888 break; 00889 art = art->next; 00890 } while (art != NULL); 00891 if (!art) { 00892 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00893 "No such artifact ([%d] of %s)", 00894 "No such artifact ([%d] of %s)", 00895 at->clone.type, cp); 00896 } 00897 } 00898 LOG(llevDebug, "%s creates: (%d) (%d) (%s) of (%s)\n", op->name, set_nrof ? nrof : 0, set_magic ? magic : 0, bp, cp); 00899 } 00900 } /* if cp */ 00901 00902 if ((at->clone.type == ROD || at->clone.type == WAND || at->clone.type == SCROLL || at->clone.type == HORN || at->clone.type == SPELLBOOK) 00903 && !at_spell) { 00904 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00905 "Unable to find spell %s for object that needs it, or it is of wrong type", 00906 "Unable to find spell %s for object that needs it, or it is of wrong type", 00907 cp); 00908 return 1; 00909 } 00910 00911 /* 00912 * Rather than have two different blocks with a lot of similar code, 00913 * just create one object, do all the processing, and then determine 00914 * if that one object should be inserted or if we need to make copies. 00915 */ 00916 tmp = object_create_arch(at); 00917 if (settings.real_wiz == FALSE) 00918 SET_FLAG(tmp, FLAG_WAS_WIZ); 00919 if (set_magic) 00920 set_abs_magic(tmp, magic); 00921 if (art) 00922 give_artifact_abilities(tmp, art->item); 00923 if (need_identify(tmp)) { 00924 SET_FLAG(tmp, FLAG_IDENTIFIED); 00925 CLEAR_FLAG(tmp, FLAG_KNOWN_MAGICAL); 00926 } 00927 00928 /* 00929 * This entire block here tries to find variable pairings, 00930 * eg, 'hp 4' or the like. The mess here is that values 00931 * can be quoted (eg "my cool sword"); So the basic logic 00932 * is we want to find two spaces, but if we got a quote, 00933 * any spaces there don't count. 00934 */ 00935 while (*bp2 && bp2 <= endline) { 00936 bp4 = NULL; 00937 gotspace = 0; 00938 gotquote = 0; 00939 /* find the first quote */ 00940 for (bp3 = bp2; *bp3 && gotspace < 2 && gotquote < 2; bp3++) { 00941 00942 /* Found a quote - now lets find the second one */ 00943 if (*bp3 == '"') { 00944 *bp3 = ' '; 00945 bp2 = bp3+1; /* Update start of string */ 00946 bp3++; 00947 gotquote++; 00948 while (*bp3) { 00949 if (*bp3 == '"') { 00950 *bp3 = '\0'; 00951 gotquote++; 00952 } else 00953 bp3++; 00954 } 00955 } else if (*bp3 == ' ') { 00956 gotspace++; 00957 } 00958 } 00959 00960 /* 00961 * If we got two spaces, send the second one to null. 00962 * if we've reached the end of the line, increase gotspace - 00963 * this is perfectly valid for the list entry listed. 00964 */ 00965 if (gotspace == 2 || gotquote == 2) { 00966 bp3--; /* Undo the extra increment */ 00967 *bp3 = '\0'; 00968 } else if (*bp3 == '\0') 00969 gotspace++; 00970 00971 if ((gotquote && gotquote != 2) 00972 || (gotspace != 2 && gotquote != 2)) { 00973 /* 00974 * Unfortunately, we've clobbered lots of values, so printing 00975 * out what we have probably isn't useful. Break out, because 00976 * trying to recover is probably won't get anything useful 00977 * anyways, and we'd be confused about end of line pointers 00978 * anyways. 00979 */ 00980 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00981 "Malformed create line: %s", 00982 "Malformed create line: %s", 00983 bp2); 00984 break; 00985 } 00986 /* bp2 should still point to the start of this line, 00987 * with bp3 pointing to the end 00988 */ 00989 if (set_variable(tmp, bp2) == -1) 00990 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00991 "Unknown variable %s", 00992 "Unknown variable %s", 00993 bp2); 00994 else 00995 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 00996 "(%s#%d)->%s", 00997 "(%s#%d)->%s", 00998 tmp->name, tmp->count, bp2); 00999 bp2 = bp3+1; 01000 } 01001 01002 if (at->clone.nrof) { 01003 if (at_spell) 01004 insert_ob_in_ob(arch_to_object(at_spell), tmp); 01005 01006 tmp->x = op->x; 01007 tmp->y = op->y; 01008 if (set_nrof) 01009 tmp->nrof = nrof; 01010 tmp->map = op->map; 01011 01012 if (at->clone.randomitems != NULL && !at_spell) 01013 create_treasure(at->clone.randomitems, tmp, GT_APPLY, 01014 op->map->difficulty, 0); 01015 01016 /* Multipart objects can't be in inventory, put'em on floor. */ 01017 if (!tmp->more) { 01018 tmp = insert_ob_in_ob(tmp, op); 01019 } else { 01020 insert_ob_in_map_at(tmp, op->map, op, 0, op->x, op->y); 01021 } 01022 01023 /* Let's put this created item on stack so dm can access it easily. */ 01024 dm_stack_push(op->contr, tmp->count); 01025 01026 return 1; 01027 } else { 01028 for (i = 0; i < (set_nrof ? nrof : 1); i++) { 01029 archetype *atmp; 01030 object *prev = NULL, *head = NULL, *dup; 01031 01032 for (atmp = at; atmp != NULL; atmp = atmp->more) { 01033 dup = arch_to_object(atmp); 01034 01035 if (at_spell) 01036 insert_ob_in_ob(arch_to_object(at_spell), dup); 01037 01038 /* 01039 * The head is what contains all the important bits, 01040 * so just copying it over should be fine. 01041 */ 01042 if (head == NULL) { 01043 head = dup; 01044 copy_object(tmp, dup); 01045 } 01046 if (settings.real_wiz == FALSE) 01047 SET_FLAG(dup, FLAG_WAS_WIZ); 01048 dup->x = op->x+dup->arch->clone.x; 01049 dup->y = op->y+dup->arch->clone.y; 01050 dup->map = op->map; 01051 01052 if (head != dup) { 01053 dup->head = head; 01054 prev->more = dup; 01055 } 01056 prev = dup; 01057 } 01058 01059 if (QUERY_FLAG(head, FLAG_ALIVE)) { 01060 object *check = head; 01061 int size_x = 0; 01062 int size_y = 0; 01063 01064 while (check) { 01065 size_x = MAX(size_x, check->arch->clone.x); 01066 size_y = MAX(size_y, check->arch->clone.y); 01067 check = check->more; 01068 } 01069 01070 if (out_of_map(op->map, head->x+size_x, head->y+size_y)) { 01071 if (head->x < size_x || head->y < size_y) { 01072 dm_stack_pop(op->contr); 01073 free_object(head); 01074 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01075 "Object too big to insert in map, or wrong position.", NULL); 01076 free_object(tmp); 01077 return 1; 01078 } 01079 01080 check = head; 01081 while (check) { 01082 check->x -= size_x; 01083 check->y -= size_y; 01084 check = check->more; 01085 } 01086 } 01087 01088 insert_ob_in_map(head, op->map, op, 0); 01089 } else 01090 head = insert_ob_in_ob(head, op); 01091 01092 /* Let's put this created item on stack so dm can access it easily. */ 01093 /* Wonder if we really want to push all of these, but since 01094 * things like rods have nrof 0, we want to cover those. 01095 */ 01096 dm_stack_push(op->contr, head->count); 01097 01098 if (at->clone.randomitems != NULL && !at_spell) 01099 create_treasure(at->clone.randomitems, head, GT_APPLY, op->map->difficulty, 0); 01100 } 01101 01102 /* free the one we used to copy */ 01103 free_object(tmp); 01104 } 01105 01106 return 1; 01107 } 01108 01109 /* 01110 * Now follows dm-commands which are also acceptable from sockets 01111 */ 01112 01123 int command_inventory(object *op, char *params) { 01124 object *tmp; 01125 int i; 01126 01127 if (!params) { 01128 inventory(op, NULL); 01129 return 0; 01130 } 01131 01132 if (!sscanf(params, "%d", &i) || (tmp = find_object(i)) == NULL) { 01133 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01134 "Inventory of what object (nr)?", NULL); 01135 return 1; 01136 } 01137 01138 inventory(op, tmp); 01139 return 1; 01140 } 01141 01156 int command_skills(object *op, char *params) { 01157 show_skills(op, params); 01158 return 0; 01159 } 01160 01171 int command_dump(object *op, char *params) { 01172 object *tmp; 01173 StringBuffer *sb; 01174 char *diff; 01175 01176 tmp = get_dm_object(op->contr, ¶ms, NULL); 01177 if (!tmp) 01178 return 1; 01179 01180 sb = stringbuffer_new(); 01181 dump_object(tmp, sb); 01182 diff = stringbuffer_finish(sb); 01183 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, diff, diff); 01184 free(diff); 01185 if (QUERY_FLAG(tmp, FLAG_OBJ_ORIGINAL)) 01186 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01187 "Object is marked original", NULL); 01188 return 1; 01189 } 01190 01202 int command_mon_aggr(object *op, char *params) { 01203 if (op->enemy || !QUERY_FLAG(op, FLAG_UNAGGRESSIVE)) { 01204 op->enemy = NULL; 01205 SET_FLAG(op, FLAG_UNAGGRESSIVE); 01206 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01207 "Aggression turned OFF", NULL); 01208 } else { 01209 CLEAR_FLAG(op, FLAG_FRIENDLY); 01210 CLEAR_FLAG(op, FLAG_UNAGGRESSIVE); 01211 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01212 "Aggression turned ON", NULL); 01213 } 01214 01215 return 1; 01216 } 01217 01232 int command_possess(object *op, char *params) { 01233 object *victim; 01234 player *pl; 01235 int i; 01236 char buf[MAX_BUF]; 01237 01238 victim = NULL; 01239 if (params != NULL) { 01240 if (sscanf(params, "%d", &i)) 01241 victim = find_object(i); 01242 else if (sscanf(params, "%s", buf)) 01243 victim = find_object_name(buf); 01244 } 01245 if (victim == NULL) { 01246 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01247 "Patch what object (nr)?", NULL); 01248 return 1; 01249 } 01250 01251 if (victim == op) { 01252 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01253 "As insane as you are, I cannot allow you to possess yourself.", NULL); 01254 return 1; 01255 } 01256 01257 /* make the switch */ 01258 pl = op->contr; 01259 victim->contr = pl; 01260 pl->ob = victim; 01261 victim->type = PLAYER; 01262 SET_FLAG(victim, FLAG_WIZ); 01263 01264 /* basic patchup */ 01265 /* The use of hard coded values is terrible. Note 01266 * that really, to be fair, this shouldn't get changed at 01267 * all - if you are possessing a kobold, you should have the 01268 * same limitations. As it is, as more body locations are added, 01269 * this will give this player more locations than perhaps 01270 * they should be allowed. 01271 */ 01272 for (i = 0; i < NUM_BODY_LOCATIONS; i++) 01273 if (i == 1 || i == 6 || i == 8 || i == 9) 01274 victim->body_info[i] = 2; 01275 else 01276 victim->body_info[i] = 1; 01277 01278 esrv_new_player(pl, 80); /* just pick a weight, we don't care */ 01279 esrv_send_inventory(victim, victim); 01280 01281 fix_object(victim); 01282 01283 do_some_living(victim); 01284 return 1; 01285 } 01286 01296 int command_patch(object *op, char *params) { 01297 char *arg, *arg2; 01298 object *tmp; 01299 01300 tmp = get_dm_object(op->contr, ¶ms, NULL); 01301 if (!tmp) 01302 /* Player already informed of failure */ 01303 return 1; 01304 01305 /* params set to first value by get_dm_default */ 01306 arg = params; 01307 if (arg == NULL) { 01308 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01309 "Patch what values?", NULL); 01310 return 1; 01311 } 01312 01313 if ((arg2 = strchr(arg, ' '))) 01314 arg2++; 01315 if (settings.real_wiz == FALSE) 01316 SET_FLAG(tmp, FLAG_WAS_WIZ); /* To avoid cheating */ 01317 if (set_variable(tmp, arg) == -1) 01318 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01319 "Unknown variable %s", 01320 "Unknown variable %s", 01321 arg); 01322 else { 01323 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01324 "(%s#%d)->%s=%s", 01325 "(%s#%d)->%s=%s", 01326 tmp->name, tmp->count, arg, arg2); 01327 } 01328 01329 return 1; 01330 } 01331 01342 int command_remove(object *op, char *params) { 01343 object *tmp; 01344 int from; 01345 01346 tmp = get_dm_object(op->contr, ¶ms, &from); 01347 if (!tmp) { 01348 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01349 "Remove what object (nr)?", NULL); 01350 return 1; 01351 } 01352 01353 if (tmp->type == PLAYER) { 01354 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01355 "Unable to remove a player!", NULL); 01356 return 1; 01357 } 01358 01359 if (QUERY_FLAG(tmp, FLAG_REMOVED)) { 01360 char name[MAX_BUF]; 01361 01362 query_name(tmp, name, MAX_BUF); 01363 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01364 "%s is already removed!", 01365 "%s is already removed!", 01366 name); 01367 return 1; 01368 } 01369 01370 if (from != STACK_FROM_STACK) 01371 /* Item is either stack top, or is a number thus is now stack top, let's remove it */ 01372 dm_stack_pop(op->contr); 01373 01374 /* Always work on the head - otherwise object will get in odd state */ 01375 if (tmp->head) 01376 tmp = tmp->head; 01377 if (tmp->speed != 0) { 01378 tmp->speed = 0; 01379 update_ob_speed(tmp); 01380 } 01381 remove_ob(tmp); 01382 return 1; 01383 } 01384 01394 int command_free(object *op, char *params) { 01395 object *tmp; 01396 int from; 01397 01398 tmp = get_dm_object(op->contr, ¶ms, &from); 01399 01400 if (!tmp) { 01401 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01402 "Free what object (nr)?", NULL); 01403 return 1; 01404 } 01405 01406 if (from != STACK_FROM_STACK) 01407 /* Item is either stack top, or is a number thus is now stack top, let's remove it */ 01408 dm_stack_pop(op->contr); 01409 01410 if (tmp->head) 01411 tmp = tmp->head; 01412 01413 if (!QUERY_FLAG(tmp, FLAG_REMOVED)) { 01414 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01415 "Warning: item was not removed, will do so now.", NULL); 01416 remove_ob(tmp); 01417 } 01418 01419 free_object(tmp); 01420 return 1; 01421 } 01422 01433 int command_addexp(object *op, char *params) { 01434 char buf[MAX_BUF], skill[MAX_BUF]; 01435 int i, q; 01436 object *skillob = NULL; 01437 player *pl; 01438 01439 skill[0] = '\0'; 01440 if ((params == NULL) 01441 || (strlen(params) > MAX_BUF) 01442 || ((q = sscanf(params, "%s %d %s", buf, &i, skill)) < 2)) { 01443 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01444 "Usage: addexp player quantity [skill].", NULL); 01445 return 1; 01446 } 01447 01448 for (pl = first_player; pl != NULL; pl = pl->next) 01449 if (!strncmp(pl->ob->name, buf, MAX_NAME)) 01450 break; 01451 01452 if (pl == NULL) { 01453 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01454 "No such player.", NULL); 01455 return 1; 01456 } 01457 01458 if (q >= 3) { 01459 skillob = find_skill_by_name(pl->ob, skill); 01460 if (!skillob) { 01461 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01462 "Unable to find skill %s in %s", 01463 "Unable to find skill %s in %s", 01464 skill, buf); 01465 return 1; 01466 } 01467 01468 i = check_exp_adjust(skillob, i); 01469 skillob->stats.exp += i; 01470 calc_perm_exp(skillob); 01471 player_lvl_adj(pl->ob, skillob); 01472 } 01473 01474 pl->ob->stats.exp += i; 01475 calc_perm_exp(pl->ob); 01476 player_lvl_adj(pl->ob, NULL); 01477 01478 if (settings.real_wiz == FALSE) 01479 SET_FLAG(pl->ob, FLAG_WAS_WIZ); 01480 return 1; 01481 } 01482 01493 int command_speed(object *op, char *params) { 01494 int i; 01495 01496 if (params == NULL || !sscanf(params, "%d", &i)) { 01497 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01498 "Current speed is %d", 01499 "Current speed is %d", 01500 max_time); 01501 return 1; 01502 } 01503 01504 set_max_time(i); 01505 reset_sleep(); 01506 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01507 "The speed is changed to %d.", 01508 "The speed is changed to %d.", 01509 i); 01510 return 1; 01511 } 01512 01513 /**************************************************************************/ 01514 /* Mods made by Tyler Van Gorder, May 10-13, 1992. */ 01515 /* CSUChico : tvangod@cscihp.ecst.csuchico.edu */ 01516 /**************************************************************************/ 01517 01528 int command_stats(object *op, char *params) { 01529 player *pl; 01530 01531 if (params == NULL) { 01532 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01533 "Who?", NULL); 01534 return 1; 01535 } 01536 01537 pl = find_player_partial_name(params); 01538 if (pl == NULL) { 01539 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01540 "No such player.", NULL); 01541 return 1; 01542 } 01543 01544 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01545 "[Fixed]Statistics for %s:", "Statistics for %s:", pl->ob->name); 01546 01547 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01548 "[fixed]Str : %-2d H.P. : %-4d MAX : %d", 01549 "Str : %-2d H.P. : %-4d MAX : %d", 01550 pl->ob->stats.Str, pl->ob->stats.hp, pl->ob->stats.maxhp); 01551 01552 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01553 "[fixed]Dex : %-2d S.P. : %-4d MAX : %d", 01554 "Dex : %-2d S.P. : %-4d MAX : %d", 01555 pl->ob->stats.Dex, pl->ob->stats.sp, pl->ob->stats.maxsp); 01556 01557 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01558 "[fixed]Con : %-2d AC : %-4d WC : %d", 01559 "Con : %-2d AC : %-4d WC : %d", 01560 pl->ob->stats.Con, pl->ob->stats.ac, pl->ob->stats.wc); 01561 01562 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01563 "[fixed]Int : %-2d Damage : %d", 01564 "Int : %-2d Damage : %d", 01565 pl->ob->stats.Int, pl->ob->stats.dam); 01566 01567 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01568 "[fixed]Wis : %-2d EXP : %"FMT64, 01569 "Wis : %-2d EXP : %"FMT64, 01570 pl->ob->stats.Wis, pl->ob->stats.exp); 01571 01572 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01573 "[fixed]Pow : %-2d Grace : %d", 01574 "Pow : %-2d Grace : %d", 01575 pl->ob->stats.Pow, pl->ob->stats.grace); 01576 01577 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01578 "[fixed]Cha : %-2d Food : %d", 01579 "Cha : %-2d Food : %d", 01580 pl->ob->stats.Cha, pl->ob->stats.food); 01581 return 1; 01582 } 01583 01595 int command_abil(object *op, char *params) { 01596 char thing[20], thing2[20]; 01597 int iii; 01598 player *pl; 01599 01600 iii = 0; 01601 thing[0] = '\0'; 01602 thing2[0] = '\0'; 01603 if (params == NULL 01604 || !sscanf(params, "%s %s %d", thing, thing2, &iii) 01605 || thing == NULL) { 01606 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01607 "Who?", NULL); 01608 return 1; 01609 } 01610 01611 if (thing2 == NULL) { 01612 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01613 "You can't change that.", NULL); 01614 return 1; 01615 } 01616 01617 if (iii < MIN_STAT || iii > MAX_STAT) { 01618 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01619 "Illegal range of stat.\n", NULL); 01620 return 1; 01621 } 01622 01623 for (pl = first_player; pl != NULL; pl = pl->next) { 01624 if (!strcmp(pl->ob->name, thing)) { 01625 if (settings.real_wiz == FALSE) 01626 SET_FLAG(pl->ob, FLAG_WAS_WIZ); 01627 if (!strcmp("str", thing2)) 01628 pl->ob->stats.Str = iii, pl->orig_stats.Str = iii; 01629 if (!strcmp("dex", thing2)) 01630 pl->ob->stats.Dex = iii, pl->orig_stats.Dex = iii; 01631 if (!strcmp("con", thing2)) 01632 pl->ob->stats.Con = iii, pl->orig_stats.Con = iii; 01633 if (!strcmp("wis", thing2)) 01634 pl->ob->stats.Wis = iii, pl->orig_stats.Wis = iii; 01635 if (!strcmp("cha", thing2)) 01636 pl->ob->stats.Cha = iii, pl->orig_stats.Cha = iii; 01637 if (!strcmp("int", thing2)) 01638 pl->ob->stats.Int = iii, pl->orig_stats.Int = iii; 01639 if (!strcmp("pow", thing2)) 01640 pl->ob->stats.Pow = iii, pl->orig_stats.Pow = iii; 01641 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01642 "%s has been altered.", 01643 "%s has been altered.", 01644 pl->ob->name); 01645 fix_object(pl->ob); 01646 return 1; 01647 } 01648 } 01649 01650 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01651 "No such player.", NULL); 01652 return 1; 01653 } 01654 01665 int command_reset(object *op, char *params) { 01666 mapstruct *m; 01667 object *dummy = NULL, *tmp = NULL; 01668 char path[HUGE_BUF]; 01669 char *space, *confirmation = NULL; 01670 int res = 0; 01671 01672 if (params == NULL) { 01673 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01674 "Reset what map [name]?", NULL); 01675 return 1; 01676 } 01677 01678 space = strchr(params, ' '); 01679 if (space != NULL) { 01680 confirmation = params; 01681 params = space + 1; 01682 } 01683 01684 if (strcmp(params, ".") == 0) 01685 snprintf(path, sizeof(path), "%s", op->map->path); 01686 else 01687 path_combine_and_normalize(op->map->path, params, path, sizeof(path)); 01688 m = has_been_loaded(path); 01689 if (m == NULL) { 01690 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01691 "No such map.", NULL); 01692 return 1; 01693 } 01694 01695 if (confirmation) { 01696 if (strcmp(params, ".") == 0 && m->unique) { 01697 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01698 "Can't reset a player unique map while on it, use 'reset full-reset %s' while not on it.", 01699 "Can't reset a player unique map while on it, use 'reset full-reset %s' while not on it.", 01700 m->path); 01701 return; 01702 } 01703 01704 if (strncmp("full-reset", confirmation, strlen("full-reset"))) { 01705 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01706 "Invalid confirmation, must be 'full-reset'.", "Invalid confirmation, must be 'full-reset'."); 01707 return; 01708 } 01709 } 01710 01711 /* Forbid using reset on our own map when we're in a transport, as 01712 * it has the displeasant effect of crashing the server. 01713 * - gros, July 25th 2006 */ 01714 if ((op->contr && op->contr->transport) && (op->map == m)) { 01715 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01716 "You need to disembark first.", NULL); 01717 return 1; 01718 } 01719 01720 snprintf(path, sizeof(path), "%s", m->path); 01721 01722 if (m->in_memory != MAP_SWAPPED) { 01723 if (m->in_memory != MAP_IN_MEMORY) { 01724 LOG(llevError, "Tried to swap out map which was not in memory.\n"); 01725 return 0; 01726 } 01727 01728 /* 01729 * Only attempt to remove the player that is doing the reset, and not other 01730 * players or wiz's. 01731 */ 01732 if (op->map == m) { 01733 if (strncmp(m->path, "/random/", 8) == 0) { 01734 /* This is not a very satisfying solution - it would be much better 01735 * to recreate a random map with the same seed value as the old one. 01736 * Unfortunately, I think recreating the map would require some 01737 * knowledge about its 'parent', which appears very non-trivial to 01738 * me. 01739 * On the other hand, this should prevent the freeze that this 01740 * situation caused. - gros, 26th July 2006. 01741 */ 01742 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01743 "You cannot reset a random map when inside it.", NULL); 01744 return 1; 01745 } 01746 01747 dummy = get_object(); 01748 dummy->map = NULL; 01749 EXIT_X(dummy) = op->x; 01750 EXIT_Y(dummy) = op->y; 01751 EXIT_PATH(dummy) = add_string(op->map->path); 01752 remove_ob(op); 01753 op->map = NULL; 01754 tmp = op; 01755 } 01756 res = swap_map(m); 01757 } 01758 01759 if (res < 0 || m->in_memory != MAP_SWAPPED) { 01760 player *pl; 01761 int playercount = 0; 01762 01763 /* Need to re-insert player if swap failed for some reason */ 01764 if (tmp) { 01765 insert_ob_in_map(op, m, NULL, 0); 01766 free_object(dummy); 01767 } 01768 01769 if (res < 0 && res != SAVE_ERROR_PLAYER) 01770 /* no need to warn if player on map, code below checks that. */ 01771 draw_ext_info_format(NDI_UNIQUE|NDI_RED, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01772 "Reset failed, error code: %d.", NULL, res); 01773 else { 01774 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01775 "Reset failed, couldn't swap map, the following players are on it:", 01776 NULL); 01777 for (pl = first_player; pl != NULL; pl = pl->next) { 01778 if (pl->ob->map == m && pl->ob != op) { 01779 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01780 pl->ob->name, NULL); 01781 playercount++; 01782 } 01783 } 01784 if (!playercount) 01785 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01786 "hmm, I don't see any other players on this map, something else is the problem.", 01787 NULL); 01788 return 1; 01789 } 01790 } 01791 01792 /* Here, map reset succeeded. */ 01793 01794 if (m && m->in_memory == MAP_SWAPPED) { 01795 01796 if (confirmation) { 01797 map_remove_unique_files(m); 01798 LOG(llevDebug, "DM %s fully resetting map %s.\n", op->name, m->path); 01799 } else 01800 LOG(llevDebug, "DM %s resetting map %s.\n", op->name, m->path); 01801 01802 /* setting this effectively causes an immediate reload */ 01803 m->reset_time = 1; 01804 flush_old_maps(); 01805 } 01806 01807 if (confirmation) 01808 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01809 "Fully resetting map %s.", "Fully resetting map %s.", 01810 path); 01811 else 01812 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01813 "Resetting map %s.", "Resetting map %s.", 01814 path); 01815 01816 if (tmp) { 01817 enter_exit(tmp, dummy); 01818 free_object(dummy); 01819 } 01820 01821 if (confirmation == NULL) { 01822 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01823 "Use 'reset full-reset %s' to fully reset the map.", params); 01824 } 01825 01826 return 1; 01827 } 01828 01839 int command_nowiz(object *op, char *params) { /* 'noadm' is alias */ 01840 CLEAR_FLAG(op, FLAG_WIZ); 01841 CLEAR_FLAG(op, FLAG_WIZPASS); 01842 CLEAR_FLAG(op, FLAG_WIZCAST); 01843 if (op->contr->followed_player) 01844 FREE_AND_CLEAR_STR(op->contr->followed_player); 01845 01846 if (settings.real_wiz == TRUE) 01847 CLEAR_FLAG(op, FLAG_WAS_WIZ); 01848 if (op->contr->hidden) { 01849 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01850 "You are no longer hidden from other players", NULL); 01851 op->map->players++; 01852 draw_ext_info_format(NDI_UNIQUE|NDI_ALL|NDI_DK_ORANGE, 5, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_PLAYER, 01853 "%s has entered the game.", 01854 "%s has entered the game.", 01855 op->name); 01856 op->contr->hidden = 0; 01857 op->invisible = 1; 01858 } else 01859 draw_ext_info(NDI_UNIQUE|NDI_ALL|NDI_LT_GREEN, 1, NULL, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 01860 "The Dungeon Master is gone..", NULL); 01861 01862 update_los(op); 01863 01864 return 1; 01865 } 01866 01887 static int checkdm(object *op, const char *pl_name, const char *pl_passwd, const char *pl_host) { 01888 FILE *dmfile; 01889 char buf[MAX_BUF]; 01890 char line_buf[160], name[160], passwd[160], host[160]; 01891 01892 #ifdef RESTRICTIVE_DM 01893 *pl_name = op->name ? op->name : "*"; 01894 #endif 01895 01896 snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, DMFILE); 01897 if ((dmfile = fopen(buf, "r")) == NULL) { 01898 LOG(llevDebug, "Could not find DM file.\n"); 01899 return 0; 01900 } 01901 01902 while (fgets(line_buf, 160, dmfile) != NULL) { 01903 if (line_buf[0] == '#') 01904 continue; 01905 if (sscanf(line_buf, "%[^:]:%[^:]:%s\n", name, passwd, host) != 3) { 01906 LOG(llevError, "Warning - malformed dm file entry: %s\n", line_buf); 01907 } else if ((!strcmp(name, "*") || (pl_name && !strcmp(pl_name, name))) 01908 && (!strcmp(passwd, "*") || !strcmp(passwd, pl_passwd)) 01909 && (!strcmp(host, "*") || !strcmp(host, pl_host))) { 01910 fclose(dmfile); 01911 return (1); 01912 } 01913 } 01914 fclose(dmfile); 01915 return (0); 01916 } 01917 01932 int do_wizard_dm(object *op, char *params, int silent) { 01933 if (!op->contr) 01934 return 0; 01935 01936 if (QUERY_FLAG(op, FLAG_WIZ)) { 01937 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01938 "You are already the Dungeon Master!", NULL); 01939 return 0; 01940 } 01941 01942 if (checkdm(op, op->name, (params ? params : "*"), op->contr->socket.host)) { 01943 SET_FLAG(op, FLAG_WIZ); 01944 SET_FLAG(op, FLAG_WAS_WIZ); 01945 SET_FLAG(op, FLAG_WIZPASS); 01946 SET_FLAG(op, FLAG_WIZCAST); 01947 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 01948 "Ok, you are the Dungeon Master!", NULL); 01949 /* 01950 * Remove setting flying here - that won't work, because next 01951 * fix_object() is called that will get cleared - proper solution 01952 * is probably something like a wiz_force which gives that and any 01953 * other desired abilities. 01954 */ 01955 clear_los(op); 01956 op->contr->write_buf[0] = '\0'; 01957 01958 if (!silent) 01959 draw_ext_info(NDI_UNIQUE|NDI_ALL|NDI_LT_GREEN, 1, NULL, 01960 MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, 01961 "The Dungeon Master has arrived!", NULL); 01962 01963 return 1; 01964 } else { 01965 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 01966 "Sorry Pal, I don't think so.", NULL); 01967 op->contr->write_buf[0] = '\0'; 01968 return 0; 01969 } 01970 } 01971 01983 int command_dm(object *op, char *params) { 01984 do_wizard_dm(op, params, 0); 01985 return 1; 01986 } 01987 01998 int command_invisible(object *op, char *params) { 01999 if (op) { 02000 op->invisible += 100; 02001 update_object(op, UP_OBJ_FACE); 02002 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02003 "You turn invisible.", NULL); 02004 } 02005 02006 return 0; 02007 } 02008 02026 static object *get_spell_by_name(object *op, const char *spell_name) { 02027 archetype *ar; 02028 archetype *found; 02029 int conflict_found; 02030 size_t spell_name_length; 02031 02032 /* First check for full name matches. */ 02033 conflict_found = 0; 02034 found = NULL; 02035 for (ar = first_archetype; ar != NULL; ar = ar->next) { 02036 if (ar->clone.type != SPELL) 02037 continue; 02038 02039 if (strncmp(ar->name, "spelldirect_", 12) == 0) 02040 continue; 02041 02042 if (strcmp(ar->clone.name, spell_name) != 0) 02043 continue; 02044 02045 if (found != NULL) { 02046 if (!conflict_found) { 02047 conflict_found = 1; 02048 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02049 "More than one archetype matches the spell name %s:", 02050 "More than one archetype matches the spell name %s:", 02051 spell_name); 02052 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02053 "- %s", 02054 "- %s", 02055 found->name); 02056 } 02057 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02058 "- %s", 02059 "- %s", 02060 ar->name); 02061 continue; 02062 } 02063 02064 found = ar; 02065 } 02066 02067 /* No match if more more than one archetype matches. */ 02068 if (conflict_found) 02069 return NULL; 02070 02071 /* Return if exactly one archetype matches. */ 02072 if (found != NULL) 02073 return arch_to_object(found); 02074 02075 /* No full match found: now check for partial matches. */ 02076 spell_name_length = strlen(spell_name); 02077 conflict_found = 0; 02078 found = NULL; 02079 for (ar = first_archetype; ar != NULL; ar = ar->next) { 02080 if (ar->clone.type != SPELL) 02081 continue; 02082 02083 if (strncmp(ar->name, "spelldirect_", 12) == 0) 02084 continue; 02085 02086 if (strncmp(ar->clone.name, spell_name, spell_name_length) != 0) 02087 continue; 02088 02089 if (found != NULL) { 02090 if (!conflict_found) { 02091 conflict_found = 1; 02092 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02093 "More than one spell matches %s:", 02094 "More than one spell matches %s:", 02095 spell_name); 02096 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02097 "- %s", 02098 "- %s", 02099 found->clone.name); 02100 } 02101 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02102 "- %s", 02103 "- %s", 02104 ar->clone.name); 02105 continue; 02106 } 02107 02108 found = ar; 02109 } 02110 02111 /* No match if more more than one archetype matches. */ 02112 if (conflict_found) 02113 return NULL; 02114 02115 /* Return if exactly one archetype matches. */ 02116 if (found != NULL) 02117 return arch_to_object(found); 02118 02119 /* No spell found: just print an error message. */ 02120 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02121 "The spell %s does not exist.", 02122 "The spell %s does not exist.", 02123 spell_name); 02124 return NULL; 02125 } 02126 02141 static int command_learn_spell_or_prayer(object *op, char *params, int special_prayer) { 02142 object *tmp; 02143 02144 if (op->contr == NULL || params == NULL) { 02145 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02146 "Which spell do you want to learn?", NULL); 02147 return 0; 02148 } 02149 02150 tmp = get_spell_by_name(op, params); 02151 if (tmp == NULL) { 02152 return 0; 02153 } 02154 02155 if (check_spell_known(op, tmp->name)) { 02156 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02157 "You already know the spell %s.", 02158 "You already know the spell %s.", 02159 tmp->name); 02160 return 0; 02161 } 02162 02163 do_learn_spell(op, tmp, special_prayer); 02164 free_object(tmp); 02165 return 1; 02166 } 02167 02180 int command_learn_spell(object *op, char *params) { 02181 return command_learn_spell_or_prayer(op, params, 0); 02182 } 02183 02196 int command_learn_special_prayer(object *op, char *params) { 02197 return command_learn_spell_or_prayer(op, params, 1); 02198 } 02199 02210 int command_forget_spell(object *op, char *params) { 02211 object *spell; 02212 02213 if (op->contr == NULL || params == NULL) { 02214 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02215 "Which spell do you want to forget?", NULL); 02216 return 0; 02217 } 02218 02219 spell = lookup_spell_by_name(op, params); 02220 if (spell == NULL) { 02221 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02222 "You do not know the spell %s.", 02223 "You do not know the spell %s.", 02224 params); 02225 return 0; 02226 } 02227 02228 do_forget_spell(op, spell->name); 02229 return 1; 02230 } 02231 02242 int command_listplugins(object *op, char *params) { 02243 plugins_display_list(op); 02244 return 1; 02245 } 02246 02259 int command_loadplugin(object *op, char *params) { 02260 char buf[MAX_BUF]; 02261 02262 if (params == NULL) { 02263 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02264 "Load which plugin?", NULL); 02265 return 1; 02266 } 02267 02268 strcpy(buf, LIBDIR); 02269 strcat(buf, "/plugins/"); 02270 strcat(buf, params); 02271 LOG(llevDebug, "Requested plugin file is %s\n", buf); 02272 if (plugins_init_plugin(buf) == 0) { 02273 LOG(llevInfo, "DM %s loaded plugin %s\n", op->name, params); 02274 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02275 "Plugin %s successfully loaded.", 02276 "Plugin %s successfully loaded.", 02277 params); 02278 } else 02279 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02280 "Could not load plugin %s.", 02281 "Could not load plugin %s.", 02282 params); 02283 return 1; 02284 } 02285 02298 int command_unloadplugin(object *op, char *params) { 02299 if (params == NULL) { 02300 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02301 "Remove which plugin?", NULL); 02302 return 1; 02303 } 02304 02305 if (plugins_remove_plugin(params) == 0) { 02306 LOG(llevInfo, "DM %s unloaded plugin %s\n", op->name, params); 02307 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02308 "Plugin %s successfully removed.", 02309 "Plugin %s successfully removed.", 02310 params); 02311 } else 02312 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02313 "Could not remove plugin %s.", 02314 "Could not remove plugin %s.", 02315 params); 02316 return 1; 02317 } 02318 02333 int command_dmhide(object *op, char *params) { 02334 if (!do_wizard_dm(op, params, 1)) 02335 return 0; 02336 02337 do_wizard_hide(op, 1); 02338 return 1; 02339 } 02340 02347 void dm_stack_pop(player *pl) { 02348 if (!pl->stack_items || !pl->stack_position) { 02349 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02350 "Empty stack!", NULL); 02351 return; 02352 } 02353 02354 pl->stack_position--; 02355 draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02356 "Popped item from stack, %d left.", 02357 "Popped item from stack, %d left.", 02358 pl->stack_position); 02359 } 02360 02373 object *dm_stack_peek(player *pl) { 02374 object *ob; 02375 02376 if (!pl->stack_position) { 02377 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02378 "Empty stack!", NULL); 02379 return NULL; 02380 } 02381 02382 ob = find_object(pl->stack_items[pl->stack_position-1]); 02383 if (!ob) { 02384 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02385 "Stacked item was removed!", NULL); 02386 dm_stack_pop(pl); 02387 return NULL; 02388 } 02389 02390 return ob; 02391 } 02392 02403 void dm_stack_push(player *pl, tag_t item) { 02404 if (!pl->stack_items) { 02405 pl->stack_items = (tag_t *)malloc(sizeof(tag_t)*STACK_SIZE); 02406 memset(pl->stack_items, 0, sizeof(tag_t)*STACK_SIZE); 02407 } 02408 02409 if (pl->stack_position == STACK_SIZE) { 02410 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02411 "Item stack full!", NULL); 02412 return; 02413 } 02414 02415 pl->stack_items[pl->stack_position] = item; 02416 draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02417 "Item stacked as %d.", 02418 "Item stacked as %d.", 02419 pl->stack_position); 02420 pl->stack_position++; 02421 } 02422 02450 object *get_dm_object(player *pl, char **params, int *from) { 02451 int item_tag, item_position; 02452 object *ob; 02453 02454 if (!pl) 02455 return NULL; 02456 02457 if (!params || !*params || **params == '\0') { 02458 if (from) 02459 *from = STACK_FROM_TOP; 02460 /* No parameter => get stack item */ 02461 return dm_stack_peek(pl); 02462 } 02463 02464 /* Let's clean white spaces */ 02465 while (**params == ' ') 02466 (*params)++; 02467 02468 /* Next case: number => item tag */ 02469 if (sscanf(*params, "%d", &item_tag)) { 02470 /* Move parameter to next item */ 02471 while (isdigit(**params)) 02472 (*params)++; 02473 02474 /* And skip blanks, too */ 02475 while (**params == ' ') 02476 (*params)++; 02477 02478 /* Get item */ 02479 ob = find_object(item_tag); 02480 if (!ob) { 02481 if (from) 02482 *from = STACK_FROM_NONE; 02483 draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02484 "No such item %d!", 02485 "No such item %d!", 02486 item_tag); 02487 return NULL; 02488 } 02489 02490 /* Got one, let's push it on stack */ 02491 dm_stack_push(pl, item_tag); 02492 if (from) 02493 *from = STACK_FROM_NUMBER; 02494 return ob; 02495 } 02496 02497 /* Next case: $number => stack item */ 02498 if (sscanf(*params, "$%d", &item_position)) { 02499 /* Move parameter to next item */ 02500 (*params)++; 02501 02502 while (isdigit(**params)) 02503 (*params)++; 02504 while (**params == ' ') 02505 (*params)++; 02506 02507 if (item_position >= pl->stack_position) { 02508 if (from) 02509 *from = STACK_FROM_NONE; 02510 draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02511 "No such stack item %d!", 02512 "No such stack item %d!", 02513 item_position); 02514 return NULL; 02515 } 02516 02517 ob = find_object(pl->stack_items[item_position]); 02518 if (!ob) { 02519 if (from) 02520 *from = STACK_FROM_NONE; 02521 draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02522 "Stack item %d was removed.", 02523 "Stack item %d was removed.", 02524 item_position); 02525 return NULL; 02526 } 02527 02528 if (from) 02529 *from = item_position < pl->stack_position-1 ? STACK_FROM_STACK : STACK_FROM_TOP; 02530 return ob; 02531 } 02532 02533 /* Next case: 'me' => return pl->ob */ 02534 if (!strncmp(*params, "me", 2)) { 02535 if (from) 02536 *from = STACK_FROM_NUMBER; 02537 dm_stack_push(pl, pl->ob->count); 02538 02539 /* Skip to next token */ 02540 (*params) += 2; 02541 while (**params == ' ') 02542 (*params)++; 02543 02544 return pl->ob; 02545 } 02546 02547 /* Last case: get stack top */ 02548 if (from) 02549 *from = STACK_FROM_TOP; 02550 return dm_stack_peek(pl); 02551 } 02552 02563 int command_stack_pop(object *op, char *params) { 02564 dm_stack_pop(op->contr); 02565 return 0; 02566 } 02567 02578 int command_stack_push(object *op, char *params) { 02579 object *ob; 02580 int from; 02581 ob = get_dm_object(op->contr, ¶ms, &from); 02582 02583 if (ob && from != STACK_FROM_NUMBER) 02584 /* Object was from stack, need to push it again */ 02585 dm_stack_push(op->contr, ob->count); 02586 02587 return 0; 02588 } 02589 02600 int command_stack_list(object *op, char *params) { 02601 int item; 02602 object *display; 02603 player *pl = op->contr; 02604 02605 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02606 "Item stack contents:", NULL); 02607 02608 for (item = 0; item < pl->stack_position; item++) { 02609 display = find_object(pl->stack_items[item]); 02610 if (display) 02611 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02612 " %d : %s [%d]", 02613 " %d : %s [%d]", 02614 item, display->name, display->count); 02615 else 02616 /* Item was freed */ 02617 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02618 " %d : (lost item: %d)", 02619 " %d : (lost item: %d)", 02620 item, pl->stack_items[item]); 02621 } 02622 02623 return 0; 02624 } 02625 02636 int command_stack_clear(object *op, char *params) { 02637 op->contr->stack_position = 0; 02638 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02639 "Item stack cleared.", NULL); 02640 return 0; 02641 } 02642 02664 int command_diff(object *op, char *params) { 02665 object *left, *right, *top; 02666 char *diff; 02667 StringBuffer *sb; 02668 int left_from, right_from; 02669 02670 top = NULL; 02671 02672 left = get_dm_object(op->contr, ¶ms, &left_from); 02673 if (!left) { 02674 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02675 "Compare to what item?", NULL); 02676 return 0; 02677 } 02678 02679 if (left_from == STACK_FROM_NUMBER) 02680 /* Item was stacked, remove it else right will be the same... */ 02681 dm_stack_pop(op->contr); 02682 02683 right = get_dm_object(op->contr, ¶ms, &right_from); 02684 02685 if (!right) { 02686 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02687 "Compare what item?", NULL); 02688 return 0; 02689 } 02690 02691 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02692 "Item difference:", NULL); 02693 02694 if (left_from == STACK_FROM_TOP && right_from == STACK_FROM_TOP) { 02695 /* 02696 * Special case: both items were taken from stack top. 02697 * Override the behaviour, taking left as item just below top, if exists. 02698 * See function description for why. 02699 * Besides, if we don't do anything, compare an item to itself, not really useful. 02700 */ 02701 if (op->contr->stack_position > 1) { 02702 left = find_object(op->contr->stack_items[op->contr->stack_position-2]); 02703 if (left) 02704 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02705 "(Note: first item taken from undertop)", NULL); 02706 else 02707 /* Stupid case: item under top was freed, fallback to stack top */ 02708 left = right; 02709 } 02710 } 02711 02712 sb = stringbuffer_new(); 02713 get_ob_diff(sb, left, right); 02714 diff = stringbuffer_finish(sb); 02715 if (*diff == '\0') { 02716 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, "Objects are the same.", NULL); 02717 } else { 02718 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, diff, NULL); 02719 } 02720 free(diff); 02721 return 0; 02722 } 02723 02733 int command_insert_into(object *op, char *params) { 02734 object *left, *right, *inserted; 02735 int left_from, right_from; 02736 char what[MAX_BUF], where[MAX_BUF]; 02737 02738 left = get_dm_object(op->contr, ¶ms, &left_from); 02739 if (!left) { 02740 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02741 "Insert into what object?", NULL); 02742 return 0; 02743 } 02744 02745 if (left_from == STACK_FROM_NUMBER) 02746 /* Item was stacked, remove it else right will be the same... */ 02747 dm_stack_pop(op->contr); 02748 02749 right = get_dm_object(op->contr, ¶ms, &right_from); 02750 02751 if (!right) { 02752 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02753 "Insert what item?", NULL); 02754 return 0; 02755 } 02756 02757 if (left_from == STACK_FROM_TOP && right_from == STACK_FROM_TOP) { 02758 /* 02759 * Special case: both items were taken from stack top. 02760 * Override the behaviour, taking left as item just below top, if exists. 02761 * See function description for why. 02762 * Besides, can't insert an item into itself. 02763 */ 02764 if (op->contr->stack_position > 1) { 02765 left = find_object(op->contr->stack_items[op->contr->stack_position-2]); 02766 if (left) 02767 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02768 "(Note: item to insert into taken from undertop)", NULL); 02769 else 02770 /* Stupid case: item under top was freed, fallback to stack top */ 02771 left = right; 02772 } 02773 } 02774 02775 if (left == right) { 02776 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02777 "Can't insert an object into itself!", NULL); 02778 return 0; 02779 } 02780 02781 if (right->type == PLAYER) { 02782 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 02783 "Can't insert a player into something!", NULL); 02784 return 0; 02785 } 02786 02787 if (!QUERY_FLAG(right, FLAG_REMOVED)) 02788 remove_ob(right); 02789 inserted = insert_ob_in_ob(right, left); 02790 if (left->type == PLAYER) { 02791 if (inserted != right) 02792 /* item was merged, so updating name and such. */ 02793 esrv_update_item(UPD_WEIGHT|UPD_NAME|UPD_NROF, left, inserted); 02794 } 02795 query_name(inserted, what, MAX_BUF); 02796 query_name(left, where, MAX_BUF); 02797 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DM, 02798 "Inserted %s in %s", 02799 "Inserted %s in %s", 02800 what, where); 02801 return 0; 02802 02803 } 02804 02815 int command_style_map_info(object *op, char *params) { 02816 extern mapstruct *styles; 02817 mapstruct *mp; 02818 int maps_used = 0, mapmem = 0, objects_used = 0, x, y; 02819 object *tmp; 02820 02821 for (mp = styles; mp != NULL; mp = mp->next) { 02822 maps_used++; 02823 mapmem += MAP_WIDTH(mp)*MAP_HEIGHT(mp)*(sizeof(object *)+sizeof(MapSpace))+sizeof(mapstruct); 02824 for (x = 0; x < MAP_WIDTH(mp); x++) { 02825 for (y = 0; y < MAP_HEIGHT(mp); y++) { 02826 for (tmp = GET_MAP_OB(mp, x, y); tmp != NULL; tmp = tmp->above) 02827 objects_used++; 02828 } 02829 } 02830 } 02831 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS, 02832 "[fixed]Style maps loaded: %d", 02833 "Style maps loaded: %d", 02834 maps_used); 02835 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS, 02836 "[fixed]Memory used, not", 02837 "Memory used, not"); 02838 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS, 02839 "[fixed]including objects: %d", 02840 "including objects: %d", 02841 mapmem); 02842 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS, 02843 "Style objects: %d", 02844 "Style objects: %d", 02845 objects_used); 02846 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MAPS, 02847 "Mem for objects: %d", 02848 "Mem for objects: %d", 02849 objects_used*sizeof(object)); 02850 return 0; 02851 } 02852 02863 int command_follow(object *op, char *params) { 02864 player *other; 02865 02866 if (!params) { 02867 if (op->contr->followed_player != NULL) { 02868 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "You stop following %s.", NULL, op->contr->followed_player); 02869 FREE_AND_CLEAR_STR(op->contr->followed_player); 02870 } 02871 return 0; 02872 } 02873 02874 other = find_player_partial_name(params); 02875 if (!other) { 02876 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "No such player or ambiguous name.", NULL); 02877 return 0; 02878 } 02879 if (other == op->contr) { 02880 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "You can't follow yourself.", NULL); 02881 return 0; 02882 } 02883 02884 if (op->contr->followed_player) 02885 FREE_AND_CLEAR_STR(op->contr->followed_player); 02886 02887 op->contr->followed_player = add_string(other->ob->name); 02888 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "Following %s.", NULL, op->contr->followed_player); 02889 return 0; 02890 }