mirror of
https://github.com/tbamud/tbamud.git
synced 2025-09-22 05:50:48 +02:00
1865 lines
77 KiB
C
1865 lines
77 KiB
C
/**************************************************************************
|
|
* File: interpreter.c Part of tbaMUD *
|
|
* Usage: Parse user commands, search for specials, call ACMD functions. *
|
|
* *
|
|
* All rights reserved. See license for complete information. *
|
|
* *
|
|
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
|
|
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
|
|
**************************************************************************/
|
|
|
|
#define __INTERPRETER_C__
|
|
|
|
#include "conf.h"
|
|
#include "sysdep.h"
|
|
#include "structs.h"
|
|
#include "utils.h"
|
|
#include "comm.h"
|
|
#include "interpreter.h"
|
|
#include "db.h"
|
|
#include "spells.h"
|
|
#include "handler.h"
|
|
#include "mail.h"
|
|
#include "screen.h"
|
|
#include "genolc.h"
|
|
#include "oasis.h"
|
|
#include "improved-edit.h"
|
|
#include "dg_scripts.h"
|
|
#include "constants.h"
|
|
#include "act.h" /* ACMDs located within the act*.c files */
|
|
#include "ban.h"
|
|
#include "class.h"
|
|
#include "graph.h"
|
|
#include "hedit.h"
|
|
#include "house.h"
|
|
#include "config.h"
|
|
#include "modify.h" /* for do_skillset... */
|
|
#include "quest.h"
|
|
#include "asciimap.h"
|
|
#include "prefedit.h"
|
|
#include "ibt.h"
|
|
|
|
/* local (file scope) functions */
|
|
static int perform_dupe_check(struct descriptor_data *d);
|
|
static bool perform_new_char_dupe_check(struct descriptor_data *d);
|
|
static struct alias_data *find_alias(struct alias_data *alias_list, char *str);
|
|
static void perform_complex_alias(struct txt_q *input_q, char *orig, struct alias_data *a);
|
|
static int _parse_name(char *arg, char *name);
|
|
/* sort_commands utility */
|
|
static int sort_commands_helper(const void *a, const void *b);
|
|
|
|
/* globals defined here, used here and elsewhere */
|
|
int *cmd_sort_info = NULL;
|
|
|
|
struct command_info *complete_cmd_info;
|
|
|
|
/* This is the Master Command List. You can put new commands in, take commands
|
|
* out, change the order they appear in, etc. You can adjust the "priority"
|
|
* of commands simply by changing the order they appear in the command list.
|
|
* (For example, if you want "as" to mean "assist" instead of "ask", just put
|
|
* "assist" above "ask" in the Master Command List. In general, utility
|
|
* commands such as "at" should have high priority; infrequently used and
|
|
* dangerously destructive commands should have low priority. */
|
|
|
|
/* The new command list has 8 columns, which are:
|
|
* command - The full command typed by players
|
|
* sort by - Ensure a command is sorted before a similar social
|
|
* min pos - Minimum position for player to use the command
|
|
* ACMD func - The handler function called when commmand is used
|
|
* Min Level - The minimum mortal level for this command
|
|
* Min Admin - Min. Admin level - over-rides mortal level unless ADMLVL_MORTAL
|
|
* Admin Flag - Required admin flag - over-rides admin level unless ADM_NONE
|
|
* Subcommand - Subcommand passed to handler function
|
|
*
|
|
* If Admin flag is set, admin level should be what would normally be set for the command, even
|
|
* though it's not used. This then shows in wizhelp or commands.
|
|
*/
|
|
cpp_extern const struct command_info cmd_info[] = {
|
|
{ "RESERVED", "", 0, 0, 0, 0, 0, 0 }, /* this must be first -- for specprocs */
|
|
|
|
/* directions must come before other commands but after RESERVED */
|
|
{ "north" , "n" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NORTH },
|
|
{ "east" , "e" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_EAST },
|
|
{ "south" , "s" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SOUTH },
|
|
{ "west" , "w" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_WEST },
|
|
{ "up" , "u" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_UP },
|
|
{ "down" , "d" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_DOWN },
|
|
{ "northwest", "northw" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NW },
|
|
{ "nw" , "nw" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NW },
|
|
{ "northeast", "northe" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NE },
|
|
{ "ne" , "ne" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NE },
|
|
{ "southeast", "southe" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SE },
|
|
{ "se" , "se" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SE },
|
|
{ "southwest", "southw" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SW },
|
|
{ "sw" , "sw" , POS_STANDING, do_move , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SW },
|
|
|
|
/* now, the main list */
|
|
{ "at" , "at" , POS_DEAD , do_at , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "admin" , "adm" , POS_DEAD , do_admin , 0, ADMLVL_IMPL, ADM_ADMIN, 0 },
|
|
{ "advance" , "adv" , POS_DEAD , do_advance , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "aedit" , "aed" , POS_DEAD , do_oasis_aedit,0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "alias" , "ali" , POS_DEAD , do_alias , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "afk" , "afk" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AFK },
|
|
{ "areas" , "are" , POS_DEAD , do_areas , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "assist" , "as" , POS_FIGHTING, do_assist , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "ask" , "ask" , POS_RESTING , do_spec_comm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_ASK },
|
|
{ "astat" , "ast" , POS_DEAD , do_astat , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "attach" , "attach" , POS_DEAD , do_attach , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "auction" , "auc" , POS_SLEEPING, do_gen_comm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUCTION },
|
|
{ "autoexits" , "autoex" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOEXIT },
|
|
{ "autoassist","autoass" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOASSIST },
|
|
{ "autodoor" , "autodoor", POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTODOOR },
|
|
{ "autogold" , "autogold", POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOGOLD },
|
|
{ "autokey" , "autokey" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOKEY },
|
|
{ "autoloot" , "autoloot", POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOLOOT },
|
|
{ "automap" , "automap" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOMAP },
|
|
{ "autosac" , "autosac" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOSAC },
|
|
{ "autosplit", "autospl" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_AUTOSPLIT },
|
|
|
|
{ "backstab" , "ba" , POS_STANDING, do_backstab , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "ban" , "ban" , POS_DEAD , do_ban , 0, ADMLVL_GRGOD, ADM_NONE, 0 },
|
|
{ "balance" , "bal" , POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "bash" , "bas" , POS_FIGHTING, do_bash , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "brief" , "br" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_BRIEF },
|
|
{ "buildwalk", "buildwalk",POS_STANDING, do_gen_tog , 0, ADMLVL_BUILDER, ADM_NONE, SCMD_BUILDWALK },
|
|
{ "buy" , "bu" , POS_STANDING, do_not_here , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "bug" , "bug" , POS_DEAD , do_ibt , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_BUG },
|
|
|
|
{ "cast" , "c" , POS_SITTING , do_cast , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "cedit" , "cedit" , POS_DEAD , do_oasis_cedit,0, ADMLVL_IMPL, ADM_CEDIT, 0 },
|
|
{ "changelog", "cha" , POS_DEAD , do_changelog , 0, ADMLVL_IMPL, ADM_NONE, 0 },
|
|
{ "check" , "ch" , POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "checkload", "checkl" , POS_DEAD , do_checkloadstatus,0, ADMLVL_GOD, ADM_ADVBUILD, 0 },
|
|
{ "close" , "cl" , POS_SITTING , do_gen_door , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_CLOSE },
|
|
{ "clear" , "cle" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_CLEAR },
|
|
{ "cls" , "cls" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_CLEAR },
|
|
{ "cmdinfo" , "cmd" , POS_DEAD , do_cmdinfo , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "consider" , "con" , POS_RESTING , do_consider , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "commands" , "com" , POS_DEAD , do_commands , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_COMMANDS },
|
|
{ "compact" , "comp" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_COMPACT },
|
|
{ "copyover" , "copyover", POS_DEAD , do_copyover , 0, ADMLVL_GRGOD, ADM_NONE, 0 },
|
|
{ "credits" , "cred" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_CREDITS },
|
|
|
|
{ "date" , "da" , POS_DEAD , do_date , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_DATE },
|
|
{ "dc" , "dc" , POS_DEAD , do_dc , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "deposit" , "depo" , POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "detach" , "detach" , POS_DEAD , do_detach , 0, ADMLVL_BUILDER, ADM_ADVBUILD, 0 },
|
|
{ "diagnose" , "diag" , POS_RESTING , do_diagnose , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "dig" , "dig" , POS_DEAD , do_dig , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "display" , "disp" , POS_DEAD , do_display , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "donate" , "don" , POS_RESTING , do_drop , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_DONATE },
|
|
{ "drink" , "dri" , POS_RESTING , do_drink , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_DRINK },
|
|
{ "drop" , "dro" , POS_RESTING , do_drop , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_DROP },
|
|
|
|
{ "eat" , "ea" , POS_RESTING , do_eat , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_EAT },
|
|
{ "echo" , "ec" , POS_SLEEPING, do_echo , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_ECHO },
|
|
{ "emote" , "em" , POS_RESTING , do_echo , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_EMOTE },
|
|
{ ":" , ":" , POS_RESTING, do_echo , 1, ADMLVL_MORTAL, ADM_NONE, SCMD_EMOTE },
|
|
{ "enter" , "ent" , POS_STANDING, do_enter , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "equipment", "eq" , POS_SLEEPING, do_equipment , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "exits" , "ex" , POS_RESTING , do_exits , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "examine" , "exa" , POS_SITTING , do_examine , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "export" , "export" , POS_DEAD , do_export_zone,0, ADMLVL_IMPL, ADM_NONE, 0 },
|
|
|
|
{ "force" , "force" , POS_SLEEPING, do_force , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "fill" , "fil" , POS_STANDING, do_pour , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_FILL },
|
|
{ "file" , "file" , POS_SLEEPING, do_file , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "flee" , "fl" , POS_FIGHTING, do_flee , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "follow" , "fol" , POS_RESTING , do_follow , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "freeze" , "freeze" , POS_DEAD , do_wizutil , 0, ADMLVL_GRGOD, ADM_NONE, SCMD_FREEZE },
|
|
|
|
{ "get" , "g" , POS_RESTING , do_get , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "gecho" , "gecho" , POS_DEAD , do_gecho , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "gemote" , "gem" , POS_SLEEPING, do_gen_comm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_GEMOTE },
|
|
{ "give" , "giv" , POS_RESTING , do_give , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "goto" , "go" , POS_SLEEPING, do_goto , 0, ADMLVL_MORTAL, ADM_POOF, 0 },
|
|
{ "gold" , "gol" , POS_RESTING , do_gold , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "gossip" , "gos" , POS_SLEEPING, do_gen_comm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_GOSSIP },
|
|
{ "group" , "gr" , POS_RESTING , do_group , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "grab" , "grab" , POS_RESTING , do_grab , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "grats" , "grat" , POS_SLEEPING, do_gen_comm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_GRATZ },
|
|
{ "gsay" , "gsay" , POS_SLEEPING, do_gsay , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "gtell" , "gt" , POS_SLEEPING, do_gsay , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
|
|
{ "help" , "h" , POS_DEAD , do_help , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "happyhour", "ha" , POS_DEAD , do_happyhour , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "hedit" , "hedit" , POS_DEAD , do_oasis_hedit,0, ADMLVL_GOD, ADM_ADVBUILD, 0 },
|
|
{ "hindex" , "hind" , POS_DEAD , do_hindex , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "helpcheck", "helpch" , POS_DEAD , do_helpcheck , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "hide" , "hi" , POS_RESTING , do_hide , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "handbook" , "handb" , POS_DEAD , do_gen_ps , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_HANDBOOK },
|
|
{ "hcontrol" , "hcontrol", POS_DEAD , do_hcontrol , 0, ADMLVL_GRGOD, ADM_NONE, 0 },
|
|
{ "history" , "history" , POS_DEAD , do_history , 0, ADMLVL_MORTAL, ADM_NONE, 0},
|
|
{ "hit" , "hit" , POS_FIGHTING, do_hit , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_HIT },
|
|
{ "hold" , "hold" , POS_RESTING , do_grab , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "holler" , "holler" , POS_RESTING , do_gen_comm , 1, ADMLVL_MORTAL, ADM_NONE, SCMD_HOLLER },
|
|
{ "holylight", "holy" , POS_DEAD , do_gen_tog , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_HOLYLIGHT },
|
|
{ "house" , "house" , POS_RESTING , do_house , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "hsedit" , "hsedit" , POS_DEAD , do_oasis_hsedit,0,ADMLVL_GOD, ADM_ADVBUILD, 0 },
|
|
|
|
{ "inventory", "i" , POS_DEAD , do_inventory , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "identify" , "id" , POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "idea" , "ide" , POS_DEAD , do_ibt , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_IDEA },
|
|
{ "imotd" , "imo" , POS_DEAD , do_gen_ps , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_IMOTD },
|
|
{ "immlist" , "imm" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_IMMLIST },
|
|
{ "info" , "info" , POS_SLEEPING, do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_INFO },
|
|
{ "invis" , "invi" , POS_DEAD , do_invis , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
|
|
{ "junk" , "j" , POS_RESTING , do_drop , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_JUNK },
|
|
|
|
{ "kill" , "k" , POS_FIGHTING, do_kill , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "kick" , "ki" , POS_FIGHTING, do_kick , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
|
|
{ "look" , "l" , POS_RESTING , do_look , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_LOOK },
|
|
{ "last" , "last" , POS_DEAD , do_last , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "leave" , "lea" , POS_STANDING, do_leave , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "levels" , "lev" , POS_DEAD , do_levels , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "list" , "lis" , POS_STANDING, do_not_here , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "links" , "lin" , POS_STANDING, do_links , 0, ADMLVL_GOD, ADM_ADVBUILD, 0 },
|
|
{ "lock" , "loc" , POS_SITTING , do_gen_door , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_LOCK },
|
|
{ "load" , "load" , POS_DEAD , do_load , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
|
|
{ "motd" , "motd" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_MOTD },
|
|
{ "mortal" , "mort" , POS_DEAD , do_mortal , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "mail" , "mail" , POS_STANDING, do_mail , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "map" , "map" , POS_STANDING, do_map , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "medit" , "med" , POS_DEAD , do_oasis_medit,0, ADMLVL_BUILDER, ADM_NONE, 0 },
|
|
{ "mlist" , "mlist" , POS_DEAD , do_oasis_list, 0, ADMLVL_BUILDER, ADM_BUILD, SCMD_OASIS_MLIST },
|
|
{ "mcopy" , "mcopy" , POS_DEAD , do_oasis_copy, 0, ADMLVL_GOD, ADM_ADVBUILD, CON_MEDIT },
|
|
{ "mute" , "mute" , POS_DEAD , do_wizutil , 0, ADMLVL_GOD, ADM_NONE, SCMD_MUTE },
|
|
|
|
{ "news" , "news" , POS_SLEEPING, do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NEWS },
|
|
{ "noauction", "noauction",POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NOAUCTION },
|
|
{ "nogossip" , "nogossip", POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NOGOSSIP },
|
|
{ "nograts" , "nograts" , POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NOGRATZ },
|
|
{ "nohassle" , "nohassle", POS_DEAD , do_gen_tog , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_NOHASSLE },
|
|
{ "norepeat" , "norepeat", POS_DEAD , do_gen_tog , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_NOREPEAT },
|
|
{ "noshout" , "noshout" , POS_SLEEPING, do_gen_tog , 1, ADMLVL_MORTAL, ADM_NONE, SCMD_NOSHOUT },
|
|
{ "nosummon" , "nosummon", POS_DEAD , do_gen_tog , 1, ADMLVL_MORTAL, ADM_NONE, SCMD_NOSUMMON },
|
|
{ "notell" , "notell" , POS_DEAD , do_gen_tog , 1, ADMLVL_MORTAL, ADM_NONE, SCMD_NOTELL },
|
|
{ "notitle" , "notitle" , POS_DEAD , do_wizutil , 0, ADMLVL_GOD, ADM_NONE, SCMD_NOTITLE },
|
|
{ "nowiz" , "nowiz" , POS_DEAD , do_gen_tog , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_NOWIZ },
|
|
|
|
{ "open" , "o" , POS_SITTING , do_gen_door , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_OPEN },
|
|
{ "order" , "ord" , POS_RESTING , do_order , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "offer" , "off" , POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "olc" , "olc" , POS_DEAD , do_show_save_list,0,ADMLVL_BUILDER,ADM_BUILD,0 },
|
|
{ "olist" , "olist" , POS_DEAD , do_oasis_list, 0, ADMLVL_BUILDER, ADM_BUILD, SCMD_OASIS_OLIST },
|
|
{ "oedit" , "oedit" , POS_DEAD , do_oasis_oedit,0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "ocopy" , "ocopy" , POS_DEAD , do_oasis_copy, 0, ADMLVL_GOD, ADM_ADVBUILD, CON_OEDIT },
|
|
|
|
{ "put" , "p" , POS_RESTING , do_put , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "peace" , "pe" , POS_DEAD , do_peace , 0, ADMLVL_BUILDER, ADM_NONE, 0 },
|
|
{ "pick" , "pi" , POS_STANDING, do_gen_door , 1, ADMLVL_MORTAL, ADM_NONE, SCMD_PICK },
|
|
{ "practice" , "pr" , POS_RESTING , do_practice , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "page" , "pag" , POS_DEAD , do_page , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "pardon" , "pardon" , POS_DEAD , do_wizutil , 0, ADMLVL_GOD, ADM_NONE, SCMD_PARDON },
|
|
{ "plist" , "plist" , POS_DEAD , do_plist , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "policy" , "pol" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_POLICIES },
|
|
{ "pour" , "pour" , POS_STANDING, do_pour , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_POUR },
|
|
{ "prompt" , "pro" , POS_DEAD , do_display , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "prefedit" , "pre" , POS_DEAD , do_oasis_prefedit,0,ADMLVL_MORTAL,ADM_NONE, 0 },
|
|
{ "purge" , "purge" , POS_DEAD , do_purge , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
|
|
{ "qedit" , "qedit" , POS_DEAD , do_oasis_qedit,0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "qlist" , "qlist" , POS_DEAD , do_oasis_list, 0, ADMLVL_BUILDER, ADM_BUILD, SCMD_OASIS_QLIST },
|
|
{ "quaff" , "qua" , POS_RESTING , do_use , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_QUAFF },
|
|
{ "qecho" , "qec" , POS_DEAD , do_qcomm , 0, ADMLVL_GOD, ADM_NONE, SCMD_QECHO },
|
|
{ "quest" , "que" , POS_DEAD , do_quest , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "qui" , "qui" , POS_DEAD , do_quit , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "quit" , "quit" , POS_DEAD , do_quit , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_QUIT },
|
|
{ "qsay" , "qsay" , POS_RESTING , do_qcomm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_QSAY },
|
|
|
|
{ "reply" , "r" , POS_SLEEPING, do_reply , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "rest" , "res" , POS_RESTING , do_rest , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "read" , "rea" , POS_RESTING , do_look , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_READ },
|
|
{ "reload" , "reload" , POS_DEAD , do_reboot , 0, ADMLVL_IMPL, ADM_NONE, 0 },
|
|
{ "recite" , "reci" , POS_RESTING , do_use , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_RECITE },
|
|
{ "receive" , "rece" , POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "recent" , "recent" , POS_DEAD , do_recent , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "remove" , "rem" , POS_RESTING , do_remove , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "rent" , "rent" , POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "report" , "repo" , POS_RESTING , do_report , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "reroll" , "rero" , POS_DEAD , do_wizutil , 0, ADMLVL_GRGOD, ADM_NONE, SCMD_REROLL },
|
|
{ "rescue" , "resc" , POS_FIGHTING, do_rescue , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "restore" , "resto" , POS_DEAD , do_restore , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "return" , "retu" , POS_DEAD , do_return , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "redit" , "redit" , POS_DEAD , do_oasis_redit,0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "rlist" , "rlist" , POS_DEAD , do_oasis_list, 0, ADMLVL_BUILDER, ADM_BUILD, SCMD_OASIS_RLIST },
|
|
{ "rcopy" , "rcopy" , POS_DEAD , do_oasis_copy, 0, ADMLVL_GOD, ADM_ADVBUILD, CON_REDIT },
|
|
{ "roomflags", "roomflags", POS_DEAD , do_gen_tog , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_SHOWVNUMS },
|
|
|
|
{ "say" , "s" , POS_RESTING , do_say , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "sacrifice", "sac" , POS_RESTING , do_sac , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "score" , "sc" , POS_DEAD , do_score , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "scan" , "sca" , POS_RESTING , do_scan , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "scopy" , "scopy" , POS_DEAD , do_oasis_copy, 0, ADMLVL_GOD, ADM_ADVBUILD, CON_SEDIT },
|
|
{ "sit" , "si" , POS_RESTING , do_sit , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "'" , "'" , POS_RESTING , do_say , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "save" , "sav" , POS_SLEEPING, do_save , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "saveall" , "saveall" , POS_DEAD , do_saveall , 0, ADMLVL_BUILDER, ADM_BUILD, 0},
|
|
{ "sell" , "sell" , POS_STANDING, do_not_here , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "sedit" , "sedit" , POS_DEAD , do_oasis_sedit,0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "send" , "send" , POS_SLEEPING, do_send , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "set" , "set" , POS_DEAD , do_set , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "shout" , "sho" , POS_RESTING , do_gen_comm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SHOUT },
|
|
{ "show" , "show" , POS_DEAD , do_show , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "shutdow" , "shutdow" , POS_DEAD , do_shutdown , 0, ADMLVL_IMPL, ADM_NONE, 0 },
|
|
{ "shutdown" , "shutdown", POS_DEAD , do_shutdown , 0, ADMLVL_IMPL, ADM_NONE, SCMD_SHUTDOWN },
|
|
{ "sip" , "sip" , POS_RESTING , do_drink , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SIP },
|
|
{ "skillset" , "skillset", POS_SLEEPING, do_skillset , 0, ADMLVL_GRGOD, ADM_NONE, 0 },
|
|
{ "sleep" , "sl" , POS_SLEEPING, do_sleep , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "slist" , "slist" , POS_SLEEPING, do_oasis_list, 0, ADMLVL_BUILDER, ADM_BUILD, SCMD_OASIS_SLIST },
|
|
{ "sneak" , "sneak" , POS_STANDING, do_sneak , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "snoop" , "snoop" , POS_DEAD , do_snoop , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
{ "socials" , "socials" , POS_DEAD , do_commands , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_SOCIALS },
|
|
{ "split" , "split" , POS_SITTING , do_split , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "stand" , "st" , POS_RESTING , do_stand , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "stat" , "stat" , POS_DEAD , do_stat , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "steal" , "ste" , POS_STANDING, do_steal , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "switch" , "switch" , POS_DEAD , do_switch , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
|
|
{ "tell" , "t" , POS_DEAD , do_tell , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "take" , "ta" , POS_RESTING , do_get , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "taste" , "tas" , POS_RESTING , do_eat , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_TASTE },
|
|
{ "teleport" , "tele" , POS_DEAD , do_teleport , 0, ADMLVL_BUILDER, ADM_POOF, 0 },
|
|
{ "tedit" , "tedit" , POS_DEAD , do_tedit , 0, ADMLVL_GOD, ADM_ADVBUILD, 0 }, /* XXX: Oasisify */
|
|
{ "thaw" , "thaw" , POS_DEAD , do_wizutil , 0, ADMLVL_GRGOD, ADM_NONE, SCMD_THAW },
|
|
{ "title" , "title" , POS_DEAD , do_title , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "time" , "time" , POS_DEAD , do_time , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "toggle" , "toggle" , POS_DEAD , do_toggle , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "track" , "track" , POS_STANDING, do_track , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "transfer" , "transfer", POS_SLEEPING, do_trans , 0, ADMLVL_GOD, ADM_POOF, 0 },
|
|
{ "trigedit" , "trigedit", POS_DEAD , do_oasis_trigedit,0,ADMLVL_BUILDER,ADM_BUILD,0 },
|
|
{ "typo" , "typo" , POS_DEAD , do_ibt , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_TYPO },
|
|
{ "tlist" , "tlist" , POS_DEAD , do_oasis_list, 0, ADMLVL_BUILDER, ADM_BUILD, SCMD_OASIS_TLIST },
|
|
{ "tcopy" , "tcopy" , POS_DEAD , do_oasis_copy, 0, ADMLVL_GOD, ADM_ADVBUILD, CON_TRIGEDIT },
|
|
{ "tstat" , "tstat" , POS_DEAD , do_tstat , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
|
|
{ "unlock" , "unlock" , POS_SITTING , do_gen_door , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_UNLOCK },
|
|
{ "ungroup" , "ungroup" , POS_DEAD , do_ungroup , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "unban" , "unban" , POS_DEAD , do_unban , 0, ADMLVL_GRGOD, ADM_NONE, 0 },
|
|
{ "unaffect" , "unaffect", POS_DEAD , do_wizutil , 0, ADMLVL_GOD, ADM_NONE, SCMD_UNAFFECT },
|
|
{ "uptime" , "uptime" , POS_DEAD , do_date , 0, ADMLVL_GOD, ADM_NONE, SCMD_UPTIME },
|
|
{ "use" , "use" , POS_SITTING , do_use , 1, ADMLVL_MORTAL, ADM_NONE, SCMD_USE },
|
|
{ "users" , "users" , POS_DEAD , do_users , 0, ADMLVL_GOD, ADM_NONE, 0 },
|
|
|
|
{ "value" , "val" , POS_STANDING, do_not_here , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "version" , "ver" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_VERSION },
|
|
{ "visible" , "vis" , POS_RESTING , do_visible , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "vnum" , "vnum" , POS_DEAD , do_vnum , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "vstat" , "vstat" , POS_DEAD , do_vstat , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "vdelete" , "vdelete" , POS_DEAD , do_vdelete , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
|
|
{ "wake" , "wake" , POS_SLEEPING, do_wake , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "wear" , "wea" , POS_RESTING , do_wear , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "weather" , "weather" , POS_RESTING , do_weather , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "who" , "wh" , POS_DEAD , do_who , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "whois" , "whoi" , POS_DEAD , do_whois , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "whoami" , "whoami" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_WHOAMI },
|
|
{ "where" , "where" , POS_RESTING , do_where , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "whisper" , "whisper" , POS_RESTING , do_spec_comm , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_WHISPER },
|
|
{ "wield" , "wie" , POS_RESTING , do_wield , 0, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "withdraw" , "withdraw", POS_STANDING, do_not_here , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
{ "wiznet" , "wiz" , POS_DEAD , do_wiznet , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ ";" , ";" , POS_DEAD , do_wiznet , 0, ADMLVL_IMMORT, ADM_NONE, 0 },
|
|
{ "wizhelp" , "wizhelp" , POS_SLEEPING, do_commands , 0, ADMLVL_IMMORT, ADM_NONE, SCMD_WIZHELP },
|
|
{ "wizlist" , "wizlist" , POS_DEAD , do_gen_ps , 0, ADMLVL_MORTAL, ADM_NONE, SCMD_WIZLIST },
|
|
{ "wizupdate", "wizupde" , POS_DEAD , do_wizupdate , 0, ADMLVL_GRGOD, ADM_NONE, 0 },
|
|
{ "wizlock" , "wizlock" , POS_DEAD , do_wizlock , 0, ADMLVL_IMPL, ADM_NONE, 0 },
|
|
{ "write" , "write" , POS_STANDING, do_write , 1, ADMLVL_MORTAL, ADM_NONE, 0 },
|
|
|
|
{ "zreset" , "zreset" , POS_DEAD , do_zreset , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "zedit" , "zedit" , POS_DEAD , do_oasis_zedit,0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "zlist" , "zlist" , POS_DEAD , do_oasis_list, 0, ADMLVL_BUILDER, ADM_BUILD, SCMD_OASIS_ZLIST },
|
|
{ "zlock" , "zlock" , POS_DEAD , do_zlock , 0, ADMLVL_GOD, ADM_ADVBUILD, 0 },
|
|
{ "zunlock" , "zunlock" , POS_DEAD , do_zunlock , 0, ADMLVL_GOD, ADM_ADVBUILD, 0 },
|
|
{ "zcheck" , "zcheck" , POS_DEAD , do_zcheck , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
{ "zpurge" , "zpurge" , POS_DEAD , do_zpurge , 0, ADMLVL_BUILDER, ADM_BUILD, 0 },
|
|
|
|
{ "\n", "zzzzzzz", 0, 0, 0, 0, 0, 0 } }; /* this must be last */
|
|
|
|
|
|
/* Thanks to Melzaren for this change to allow DG Scripts to be attachable
|
|
*to player's while still disallowing them to manually use the DG-Commands. */
|
|
const struct mob_script_command_t mob_script_commands[] = {
|
|
|
|
/* DG trigger commands. minimum_level should be set to -1. */
|
|
{ "masound" , do_masound , 0 },
|
|
{ "mkill" , do_mkill , 0 },
|
|
{ "mjunk" , do_mjunk , 0 },
|
|
{ "mdamage" , do_mdamage , 0 },
|
|
{ "mdoor" , do_mdoor , 0 },
|
|
{ "mecho" , do_mecho , 0 },
|
|
{ "mrecho" , do_mrecho , 0 },
|
|
{ "mechoaround", do_mechoaround , 0 },
|
|
{ "msend" , do_msend , 0 },
|
|
{ "mload" , do_mload , 0 },
|
|
{ "mpurge" , do_mpurge , 0 },
|
|
{ "mgoto" , do_mgoto , 0 },
|
|
{ "mat" , do_mat , 0 },
|
|
{ "mteleport", do_mteleport, 0 },
|
|
{ "mforce" , do_mforce , 0 },
|
|
{ "mhunt" , do_mhunt , 0 },
|
|
{ "mremember", do_mremember, 0 },
|
|
{ "mforget" , do_mforget , 0 },
|
|
{ "mtransform", do_mtransform , 0 },
|
|
{ "mzoneecho", do_mzoneecho, 0 },
|
|
{ "mfollow" , do_mfollow , 0 },
|
|
{ "mmail" , do_mmail , 0 },
|
|
{ "\n" , do_not_here , 0 } };
|
|
|
|
int script_command_interpreter(struct char_data *ch, char *arg) {
|
|
/* DG trigger commands */
|
|
|
|
int i;
|
|
char first_arg[MAX_INPUT_LENGTH];
|
|
char *line;
|
|
|
|
skip_spaces(&arg);
|
|
if (!*arg)
|
|
return 0;
|
|
|
|
line = any_one_arg(arg, first_arg);
|
|
|
|
for (i = 0; *mob_script_commands[i].command_name != '\n'; i++)
|
|
if (!str_cmp(first_arg, mob_script_commands[i].command_name))
|
|
break; // NB - only allow full matches.
|
|
|
|
if (*mob_script_commands[i].command_name == '\n')
|
|
return 0; // no matching commands.
|
|
|
|
/* Poiner to the command? */
|
|
((*mob_script_commands[i].command_pointer) (ch, line, 0,
|
|
mob_script_commands[i].subcmd));
|
|
return 1; // We took care of execution. Let caller know.
|
|
}
|
|
|
|
const char *fill[] =
|
|
{
|
|
"in",
|
|
"from",
|
|
"with",
|
|
"the",
|
|
"on",
|
|
"at",
|
|
"to",
|
|
"\n"
|
|
};
|
|
|
|
const char *reserved[] =
|
|
{
|
|
"a",
|
|
"an",
|
|
"self",
|
|
"me",
|
|
"all",
|
|
"room",
|
|
"someone",
|
|
"something",
|
|
"\n"
|
|
};
|
|
|
|
static int sort_commands_helper(const void *a, const void *b)
|
|
{
|
|
return strcmp(complete_cmd_info[*(const int *)a].sort_as,
|
|
complete_cmd_info[*(const int *)b].sort_as);
|
|
}
|
|
|
|
void sort_commands(void)
|
|
{
|
|
int a, num_of_cmds = 0;
|
|
|
|
while (complete_cmd_info[num_of_cmds].command[0] != '\n')
|
|
num_of_cmds++;
|
|
num_of_cmds++; /* \n */
|
|
|
|
CREATE(cmd_sort_info, int, num_of_cmds);
|
|
|
|
for (a = 0; a < num_of_cmds; a++)
|
|
cmd_sort_info[a] = a;
|
|
|
|
/* Don't sort the RESERVED or \n entries. */
|
|
qsort(cmd_sort_info + 1, num_of_cmds - 2, sizeof(int), sort_commands_helper);
|
|
}
|
|
|
|
/* Returns TRUE if 'ch' has sufficient access to use the command 'cmd' */
|
|
bool can_use_command(struct char_data *ch, int cmd)
|
|
{
|
|
if (complete_cmd_info[cmd].admin_flag == ADM_NONE &&
|
|
complete_cmd_info[cmd].minimum_admlevel == ADMLVL_MORTAL &&
|
|
GET_LEVEL(ch) >= complete_cmd_info[cmd].minimum_level)
|
|
return TRUE;
|
|
|
|
if (complete_cmd_info[cmd].admin_flag == ADM_NONE && GET_ADMLEVEL(ch) >= complete_cmd_info[cmd].minimum_admlevel)
|
|
return TRUE;
|
|
|
|
if (complete_cmd_info[cmd].admin_flag != ADM_NONE && ADM_FLAGGED(ch, complete_cmd_info[cmd].admin_flag))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* This is the actual command interpreter called from game_loop() in comm.c
|
|
* It makes sure you are the proper level and position to execute the command,
|
|
* then calls the appropriate function. */
|
|
void command_interpreter(struct char_data *ch, char *argument)
|
|
{
|
|
int cmd, length;
|
|
char *line;
|
|
char arg[MAX_INPUT_LENGTH];
|
|
|
|
REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_HIDE);
|
|
|
|
/* just drop to next line for hitting CR */
|
|
skip_spaces(&argument);
|
|
if (!*argument)
|
|
return;
|
|
|
|
/* special case to handle one-character, non-alphanumeric commands; requested
|
|
* by many people so "'hi" or ";godnet test" is possible. Patch sent by Eric
|
|
* Green and Stefan Wasilewski. */
|
|
if (!isalpha(*argument)) {
|
|
arg[0] = argument[0];
|
|
arg[1] = '\0';
|
|
line = argument + 1;
|
|
} else
|
|
line = any_one_arg(argument, arg);
|
|
|
|
/* Since all command triggers check for valid_dg_target before acting, the levelcheck
|
|
* here has been removed. Otherwise, find the command. */
|
|
{
|
|
int cont; /* continue the command checks */
|
|
cont = command_wtrigger(ch, arg, line); /* any world triggers ? */
|
|
if (!cont) cont = command_mtrigger(ch, arg, line); /* any mobile triggers ? */
|
|
if (!cont) cont = command_otrigger(ch, arg, line); /* any object triggers ? */
|
|
if (cont) return; /* yes, command trigger took over */
|
|
}
|
|
|
|
/* Allow IMPLs to switch into mobs to test the commands. */
|
|
if (IS_NPC(ch) && ch->desc && IS_ADMIN(ch->desc->original, ADMLVL_IMPL)) {
|
|
if (script_command_interpreter(ch, argument))
|
|
return;
|
|
}
|
|
|
|
for (length = strlen(arg), cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++)
|
|
if(complete_cmd_info[cmd].command_pointer != do_action &&
|
|
!strncmp(complete_cmd_info[cmd].command, arg, length)) {
|
|
if (complete_cmd_info[cmd].admin_flag == ADM_NONE &&
|
|
complete_cmd_info[cmd].minimum_admlevel == ADMLVL_MORTAL &&
|
|
GET_LEVEL(ch) >= complete_cmd_info[cmd].minimum_level)
|
|
break;
|
|
if (complete_cmd_info[cmd].admin_flag == ADM_NONE && GET_ADMLEVEL(ch) >= complete_cmd_info[cmd].minimum_admlevel)
|
|
break;
|
|
if (complete_cmd_info[cmd].admin_flag != ADM_NONE && ADM_FLAGGED(ch, complete_cmd_info[cmd].admin_flag))
|
|
break;
|
|
}
|
|
|
|
/* it's not a 'real' command, so it's a social */
|
|
|
|
if(*complete_cmd_info[cmd].command == '\n')
|
|
for (length = strlen(arg), cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++)
|
|
if (complete_cmd_info[cmd].command_pointer == do_action &&
|
|
!strncmp(complete_cmd_info[cmd].command, arg, length)) {
|
|
if (complete_cmd_info[cmd].admin_flag == ADM_NONE &&
|
|
complete_cmd_info[cmd].minimum_admlevel == ADMLVL_MORTAL &&
|
|
GET_LEVEL(ch) >= complete_cmd_info[cmd].minimum_level)
|
|
break;
|
|
if (complete_cmd_info[cmd].admin_flag == ADM_NONE && GET_ADMLEVEL(ch) >= complete_cmd_info[cmd].minimum_admlevel)
|
|
break;
|
|
if (complete_cmd_info[cmd].admin_flag != ADM_NONE && ADM_FLAGGED(ch, complete_cmd_info[cmd].admin_flag))
|
|
break;
|
|
}
|
|
|
|
if (*complete_cmd_info[cmd].command == '\n') {
|
|
int found = 0;
|
|
send_to_char(ch, "Huh!?!\r\n");
|
|
|
|
for (cmd = 0; *cmd_info[cmd].command != '\n'; cmd++)
|
|
{
|
|
if (*arg != *cmd_info[cmd].command || cmd_info[cmd].minimum_level > GET_LEVEL(ch))
|
|
continue;
|
|
|
|
/* Only apply levenshtein counts if the command is not a trigger command. */
|
|
if ( (levenshtein_distance(arg, cmd_info[cmd].command) <= 2) &&
|
|
(cmd_info[cmd].minimum_level >= 0) )
|
|
{
|
|
/* Does this person have access to this command? */
|
|
if (can_use_command(ch, cmd)) {
|
|
if (!found)
|
|
{
|
|
send_to_char(ch, "\r\nDid you mean:\r\n");
|
|
found = 1;
|
|
}
|
|
send_to_char(ch, " %s\r\n", cmd_info[cmd].command);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!IS_NPC(ch) && PLR_FLAGGED(ch, PLR_FROZEN) && !IS_ADMIN(ch, ADMLVL_IMPL))
|
|
send_to_char(ch, "You try, but the mind-numbing cold prevents you...\r\n");
|
|
else if (complete_cmd_info[cmd].command_pointer == NULL)
|
|
send_to_char(ch, "Sorry, that command hasn't been implemented yet.\r\n");
|
|
else if (IS_NPC(ch) && complete_cmd_info[cmd].minimum_admlevel >= ADMLVL_IMMORT)
|
|
send_to_char(ch, "You can't use immortal commands while switched.\r\n");
|
|
else if (GET_POS(ch) < complete_cmd_info[cmd].minimum_position)
|
|
switch (GET_POS(ch)) {
|
|
case POS_DEAD:
|
|
send_to_char(ch, "Lie still; you are DEAD!!! :-(\r\n");
|
|
break;
|
|
case POS_INCAP:
|
|
case POS_MORTALLYW:
|
|
send_to_char(ch, "You are in a pretty bad shape, unable to do anything!\r\n");
|
|
break;
|
|
case POS_STUNNED:
|
|
send_to_char(ch, "All you can do right now is think about the stars!\r\n");
|
|
break;
|
|
case POS_SLEEPING:
|
|
send_to_char(ch, "In your dreams, or what?\r\n");
|
|
break;
|
|
case POS_RESTING:
|
|
send_to_char(ch, "Nah... You feel too relaxed to do that..\r\n");
|
|
break;
|
|
case POS_SITTING:
|
|
send_to_char(ch, "Maybe you should get on your feet first?\r\n");
|
|
break;
|
|
case POS_FIGHTING:
|
|
send_to_char(ch, "No way! You're fighting for your life!\r\n");
|
|
break;
|
|
} else if (no_specials || !special(ch, cmd, line))
|
|
((*complete_cmd_info[cmd].command_pointer) (ch, line, cmd, complete_cmd_info[cmd].subcmd));
|
|
}
|
|
|
|
/* Routines to handle aliasing. */
|
|
static struct alias_data *find_alias(struct alias_data *alias_list, char *str)
|
|
{
|
|
while (alias_list != NULL) {
|
|
if (*str == *alias_list->alias) /* hey, every little bit counts :-) */
|
|
if (!strcmp(str, alias_list->alias))
|
|
return (alias_list);
|
|
|
|
alias_list = alias_list->next;
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
void free_alias(struct alias_data *a)
|
|
{
|
|
if (a->alias)
|
|
free(a->alias);
|
|
if (a->replacement)
|
|
free(a->replacement);
|
|
free(a);
|
|
}
|
|
|
|
/* The interface to the outside world: do_alias */
|
|
ACMD(do_alias)
|
|
{
|
|
char arg[MAX_INPUT_LENGTH];
|
|
char *repl;
|
|
struct alias_data *a, *temp;
|
|
|
|
if (IS_NPC(ch))
|
|
return;
|
|
|
|
repl = any_one_arg(argument, arg);
|
|
|
|
if (!*arg) { /* no argument specified -- list currently defined aliases */
|
|
send_to_char(ch, "Currently defined aliases:\r\n");
|
|
if ((a = GET_ALIASES(ch)) == NULL)
|
|
send_to_char(ch, " None.\r\n");
|
|
else {
|
|
while (a != NULL) {
|
|
send_to_char(ch, "%-15s %s\r\n", a->alias, a->replacement);
|
|
a = a->next;
|
|
}
|
|
}
|
|
} else { /* otherwise, add or remove aliases */
|
|
/* is this an alias we've already defined? */
|
|
if ((a = find_alias(GET_ALIASES(ch), arg)) != NULL) {
|
|
REMOVE_FROM_LIST(a, GET_ALIASES(ch), next);
|
|
free_alias(a);
|
|
}
|
|
/* if no replacement string is specified, assume we want to delete */
|
|
if (!*repl) {
|
|
if (a == NULL)
|
|
send_to_char(ch, "No such alias.\r\n");
|
|
else
|
|
send_to_char(ch, "Alias deleted.\r\n");
|
|
} else { /* otherwise, either add or redefine an alias */
|
|
if (!str_cmp(arg, "alias")) {
|
|
send_to_char(ch, "You can't alias 'alias'.\r\n");
|
|
return;
|
|
}
|
|
CREATE(a, struct alias_data, 1);
|
|
a->alias = strdup(arg);
|
|
delete_doubledollar(repl);
|
|
a->replacement = strdup(repl);
|
|
if (strchr(repl, ALIAS_SEP_CHAR) || strchr(repl, ALIAS_VAR_CHAR))
|
|
a->type = ALIAS_COMPLEX;
|
|
else
|
|
a->type = ALIAS_SIMPLE;
|
|
a->next = GET_ALIASES(ch);
|
|
GET_ALIASES(ch) = a;
|
|
save_char(ch);
|
|
send_to_char(ch, "Alias ready.\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Valid numeric replacements are only $1 .. $9 (makes parsing a little easier,
|
|
* and it's not that much of a limitation anyway.) Also valid is "$*", which
|
|
* stands for the entire original line after the alias. ";" is used to delimit
|
|
* commands. */
|
|
#define NUM_TOKENS 9
|
|
|
|
static void perform_complex_alias(struct txt_q *input_q, char *orig, struct alias_data *a)
|
|
{
|
|
struct txt_q temp_queue;
|
|
char *tokens[NUM_TOKENS], *temp, *write_point;
|
|
char buf2[MAX_RAW_INPUT_LENGTH], buf[MAX_RAW_INPUT_LENGTH]; /* raw? */
|
|
int num_of_tokens = 0, num;
|
|
|
|
/* First, parse the original string */
|
|
strcpy(buf2, orig); /* strcpy: OK (orig:MAX_INPUT_LENGTH < buf2:MAX_RAW_INPUT_LENGTH) */
|
|
temp = strtok(buf2, " ");
|
|
while (temp != NULL && num_of_tokens < NUM_TOKENS) {
|
|
tokens[num_of_tokens++] = temp;
|
|
temp = strtok(NULL, " ");
|
|
}
|
|
|
|
/* initialize */
|
|
write_point = buf;
|
|
temp_queue.head = temp_queue.tail = NULL;
|
|
|
|
/* now parse the alias */
|
|
for (temp = a->replacement; *temp; temp++) {
|
|
if (*temp == ALIAS_SEP_CHAR) {
|
|
*write_point = '\0';
|
|
buf[MAX_INPUT_LENGTH - 1] = '\0';
|
|
write_to_q(buf, &temp_queue, 1);
|
|
write_point = buf;
|
|
} else if (*temp == ALIAS_VAR_CHAR) {
|
|
temp++;
|
|
if ((num = *temp - '1') < num_of_tokens && num >= 0) {
|
|
strcpy(write_point, tokens[num]); /* strcpy: OK */
|
|
write_point += strlen(tokens[num]);
|
|
} else if (*temp == ALIAS_GLOB_CHAR) {
|
|
strcpy(write_point, orig); /* strcpy: OK */
|
|
write_point += strlen(orig);
|
|
} else if ((*(write_point++) = *temp) == '$') /* redouble $ for act safety */
|
|
*(write_point++) = '$';
|
|
} else
|
|
*(write_point++) = *temp;
|
|
}
|
|
|
|
*write_point = '\0';
|
|
buf[MAX_INPUT_LENGTH - 1] = '\0';
|
|
write_to_q(buf, &temp_queue, 1);
|
|
|
|
/* push our temp_queue on to the _front_ of the input queue */
|
|
if (input_q->head == NULL)
|
|
*input_q = temp_queue;
|
|
else {
|
|
temp_queue.tail->next = input_q->head;
|
|
input_q->head = temp_queue.head;
|
|
}
|
|
}
|
|
|
|
/* Given a character and a string, perform alias replacement on it.
|
|
* Return values:
|
|
* 0: String was modified in place; call command_interpreter immediately.
|
|
* 1: String was _not_ modified in place; rather, the expanded aliases
|
|
* have been placed at the front of the character's input queue. */
|
|
int perform_alias(struct descriptor_data *d, char *orig, size_t maxlen)
|
|
{
|
|
char first_arg[MAX_INPUT_LENGTH], *ptr;
|
|
struct alias_data *a, *tmp;
|
|
|
|
/* Mobs don't have alaises. */
|
|
if (IS_NPC(d->character))
|
|
return (0);
|
|
|
|
/* bail out immediately if the guy doesn't have any aliases */
|
|
if ((tmp = GET_ALIASES(d->character)) == NULL)
|
|
return (0);
|
|
|
|
/* find the alias we're supposed to match */
|
|
ptr = any_one_arg(orig, first_arg);
|
|
|
|
/* bail out if it's null */
|
|
if (!*first_arg)
|
|
return (0);
|
|
|
|
/* if the first arg is not an alias, return without doing anything */
|
|
if ((a = find_alias(tmp, first_arg)) == NULL)
|
|
return (0);
|
|
|
|
if (a->type == ALIAS_SIMPLE) {
|
|
strlcpy(orig, a->replacement, maxlen);
|
|
return (0);
|
|
} else {
|
|
perform_complex_alias(&d->input, ptr, a);
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
/* Various other parsing utilities. */
|
|
|
|
/* Searches an array of strings for a target string. "exact" can be 0 or non-0,
|
|
* depending on whether or not the match must be exact for it to be returned.
|
|
* Returns -1 if not found; 0..n otherwise. Array must be terminated with a
|
|
* '\n' so it knows to stop searching. */
|
|
int search_block(char *arg, const char **list, int exact)
|
|
{
|
|
int i, l;
|
|
|
|
/* We used to have \r as the first character on certain array items to
|
|
* prevent the explicit choice of that point. It seems a bit silly to
|
|
* dump control characters into arrays to prevent that, so we'll just
|
|
* check in here to see if the first character of the argument is '!',
|
|
* and if so, just blindly return a '-1' for not found. - ae. */
|
|
if (*arg == '!')
|
|
return (-1);
|
|
|
|
/* Make into lower case, and get length of string */
|
|
for (l = 0; *(arg + l); l++)
|
|
*(arg + l) = LOWER(*(arg + l));
|
|
|
|
if (exact) {
|
|
for (i = 0; **(list + i) != '\n'; i++)
|
|
if (!strcmp(arg, *(list + i)))
|
|
return (i);
|
|
} else {
|
|
if (!l)
|
|
l = 1; /* Avoid "" to match the first available
|
|
* string */
|
|
for (i = 0; **(list + i) != '\n'; i++)
|
|
if (!strncmp(arg, *(list + i), l))
|
|
return (i);
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
int is_number(const char *str)
|
|
{
|
|
if(*str == '-')
|
|
str++;
|
|
if(!*str)
|
|
return (0);
|
|
while (*str)
|
|
if (!isdigit(*(str++)))
|
|
return (0);
|
|
|
|
return (1);
|
|
}
|
|
|
|
/* Function to skip over the leading spaces of a string. */
|
|
void skip_spaces(char **string)
|
|
{
|
|
for (; **string && isspace(**string); (*string)++);
|
|
}
|
|
|
|
/* Given a string, change all instances of double dollar signs ($$) to single
|
|
* dollar signs ($). When strings come in, all $'s are changed to $$'s to
|
|
* avoid having users be able to crash the system if the inputted string is
|
|
* eventually sent to act(). If you are using user input to produce screen
|
|
* output AND YOU ARE SURE IT WILL NOT BE SENT THROUGH THE act() FUNCTION
|
|
* (i.e., do_gecho, do_title, but NOT do_say), you can call
|
|
* delete_doubledollar() to make the output look correct.
|
|
* Modifies the string in-place. */
|
|
char *delete_doubledollar(char *string)
|
|
{
|
|
char *ddread, *ddwrite;
|
|
|
|
/* If the string has no dollar signs, return immediately */
|
|
if ((ddwrite = strchr(string, '$')) == NULL)
|
|
return (string);
|
|
|
|
/* Start from the location of the first dollar sign */
|
|
ddread = ddwrite;
|
|
|
|
|
|
while (*ddread) /* Until we reach the end of the string... */
|
|
if ((*(ddwrite++) = *(ddread++)) == '$') /* copy one char */
|
|
if (*ddread == '$')
|
|
ddread++; /* skip if we saw 2 $'s in a row */
|
|
|
|
*ddwrite = '\0';
|
|
|
|
return (string);
|
|
}
|
|
|
|
int fill_word(char *argument)
|
|
{
|
|
return (search_block(argument, fill, TRUE) >= 0);
|
|
}
|
|
|
|
int reserved_word(char *argument)
|
|
{
|
|
return (search_block(argument, reserved, TRUE) >= 0);
|
|
}
|
|
|
|
/* Copy the first non-fill-word, space-delimited argument of 'argument'
|
|
* to 'first_arg'; return a pointer to the remainder of the string. */
|
|
char *one_argument(char *argument, char *first_arg)
|
|
{
|
|
char *begin = first_arg;
|
|
|
|
if (!argument) {
|
|
log("SYSERR: one_argument received a NULL pointer!");
|
|
*first_arg = '\0';
|
|
return (NULL);
|
|
}
|
|
|
|
do {
|
|
skip_spaces(&argument);
|
|
|
|
first_arg = begin;
|
|
while (*argument && !isspace(*argument)) {
|
|
*(first_arg++) = LOWER(*argument);
|
|
argument++;
|
|
}
|
|
|
|
*first_arg = '\0';
|
|
} while (fill_word(begin));
|
|
|
|
return (argument);
|
|
}
|
|
|
|
/* one_word is like any_one_arg, except that words in quotes ("") are
|
|
* considered one word. No longer ignores fill words. -dak */
|
|
char *one_word(char *argument, char *first_arg)
|
|
{
|
|
skip_spaces(&argument);
|
|
|
|
if (*argument == '\"') {
|
|
argument++;
|
|
while (*argument && *argument != '\"') {
|
|
*(first_arg++) = LOWER(*argument);
|
|
argument++;
|
|
}
|
|
argument++;
|
|
} else {
|
|
while (*argument && !isspace(*argument)) {
|
|
*(first_arg++) = LOWER(*argument);
|
|
argument++;
|
|
}
|
|
}
|
|
|
|
*first_arg = '\0';
|
|
return (argument);
|
|
}
|
|
|
|
/* Same as one_argument except that it doesn't ignore fill words. */
|
|
char *any_one_arg(char *argument, char *first_arg)
|
|
{
|
|
skip_spaces(&argument);
|
|
|
|
while (*argument && !isspace(*argument)) {
|
|
*(first_arg++) = LOWER(*argument);
|
|
argument++;
|
|
}
|
|
|
|
*first_arg = '\0';
|
|
|
|
return (argument);
|
|
}
|
|
|
|
/* Same as one_argument except that it takes two args and returns the rest;
|
|
* ignores fill words */
|
|
char *two_arguments(char *argument, char *first_arg, char *second_arg)
|
|
{
|
|
return (one_argument(one_argument(argument, first_arg), second_arg)); /* :-) */
|
|
}
|
|
|
|
/* Determine if a given string is an abbreviation of another.
|
|
* Returns 1 if arg1 is an abbreviation of arg2. */
|
|
int is_abbrev(const char *arg1, const char *arg2)
|
|
{
|
|
if (!*arg1)
|
|
return (0);
|
|
|
|
for (; *arg1 && *arg2; arg1++, arg2++)
|
|
if (LOWER(*arg1) != LOWER(*arg2))
|
|
return (0);
|
|
|
|
if (!*arg1)
|
|
return (1);
|
|
else
|
|
return (0);
|
|
}
|
|
|
|
/* Return first space-delimited token in arg1; remainder of string in arg2.
|
|
* NOTE: Requires sizeof(arg2) >= sizeof(string) */
|
|
void half_chop(char *string, char *arg1, char *arg2)
|
|
{
|
|
char *temp;
|
|
|
|
temp = any_one_arg(string, arg1);
|
|
skip_spaces(&temp);
|
|
strcpy(arg2, temp); /* strcpy: OK (documentation) */
|
|
}
|
|
|
|
/* Used in specprocs, mostly. (Exactly) matches "command" to cmd number */
|
|
int find_command(const char *command)
|
|
{
|
|
int cmd;
|
|
|
|
for (cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++)
|
|
if (!strcmp(complete_cmd_info[cmd].command, command))
|
|
return (cmd);
|
|
|
|
return (-1);
|
|
}
|
|
|
|
int special(struct char_data *ch, int cmd, char *arg)
|
|
{
|
|
struct obj_data *i;
|
|
struct char_data *k;
|
|
int j;
|
|
|
|
/* special in room? */
|
|
if (GET_ROOM_SPEC(IN_ROOM(ch)) != NULL)
|
|
if (GET_ROOM_SPEC(IN_ROOM(ch)) (ch, world + IN_ROOM(ch), cmd, arg))
|
|
return (1);
|
|
|
|
/* special in equipment list? */
|
|
for (j = 0; j < NUM_WEARS; j++)
|
|
if (GET_EQ(ch, j) && GET_OBJ_SPEC(GET_EQ(ch, j)) != NULL)
|
|
if (GET_OBJ_SPEC(GET_EQ(ch, j)) (ch, GET_EQ(ch, j), cmd, arg))
|
|
return (1);
|
|
|
|
/* special in inventory? */
|
|
for (i = ch->carrying; i; i = i->next_content)
|
|
if (GET_OBJ_SPEC(i) != NULL)
|
|
if (GET_OBJ_SPEC(i) (ch, i, cmd, arg))
|
|
return (1);
|
|
|
|
/* special in mobile present? */
|
|
for (k = world[IN_ROOM(ch)].people; k; k = k->next_in_room)
|
|
if (!MOB_FLAGGED(k, MOB_NOTDEADYET))
|
|
if (GET_MOB_SPEC(k) && GET_MOB_SPEC(k) (ch, k, cmd, arg))
|
|
return (1);
|
|
|
|
/* special in object present? */
|
|
for (i = world[IN_ROOM(ch)].contents; i; i = i->next_content)
|
|
if (GET_OBJ_SPEC(i) != NULL)
|
|
if (GET_OBJ_SPEC(i) (ch, i, cmd, arg))
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* Stuff for controlling the non-playing sockets (get name, pwd etc).
|
|
* This function needs to die. */
|
|
static int _parse_name(char *arg, char *name)
|
|
{
|
|
int i;
|
|
|
|
skip_spaces(&arg);
|
|
for (i = 0; (*name = *arg); arg++, i++, name++)
|
|
if (!isalpha(*arg))
|
|
return (1);
|
|
|
|
if (!i)
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
#define RECON 1
|
|
#define USURP 2
|
|
#define UNSWITCH 3
|
|
|
|
/* This function seems a bit over-extended. */
|
|
static int perform_dupe_check(struct descriptor_data *d)
|
|
{
|
|
struct descriptor_data *k, *next_k;
|
|
struct char_data *target = NULL, *ch, *next_ch;
|
|
int mode = 0;
|
|
int pref_temp = 0; /* for "last" log */
|
|
int id = GET_IDNUM(d->character);
|
|
|
|
/* Now that this descriptor has successfully logged in, disconnect all
|
|
* other descriptors controlling a character with the same ID number. */
|
|
|
|
for (k = descriptor_list; k; k = next_k) {
|
|
next_k = k->next;
|
|
|
|
if (k == d)
|
|
continue;
|
|
|
|
if (k->original && (GET_IDNUM(k->original) == id)) {
|
|
/* Original descriptor was switched, booting it and restoring normal body control. */
|
|
|
|
write_to_output(d, "\r\nMultiple login detected -- disconnecting.\r\n");
|
|
STATE(k) = CON_CLOSE;
|
|
pref_temp=GET_PREF(k->character);
|
|
if (!target) {
|
|
target = k->original;
|
|
mode = UNSWITCH;
|
|
}
|
|
if (k->character)
|
|
k->character->desc = NULL;
|
|
k->character = NULL;
|
|
k->original = NULL;
|
|
} else if (k->character && GET_IDNUM(k->character) == id && k->original) {
|
|
/* Character taking over their own body, while an immortal was switched to it. */
|
|
|
|
do_return(k->character, NULL, 0, 0);
|
|
} else if (k->character && GET_IDNUM(k->character) == id) {
|
|
/* Character taking over their own body. */
|
|
pref_temp=GET_PREF(k->character);
|
|
|
|
if (!target && STATE(k) == CON_PLAYING) {
|
|
write_to_output(k, "\r\nThis body has been usurped!\r\n");
|
|
target = k->character;
|
|
mode = USURP;
|
|
}
|
|
k->character->desc = NULL;
|
|
k->character = NULL;
|
|
k->original = NULL;
|
|
write_to_output(k, "\r\nMultiple login detected -- disconnecting.\r\n");
|
|
STATE(k) = CON_CLOSE;
|
|
}
|
|
}
|
|
|
|
/* Now, go through the character list, deleting all characters that are not
|
|
* already marked for deletion from the above step (i.e., in the CON_HANGUP
|
|
* state), and have not already been selected as a target for switching into.
|
|
* In addition, if we haven't already found a target, choose one if one is
|
|
* available (while still deleting the other duplicates, though theoretically
|
|
* none should be able to exist). */
|
|
for (ch = character_list; ch; ch = next_ch) {
|
|
next_ch = ch->next;
|
|
|
|
if (IS_NPC(ch))
|
|
continue;
|
|
if (GET_IDNUM(ch) != id)
|
|
continue;
|
|
|
|
/* ignore chars with descriptors (already handled by above step) */
|
|
if (ch->desc)
|
|
continue;
|
|
|
|
/* don't extract the target char we've found one already */
|
|
if (ch == target)
|
|
continue;
|
|
|
|
/* we don't already have a target and found a candidate for switching */
|
|
if (!target) {
|
|
target = ch;
|
|
mode = RECON;
|
|
pref_temp = GET_PREF(ch);
|
|
continue;
|
|
}
|
|
|
|
/* we've found a duplicate - blow him away, dumping his eq in limbo. */
|
|
if (IN_ROOM(ch) != NOWHERE)
|
|
char_from_room(ch);
|
|
char_to_room(ch, 1);
|
|
extract_char(ch);
|
|
}
|
|
|
|
/* no target for switching into was found - allow login to continue */
|
|
if (!target) {
|
|
GET_PREF(d->character) = rand_number(1, 128000);
|
|
if (GET_HOST(d->character))
|
|
free(GET_HOST(d->character));
|
|
GET_HOST(d->character) = strdup(d->host);
|
|
return 0;
|
|
}
|
|
|
|
if (GET_HOST(target)) free(GET_HOST(target));
|
|
GET_HOST(target) = strdup(d->host);
|
|
|
|
GET_PREF(target) = pref_temp;
|
|
add_llog_entry(target, LAST_RECONNECT);
|
|
|
|
/* Okay, we've found a target. Connect d to target. */
|
|
free_char(d->character); /* get rid of the old char */
|
|
d->character = target;
|
|
d->character->desc = d;
|
|
d->original = NULL;
|
|
d->character->char_specials.timer = 0;
|
|
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_MAILING);
|
|
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING);
|
|
REMOVE_BIT_AR(AFF_FLAGS(d->character), AFF_GROUP);
|
|
STATE(d) = CON_PLAYING;
|
|
|
|
switch (mode) {
|
|
case RECON:
|
|
write_to_output(d, "Reconnecting.\r\n");
|
|
act("$n has reconnected.", TRUE, d->character, 0, 0, TO_ROOM);
|
|
mudlog(NRM, MAX(ADMLVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "%s [%s] has reconnected.", GET_NAME(d->character), d->host);
|
|
if (has_mail(d->character))
|
|
write_to_output(d, "You have mail waiting.\r\n");
|
|
break;
|
|
case USURP:
|
|
write_to_output(d, "You take over your own body, already in use!\r\n");
|
|
act("$n suddenly keels over in pain, surrounded by a white aura...\r\n"
|
|
"$n's body has been taken over by a new spirit!",
|
|
TRUE, d->character, 0, 0, TO_ROOM);
|
|
mudlog(NRM, MAX(ADMLVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE,
|
|
"%s has re-logged in ... disconnecting old socket.", GET_NAME(d->character));
|
|
break;
|
|
case UNSWITCH:
|
|
write_to_output(d, "Reconnecting to unswitched char.");
|
|
mudlog(NRM, MAX(ADMLVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "%s [%s] has reconnected.", GET_NAME(d->character), d->host);
|
|
break;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
/* New Char dupe-check called at the start of character creation */
|
|
static bool perform_new_char_dupe_check(struct descriptor_data *d)
|
|
{
|
|
struct descriptor_data *k, *next_k;
|
|
bool found = FALSE;
|
|
|
|
/* Now that this descriptor has successfully logged in, disconnect all
|
|
* other descriptors controlling a character with the same ID number. */
|
|
|
|
for (k = descriptor_list; k; k = next_k) {
|
|
next_k = k->next;
|
|
|
|
if (k == d)
|
|
continue;
|
|
|
|
/* Do the player names match? */
|
|
if (!strcmp(GET_NAME(k->character), GET_NAME(d->character))) {
|
|
/* Check the other character is still in creation? */
|
|
if ((STATE(k) > CON_PLAYING) && (STATE(k) < CON_QCLASS)) {
|
|
/* Boot the older one */
|
|
k->character->desc = NULL;
|
|
k->character = NULL;
|
|
k->original = NULL;
|
|
write_to_output(k, "\r\nMultiple login detected -- disconnecting.\r\n");
|
|
STATE(k) = CON_CLOSE;
|
|
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "Multiple logins detected in char creation for %s.", GET_NAME(d->character));
|
|
|
|
found = TRUE;
|
|
} else {
|
|
/* Something went VERY wrong, boot both chars */
|
|
k->character->desc = NULL;
|
|
k->character = NULL;
|
|
k->original = NULL;
|
|
write_to_output(k, "\r\nMultiple login detected -- disconnecting.\r\n");
|
|
STATE(k) = CON_CLOSE;
|
|
|
|
d->character->desc = NULL;
|
|
d->character = NULL;
|
|
d->original = NULL;
|
|
write_to_output(d, "\r\nSorry, due to multiple connections, all your connections are being closed.\r\n");
|
|
write_to_output(d, "\r\nPlease reconnect.\r\n");
|
|
STATE(d) = CON_CLOSE;
|
|
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "SYSERR: Multiple logins with 1st in-game and the 2nd in char creation.");
|
|
|
|
found = TRUE;
|
|
}
|
|
}
|
|
}
|
|
return (found);
|
|
}
|
|
|
|
/* load the player, put them in the right room - used by copyover_recover too */
|
|
int enter_player_game (struct descriptor_data *d)
|
|
{
|
|
int load_result;
|
|
room_vnum load_room;
|
|
|
|
reset_char(d->character);
|
|
|
|
if (PLR_FLAGGED(d->character, PLR_INVSTART))
|
|
GET_INVIS_LEV(d->character) = GET_ADMLEVEL(d->character);
|
|
|
|
/* We have to place the character in a room before equipping them
|
|
* or equip_char() will gripe about the person in NOWHERE. */
|
|
if ((load_room = GET_LOADROOM(d->character)) != NOWHERE)
|
|
load_room = real_room(load_room);
|
|
|
|
/* If char was saved with NOWHERE, or real_room above failed... */
|
|
if (load_room == NOWHERE) {
|
|
if (IS_ADMIN(d->character, ADMLVL_IMMORT))
|
|
load_room = r_immort_start_room;
|
|
else
|
|
load_room = r_mortal_start_room;
|
|
}
|
|
|
|
if (PLR_FLAGGED(d->character, PLR_FROZEN))
|
|
load_room = r_frozen_start_room;
|
|
|
|
/* copyover */
|
|
GET_ID(d->character) = GET_IDNUM(d->character);
|
|
/* find_char helper */
|
|
add_to_lookup_table(GET_ID(d->character), (void *)d->character);
|
|
|
|
/* After moving saving of variables to the player file, this should only
|
|
* be called in case nothing was found in the pfile. If something was
|
|
* found, SCRIPT(ch) will be set. */
|
|
if (!SCRIPT(d->character))
|
|
read_saved_vars(d->character);
|
|
|
|
d->character->next = character_list;
|
|
character_list = d->character;
|
|
char_to_room(d->character, load_room);
|
|
load_result = Crash_load(d->character);
|
|
save_char(d->character);
|
|
|
|
/* Check for a login trigger in the players' start room */
|
|
login_wtrigger(&world[IN_ROOM(d->character)], d->character);
|
|
|
|
return load_result;
|
|
}
|
|
|
|
/* deal with newcomers and other non-playing sockets */
|
|
void nanny(struct descriptor_data *d, char *arg)
|
|
{
|
|
int load_result; /* Overloaded variable */
|
|
int player_i;
|
|
|
|
/* OasisOLC states */
|
|
struct {
|
|
int state;
|
|
void (*func)(struct descriptor_data *, char *);
|
|
} olc_functions[] = {
|
|
{ CON_OEDIT, oedit_parse },
|
|
{ CON_ZEDIT, zedit_parse },
|
|
{ CON_SEDIT, sedit_parse },
|
|
{ CON_MEDIT, medit_parse },
|
|
{ CON_REDIT, redit_parse },
|
|
{ CON_CEDIT, cedit_parse },
|
|
{ CON_TRIGEDIT, trigedit_parse },
|
|
{ CON_AEDIT, aedit_parse },
|
|
{ CON_HEDIT, hedit_parse },
|
|
{ CON_QEDIT, qedit_parse },
|
|
{ CON_PREFEDIT, prefedit_parse },
|
|
{ CON_IBTEDIT, ibtedit_parse },
|
|
{ CON_HSEDIT, hsedit_parse },
|
|
{ CON_MAILEDIT, mailedit_parse },
|
|
{ -1, NULL }
|
|
};
|
|
|
|
skip_spaces(&arg);
|
|
|
|
/* Quick check for the OLC states. */
|
|
for (player_i = 0; olc_functions[player_i].state >= 0; player_i++)
|
|
if (STATE(d) == olc_functions[player_i].state) {
|
|
(*olc_functions[player_i].func)(d, arg);
|
|
return;
|
|
}
|
|
|
|
/* Not in OLC. */
|
|
switch (STATE(d)) {
|
|
case CON_GET_NAME: /* wait for input of name */
|
|
if (d->character == NULL) {
|
|
CREATE(d->character, struct char_data, 1);
|
|
clear_char(d->character);
|
|
CREATE(d->character->player_specials, struct player_special_data, 1);
|
|
GET_HOST(d->character) = strdup(d->host);
|
|
d->character->desc = d;
|
|
}
|
|
if (!*arg)
|
|
STATE(d) = CON_CLOSE;
|
|
else {
|
|
char buf[MAX_INPUT_LENGTH], tmp_name[MAX_INPUT_LENGTH];
|
|
|
|
if ((_parse_name(arg, tmp_name)) || strlen(tmp_name) < 2 ||
|
|
strlen(tmp_name) > MAX_NAME_LENGTH || !valid_name(tmp_name) ||
|
|
fill_word(strcpy(buf, tmp_name)) || reserved_word(buf)) { /* strcpy: OK (mutual MAX_INPUT_LENGTH) */
|
|
write_to_output(d, "Invalid name, please try another.\r\nName: ");
|
|
return;
|
|
}
|
|
if ((player_i = load_char(tmp_name, d->character)) > -1) {
|
|
GET_PFILEPOS(d->character) = player_i;
|
|
|
|
if (PLR_FLAGGED(d->character, PLR_DELETED)) {
|
|
/* Make sure old files are removed so the new player doesn't get the
|
|
* deleted player's equipment. */
|
|
if ((player_i = get_ptable_by_name(tmp_name)) >= 0)
|
|
remove_player(player_i);
|
|
|
|
/* We get a false positive from the original deleted character. */
|
|
free_char(d->character);
|
|
|
|
/* Check for multiple creations. */
|
|
if (!valid_name(tmp_name)) {
|
|
write_to_output(d, "Invalid name, please try another.\r\nName: ");
|
|
return;
|
|
}
|
|
CREATE(d->character, struct char_data, 1);
|
|
clear_char(d->character);
|
|
CREATE(d->character->player_specials, struct player_special_data, 1);
|
|
|
|
if (GET_HOST(d->character))
|
|
free(GET_HOST(d->character));
|
|
GET_HOST(d->character) = strdup(d->host);
|
|
|
|
d->character->desc = d;
|
|
CREATE(d->character->player.name, char, strlen(tmp_name) + 1);
|
|
strcpy(d->character->player.name, CAP(tmp_name)); /* strcpy: OK (size checked above) */
|
|
GET_PFILEPOS(d->character) = player_i;
|
|
write_to_output(d, "Did I get that right, %s (Y/N)? ", tmp_name);
|
|
STATE(d) = CON_NAME_CNFRM;
|
|
} else {
|
|
/* undo it just in case they are set */
|
|
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING);
|
|
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_MAILING);
|
|
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_CRYO);
|
|
REMOVE_BIT_AR(AFF_FLAGS(d->character), AFF_GROUP);
|
|
d->character->player.time.logon = time(0);
|
|
write_to_output(d, "Password: ");
|
|
echo_off(d);
|
|
d->idle_tics = 0;
|
|
STATE(d) = CON_PASSWORD;
|
|
}
|
|
} else {
|
|
/* player unknown -- make new character */
|
|
|
|
/* Check for multiple creations of a character. */
|
|
if (!valid_name(tmp_name)) {
|
|
write_to_output(d, "Invalid name, please try another.\r\nName: ");
|
|
return;
|
|
}
|
|
CREATE(d->character->player.name, char, strlen(tmp_name) + 1);
|
|
strcpy(d->character->player.name, CAP(tmp_name)); /* strcpy: OK (size checked above) */
|
|
|
|
write_to_output(d, "Did I get that right, %s (Y/N)? ", tmp_name);
|
|
STATE(d) = CON_NAME_CNFRM;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CON_NAME_CNFRM: /* wait for conf. of new name */
|
|
if (UPPER(*arg) == 'Y') {
|
|
if (isbanned(d->host) >= BAN_NEW) {
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "Request for new char %s denied from [%s] (siteban)", GET_PC_NAME(d->character), d->host);
|
|
write_to_output(d, "Sorry, new characters are not allowed from your site!\r\n");
|
|
STATE(d) = CON_CLOSE;
|
|
return;
|
|
}
|
|
if (circle_restrict) {
|
|
write_to_output(d, "Sorry, new players can't be created at the moment.\r\n");
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "Request for new char %s denied from [%s] (wizlock)", GET_PC_NAME(d->character), d->host);
|
|
STATE(d) = CON_CLOSE;
|
|
return;
|
|
}
|
|
perform_new_char_dupe_check(d);
|
|
write_to_output(d, "New character.\r\nGive me a password for %s: ", GET_PC_NAME(d->character));
|
|
echo_off(d);
|
|
STATE(d) = CON_NEWPASSWD;
|
|
} else if (*arg == 'n' || *arg == 'N') {
|
|
write_to_output(d, "Okay, what IS it, then? ");
|
|
free(d->character->player.name);
|
|
d->character->player.name = NULL;
|
|
STATE(d) = CON_GET_NAME;
|
|
} else
|
|
write_to_output(d, "Please type Yes or No: ");
|
|
break;
|
|
|
|
case CON_PASSWORD: /* get pwd for known player */
|
|
/* To really prevent duping correctly, the player's record should be reloaded
|
|
* from disk at this point (after the password has been typed). However I'm
|
|
* afraid that trying to load a character over an already loaded character is
|
|
* going to cause some problem down the road that I can't see at the moment.
|
|
* So to compensate, I'm going to (1) add a 15 or 20-second time limit for
|
|
* entering a password, and (2) re-add the code to cut off duplicates when a
|
|
* player quits. JE 6 Feb 96 */
|
|
|
|
echo_on(d); /* turn echo back on */
|
|
|
|
/* New echo_on() eats the return on telnet. Extra space better than none. */
|
|
write_to_output(d, "\r\n");
|
|
|
|
if (!*arg)
|
|
STATE(d) = CON_CLOSE;
|
|
else {
|
|
if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
|
|
mudlog(BRF, ADMLVL_GOD, TRUE, "Bad PW: %s [%s]", GET_NAME(d->character), d->host);
|
|
GET_BAD_PWS(d->character)++;
|
|
save_char(d->character);
|
|
if (++(d->bad_pws) >= CONFIG_MAX_BAD_PWS) { /* 3 strikes and you're out. */
|
|
write_to_output(d, "Wrong password... disconnecting.\r\n");
|
|
STATE(d) = CON_CLOSE;
|
|
} else {
|
|
write_to_output(d, "Wrong password.\r\nPassword: ");
|
|
echo_off(d);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Password was correct. */
|
|
load_result = GET_BAD_PWS(d->character);
|
|
GET_BAD_PWS(d->character) = 0;
|
|
d->bad_pws = 0;
|
|
|
|
if (isbanned(d->host) == BAN_SELECT &&
|
|
!PLR_FLAGGED(d->character, PLR_SITEOK)) {
|
|
write_to_output(d, "Sorry, this char has not been cleared for login from your site!\r\n");
|
|
STATE(d) = CON_CLOSE;
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "Connection attempt for %s denied from %s", GET_NAME(d->character), d->host);
|
|
return;
|
|
}
|
|
if (GET_LEVEL(d->character) < circle_restrict) {
|
|
write_to_output(d, "The game is temporarily restricted.. try again later.\r\n");
|
|
STATE(d) = CON_CLOSE;
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "Request for login denied for %s [%s] (wizlock)", GET_NAME(d->character), d->host);
|
|
return;
|
|
}
|
|
/* check and make sure no other copies of this player are logged in */
|
|
if (perform_dupe_check(d))
|
|
return;
|
|
|
|
if (IS_ADMIN(d->character, ADMLVL_IMMORT))
|
|
write_to_output(d, "%s", imotd);
|
|
else
|
|
write_to_output(d, "%s", motd);
|
|
|
|
if (GET_INVIS_LEV(d->character))
|
|
mudlog(BRF, MAX(ADMLVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "%s has connected. (invis %d)", GET_NAME(d->character), GET_INVIS_LEV(d->character));
|
|
else
|
|
mudlog(BRF, ADMLVL_IMMORT, TRUE, "%s has connected.", GET_NAME(d->character));
|
|
|
|
/* Add to the list of 'recent' players (since last reboot) */
|
|
if (AddRecentPlayer(GET_NAME(d->character), d->host, FALSE, FALSE) == FALSE)
|
|
{
|
|
mudlog(BRF, MAX(ADMLVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "Failure to AddRecentPlayer (returned FALSE).");
|
|
}
|
|
|
|
if (load_result) {
|
|
write_to_output(d, "\r\n\r\n\007\007\007"
|
|
"%s%d LOGIN FAILURE%s SINCE LAST SUCCESSFUL LOGIN.%s\r\n",
|
|
CCRED(d->character, C_SPR), load_result,
|
|
(load_result > 1) ? "S" : "", CCNRM(d->character, C_SPR));
|
|
GET_BAD_PWS(d->character) = 0;
|
|
}
|
|
write_to_output(d, "\r\n*** PRESS RETURN: ");
|
|
STATE(d) = CON_RMOTD;
|
|
}
|
|
break;
|
|
|
|
case CON_NEWPASSWD:
|
|
case CON_CHPWD_GETNEW:
|
|
if (!*arg || strlen(arg) > MAX_PWD_LENGTH || strlen(arg) < 3 ||
|
|
!str_cmp(arg, GET_PC_NAME(d->character))) {
|
|
write_to_output(d, "\r\nIllegal password.\r\nPassword: ");
|
|
return;
|
|
}
|
|
strncpy(GET_PASSWD(d->character), CRYPT(arg, GET_PC_NAME(d->character)), MAX_PWD_LENGTH); /* strncpy: OK (G_P:MAX_PWD_LENGTH+1) */
|
|
*(GET_PASSWD(d->character) + MAX_PWD_LENGTH) = '\0';
|
|
|
|
write_to_output(d, "\r\nPlease retype password: ");
|
|
if (STATE(d) == CON_NEWPASSWD)
|
|
STATE(d) = CON_CNFPASSWD;
|
|
else
|
|
STATE(d) = CON_CHPWD_VRFY;
|
|
break;
|
|
|
|
case CON_CNFPASSWD:
|
|
case CON_CHPWD_VRFY:
|
|
if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character),
|
|
MAX_PWD_LENGTH)) {
|
|
write_to_output(d, "\r\nPasswords don't match... start over.\r\nPassword: ");
|
|
if (STATE(d) == CON_CNFPASSWD)
|
|
STATE(d) = CON_NEWPASSWD;
|
|
else
|
|
STATE(d) = CON_CHPWD_GETNEW;
|
|
return;
|
|
}
|
|
echo_on(d);
|
|
|
|
if (STATE(d) == CON_CNFPASSWD) {
|
|
write_to_output(d, "\r\nWhat is your sex (M/F)? ");
|
|
STATE(d) = CON_QSEX;
|
|
} else {
|
|
save_char(d->character);
|
|
write_to_output(d, "\r\nDone.\r\n%s", CONFIG_MENU);
|
|
STATE(d) = CON_MENU;
|
|
}
|
|
break;
|
|
|
|
case CON_QSEX: /* query sex of new user */
|
|
switch (*arg) {
|
|
case 'm':
|
|
case 'M':
|
|
d->character->player.sex = SEX_MALE;
|
|
break;
|
|
case 'f':
|
|
case 'F':
|
|
d->character->player.sex = SEX_FEMALE;
|
|
break;
|
|
default:
|
|
write_to_output(d, "That is not a sex..\r\n"
|
|
"What IS your sex? ");
|
|
return;
|
|
}
|
|
|
|
write_to_output(d, "%s\r\nClass: ", class_menu);
|
|
STATE(d) = CON_QCLASS;
|
|
break;
|
|
|
|
case CON_QCLASS:
|
|
load_result = parse_class(*arg);
|
|
if (load_result == CLASS_UNDEFINED) {
|
|
write_to_output(d, "\r\nThat's not a class.\r\nClass: ");
|
|
return;
|
|
} else
|
|
GET_CLASS(d->character) = load_result;
|
|
|
|
if (d->olc) {
|
|
free(d->olc);
|
|
d->olc = NULL;
|
|
}
|
|
if (GET_PFILEPOS(d->character) < 0)
|
|
GET_PFILEPOS(d->character) = create_entry(GET_PC_NAME(d->character));
|
|
/* Now GET_NAME() will work properly. */
|
|
init_char(d->character);
|
|
save_char(d->character);
|
|
save_player_index();
|
|
write_to_output(d, "%s\r\n*** PRESS RETURN: ", motd);
|
|
STATE(d) = CON_RMOTD;
|
|
/* make sure the last log is updated correctly. */
|
|
GET_PREF(d->character)= rand_number(1, 128000);
|
|
GET_HOST(d->character)= strdup(d->host);
|
|
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "%s [%s] new player.", GET_NAME(d->character), d->host);
|
|
|
|
/* Add to the list of 'recent' players (since last reboot) */
|
|
if (AddRecentPlayer(GET_NAME(d->character), d->host, TRUE, FALSE) == FALSE)
|
|
{
|
|
mudlog(BRF, MAX(ADMLVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "Failure to AddRecentPlayer (returned FALSE).");
|
|
}
|
|
break;
|
|
|
|
case CON_RMOTD: /* read CR after printing motd */
|
|
write_to_output(d, "%s", CONFIG_MENU);
|
|
if (IS_HAPPYHOUR > 0){
|
|
write_to_output(d, "\r\n");
|
|
write_to_output(d, "@yThere is currently a Happyhour!@n\r\n");
|
|
write_to_output(d, "\r\n");
|
|
}
|
|
add_llog_entry(d->character, LAST_CONNECT);
|
|
STATE(d) = CON_MENU;
|
|
break;
|
|
|
|
case CON_MENU: { /* get selection from main menu */
|
|
|
|
switch (*arg) {
|
|
case '0':
|
|
write_to_output(d, "Goodbye.\r\n");
|
|
add_llog_entry(d->character, LAST_QUIT);
|
|
STATE(d) = CON_CLOSE;
|
|
break;
|
|
|
|
case '1':
|
|
load_result = enter_player_game(d);
|
|
send_to_char(d->character, "%s", CONFIG_WELC_MESSG);
|
|
|
|
/* Clear their load room if it's not persistant. */
|
|
if (!PLR_FLAGGED(d->character, PLR_LOADROOM))
|
|
GET_LOADROOM(d->character) = NOWHERE;
|
|
save_char(d->character);
|
|
|
|
greet_mtrigger(d->character, -1);
|
|
greet_memory_mtrigger(d->character);
|
|
|
|
act("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM);
|
|
|
|
STATE(d) = CON_PLAYING;
|
|
if (GET_LEVEL(d->character) == 0) {
|
|
do_start(d->character);
|
|
send_to_char(d->character, "%s", CONFIG_START_MESSG);
|
|
}
|
|
look_at_room(d->character, 0);
|
|
if (has_mail(d->character))
|
|
notify_on_login(d->character);
|
|
if (load_result == 2) { /* rented items lost */
|
|
send_to_char(d->character, "\r\n\007You could not afford your rent!\r\n"
|
|
"Your possesions have been donated to the Salvation Army!\r\n");
|
|
}
|
|
d->has_prompt = 0;
|
|
/* We've updated to 3.1 - some bits might be set wrongly: */
|
|
REMOVE_BIT_AR(PRF_FLAGS(d->character), PRF_BUILDWALK);
|
|
break;
|
|
|
|
case '2':
|
|
if (d->character->player.description) {
|
|
write_to_output(d, "Current description:\r\n%s", d->character->player.description);
|
|
/* Don't free this now... so that the old description gets loaded as the
|
|
* current buffer in the editor. Do setup the ABORT buffer here, however. */
|
|
d->backstr = strdup(d->character->player.description);
|
|
}
|
|
write_to_output(d, "Enter the new text you'd like others to see when they look at you.\r\n");
|
|
send_editor_help(d);
|
|
d->str = &d->character->player.description;
|
|
d->max_str = PLR_DESC_LENGTH;
|
|
STATE(d) = CON_PLR_DESC;
|
|
break;
|
|
|
|
case '3':
|
|
page_string(d, background, 0);
|
|
STATE(d) = CON_RMOTD;
|
|
break;
|
|
|
|
case '4':
|
|
write_to_output(d, "\r\nEnter your old password: ");
|
|
echo_off(d);
|
|
STATE(d) = CON_CHPWD_GETOLD;
|
|
break;
|
|
|
|
case '5':
|
|
write_to_output(d, "\r\nEnter your password for verification: ");
|
|
echo_off(d);
|
|
STATE(d) = CON_DELCNF1;
|
|
break;
|
|
|
|
default:
|
|
write_to_output(d, "\r\nThat's not a menu choice!\r\n%s", CONFIG_MENU);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CON_CHPWD_GETOLD:
|
|
if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
|
|
echo_on(d);
|
|
write_to_output(d, "\r\nIncorrect password.\r\n%s", CONFIG_MENU);
|
|
STATE(d) = CON_MENU;
|
|
} else {
|
|
write_to_output(d, "\r\nEnter a new password: ");
|
|
STATE(d) = CON_CHPWD_GETNEW;
|
|
}
|
|
return;
|
|
|
|
case CON_DELCNF1:
|
|
echo_on(d);
|
|
if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
|
|
write_to_output(d, "\r\nIncorrect password.\r\n%s", CONFIG_MENU);
|
|
STATE(d) = CON_MENU;
|
|
} else {
|
|
write_to_output(d, "\r\nYOU ARE ABOUT TO DELETE THIS CHARACTER PERMANENTLY.\r\n"
|
|
"ARE YOU ABSOLUTELY SURE?\r\n\r\n"
|
|
"Please type \"yes\" to confirm: ");
|
|
STATE(d) = CON_DELCNF2;
|
|
}
|
|
break;
|
|
|
|
case CON_DELCNF2:
|
|
if (!strcmp(arg, "yes") || !strcmp(arg, "YES")) {
|
|
if (PLR_FLAGGED(d->character, PLR_FROZEN)) {
|
|
write_to_output(d, "You try to kill yourself, but the ice stops you.\r\n"
|
|
"Character not deleted.\r\n\r\n");
|
|
STATE(d) = CON_CLOSE;
|
|
return;
|
|
}
|
|
if (!IS_ADMIN(d->character, ADMLVL_GRGOD))
|
|
SET_BIT_AR(PLR_FLAGS(d->character), PLR_DELETED);
|
|
save_char(d->character);
|
|
Crash_delete_file(GET_NAME(d->character));
|
|
/* If the selfdelete_fastwipe flag is set (in config.c), remove all the
|
|
* player's immediately. */
|
|
if (selfdelete_fastwipe)
|
|
if ((player_i = get_ptable_by_name(GET_NAME(d->character))) >= 0) {
|
|
SET_BIT(player_table[player_i].flags, PINDEX_SELFDELETE);
|
|
remove_player(player_i);
|
|
}
|
|
|
|
delete_variables(GET_NAME(d->character));
|
|
write_to_output(d, "Character '%s' deleted! Goodbye.\r\n", GET_NAME(d->character));
|
|
mudlog(NRM, ADMLVL_GOD, TRUE, "%s (lev %d) has self-deleted.", GET_NAME(d->character), GET_LEVEL(d->character));
|
|
STATE(d) = CON_CLOSE;
|
|
return;
|
|
} else {
|
|
write_to_output(d, "\r\nCharacter not deleted.\r\n%s", CONFIG_MENU);
|
|
STATE(d) = CON_MENU;
|
|
}
|
|
break;
|
|
|
|
/* It is possible, if enough pulses are missed, to kick someone off while they
|
|
* are at the password prompt. We'll let the game_loop()axe them. */
|
|
case CON_CLOSE:
|
|
break;
|
|
|
|
default:
|
|
log("SYSERR: Nanny: illegal state of con'ness (%d) for '%s'; closing connection.",
|
|
STATE(d), d->character ? GET_NAME(d->character) : "<unknown>");
|
|
STATE(d) = CON_DISCONNECT; /* Safest to do. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Command Info (here for convenience with command list) */
|
|
ACMD(do_cmdinfo)
|
|
{
|
|
char arg[MAX_INPUT_LENGTH];
|
|
int i, c, length;
|
|
bool first=TRUE;
|
|
|
|
one_argument(argument, arg);
|
|
|
|
if (!*arg) {
|
|
send_to_char(ch, "Usage: %scmdinfo <command>%s", QYEL, QNRM);
|
|
return;
|
|
}
|
|
|
|
for (length = strlen(arg), c = 0; *complete_cmd_info[c].command != '\n'; c++) {
|
|
if(!strncmp(complete_cmd_info[c].command, arg, length))
|
|
break;
|
|
}
|
|
|
|
if ( *complete_cmd_info[c].command == '\n' ) {
|
|
send_to_char(ch, "Unrecognised command: %s\r\n", arg);
|
|
return;
|
|
}
|
|
|
|
/* Found a match */
|
|
send_to_char(ch, "Full Command : %s%s%s\r\n", QCYN, complete_cmd_info[c].command, QNRM);
|
|
|
|
if (complete_cmd_info[c].command_pointer == do_action) {
|
|
if (complete_cmd_info[c].minimum_admlevel >= ADMLVL_MORTAL) {
|
|
send_to_char(ch, "Command Type : %sAdmin-only Social%s\r\n", QRED, QNRM);
|
|
} else {
|
|
send_to_char(ch, "Command Type : %sSocial%s\r\n", QYEL, QNRM);
|
|
}
|
|
} else if (complete_cmd_info[c].admin_flag != ADM_NONE) {
|
|
if (complete_cmd_info[c].minimum_admlevel >= ADMLVL_MORTAL) {
|
|
send_to_char(ch, "Command Type : %sAdmin Permission Required (not for mortals)%s\r\n", QYEL, QNRM);
|
|
} else {
|
|
send_to_char(ch, "Command Type : %sAdmin Permission Required%s\r\n", QYEL, QNRM);
|
|
}
|
|
} else if (complete_cmd_info[c].minimum_admlevel != ADMLVL_MORTAL) {
|
|
send_to_char(ch, "Command Type : %sAdmin/Imm-Only%s\r\n", QYEL, QNRM);
|
|
} else {
|
|
send_to_char(ch, "Command Type : %sPlayer Command%s\r\n", QYEL, QNRM);
|
|
}
|
|
|
|
if (complete_cmd_info[c].admin_flag != ADM_NONE) {
|
|
send_to_char(ch, "Permission Required: %s%s%s\r\n", QCYN, admin_flag_names[(complete_cmd_info[c].admin_flag)], QNRM);
|
|
}
|
|
|
|
send_to_char(ch, "Admin Level : %s%d%s (%s%s%s)\r\n",
|
|
((complete_cmd_info[c].admin_flag == ADM_NONE) ? QYEL : QBLK),
|
|
complete_cmd_info[c].minimum_admlevel, QNRM,
|
|
((complete_cmd_info[c].admin_flag == ADM_NONE) ? QCYN : QBLK),
|
|
admin_level_names[(complete_cmd_info[c].minimum_admlevel)], QNRM);
|
|
|
|
if (complete_cmd_info[c].minimum_level == 0) {
|
|
send_to_char(ch, "Min Level : %s<Any>%s\r\n", QYEL, QNRM);
|
|
} else {
|
|
send_to_char(ch, "Min Level : %s%d%s\r\n", QYEL, complete_cmd_info[c].minimum_level, QNRM);
|
|
}
|
|
|
|
send_to_char(ch, "Allowed Positions : %s", QCYN );
|
|
for (i=complete_cmd_info[c].minimum_position; i<NUM_POSITIONS; i++) {
|
|
if (!first) send_to_char(ch, "%s, %s", QNRM, QCYN);
|
|
send_to_char(ch, "%s", position_types[(i)]);
|
|
first = FALSE;
|
|
}
|
|
send_to_char(ch, "%s\r\n", QNRM);
|
|
}
|