empiremud/cnf/
empiremud/doc/
empiremud/lib/boards/
empiremud/lib/etc/
empiremud/lib/misc/
empiremud/lib/plralias/F-J/
empiremud/lib/plralias/K-O/
empiremud/lib/plralias/P-T/
empiremud/lib/plralias/U-Z/
empiremud/lib/plrobjs/
empiremud/lib/plrobjs/F-J/
empiremud/lib/plrobjs/K-O/
empiremud/lib/plrobjs/P-T/
empiremud/lib/plrobjs/U-Z/
empiremud/lib/world/
empiremud/lib/world/mob/
empiremud/lib/world/obj/
empiremud/log/
/* ************************************************************************
*   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 ************************************************* */
/* *********************************************************************** */