new object $foundation: $root, $dmi_data;
var $foundation defined_msgs = 0;
var $foundation edit_types = 0;
var $foundation msgs = 0;
var $root created_on = 796268969;
var $root fertile = 1;
var $root flags = ['methods, 'code, 'fertile, 'core, 'variables];
var $root inited = 1;
var $root managed = [$foundation];
var $root manager = $foundation;
var $root trusted = [];
public method .all_defined_msgs(): nooverride {
var msgs, m, a;
msgs = #[];
for a in ([this()] + ancestors()) {
if (a == definer())
break;
catch any
msgs = dict_union(msgs, a.defined_msgs());
}
return msgs;
};
public method .all_edit_types(): nooverride {
var i, l, t;
l = [];
for i in (.ancestors()) {
if (type((| (t = i.get_edit_types()) |)) == 'list)
l = l.union(i.get_edit_types());
}
return l;
};
public method .all_msgs() {
arg @ms;
var def, out, m, a, ams, av, v, b;
out = #[];
if (ms)
ms = ms[1];
else
ms = msgs || #[];
def = $compiler.compile_cml(">>NO DEFAULT<<");
for a in ([this()] + ancestors()) {
if (a == definer())
break;
catch any {
ams = a.msgs();
for m in (a.defined_msgs()) {
v = (| ms[m[1]] |);
av = (| ams[m[1]] |);
if (v) {
if (av)
v = dict_union(av, v);
else
v = dict_union(hash b in (m[2]) to ([b, def]), v);
} else if (av) {
v = av;
} else {
v = #[["general", def]];
}
out = dict_add(out, m[1], v);
}
}
}
return out;
};
public method .clear_msg(): nooverride {
arg name, @branches;
var messages, branch, msg;
(caller() != definer()) && (> .perms(sender()) <);
messages = msgs || #[];
if (!dict_contains(messages, name))
return;
if (!branches) {
messages = dict_del(messages, name);
} else {
msg = messages[name];
for branch in (branches) {
if (dict_contains(msg, branch))
msg = dict_del(msg, branch);
}
if (!msg)
messages = dict_del(messages, name);
}
if (!messages)
clear_var('msgs);
else
msgs = messages;
};
public method .configure() {
arg set;
// This is for post-creation configuration of a VR object. It is used
// to interactively configure the VR aspects and behaviour of an object.
// It should be optional, any command hooking into confingure should check
// for a -conf?igure option first (which would imply skipping configuration).
//
// Overriding methods should pass() first, giving priority to their
// ancestors. The argument 'set' is a dictionary with symbol keys
// defining what has been set. Use the definer's name + "_" + setting
// as the name of the key ("name" on $has_name would be 'has_name_name).
// If something is already in the set dictionary, do not re-set it
// again (for instance, if the command hooking into configure accepted
// the name of the object on it's command line it would put
// 'has_name_name in the dictionary and $has_name.configure() would not
// prompt for the name).
//
// "@skip" should always skip the setting, and not alter it.
// if .prompt() returns 'aborted, throw ~abort.
//
(> .perms(sender()) <);
return set;
};
public method .define_msg(): nooverride {
arg name;
(> .perms(sender()) <);
if ((.all_defined_msgs()).contains(name))
throw(~msgexists, ("Message \"" + name) + "\" is already defined.");
if (!($code_lib.valid_message_id(name)))
throw(~msgbad, ("Message \"" + name) + "\" contains invalid characters.");
defined_msgs = (.defined_msgs()).add(name, #[['branches, ["general"]]]);
};
public method .defined_msgs(): nooverride {
return defined_msgs || #[];
};
public method .environment() {
return [];
};
public method .eval_message() {
arg name, definer, vars;
var eval, msg;
eval = (| definer.get_msg_attr(name, 'evaluator) |) || $bs_eval;
msg = $message_frob.new_with(.get_msg(name, definer));
vars = dict_add(vars, 'evaluator, eval);
msg = msg.set_vars(vars);
vars = dict_add(vars, 'time, 'pre);
return msg.eval_ctext(vars);
};
public method .gender() {
return $gender_neuter;
};
public method .gender_context() {
return "it";
};
public method .get_default_msg(): nooverride {
arg name;
var def, b;
catch any {
return msgs[name];
} with {
def = $compiler.compile_cml(">>NO DEFAULT<<");
return hash b in (.get_msg_attr(name, 'branches)) to ([b, def]);
}
};
public method .get_edit_types() {
return edit_types || [];
};
public method .get_msg() {
arg name, definer;
var get;
if (!(get = (| definer.get_msg_attr(name, 'getter) |)))
return dict_union(definer.get_default_msg(name), (| msgs[name] |) || #[]);
return .(get)(name, definer);
};
public method .get_msg_attr(): nooverride {
arg name, attr;
return (defined_msgs[name])[attr];
};
public method .local_to_environment() {
arg obj;
return obj in (.environment());
};
public method .match_environment() {
arg str;
var obj, env, found, match, target;
if (!str)
throw(~objnf, "No object specified.", str);
str = str.strip_article();
// Handle special cases.
if (str in ["me", "my"])
return this();
else if (((str[1]) == "$") || ((str[1]) == "#"))
return (> $object_lib.to_dbref(str) <);
else if (str in ["it", "him", "her"])
return (| .match_context(str) |) || throw(~context, ("I don't see " + str) + " here, do you?");
// Start matching
found = [];
env = .environment();
// special case ordinal references
if ((match = $parse_lib.ordinal_reference(str)))
return env.match_nth(@match);
if ((match = $parse_lib.possessive_reference(str))) {
if ((match[1]) == "me")
obj = this();
else
obj = (> env.match_object(match[1]) <);
if (!(obj.match_name(str))) {
catch ~objnf, ~ambig, ~range {
env = (| obj.contents() |) || [];
if ((found = $parse_lib.ordinal_reference(match[2])))
return (> env.match_nth(@found) <);
else
return (> env.match_object(match[2]) <);
} with {
if (error() == ~objnf)
throw(~objnf, (((obj.name()) + " does not have ") + ((match[2]).add_indefinite())) + ".");
else if (error() == ~ambig)
throw(~ambig, ((("\"" + str) + "\" can match ") + ((((traceback()[1])[3]).mmap('namef, 'ref)).to_english("", " or "))) + ".");
else
throw(~objnf, (obj.name()) + "'s what?");
}
}
}
catch ~objnf, ~ambig {
return (> env.match_object(str) <);
} with {
if (error() == ~objnf)
throw(~objnf, ("You do not see " + (str.add_indefinite())) + " anywhere.");
throw(~ambig, ((("\"" + str) + "\" can match ") + ((((traceback()[1])[3]).mmap('namef, 'ref)).to_english("", " or "))) + ".");
}
};
public method .msg_definer(): nooverride {
arg name;
var a;
for a in (ancestors()) {
if (a == definer())
break;
catch any {
if ((a.defined_msgs())[name])
return a;
}
}
throw(~invmsg, ("Message \"" + name) + "\" is not defined.");
};
public method .msgs(): nooverride {
return msgs || #[];
};
public method .set_edit_types(): nooverride {
arg t;
(> .perms(sender()) <);
if (t)
edit_types = t;
};
public method .set_msg(): nooverride {
arg name, branch, definer, value;
var compiler, branches, msg, definer;
(> .perms(sender()) <);
compiler = (| definer.get_msg_attr(name, 'compiler) |) || $compiler;
value = (> compiler.compile_cml(value) <);
branch ?= "general";
if (!(branch in (definer.get_msg_attr(name, 'branches))))
throw(~badbranch, ((("Message branch \"" + name) + ".") + branch) + "\" is not defined.");
msgs ?= #[];
msg = dict_add((| msgs[name] |) || #[], branch, value);
msgs = dict_add(msgs, name, msg);
};
public method .set_msg_attr(): nooverride {
arg name, attr, value;
var attrs, branch;
(> .perms(sender()) <);
if ((!defined_msgs) || (!dict_contains(defined_msgs, name)))
throw(~msgnf, (("Message \"" + name) + "\" is not defined on ") + this());
if (attr == 'branches) {
if (!value)
value = ["general"];
for branch in (value) {
if (!($code_lib.valid_message_id(branch)))
throw(~msgbad, ((("Message branch \"" + name) + ".") + branch) + "\" contains invalid characters.");
}
}
if (!value)
attrs = dict_del(defined_msgs[name], attr);
else
attrs = dict_add(defined_msgs[name], attr, value);
defined_msgs = dict_add(defined_msgs, name, attrs);
};
public method .undefine_msg(): nooverride {
arg name;
var d;
(> .perms(sender()) <);
if (!((.defined_msgs()).contains(name)))
throw(~msgnf, (("Message \"" + name) + "\" is not defined by ") + this());
// clear it on all descendants, then us
for d in (.descendants()) {
d.clear_msg(name);
pause();
}
.clear_msg(name);
// bye bye
defined_msgs = dict_del(defined_msgs, name);
if (!defined_msgs)
clear_var('defined_msgs);
};
public method .will_inherit(): nooverride {
arg who;
if ((this() != definer()) && (!(sender().has_ancestor(definer()))))
throw(~perm, this() + " may only have parents who are descendants of $foundation");
(> pass(who) <);
};