/* 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); }