/* ************************************************************************ * File: olc.c EmpireMUD AD 1.0 * * Usage: On-Line Creation at player level * * * * All rights reserved. See license.doc for complete information. * * * * Code base by Paul Clarke. EmpireMUD Project, a tbgMUD Production. * * Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson. * * * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * ************************************************************************ */ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "interpreter.h" #include "handler.h" #include "db.h" #include "comm.h" #include "olc.h" /* * EmpireMUD OLC Code * Written by Paul S. Clarke * * The focus of this OLC is a non-menu base. Most commands can be done in * one line, and description editing works the same as TEDIT. The code is * modular so that commands are easily added, and they follow an ACMDesque * style. * * OLC_MODULE() passes "ch" and "argument". */ /* Externs */ extern int rev_dir[]; /* The master structure */ struct olc_data_structure { char *command; /* name to type */ int subcmd; /* SCMD required */ void (*fcn)(Creature ch, char *argument); } olc_data[] = { { "complete", SCMD_REDIT, olc_complete_room }, { "deleteexit", SCMD_REDIT, olc_delete_exit }, { "deleteroom", SCMD_REDIT, olc_delete_room }, { "description", SCMD_REDIT, olc_room_description}, { "exit", SCMD_REDIT, olc_exits }, { "icon", SCMD_REDIT, olc_icon }, { "name", SCMD_REDIT, olc_room_name }, { "passwalls", SCMD_REDIT, olc_pass_walls }, { "roomtype", SCMD_REDIT, olc_roomtype }, { "unclaimable", SCMD_REDIT, olc_unclaimable }, { "terrain", SCMD_REDIT, olc_terrain }, { "\n", 0, NULL } }; /* The main handler for the olc system *********************************** */ ACMD(do_olc) { int i, c = 0; const char *subcmds[] = { "redit", "\n" }; skip_spaces(&argument); half_chop(argument, arg, buf); /* Find the command */ for (i = 0; str_cmp(olc_data[i].command, "\n") && (!is_abbrev(arg, olc_data[i].command) || olc_data[i].subcmd != subcmd); i++); if (!*arg || !str_cmp(olc_data[i].command, "\n")) { msg_to_char(ch, "Usage: %s <function>\r\n", subcmds[subcmd]); msg_to_char(ch, "Available functions:\r\n"); for (i = 0; str_cmp(olc_data[i].command, "\n"); i++) if (olc_data[i].subcmd == subcmd) msg_to_char(ch, " %-20.20s %s", olc_data[i].command, !(++c % 3) ? "\r\n" : ""); if (c % 3) msg_to_char(ch, "\r\n"); } else ((*olc_data[i].fcn) (ch, buf)); } /* *********************************************************************** */ /* ROOM EDIT FUNCTIONS *************************************************** */ /* *********************************************************************** */ /* Module to alter terrain type ****************************************** */ OLC_MODULE(olc_terrain) { int i, j; struct terrain_data { char *name; int sect; int type, type2; } terrain_types[] = { { "field", SECT_FIELD, 0, 0 }, { "1forest", SECT_FOREST_1, 0, 0 }, { "2forest", SECT_FOREST_2, 0, 0 }, { "3forest", SECT_FOREST_3, 0, 0 }, { "4forest", SECT_FOREST_4, 0, 0 }, { "river", SECT_RIVER, 0, 0 }, { "ocean", SECT_OCEAN, 0, 0 }, { "corn", SECT_CROP, CROP_CORN, 0 }, { "wheat", SECT_CROP, CROP_WHEAT, 0 }, { "fruit", SECT_CROP, CROP_FRUIT, 0 }, { "mountain", SECT_MOUNTAIN, 0, 0 }, { "road", SECT_ROAD, 0, 0 }, { "desert", SECT_DESERT, 0, 0 }, { "desertroad", SECT_ROAD, 0, 1 }, { "bridge", SECT_ROAD, 1, 0 }, { "towerofsouls", SECT_TOWER_OF_SOULS, 0, 0 }, { "wasteland", SECT_WASTELAND, 0, 0 }, { "oasis", SECT_OASIS, 0, 0 }, { "\n", 0, 0, 0 } }; /* Find the type */ for (i = 0; str_cmp(terrain_types[i].name, "\n") && !is_abbrev(argument, terrain_types[i].name); i++); if (SECT(ch->in_room) == SECT_INSIDE) msg_to_char(ch, "Leave the building or area first.\r\n"); else if (!*argument || !str_cmp(terrain_types[i].name, "\n")) { msg_to_char(ch, "What type of terrain would you like to set?\r\nYour choices are:"); for (i = 0; str_cmp(terrain_types[i].name, "\n"); i++) msg_to_char(ch, " %s", terrain_types[i].name); } else { if (SECT(ch->in_room) == SECT_INSIDE || SECT(ch->in_room) == SECT_BUILDING || SECT(ch->in_room) == SECT_MULTI) for (j = 0; j < NUM_OF_DIRS; j++) if (EXIT(ch, j)) { if (EXIT(ch, j)->keyword) free(EXIT(ch, j)->keyword); free(EXIT(ch, j)); EXIT(ch, j) = NULL; } SECT(ch->in_room) = terrain_types[i].sect; world[ch->in_room].type = terrain_types[i].type; world[ch->in_room].type2 = terrain_types[i].type2; world[ch->in_room].base_affects = 0; world[ch->in_room].affects = world[ch->in_room].base_affects; world[ch->in_room].res.logs = 0; world[ch->in_room].res.rocks = 0; world[ch->in_room].res.iron = 0; world[ch->in_room].res.sticks = 0; IS_DISMANTLING(ch->in_room) = FALSE; if (world[ch->in_room].name) { free(world[ch->in_room].name); world[ch->in_room].name = NULL; } if (world[ch->in_room].description) { free(world[ch->in_room].description); world[ch->in_room].description = NULL; } if (world[ch->in_room].icon) { free(world[ch->in_room].icon); world[ch->in_room].icon = NULL; } msg_to_char(ch, "This room is now %s %s.\r\n", AN(terrain_types[i].name), terrain_types[i].name); } } /* Module to complete construction *************************************** */ OLC_MODULE(olc_complete_room) { if (IS_DISMANTLING(ch->in_room)) { msg_to_char(ch, "Use 'redit terrain' instead.\r\n"); return; } world[ch->in_room].res.logs = 0; world[ch->in_room].res.rocks = 0; world[ch->in_room].res.iron = 0; world[ch->in_room].res.sticks = 0; msg_to_char(ch, "Complete.\r\n"); } /* Module to set or remove claimability status *************************** */ OLC_MODULE(olc_unclaimable) { if (world[ch->in_room].owner == -1) { world[ch->in_room].owner = 0; msg_to_char(ch, "This area may now be claimed.\r\n"); } else { world[ch->in_room].owner = -1; msg_to_char(ch, "This area may no longer be claimed.\r\n"); } } /* Module to unrestrict a builder **************************************** */ OLC_MODULE(olc_pass_walls) { if (PLR_FLAGGED(ch, PLR_UNRESTRICT)) { REMOVE_BIT(PLR_FLAGS(ch), PLR_UNRESTRICT); msg_to_char(ch, "You deactivate pass-walls.\r\n"); } else { SET_BIT(PLR_FLAGS(ch), PLR_UNRESTRICT); msg_to_char(ch, "You activate pass-walls.\r\n"); } } /* Module to name/unname a room ****************************************** */ OLC_MODULE(olc_room_name) { if (!*argument) msg_to_char(ch, "What would you like to name this room/acre (or \"none\")?\r\n"); else if (!str_cmp(argument, "none")) { if (world[ch->in_room].name) { free(world[ch->in_room].name); world[ch->in_room].name = NULL; } msg_to_char(ch, "This room/acre no longer has a specialized name.\r\n"); } else { world[ch->in_room].name = str_dup(argument); msg_to_char(ch, "This room/acre is now called \"%s\".\r\n", argument); } } /* Module to set a custom icon ******************************************* */ OLC_MODULE(olc_icon) { int c = 0, i; bool bold = FALSE; if (*argument) for (i = 0; i < strlen(argument); i++) { if (argument[i] == '&') { if (argument[i + 1] == 'b') bold = TRUE; else if (argument[i + 1] == '0') bold = FALSE; else if (argument[i + 1] == '&') c++; /* Don't count the one after the & */ i++; } else c++; } if (SECT(ch->in_room) == SECT_INSIDE) msg_to_char(ch, "You may not do that here.\r\n"); else if (!str_cmp(argument, "none")) { if (world[ch->in_room].icon) { free(world[ch->in_room].icon); world[ch->in_room].icon = NULL; } msg_to_char(ch, "This area no longer has a specialized icon.\r\n"); } else if (!*argument) msg_to_char(ch, "What would you like to set the icon to (or \"none\")?\r\n"); else if (c != 4) msg_to_char(ch, "Room icons must be exactly four characters.\r\n"); else if (argument[0] != '&') msg_to_char(ch, "Icons must begin with a color code.\r\n"); else if (bold) msg_to_char(ch, "If you use a bold color in an icon, you must terminate it with &&0.\r\n"); else { world[ch->in_room].icon = str_dup(argument); msg_to_char(ch, "This area now has the icon \"%s&0\".\r\n", argument); } } /* Module to delete a room *********************************************** */ OLC_MODULE(olc_delete_room) { void delete_room(room_rnum rnum); extern room_rnum find_load_room(Creature ch); Creature c, next_c; int r, d; if (!str_cmp(argument, "ok")) msg_to_char(ch, "You MUST type \"redit deleteroom ok\". This will delete the room you're in.\r\n"); else if (SECT(ch->in_room) != SECT_INSIDE) msg_to_char(ch, "You may not delete this room.\r\n"); else { for (r = 0; r <= top_of_world; r++) if (SECT(r) == SECT_BUILDING || SECT(r) == SECT_MULTI || SECT(r) == SECT_INSIDE) for (d = 0; d < NUM_OF_DIRS; d++) if (world[r].dir_option[d] && world[r].dir_option[d]->to_room == ch->in_room) { if (world[r].dir_option[d]->keyword) free(world[r].dir_option[d]->keyword); free(world[r].dir_option[d]); world[r].dir_option[d] = NULL; } r = ch->in_room; d = HOME_ROOM(ch->in_room); for (c = world[ch->in_room].people; c; c = next_c) { next_c = c->next_in_room; char_to_room(c, d != NOWHERE ? d : find_load_room(c)); if (c != ch) msg_to_char(c, "Room deleted.\r\n"); } delete_room(r); msg_to_char(ch, "Room and all connecting exits deleted.\r\n"); } } /* Module to describe a room ********************************************* */ OLC_MODULE(olc_room_description) { if (!*argument) { msg_to_char(ch, "To set a description, use \"redit description set\".\r\n"); msg_to_char(ch, "To remove a description, use \"redit description none\".\r\n"); } else if (is_abbrev(argument, "none")) { if (world[ch->in_room].description) { free(world[ch->in_room].description); world[ch->in_room].description = NULL; } msg_to_char(ch, "This area no longer has a specialized description.\r\n"); } else if (is_abbrev(argument, "set")) { send_to_char("\x1B[H\x1B[J", ch); send_to_char("Edit room description below: (/s saves, /h for help)\r\n", ch); ch->desc->backstr = NULL; if (world[ch->in_room].description) { msg_to_char(ch, world[ch->in_room].description); ch->desc->backstr = str_dup(world[ch->in_room].description); } ch->desc->str = &(world[ch->in_room].description); ch->desc->max_str = MAX_ROOM_DESCRIPTION; ch->desc->mail_to = 0; if (world[ch->in_room].description) ch->desc->storage = str_dup(world[ch->in_room].description); else ch->desc->storage = NULL; act("$n begins editing the room description.", TRUE, ch, 0, 0, TO_ROOM); SET_BIT(PLR_FLAGS(ch), PLR_WRITING); STATE(ch->desc) = CON_EDIT_DESCRIPTION; } else msg_to_char(ch, "You must specify whether you want to set or remove the description.\r\n"); } /* Module to create/delete an exit *************************************** */ OLC_MODULE(olc_exits) { extern const char *dirs[]; extern room_rnum create_room(room_vnum vnum); extern room_vnum find_free_vnum(); int dir, rev, to_room = NOWHERE; bool new = FALSE; two_arguments(argument, arg, buf); if (!str_cmp(buf, "new")) new = TRUE; else to_room = real_room(atoi(buf)); if (SECT(ch->in_room) != SECT_BUILDING && SECT(ch->in_room) != SECT_INSIDE && SECT(ch->in_room) != SECT_MULTI) msg_to_char(ch, "You can't create exits here!\r\n"); else if (!*arg || !*buf) msg_to_char(ch, "Usage: redit exit <direction> <virtual number/new>\r\n"); else if ((dir = parse_direction(arg)) < 0 || (rev = rev_dir[dir]) < 0) msg_to_char(ch, "Invalid direction.\r\n"); else if (!new && to_room == NOWHERE) msg_to_char(ch, "Invalid destination.\r\n"); else if (!new && SECT(to_room) != SECT_BUILDING && SECT(to_room) != SECT_INSIDE && SECT(to_room) != SECT_MULTI) msg_to_char(ch, "You may only create exits to buildings.\r\n"); else if (EXIT(ch, dir)) msg_to_char(ch, "An exit already exists in that direction.\r\n"); else if (!new && world[to_room].dir_option[rev]) msg_to_char(ch, "An exit already exists in that direction in the target room.\r\n"); else { if (new) { to_room = create_room(find_free_vnum()); world[HOME_ROOM(ch->in_room)].inside_rooms++; world[to_room].type = 0; world[to_room].home_room = world[HOME_ROOM(ch->in_room)].number; world[to_room].owner = world[HOME_ROOM(ch->in_room)].owner; } CREATE(world[ch->in_room].dir_option[dir], struct room_direction_data, 1); world[ch->in_room].dir_option[dir]->exit_info = 0; world[ch->in_room].dir_option[dir]->keyword = NULL; world[ch->in_room].dir_option[dir]->to_room = to_room; CREATE(world[to_room].dir_option[rev], struct room_direction_data, 1); world[to_room].dir_option[rev]->exit_info = 0; world[to_room].dir_option[rev]->keyword = NULL; world[to_room].dir_option[rev]->to_room = ch->in_room; msg_to_char(ch, "You create an exit %s to %d.\r\n", dirs[dir], world[to_room].number); } } /* Module to delete exits ************************************************ */ OLC_MODULE(olc_delete_exit) { int dir; one_argument(argument, arg); if (!*arg) msg_to_char(ch, "Delete the exit in which direction?\r\n"); else if ((dir = parse_direction(arg)) == -1) msg_to_char(ch, "Invalid direction.\r\n"); else { if (EXIT(ch, dir)) { if (EXIT(ch, dir)->keyword) free(EXIT(ch, dir)->keyword); free(EXIT(ch, dir)); EXIT(ch, dir) = NULL; } msg_to_char(ch, "Exit deleted. Target room not deleted.\r\n"); } } /* Module to set the room type within a building ************************* */ OLC_MODULE(olc_roomtype) { int i; struct roomtype_data { char *name; int type; } room_types[] = { { "none", RTYPE_NONE }, { "armory", RTYPE_ARMORY }, { "bedroom", RTYPE_BEDROOM }, { "diningroom", RTYPE_DINING }, { "forge", RTYPE_FORGE }, { "greathall", RTYPE_GREATHALL }, { "hallway", RTYPE_HALL }, { "kitchen", RTYPE_KITCHEN }, { "sittingroom", RTYPE_SITTING }, { "study", RTYPE_STUDY }, { "throneroom", RTYPE_THRONE }, { "storageroom", RTYPE_STORAGE }, { "vault", RTYPE_VAULT }, { "tunnel", RTYPE_TUNNEL }, { "skybridge", RTYPE_SKY_BRIDGE}, { "baths", RTYPE_BATHS }, { "shieldracks", RTYPE_SHIELD_RACKS}, { "armorstorage", RTYPE_ARMOR_STORAGE}, { "closet", RTYPE_CLOSET }, { "boathelm", RTYPE_B_HELM }, { "boatondeck", RTYPE_B_ONDECK }, { "boatstorage", RTYPE_B_STORAGE }, { "boatbelowdeck", RTYPE_B_BELOWDECK}, { "\n", 0 } }; /* Find the type */ for (i = 0; str_cmp(room_types[i].name, "\n") && !is_abbrev(argument, room_types[i].name); i++); if (SECT(ch->in_room) != SECT_INSIDE) msg_to_char(ch, "You need to be inside a building first.\r\n"); else if (!*argument || !str_cmp(room_types[i].name, "\n")) { msg_to_char(ch, "What type of room would you like to set?\r\nYour choices are:"); for (i = 0; str_cmp(room_types[i].name, "\n"); i++) msg_to_char(ch, " %s", room_types[i].name); } else { world[ch->in_room].type = room_types[i].type; msg_to_char(ch, "This room is now %s %s.\r\n", AN(room_types[i].name), room_types[i].name); } } /* *********************************************************************** */ /* MOBILE EDIT FUNCTIONS ************************************************* */ /* *********************************************************************** */ /* *********************************************************************** */ /* OBJECT EDIT FUNCTIONS ************************************************* */ /* *********************************************************************** */