/*- * 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 936 2006-11-20 04:50:44Z zsuzsu $ */ /*************************************************************************** * * * 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" #include "db/lang.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 OLC_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 SoG\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)" 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_IMPL[] = "implicit"; const char ED_EXPL[] = "explicit"; const char ED_SOC[] = "social"; /*const char ED_CLASS[] = "class";*/ const char ED_RACE[] = "race"; const char ED_MATERIAL[]= "material"; olced_t olced_table[] = { { 0, ED_AREA, "AreaEd", olc_cmds_area }, { 0, ED_ROOM, "RoomEd", olc_cmds_room }, { 0, ED_OBJ, "ObjEd", olc_cmds_obj }, { 0, ED_MOB, "MobEd", olc_cmds_mob }, { 5, ED_MPCODE, "MPEd", olc_cmds_mpcode }, { 0, ED_HELP, "HelpEd", olc_cmds_help }, { 0, ED_MSG, "MsgEd", olc_cmds_msg }, { 0, ED_CLAN, "ClanEd", olc_cmds_clan }, { 0, ED_LANG, "LangEd", olc_cmds_lang }, { 0, ED_IMPL, "ImplRuleEd", olc_cmds_impl }, { 0, ED_EXPL, "ExplRuleEd", olc_cmds_expl }, { 0, ED_SOC, "SocEd", olc_cmds_soc }, /*{ ED_CLASS, "ClassEd", olc_cmds_class },*/ { 0, ED_RACE, "RaceEd", olc_cmds_race }, { 0, ED_MATERIAL,"MaterialEd", olc_cmds_material }, { 0, NULL } }; static olc_cmd_t * cmd_lookup(olc_cmd_t *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_t *cmd; const char *argument; olced_t *olced = d->olced; if ((olced = d->olced) == NULL) return FALSE; argument = one_argument(d->incomm, command, sizeof(command)); if (command[0] == '\0') { olced->cmd_table[FUN_SHOW].olc_fun(d->character, argument, olced->cmd_table+FUN_SHOW); return TRUE; } if (!str_cmp(command, "done")) { edit_done(d); return TRUE; } if ((cmd = cmd_lookup(olced->cmd_table+FUN_FIRST, command)) == NULL || cmd->olc_fun == NULL) return FALSE; if (cmd->olc_fun(d->character, argument, cmd)) olced->cmd_table[FUN_TOUCH].olc_fun(d->character, str_empty, olced->cmd_table+FUN_TOUCH); 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); } /* * olced_busy -- returns TRUE if there is another character * is using the same OLC editor */ bool olced_busy(CHAR_DATA *ch, const char *id, void *edit, void *edit2) { DESCRIPTOR_DATA *d; for (d = descriptor_list; d; d = d->next) { CHAR_DATA *vch = d->original ? d->original : d->character; if (vch != ch && d->olced && d->olced->id == id && (!edit || d->pEdit == edit) && (!edit2 || d->pEdit2 == edit2)) { char_printf(ch, "%s: %s is locking this editor " "right now.\n", d->olced->name, vch->name); return TRUE; } } return FALSE; } /* * Generic OLC editor functions. * All functions assume !IS_NPC(ch). */ OLC_FUN(olced_spell_out) { char_puts("Spell it out.\n", ch); return FALSE; } OLC_FUN(olced_dummy) { return FALSE; } bool olced_number(CHAR_DATA *ch, const char *argument, olc_cmd_t* cmd, int *pInt) { int val; char *endptr; char arg[MAX_STRING_LENGTH]; VALIDATE_FUN *validator; one_argument(argument, arg, sizeof(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_name(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, const char **pStr) { VALIDATE_FUN *validator; bool changed; char arg[MAX_INPUT_LENGTH]; argument = one_argument(argument, arg, sizeof(arg)); if (arg[0] == '\0') { char_printf(ch, "Syntax: %s string\n", cmd->name); return FALSE; } if ((validator = cmd->arg1) && !validator(ch, argument)) return FALSE; changed = FALSE; for (; arg[0]; argument = one_argument(argument, arg, sizeof(arg))) { if (!str_cmp(arg, "all")) { char_printf(ch, "%s: %s: Illegal name.\n", OLCED(ch)->name, arg); continue; } changed = TRUE; name_toggle(pStr, arg, ch, OLCED(ch)->name); } return changed; } bool olced_str(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, const char **pStr) { VALIDATE_FUN *validator; 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_cmd_t *cmd, const char **pStr) { if (argument[0] =='\0') { string_append(ch, pStr); return FALSE; } char_printf(ch, "Syntax: %s\n", cmd->name); return FALSE; } bool olced_mlstr(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, mlstring **pmlstr) { 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_cmd_t *cmd, mlstring **pmlstr) { 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_cmd_t *cmd, mlstring **pmlstr) { if (!mlstr_append(ch, pmlstr, argument)) { char_printf(ch, "Syntax: %s lang\n", cmd->name); return FALSE; } return FALSE; } static void cb_format(int lang, const char **p, void *arg) { *p = format_string(*p); } bool olced_exd(CHAR_DATA *ch, const char* argument, olc_cmd_t *cmd, ED_DATA **ped) { ED_DATA *ed; char command[MAX_INPUT_LENGTH]; char keyword[MAX_INPUT_LENGTH]; char arg[MAX_INPUT_LENGTH]; argument = one_argument(argument, command, sizeof(command)); argument = one_argument(argument, keyword, sizeof(keyword)); argument = one_argument(argument, arg, sizeof(arg)); 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, arg)) { 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, "name")) { ed = ed_lookup(keyword, *ped); if (ed == NULL) { char_printf(ch, "%s: Extra description keyword not found.\n", OLCED(ch)->name); return FALSE; } if (!str_cmp(arg, "none") || !str_cmp(arg, "all")) { char_printf(ch, "%s: %s: Illegal keyword.\n", OLCED(ch)->name, arg); return FALSE; } name_toggle(&ed->keyword, arg, ch, OLCED(ch)->name); 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(ch)->name); return FALSE; } if (!mlstr_append(ch, &ed->description, arg)) { 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(ch)->name); return FALSE; } if (prev == NULL) *ped = ed->next; else prev->next = ed->next; ed->next = NULL; 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(ch)->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(ch)->name); return FALSE; } mlstr_for_each(&ed->description, NULL, cb_format); char_puts("Extra description formatted.\n", ch); return TRUE; } do_help(ch, "'OLC EXD'"); return FALSE; } bool olced_flag64(CHAR_DATA *ch, const char *argument, olc_cmd_t* cmd, flag64_t *pflag) { const flag_t *flag64_table; const flag_t *f; flag64_t ttype; const char *tname; if (!cmd->arg1) { char_printf(ch, "%s: %s: Table of values undefined (report it to implementors).\n", OLCED(ch)->name, cmd->name); return FALSE; } if (!str_cmp(argument, "?")) { show_flags(ch, cmd->arg1); return FALSE; } flag64_table = cmd->arg1; tname = flag64_table->name; ttype = flag64_table->bit; flag64_table++; switch (ttype) { case TABLE_BITVAL: { flag64_t marked = 0; /* * Accept multiple flags. */ for (;;) { char word[MAX_INPUT_LENGTH]; argument = one_argument(argument, word, sizeof(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(ch)->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(ch)->name, cmd->name, flag_string(cmd->arg1, marked)); return TRUE; } return FALSE; /* NOT REACHED */ } case TABLE_INTVAL: 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(ch)->name, cmd->name, f->name); return FALSE; } *pflag = f->bit; char_printf(ch, "%s: %s: '%s': Ok.\n", OLCED(ch)->name, cmd->name, f->name); return TRUE; /* NOT REACHED */ default: char_printf(ch, "%s: %s: %s: table type %d unknown (report it to implementors).\n", OLCED(ch)->name, cmd->name, tname, ttype); return FALSE; /* NOT REACHED */ } } bool olced_flag32(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, flag32_t *psflag) { flag64_t flag = (flag64_t) (*psflag); bool retval = olced_flag64(ch, argument, cmd, &flag); if (retval) *psflag = (flag32_t) flag; return retval; } bool olced_dice(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, int *dice) { int num, type, bonus; char* p; 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_cmd_t *cmd, int *vnum) { int cln; 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 ((cln = cln_lookup(argument)) < 0) { char_printf(ch, "'%s': unknown clan.\n", argument); return FALSE; } *vnum = cln; return TRUE; } bool olced_material(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, material_t **matp) { int imat = 0; int i = 0; if (IS_NULLSTR(argument)) { char_printf(ch, "Syntax: %s material\n" "Use 'material ?' for list of valid materials.\n" "Use 'material none' to reset material.\n", cmd->name); return FALSE; } if (!str_cmp(argument, "?")) { for (i = 0; i < materials.nused; i++) { char_printf(ch, "[%3d] %-15s ", i, MATERIAL(i)->name); if ((i+1) % 3 == 0) char_printf(ch, "\n"); } return FALSE; } if ((imat = material_lookup_name(argument)) < 0) { char_printf(ch, "'%s': unknown material.\n", argument); return FALSE; } *matp = MATERIAL(imat); char_printf(ch, "Material set to '{c%s{x'.\n", (*matp)->name); return TRUE; } bool olced_rulecl(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, lang_t *l) { char arg[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int rulecl; argument = one_argument(argument, arg, sizeof(arg)); argument = one_argument(argument, arg2, sizeof(arg2)); if (argument[0] == '\0') { do_help(ch, "'OLC RULECLASS'"); return FALSE; } if ((rulecl = flag_value(rulecl_names, arg)) < 0) { char_printf(ch, "%s: %s: unknown rule class\n", OLCED(ch)->name, arg); return FALSE; } if (!str_prefix(arg2, "implicit")) { cmd->arg1 = validate_filename; return olced_str(ch, argument, cmd, &l->rules[rulecl].file_impl); } if (!str_prefix(arg2, "explicit")) { cmd->arg1 = validate_filename; return olced_str(ch, argument, cmd, &l->rules[rulecl].file_expl); } if (!str_prefix(arg2, "flags")) { cmd->arg1 = rulecl_flags; return olced_flag32(ch, argument, cmd, &l->rules[rulecl].flags); } do_help(ch, "'OLC RULECLASS'"); return FALSE; } bool olced_vform_add(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, rule_t *r) { char arg[MAX_STRING_LENGTH]; argument = one_argument(argument, arg, sizeof(arg)); if (argument[0] == '\0' || !is_number(arg)) { do_help(ch, "'OLC VFORM'"); return FALSE; } vform_add(r->f, atoi(arg), argument); char_puts("Form added.\n", ch); return TRUE; } bool olced_vform_del(CHAR_DATA *ch, const char *argument, olc_cmd_t *cmd, rule_t *r) { char arg[MAX_STRING_LENGTH]; argument = one_argument(argument, arg, sizeof(arg)); if (!is_number(arg)) { do_help(ch, "'OLC FORM'"); return FALSE; } vform_del(r->f, atoi(arg)); char_puts("Form deleted.\n", ch); return TRUE; } VALIDATE_FUN(validate_filename) { if (strpbrk(arg, "/")) { char_printf(ch, "%s: Invalid characters in file name.\n", OLCED(ch)->name); 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. ****************************************************************************/ OLC_FUN(show_commands) { BUFFER * output; int col; output = buf_new(-1); col = 0; for (cmd = OLCED(ch)->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; } OLC_FUN(show_version) { char_puts(OLC_VERSION "\n" AUTHOR "\n" DATE "\n" CREDITS "\n", ch); return FALSE; } AREA_DATA *get_edited_area(CHAR_DATA *ch) { int vnum; olced_t *olced = OLCED(ch); void *p = ch->desc->pEdit; if (!olced) return NULL; if (olced->id == ED_AREA) return p; if (olced->id == ED_HELP) return ((HELP_DATA*) p)->area; if (olced->id == ED_ROOM) return ch->in_room->area; if (olced->id == ED_OBJ) vnum = ((OBJ_INDEX_DATA*) p)->vnum; else if (olced->id == ED_MOB) vnum = ((MOB_INDEX_DATA*) p)->vnum; else if (olced->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->olced = NULL; } /* Local functions */ /* lookup OLC editor by id */ olced_t *olced_lookup(const char * id) { olced_t *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 name */ static olc_cmd_t *cmd_lookup(olc_cmd_t *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'", str_empty, "'OLC ASHOW'", "'OLC ALIST'" }; static void do_olc(CHAR_DATA *ch, const char *argument, int fun) { char command[MAX_INPUT_LENGTH]; olced_t *olced; if (IS_NPC(ch)) return; argument = one_argument(argument, command, sizeof(command)); if ((olced = olced_lookup(command)) == NULL) { do_help(ch, help_topics[fun]); return; } olced->cmd_table[fun].olc_fun(ch, argument, olced->cmd_table+fun); }