/*
Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/
/* configure all options BEFORE including system stuff. */
#include "config.h"
#include "mud.h"
#include "vars.h"
#include "sbuf.h"
#include "match.h"
/* WARNING - globals will robinson, globals! */
char typ_str[] = "str";
char typ_int[] = "int";
char typ_cmd[] = "cmd";
char typ_list[] = "lst";
char typ_bool[] = "boo";
char typ_obj[] = "obj";
char typ_flag[] = "flg";
char typ_u[] = "U";
char var_loc[] = "loc";
char var_cont[] = "con";
char var_xit[] = "xit";
char var_dest[] = "dst";
char var_dropto[] = "drpto";
char var_lock[] = "lok";
char var_jump[] = "jmp";
char var_link[] = "lnk";
char var_ply[] = "ply";
char var_owner[] = "own";
char var_nam[] = "nam";
char var_desc[] = "desc";
char var_text[] = "txt";
char var_pass[] = "pass";
char var_using[] = "use";
char var_wiz[] = "_wz";
char var_fail[] = "fail";
char var_ofail[] = "ofail";
char var_succ[] = "succ";
char var_osucc[] = "osucc";
char var_drop[] = "drop";
char var_odrop[] = "odrop";
char var_isplay[] = "_pl";
char var_isdark[] = "dark";
char var_isroom[] = "_rm";
char var_islocal[] = "lcl";
char var_newsart[] = "newsarticle";
char var_subive[] = "subv";
char var_Subve[] = "Subv";
char var_objive[] = "objv";
char var_Objve[] = "Objv";
char var_posive[] = "posv";
char var_Posve[] = "Posv";
char var_home[] = "home";
char var_linkmsg[] = "linkmsg";
char var_wearing[] = "_wear";
#ifdef COMBAT
char var_strength[] = "_stren";
char var_Strength[] = "_Stren";
char var_endurance[] = "_endur";
char var_Endurance[] = "_Endur";
char var_willpower[] = "_willp";
char var_Willpower[] = "_Willp";
char var_agility[] = "_dextr";
char var_Agility[] = "_Dextr";
char var_magic[] = "_magic";
char var_Magic[] = "_Magic";
char var_action[] = "_actup";
char var_Action[] = "_Actup";
char var_power[] = "_power";
char var_counters[] = "counter";
char var_lastupd[] = "_lupd";
char var_lasthit[] = "_lhit";
char var_lastatt[] = "_latt";
char var_isdead[] = "_dead";
char var_weapon[] = "_weapon";
/* flags */
char var_isweapon[] = "_isweap";
char var_isarmor[] = "_isarm";
#endif
/* system object related stuff. */
char system_object[] = "sysobj";
char var_objcnt[] = "_objcnt";
char var_syslimbo[] = "_syslimbo";
char var_wizs[] = "_wizards";
char var_bsequence[] = "_backupseq";
/* variable type table */
TypTab ttab[] = {
{typ_str},
{typ_int},
{typ_cmd},
{typ_list},
{typ_bool},
{typ_obj},
{typ_flag},
{typ_u},
{0}
};
/* Newusers allowed flag? */
char newusers = 0;
/*
variable permissions and other whatnots table. these should be
roughly in order of preference, since "set" chooses based on first
match
*/
VarTab vtab[] = {
{var_desc, "description", typ_str, VAR_LOC_PUBLIC,
"description"},
{var_text, "text", typ_str, VAR_LOC_PUBLIC,
"text inscription"},
{var_fail, "failure", typ_str, VAR_MTYP,
"failure message/command"},
{var_ofail, "ofailure", typ_str, VAR_MTYP,
"other player failure message/command"},
{var_succ, "success", typ_str, VAR_MTYP,
"success message/command"},
{var_osucc, "osuccess", typ_str, VAR_MTYP,
"other player success message/command"},
{var_drop, "drop", typ_str, VAR_MTYP,
"drop message/command"},
{var_odrop, "odrop", typ_str, VAR_MTYP,
"other player drop message/command"},
{var_subive, "subjective", typ_str, VAR_LOC_PUBLIC,
"subjective pronoun"},
{var_Subve, "Subjective", typ_str, VAR_LOC_PUBLIC,
"subjective pronoun (capitalized)"},
{var_objive, "objective", typ_str, VAR_LOC_PUBLIC,
"objective pronoun"},
{var_Objve, "Objective", typ_str, VAR_LOC_PUBLIC,
"objective pronoun (capitalized)"},
{var_posive, "possessive", typ_str, VAR_LOC_PUBLIC,
"possessive pronoun"},
{var_Posve, "Possessive", typ_str, VAR_LOC_PUBLIC,
"possessive pronoun (capitalized)"},
#ifdef PLAYER_NAMECHANGING
{var_nam, "name", typ_str, VAR_PUBLIC,
"name"},
#else
{var_nam, "name", typ_str, VAR_PRIVPLY | VAR_PUBLIC,
"name"},
#endif
{var_pass, "password", typ_str, VAR_PRIV,
"object's password"},
{var_owner, "owners", typ_list, 0,
"object owner list"},
{var_ply, "players", typ_list, VAR_LOC_PUBLIC | VAR_PRIV,
"room player list"},
{var_cont, "contents", typ_list, VAR_LOC_PUBLIC | VAR_PRIV,
"contents list"},
{var_xit, "exits", typ_list, VAR_PRIV,
"room exit list"},
{var_wizs, "wizardlist", typ_list, VAR_PRIV,
"valid wizards"},
{var_loc, "location", typ_obj, VAR_PRIV,
"location of an object"},
{var_dest, "destination", typ_obj, VAR_PRIV,
"exit destination"},
{var_dropto, "dropto", typ_obj, 0,
"dropto destination"},
{var_using, "holding", typ_obj, VAR_PRIV,
"object being held by player"},
{var_using, "using", typ_obj, VAR_PRIV,
"object being used by player"},
{var_home, "home", typ_obj, 0,
"object's home location"},
{var_jump, "jump", typ_bool, VAR_MTYP,
"object access lock"},
{var_lock, "lock", typ_bool, VAR_MTYP,
"object access lock"},
{var_link, "linkok", typ_bool, 0,
"link permissions"},
{var_isdark, "isdark", typ_flag, 0,
"object is dark"},
{var_islocal, "local", typ_flag, 0,
"object is local"},
{var_wiz, "wizard", typ_flag, VAR_PRIV,
"object is a wizard"},
{var_isplay, "isplayer", typ_flag, VAR_PRIV,
"object is a player"},
{var_isroom, "isroom", typ_flag, VAR_PRIV,
"object is a room"},
{var_newsart, "newsarticle", typ_int, 0,
"last read news article"},
{var_linkmsg, "linkmessage", typ_str, VAR_PRIV,
"portal player moved through"},
{var_wearing, "wearing", typ_list, VAR_PRIV,
"player garments"},
#ifdef COMBAT
{var_strength, "strength", typ_int, VAR_PRIV,
"player current strength"},
{var_Strength, "Strength", typ_int, VAR_PRIV,
"player maximum strength"},
{var_endurance, "endurance", typ_int, VAR_PRIV,
"player current endurance"},
{var_Endurance, "Endurance", typ_int, VAR_PRIV,
"player maximum endurance"},
{var_willpower, "willpower", typ_int, VAR_PRIV,
"player current willpower"},
{var_Willpower, "Willpower", typ_int, VAR_PRIV,
"player maximum willpower"},
{var_agility, "agility", typ_int, VAR_PRIV,
"player current agility"},
{var_Agility, "Agility", typ_int, VAR_PRIV,
"player maximum agility"},
{var_magic, "magic", typ_int, VAR_PRIV,
"player current magic level"},
{var_Magic, "Magic", typ_int, VAR_PRIV,
"player maximum magic level"},
{var_action, "action", typ_int, VAR_PRIV,
"player current action points"},
{var_Action, "Action", typ_int, VAR_PRIV,
"player maximum action points"},
{var_counters, "counters", typ_list, 0,
"player counterattack list"},
{var_power, "power", typ_int, VAR_PRIV,
"player current power level"},
{var_lastupd, "lastupd", typ_str, VAR_PRIV,
"player last combat stats update time"},
{var_lasthit, "lasthit", typ_obj, VAR_PRIV,
"player last attacker that hit"},
{var_lastatt, "lastatt", typ_obj, VAR_PRIV,
"player last attacker"},
{var_isdead, "isdead", typ_flag, VAR_PRIV,
"player killed by something"},
{var_weapon, "weapon", typ_obj, VAR_PRIV,
"player weapon in use"},
{var_isweapon, "isweapon", typ_flag, VAR_PRIV,
"object is weapon flag"},
{var_isarmor, "isarmor", typ_flag, VAR_PRIV,
"object is armor flag"},
#endif
{0, 0, 0, 0,
0}
};
/* return nonzero if the variable is public */
int var_ispublic (char *vn, char *who, char *aswho, char *what)
{
char *dst;
int exitsees = 0;
VarTab *vp = vtab;
/* If we're an exit, we can see also local_public at our dst */
if (dst = ut_getatt (aswho, 0, typ_obj, var_dest, (char *) 0))
exitsees = (!strcmp (ut_loc (what), dst));
if (*vn == LOC_PUB_COOKIE) {
return (!strcmp (ut_loc (who), ut_loc (what)) ||
!strcmp (who, ut_loc (what)) ||
!strcmp (ut_loc (who), what) || exitsees);
}
while (vp->vnam != (char *) 0) {
if (!strcmp (vp->vnam, vn)) {
if (vp->flg & VAR_PUBLIC)
return (1);
if (vp->flg & VAR_LOC_PUBLIC) {
if (ut_flagged (what, var_isdark))
return (0);
return (!strcmp (ut_loc (who), ut_loc (what)) ||
!strcmp (who, ut_loc (what)) ||
!strcmp (ut_loc (who), what) || exitsees);
}
}
vp++;
}
return (0);
}
static int set_help (char *who)
{
VarTab *vp = vtab;
TypTab *tp = ttab;
char line[60];
/* TODO - prettier format ? */
say (who, "\nData types known to this MUD:\n", (char *) 0);
while (tp->tnam != (char *) 0) {
say (who, tp->tnam, " ", (char *) 0);
tp++;
}
say (who, "\n\n", (char *) 0);
say (who, "Attributes known to this MUD:\n", (char *) 0);
say (who, "-long name- -(type : shortname)- -description-\n",
(char *) 0);
while (vp->vnam != (char *) 0) {
snprintf (line, sizeof (line), "%-13.13s(%-5.5s:%11.11s) %23.23s",
vp->vlong, vp->deftyp, vp->vnam, vp->desc);
say (who, line, (char *) 0);
if (vp->flg & VAR_PUBLIC)
say (who, " (public)", (char *) 0);
if (vp->flg & VAR_PRIV)
say (who, " (wiz-only)", (char *) 0);
if (vp->flg & VAR_MTYP)
say (who, " (multi-type)", (char *) 0);
if (vp->flg & VAR_PRIVPLY)
say (who, " (wiz-only on players)", (char *) 0);
say (who, "\n", (char *) 0);
vp++;
}
say (who, "\n", (char *) 0);
return (UERR_NONE);
}
static VarTab *var_tabfind (char *nam)
{
VarTab *vp = vtab;
while (vp->vnam != (char *) 0) {
if (!strcmp (vp->vnam, nam) || !strcmp (vp->vlong, nam))
return (vp);
vp++;
}
return ((VarTab *) 0);
}
/* resolve a possible long-form name to short form */
char *var_namatch (char *nam)
{
VarTab *vp;
if ((vp = var_tabfind (nam)) == (VarTab *) 0)
return ((char *) 0);
return (vp->vnam);
}
/* ARGSUSED */
int cmd_set (int argc, char *argv[], char *who, char *aswho)
{
char ob[MAXOID];
char *typp;
char *atpp;
char *vapp;
if (argc == 2 && !strcmp (argv[1], "help"))
return (set_help (who));
if (argc < 3 || argc > 5) {
say (who, "usage: set thing [type] attribute value\n", (char *) 0);
say (who, "or \"set help\" for help using \"set\"\n", (char *) 0);
return (UERR_ARGCNT);
}
if (matchlocal (who, argv[1], ut_loc (who),
MTCH_UNIQ | MTCH_NONLOC | MTCH_MEOK, ob))
return (UERR_NOMATCH);
typp = (char *) 0;
atpp = argv[2];
vapp = argv[3];
/* type spec given ? */
if (argc > 4) {
typp = argv[2];
atpp = argv[3];
vapp = argv[4];
}
return (var_set_internal (who, aswho, ob, typp, atpp, vapp, 1));
}
/*
internal set routine -
very gross!! but all this gook has to fit someplace
called also from U-interpreter code.
*/
int var_set_internal (char *who, char *aswho, char *ob,
char *typp, char *atpp, char *vapp, int vbose)
{
VarTab *vp;
int izlist = 0;
int wiz;
/* can we find a match in the variable table? */
if ((vp = var_tabfind (atpp)) != (VarTab *) 0) {
if (typp == (char *) 0)
typp = vp->deftyp;
atpp = vp->vnam;
}
/* if it's not one of the known attributes, we need its type */
if (typp == (char *) 0) {
if (vbose)
say (who, "\"", atpp, "\" type unknown. Provide its type.\n",
(char *) 0);
return (UERR_ILLASGN);
}
if (strlen (typp) == 0 || strlen (atpp) == 0 ||
index (typp, '=') != (char *) 0 || index (atpp, '=') != (char *) 0) {
if (vbose)
say (who,
"Attributes and types must be non-blank and contain no = characters.\n",
(char *) 0);
return (UERR_ILLASGN);
}
/* is this a priv'd attribute? */
wiz = ut_flagged (aswho, var_wiz);
/* stamp out type clash - usually - only wizards may typeclash */
if (vp != (VarTab *) 0 && !wiz && !(vp->flg & VAR_MTYP) &&
strcmp (typp, vp->deftyp)) {
if (vbose)
say (who, vp->vlong, " is only a ", vp->deftyp,
". You cannot set it to be a ", typp, ".\n", (char *) 0);
return (UERR_ILLASGN);
}
/* priv'd attribute */
if (vp != (VarTab *) 0 && (vp->flg & VAR_PRIV) && !wiz) {
if (vbose)
say (who, "You must be a wizard to set ", vp->vlong, ".\n", (char *) 0);
return (UERR_PERM);
}
/* check for wiz-only on player */
if (vp != (VarTab *) 0 && (vp->flg & VAR_PRIVPLY) && !wiz &&
ut_flagged (ob, var_isplay)) {
if (vbose)
say (who, "You must be a wizard to set ", vp->vlong, " for a player.\n",
(char *) 0);
return (UERR_PERM);
}
/* next: do we own the thang?? */
if (!wiz && !ut_isobjown (aswho, ob)) {
if (vbose)
say (who, "You don't own ", ut_name (ob), ".\n", (char *) 0);
return (UERR_PERM);
}
/* if the type is a flag, trap it here */
if (!strcmp (typp, typ_flag)) {
/* Special case for DARK */
if (!wiz && !strcmp (atpp, var_isdark) && !ut_flagged (ob, var_isroom)) {
if (vbose)
say (who, "You can't set a non-room dark!\n", (char *) 0);
return (UERR_ILLASGN);
}
if (ut_set (who, ob, typp, atpp, ""))
return (UERR_FATAL);
if (vbose && run_level () == 0)
say (who, "Set flag ", atpp, "\n", (char *) 0);
return (UERR_NONE);
}
/* at this point, we need another arg at least */
if (vapp == (char *) 0) {
if (vbose)
say (who, "Set ", typp, " ", atpp, " to what?\n", (char *) 0);
return (UERR_ARGCNT);
}
/* do not allow strings starting with '#' */
if (!wiz && !strcmp (typp, typ_str) && vapp[0] == '#') {
if (vbose)
say (who, "You cannot start a string with '#'.\n", (char *) 0);
return (UERR_ILLASGN);
}
/* do re-writing and syntax checks on booleans */
if (!strcmp (typp, typ_bool)) {
Sbuf suf;
sbuf_initstatic (&suf);
if (bool_rewrite (who, vapp, &suf)) {
if (vbose)
say (who, "Bad Boolean expression.\n", (char *) 0);
sbuf_freestatic (&suf);
return (UERR_SYNTAX);
}
vapp = sbuf_buf (&suf);
if (bool_syntax (who, vapp)) {
sbuf_freestatic (&suf);
return (UERR_SYNTAX);
}
if (ut_set (who, ob, typp, atpp, vapp)) {
sbuf_freestatic (&suf);
return (UERR_FATAL);
}
if (vbose && run_level () == 0)
say (who, "Set ", atpp, ".\n", (char *) 0);
sbuf_freestatic (&suf);
return (UERR_NONE);
}
/* special case for lists and objects being set to NULL */
izlist = !strcmp (typp, typ_list);
if ((izlist || !strcmp (typp, typ_obj)) && vapp[0] == '\0') {
if (ut_unset (who, ob, atpp))
return (UERR_FATAL);
if (vbose)
say (who, "Nulled out ", atpp, "\n", (char *) 0);
return (UERR_NONE);
}
/* special case for lists +thing and -thing */
if (izlist && (vapp[0] == '+' || vapp[0] == '-')) {
char *thang;
if (!strcmp ("me", &vapp[1]))
thang = aswho;
else if (!strcmp ("here", &vapp[1]))
thang = ut_loc (who);
else
thang = &vapp[1];
if (vapp[0] == '-') {
if (ut_listdel (who, ob, atpp, thang))
return (UERR_FATAL);
if (vbose && run_level () == 0)
say (who, "Dropped ", thang, " from ", atpp, "\n", (char *) 0);
return (UERR_NONE);
}
/* Must be adding it. Special case owners list. Xtra chex. */
if (!strcmp (atpp, var_owner) &&
(!ut_isgoodid (thang) || !cache_check (thang))) {
if (vbose && run_level () == 0)
say (who, "Cannot add ", thang, " to owners list.\n", (char *) 0);
return (UERR_BADOID);
}
/* add away */
if (ut_listadd (who, ob, atpp, thang))
return (UERR_FATAL);
if (vbose && run_level () == 0)
say (who, "Added ", thang, " to ", atpp, "\n", (char *) 0);
return (UERR_NONE);
}
if (!wiz && izlist && vbose && run_level () == 0) {
say (who, "Use + or - to manipulate lists, please.\n", (char *) 0);
return (UERR_ILLASGN);
}
/* special case for droptos */
if (!strcmp (atpp, var_dropto)) {
/* We setting this on a room? */
if (!wiz && !ut_flagged (ob, var_isroom)) {
if (vbose)
say (who, "Can't set a dropto on a non-room.\n", (char *) 0);
return (UERR_ILLASGN);
}
/* Can we link to that? */
if (!wiz && strcmp (vapp, "home") && !ut_flagged (vapp, var_isroom)) {
if (vbose)
say (who, "Can't set a dropto to a non-room.\n", (char *) 0);
return (UERR_ILLASGN);
}
if (!wiz && strcmp (vapp, "home") && !ut_isobjown (aswho, vapp)
&& bool_locked (aswho, vapp, ut_loc (aswho), var_link, 1)) {
if (vbose)
say (who, "You can't link a dropto to ", vapp, ".\n", (char *) 0);
return (UERR_ILLASGN);
}
}
/* special case for homes */
if (!strcmp (atpp, var_home)) {
char hm[MAXOID];
if (matchlocal (who, vapp, ut_loc (who),
MTCH_UNIQ | MTCH_NONLOC | MTCH_MEOK, hm)) {
if (vbose)
say (who, "I can't find ", vapp, ".\n", (char *) 0);
return (UERR_NOMATCH);
}
/* Can we set the home to it? */
if (!wiz && !ut_isobjown (aswho, hm) &&
bool_locked (aswho, hm, ut_loc (aswho), var_link, 1)) {
if (vbose)
say (who, "You can't set home to ", vapp, ".\n", (char *) 0);
return (UERR_PERM);
}
if (!wiz && ut_flagged (ob, var_isplay)) {
if (!ut_flagged (hm, var_isroom)) {
if (vbose)
say (who, vapp, " isn't a room!\n", (char *) 0);
return (UERR_ILLASGN);
}
} else if (!wiz) {
if (!ut_flagged (hm, var_isroom) && !ut_flagged (hm, var_isplay)) {
if (vbose)
say (who, "You can't set home to ", vapp, ".\n", (char *) 0);
return (UERR_ILLASGN);
}
}
if (index (hm, '@') == (char *) 0) {
/* Flesh the object ID out fully */
/* Be anal retentive about it */
if (strlen (hm) + strlen (mud_getname ()) + 1 > MAXOID) {
if (vbose)
say (who, "You can't set home to ", vapp, ".\n", (char *) 0);
return (UERR_ILLASGN);
}
strcat (hm, "@");
strcat (hm, mud_getname ());
}
if (ut_set (who, ob, typp, atpp, hm))
return (UERR_FATAL);
if (vbose && run_level () == 0)
say (who, "Set ", atpp, "\n", (char *) 0);
return (UERR_NONE);
}
#ifdef PLAYER_NAMECHANGING
/* log name changes - why not ? */
if (!wiz && !strcmp (atpp, var_nam) && ut_flagged (ob, var_isplay)) {
if (index (vapp, '\'') || index (vapp, '\"') || index (vapp, ';')) {
if (vbose)
say (who, "Illegal character in name.\n", (char *) 0);
return (UERR_ILLASGN);
}
plogf ("%s changed %s name to %s\n", who, ob, vapp);
}
#endif
if (ut_set (who, ob, typp, atpp, vapp))
return (UERR_FATAL);
if (vbose && run_level () == 0)
say (who, "Set ", atpp, "\n", (char *) 0);
return (UERR_NONE);
}
/* ARGSUSED */
int cmd_unset (int argc, char *argv[], char *who, char *aswho)
{
char ob[MAXOID];
if (matchlocal (who, argv[1], ut_loc (who),
MTCH_UNIQ | MTCH_NONLOC | MTCH_MEOK, ob))
return (UERR_NOMATCH);
return (var_unset_internal (who, aswho, ob, argv[2], 1));
}
int var_unset_internal (char *who, char *aswho, char *ob, char *atpp,
int vbose)
{
int wiz;
VarTab *vp = vtab;
while (vp->vnam != (char *) 0) {
if (!strcmp (vp->vnam, atpp))
break;
if (!strcmp (vp->vlong, atpp)) {
atpp = vp->vnam;
break;
}
vp++;
}
wiz = ut_flagged (aswho, var_wiz);
if (vp->vnam != (char *) 0 && (vp->flg & VAR_PRIV) && !wiz) {
if (vbose)
say (who, "You must be a wizard to unset ", vp->vlong, ".\n",
(char *) 0);
return (UERR_PERM);
}
if ((vp->flg & VAR_PRIVPLY) && !wiz && ut_flagged (ob, var_isplay)) {
if (vbose)
say (who, "You must be a wizard to unset ", vp->vlong,
" for a player.\n", (char *) 0);
return (UERR_PERM);
}
if (!wiz && !ut_isobjown (aswho, ob)) {
if (vbose)
say (who, "You don't own ", ut_name (ob), ".\n", (char *) 0);
return (UERR_PERM);
}
if (ut_unset (who, ob, atpp))
return (UERR_FATAL);
if (vbose && run_level () == 0)
say (who, "Unset ", atpp, "\n", (char *) 0);
return (UERR_NONE);
}
/* check if this is a known attribute and possibly */
/* get the long name (to use as a title) */
void fndvnam (char *vt, /* the attribute */
char *buf, /* long name? */
int siz)
{
VarTab *vp;
/* can we find a match in the variable table? */
for (vp = vtab; vp->vnam != (char *) 0; ++vp) {
if (!strcmp (vp->vnam, vt)) {
if (buf != (char *) 0)
strncpy (buf, vp->vlong, siz - 2);
return;
}
}
if (buf != (char *) 0)
strncpy (buf, vt, siz - 2); /* gotta tell'em something... */
buf[siz - 1] = '\0';
}
int fndtyp (char *vt)
{
TypTab *tp;
for (tp = ttab; tp->tnam != (char *) 0; tp++)
if (!strcmp (vt, tp->tnam))
return (1);
return (0);
}