/*-
* Copyright (c) 1998 fjoe <fjoe@iclub.nsu.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: olc.c,v 1.36 1998/12/23 16:11:20 fjoe Exp $
*/
/***************************************************************************
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
* *
* This code was freely distributed with the The Isles 1.1 source code, *
* and has been used here for OLC - OLC would not be what it is without *
* all the previous coders who released their source code. *
* *
***************************************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "olc.h"
/*
* The version info. Please use this info when reporting bugs.
* It is displayed in the game by typing 'version' while editing.
* Do not remove these from the code - by request of Jason Dinkel
*/
#define VERSION "ILAB Online Creation [Beta 1.0, ROM 2.3 modified]\n" \
" Port a ROM 2.4 v1.7\n"
#define AUTHOR " By Jason(jdinkel@mines.colorado.edu)\n" \
" Modified for use with ROM 2.3\n" \
" By Hans Birkeland (hansbi@ifi.uio.no)\n" \
" Modificado para uso en ROM 2.4b4a\n" \
" Por Ivan Toledo (pvillanu@choapa.cic.userena.cl)\n" \
" Modified for use with Muddy\n" \
" Farmer Joe (fjoe@iclub.nsu.ru)\n"
#define DATE " (Apr. 7, 1995 - ROM mod, Apr 16, 1995)\n" \
" (Port a ROM 2.4 - Nov 2, 1996)\n" \
" Version actual : 1.71 - Mar 22, 1998\n"
#define CREDITS " Original by Surreality(cxw197@psu.edu) and Locke(locke@lm.com)"
struct olced_data {
const char * id;
const char * name;
OLC_CMD_DATA * cmd_table;
};
typedef struct olced_data OLCED_DATA;
const char ED_AREA[] = "area";
const char ED_ROOM[] = "room";
const char ED_OBJ[] = "object";
const char ED_MOB[] = "mobile";
const char ED_MPCODE[] = "mpcode";
const char ED_HELP[] = "help";
const char ED_CLAN[] = "clan";
const char ED_MSG[] = "msgdb";
const char ED_LANG[] = "language";
const char ED_GENDER[] = "word";
const char ED_CASE[] = "word";
/*const char ED_CLASS[] = "class";*/
OLCED_DATA olced_table[] = {
{ ED_AREA, "AreaEd", olc_cmds_area },
{ ED_ROOM, "RoomEd", olc_cmds_room },
{ ED_OBJ, "ObjEd", olc_cmds_obj },
{ ED_MOB, "MobEd", olc_cmds_mob },
{ ED_MPCODE, "MPEd", olc_cmds_mpcode },
{ ED_HELP, "HelpEd", olc_cmds_help },
{ ED_MSG, "MsgEd", olc_cmds_msg },
{ ED_CLAN, "ClanEd", olc_cmds_clan },
{ ED_LANG, "LangEd", olc_cmds_lang },
/* { ED_GENDER, "WordEd", olc_cmds_word },
{ ED_CASE, "WordEd", olc_cmds_word }, */
/* { ED_CLASS, "ClassEd", olc_cmds_class }, */
{ NULL }
};
static OLCED_DATA * olced_lookup (const char * id);
static OLC_CMD_DATA * cmd_lookup (OLC_CMD_DATA *cmd_table, OLC_FUN *fun);
static OLC_CMD_DATA * cmd_name_lookup (OLC_CMD_DATA *cmd_table,
const char *name);
static void do_olc(CHAR_DATA *ch, const char *argument, int fun);
/* Executed from comm.c. Minimizes compiling when changes are made. */
bool run_olc_editor(DESCRIPTOR_DATA *d)
{
char command[MAX_INPUT_LENGTH];
OLC_CMD_DATA *cmd;
const char *argument;
OLCED_DATA *olced = olced_lookup(d->editor);
if ((olced = olced_lookup(d->editor)) == NULL)
return FALSE;
argument = one_argument(d->incomm, command);
if (command[0] == '\0') {
olced->cmd_table[FUN_SHOW].olc_fun(d->character, argument);
return TRUE;
}
if (!str_cmp(command, "done")) {
edit_done(d);
return TRUE;
}
if ((cmd = cmd_name_lookup(olced->cmd_table+FUN_FIRST, command)) == NULL
|| cmd->olc_fun == NULL)
return FALSE;
if (cmd->olc_fun(d->character, argument)
&& olced->cmd_table[FUN_TOUCH].olc_fun)
olced->cmd_table[FUN_TOUCH].olc_fun(d->character, NULL);
return TRUE;
}
void do_create(CHAR_DATA *ch, const char *argument)
{
do_olc(ch, argument, FUN_CREATE);
}
void do_edit(CHAR_DATA *ch, const char *argument)
{
do_olc(ch, argument, FUN_EDIT);
}
void do_alist(CHAR_DATA *ch, const char *argument)
{
do_olc(ch, argument, FUN_LIST);
}
void do_ashow(CHAR_DATA *ch, const char *argument)
{
do_olc(ch, argument, FUN_SHOW);
}
/*
* olc_ed_name - returns name of current OLC editor (if any).
* Called by bust_a_prompt.
*/
const char *olc_ed_name(CHAR_DATA *ch)
{
OLCED_DATA *olced;
if (IS_NPC(ch))
return str_empty;
olced = olced_lookup(ch->desc->editor);
if (olced == NULL)
return str_empty;
return olced->name;
}
/*
* Generic OLC editor functions.
* All functions assume !IS_NPC(ch).
*/
bool olced_number(CHAR_DATA *ch, const char *argument, OLC_FUN* fun, int *pInt)
{
int val;
char *endptr;
char arg[MAX_STRING_LENGTH];
OLC_CMD_DATA *cmd;
VALIDATE_FUN *validator;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
one_argument(argument, arg);
val = strtol(arg, &endptr, 0);
if (*arg == '\0' || *endptr != '\0') {
char_printf(ch, "Syntax: %s number\n", cmd->name);
return FALSE;
}
if ((validator = cmd->arg1) && !validator(ch, &val))
return FALSE;
*pInt = val;
char_puts("Ok.\n", ch);
return TRUE;
}
bool olced_str(CHAR_DATA *ch, const char *argument,
OLC_FUN *fun, const char **pStr)
{
OLC_CMD_DATA *cmd;
VALIDATE_FUN *validator;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
if (IS_NULLSTR(argument)) {
char_printf(ch, "Syntax: %s string\n", cmd->name);
return FALSE;
}
if ((validator = cmd->arg1) && !validator(ch, argument))
return FALSE;
free_string(*pStr);
*pStr = str_dup(argument);
char_puts("Ok.\n", ch);
return TRUE;
}
bool olced_str_text(CHAR_DATA *ch, const char *argument,
OLC_FUN *fun, const char **pStr)
{
OLC_CMD_DATA *cmd;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
if (argument[0] =='\0') {
string_append(ch, pStr);
return TRUE;
}
char_printf(ch, "Syntax: %s\n", cmd->name);
return FALSE;
}
bool olced_mlstr(CHAR_DATA *ch, const char *argument,
OLC_FUN *fun, mlstring **pmlstr)
{
OLC_CMD_DATA *cmd;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
if (!mlstr_edit(pmlstr, argument)) {
char_printf(ch, "Syntax: %s lang string\n", cmd->name);
return FALSE;
}
char_puts("Ok.\n", ch);
return TRUE;
}
bool olced_mlstrnl(CHAR_DATA *ch, const char *argument,
OLC_FUN *fun, mlstring **pmlstr)
{
OLC_CMD_DATA *cmd;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
if (!mlstr_editnl(pmlstr, argument)) {
char_printf(ch, "Syntax: %s lang string\n", cmd->name);
return FALSE;
}
char_puts("Ok.\n", ch);
return TRUE;
}
bool olced_mlstr_text(CHAR_DATA *ch, const char *argument,
OLC_FUN *fun, mlstring **pmlstr)
{
OLC_CMD_DATA *cmd;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
if (!mlstr_append(ch, pmlstr, argument)) {
char_printf(ch, "Syntax: %s lang\n", cmd->name);
return FALSE;
}
return TRUE;
}
bool olced_exd(CHAR_DATA *ch, const char* argument, ED_DATA **ped)
{
ED_DATA *ed;
char command[MAX_INPUT_LENGTH];
char keyword[MAX_INPUT_LENGTH];
char lang[MAX_INPUT_LENGTH];
OLCED_DATA *olced;
if ((olced = olced_lookup(ch->desc->editor)) == NULL)
return FALSE;
argument = one_argument(argument, command);
argument = one_argument(argument, keyword);
argument = one_argument(argument, lang);
if (command[0] == '\0' || keyword[0] == '\0') {
do_help(ch, "'OLC EXD'");
return FALSE;
}
if (!str_cmp(command, "add")) {
ed = ed_new();
ed->keyword = str_dup(keyword);
if (!mlstr_append(ch, &ed->description, lang)) {
ed_free(ed);
do_help(ch, "'OLC EXD'");
return FALSE;
}
ed->next = *ped;
*ped = ed;
char_puts("Extra description added.\n", ch);
return TRUE;
}
if (!str_cmp(command, "edit")) {
ed = ed_lookup(keyword, *ped);
if (ed == NULL) {
char_printf(ch, "%s: Extra description keyword not found.\n", olced->name);
return FALSE;
}
if (!mlstr_append(ch, &ed->description, lang)) {
do_help(ch, "'OLC EXD'");
return FALSE;
}
return TRUE;
}
if (!str_cmp(command, "delete")) {
ED_DATA *prev = NULL;
for (ed = *ped; ed; ed = ed->next) {
if (is_name(keyword, ed->keyword))
break;
prev = ed;
}
if (ed == NULL) {
char_printf(ch, "%s: Extra description keyword not found.\n", olced->name);
return FALSE;
}
if (prev == NULL)
*ped = ed->next;
else
prev->next = ed->next;
ed_free(ed);
char_puts("Extra description deleted.\n", ch);
return TRUE;
}
if (!str_cmp(command, "show")) {
BUFFER *output;
ed = ed_lookup(keyword, *ped);
if (ed == NULL) {
char_printf(ch, "%s: Extra description keyword not found.\n", olced->name);
return FALSE;
}
output = buf_new(-1);
buf_printf(output, "Keyword: [%s]\n", ed->keyword);
mlstr_dump(output, "Description: ", ed->description);
page_to_char(buf_string(output), ch);
buf_free(output);
return FALSE;
}
if (!str_cmp(command, "format")) {
ed = ed_lookup(keyword, *ped);
if (ed == NULL) {
char_printf(ch, "%s: Extra description keyword not found.\n", olced->name);
return FALSE;
}
mlstr_format(&ed->description);
char_puts("Extra description formatted.\n", ch);
return TRUE;
}
do_help(ch, "'OLC EXD'");
return FALSE;
}
bool olced_flag(CHAR_DATA *ch, const char *argument,
OLC_FUN* fun, flag_t *pflag)
{
int stat;
OLC_CMD_DATA *cmd;
OLCED_DATA *olced;
const FLAG *f;
flag_t marked;
if ((olced = olced_lookup(ch->desc->editor)) == NULL
|| (cmd = cmd_lookup(olced->cmd_table, fun)) == NULL)
return FALSE;
if (!cmd->arg1) {
char_printf(ch, "%s: %s: Table of values undefined (report it to implementors).\n", olced->name, cmd->name);
return FALSE;
}
if ((stat = is_stat(cmd->arg1)) < 0) {
char_printf(ch, "%s: %s: Unknown table of values (report it to implementors).\n", olced->name, cmd->name);
return FALSE;
}
if (!str_cmp(argument, "?")) {
show_flags(ch, cmd->arg1);
return FALSE;
}
if (stat) {
if ((f = flag_lookup(cmd->arg1, argument)) == NULL) {
char_printf(ch, "Syntax: %s value\n"
"Type '%s ?' for a list of "
"acceptable values.\n",
cmd->name, cmd->name);
return FALSE;
}
if (!f->settable) {
char_printf(ch, "%s: %s: '%s': value is not settable.\n",
olced->name, cmd->name, f->name);
return FALSE;
}
*pflag = f->bit;
char_printf(ch, "%s: %s: '%s': Ok.\n",
olced->name, cmd->name, f->name);
return TRUE;
}
marked = 0;
/*
* Accept multiple flags.
*/
for (;;) {
char word[MAX_INPUT_LENGTH];
argument = one_argument(argument, word);
if (word[0] == '\0')
break;
if ((f = flag_lookup(cmd->arg1, word)) == NULL) {
char_printf(ch, "Syntax: %s flag...\n"
"Type '%s ?' for a list of "
"acceptable flags.\n",
cmd->name, cmd->name);
return FALSE;
}
if (!f->settable) {
char_printf(ch, "%s: %s: '%s': flag is not settable.\n",
olced->name, cmd->name, f->name);
continue;
}
SET_BIT(marked, f->bit);
}
if (marked) {
TOGGLE_BIT(*pflag, marked);
char_printf(ch, "%s: %s: '%s': flag(s) toggled.\n",
olced->name, cmd->name,
flag_string(cmd->arg1, marked));
return TRUE;
}
return FALSE;
}
bool olced_dice(CHAR_DATA *ch, const char *argument, OLC_FUN *fun, int *dice)
{
int num, type, bonus;
char* p;
OLC_CMD_DATA *cmd;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
if (argument[0] == '\0')
goto bail_out;
num = strtol(argument, &p, 0);
if (num < 1 || *p != 'd')
goto bail_out;
type = strtol(p+1, &p, 0);
if (type < 1 || *p != '+')
goto bail_out;
bonus = strtol(p+1, &p, 0);
if (bonus < 0 || *p != '\0')
goto bail_out;
dice[DICE_NUMBER] = num;
dice[DICE_TYPE] = type;
dice[DICE_BONUS] = bonus;
char_printf(ch, "%s set to %dd%d+%d.\n", cmd->name, num, type, bonus);
return TRUE;
bail_out:
char_printf(ch, "Syntax: %s <number>d<type>+<bonus>\n", cmd->name);
return FALSE;
}
bool olced_clan(CHAR_DATA *ch, const char *argument, OLC_FUN *fun, int *vnum)
{
OLC_CMD_DATA *cmd;
int cn;
if ((cmd = olc_cmd_lookup(ch, fun)) == NULL)
return FALSE;
if (IS_NULLSTR(argument)) {
char_printf(ch, "Syntax: %s clan\n"
"Use 'clan ?' for list of valid clans.\n"
"Use 'clan none' to reset clan.\n",
cmd->name);
return FALSE;
}
if (!str_cmp(argument, "none")) {
*vnum = 0;
return TRUE;
}
if ((cn = cn_lookup(argument)) < 0) {
char_printf(ch, "'%s': unknown clan.\n", argument);
return FALSE;
}
*vnum = cn;
return TRUE;
}
VALIDATE_FUN(validate_filename)
{
if (strpbrk(arg, "/")) {
char_printf(ch, "%s: Invalid characters in file name.\n",
olc_ed_name(ch));
return FALSE;
}
return TRUE;
}
VALIDATE_FUN(validate_room_vnum)
{
int vnum = *(int*) arg;
if (vnum && get_room_index(vnum) == NULL) {
char_printf(ch, "OLC: %d: no such room.\n", vnum);
return FALSE;
}
return TRUE;
}
/*****************************************************************************
Name: show_commands
Purpose: Display all olc commands.
Called by: olc interpreters.
****************************************************************************/
bool show_commands(CHAR_DATA *ch, const char *argument)
{
OLCED_DATA * olced;
OLC_CMD_DATA * cmd;
BUFFER * output;
int col;
olced = olced_lookup(ch->desc->editor);
if (olced == NULL)
return FALSE;
output = buf_new(-1);
for (col = 0, cmd = olced->cmd_table+FUN_FIRST; cmd->name; cmd++) {
buf_printf(output, "%-15.15s", cmd->name);
if (++col % 5 == 0)
buf_add(output, "\n");
}
if (col % 5 != 0)
buf_add(output, "\n");
page_to_char(buf_string(output), ch);
buf_free(output);
return FALSE;
}
bool show_version(CHAR_DATA *ch, const char *argument)
{
char_puts(VERSION "\n"
AUTHOR "\n"
DATE "\n"
CREDITS "\n", ch);
return FALSE;
}
AREA_DATA *get_edited_area(CHAR_DATA *ch)
{
int vnum;
const char *id = ch->desc->editor;
void *p = ch->desc->pEdit;
if (id == ED_AREA)
return p;
if (id == ED_HELP)
return ((HELP_DATA*) p)->area;
if (id == ED_ROOM)
return ch->in_room->area;
if (id == ED_OBJ)
vnum = ((OBJ_INDEX_DATA*) p)->vnum;
else if (id == ED_MOB)
vnum = ((MOB_INDEX_DATA*) p)->vnum;
else if (id == ED_MPCODE)
vnum = ((MPCODE*) p)->vnum;
else
return NULL;
return area_vnum_lookup(vnum);
}
bool touch_area(AREA_DATA *pArea)
{
if (pArea)
SET_BIT(pArea->flags, AREA_CHANGED);
return FALSE;
}
bool touch_vnum(int vnum)
{
return touch_area(area_vnum_lookup(vnum));
}
void edit_done(DESCRIPTOR_DATA *d)
{
d->pEdit = NULL;
d->editor = NULL;
}
OLC_CMD_DATA *olc_cmd_lookup(CHAR_DATA *ch, OLC_FUN *fun)
{
OLCED_DATA *olced = olced_lookup(ch->desc->editor);
if ((olced = olced_lookup(ch->desc->editor)) == NULL)
return NULL;
return cmd_lookup(olced->cmd_table, fun);
}
/* Local functions */
/* lookup OLC editor by id */
static OLCED_DATA *olced_lookup(const char * id)
{
OLCED_DATA *olced;
if (IS_NULLSTR(id))
return NULL;
for (olced = olced_table; olced->id; olced++)
if (!str_prefix(id, olced->id))
return olced;
return NULL;
}
/* lookup cmd function by pointer */
static OLC_CMD_DATA *cmd_lookup(OLC_CMD_DATA *cmd_table, OLC_FUN *fun)
{
for (; cmd_table->name; cmd_table++)
if (cmd_table->olc_fun == fun)
return cmd_table;
return NULL;
}
/* lookup cmd function by name */
static OLC_CMD_DATA *cmd_name_lookup(OLC_CMD_DATA *cmd_table, const char *name)
{
for (; cmd_table->name; cmd_table++)
if (!str_prefix(name, cmd_table->name))
return cmd_table;
return NULL;
}
char* help_topics[FUN_MAX] =
{
"'OLC CREATE'",
"'OLC EDIT'",
NULL,
"'OLC ASHOW'",
"'OLC ALIST'"
};
static void do_olc(CHAR_DATA *ch, const char *argument, int fun)
{
char command[MAX_INPUT_LENGTH];
OLCED_DATA *olced;
OLC_FUN *olcfun;
if (IS_NPC(ch))
return;
argument = one_argument(argument, command);
if ((olced = olced_lookup(command)) == NULL
|| (olcfun = olced->cmd_table[fun].olc_fun) == NULL) {
do_help(ch, help_topics[fun]);
return;
}
olcfun(ch, argument);
}