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