/
ColdCore-3.0a9.02/
ColdCore-3.0a9.02/src/
new object $thing_frob: $frob, $thing;

var $described prose = [];
var $has_name name = ['uniq, "Thing Frob", "the Thing Frob"];
var $located location = $void;
var $located obvious = 1;
var $root created_on = 796268969;
var $root fertile = 1;
var $root flags = ['methods, 'code, 'fertile, 'variables, 'core, 'frob];
var $root inited = 1;
var $root managed = [$thing_frob];
var $root manager = $thing_frob;
var $thing gender = $gender_neuter;

frob method .add_name_template() {
    arg this, template;
    var new;
    
    new = setadd(.name_templates(this), template);
    return .change_data(this, 'name_templates, new);
};

frob method .all_defined_settings(): nooverride  {
    arg this;
    
    (> .perms(this, sender()) <);
    return ._all_defined_settings();
};

frob method .all_local_commands() {
    arg this;
    
    return pass();
};

frob method .all_msgs(): nooverride  {
    arg this;
    
    if (dict_contains(this, 'msgs))
        return pass(this['msgs]);
    return pass();
};

frob method .all_remote_commands() {
    arg this;
    
    return pass();
};

frob method .all_shortcuts() {
    arg this;
    
    return pass();
};

private method .change_data() {
    arg this, what, new, @remove;
    
    if (valid(this['location]))
        (this['location]).del_frob_from_contents((<this(), this>));
    if (remove)
        this = this.del(what);
    else
        this = this.add(what, new);
    if (valid(this['location]))
        (this['location]).add_frob_to_contents((<this(), this>));
    return (<this(), this>);
};

frob method .clear_msg(): nooverride  {
    arg this, name, @branches;
    var messages, branch, msg;
    
    (caller() != definer()) && (> .perms(this, sender()) <);
    if (dict_contains(this, 'msgs))
        messages = this['msgs];
    else
        messages = #[];
    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)
        return .change_data(this, 'msgs, 0, 'remove);
    else
        return .change_data(this, 'msgs, messages);
};

frob method .clear_setting(): nooverride  {
    arg this, name, definer;
    var info, args, settings;
    
    (caller() == definer()) || (> .perms(this, sender()) <);
    info = (> definer.setting_info(name) <);
    if (dict_contains(info, 'clear)) {
        args = sublist(info['clear], 2);
        return (> .((info['clear])[1])(this, name) <);
    } else if (dict_contains(this, 'settings) && dict_contains(this['settings], name)) {
        settings = dict_del(settings, name);
        if (!settings)
            return .change_data(this, 'settings, 0, 'remove);
        else
            return .change_data(this, 'settings, settings);
    }
};

frob method .configure() {
    arg this, set;
    var p, end, ctext, s, still, type;
    
    (> .perms(this, sender()) <);
    s = sender();
    still = ("Do you still want to describe " + (.name(this))) + "? [no] ";
    if (!(set.contains('described_prose))) {
        while (!end) {
            if (.is(this, $exit))
                type = "exit ";
            else
                type = "";
            p = s.read((("Describe " + type) + (.name(this))) + ", Enter \".\" to finish or \"@abort\" to abort description.");
            if (p == 'aborted) {
                end = !(s.prompt_yesno(still, 0));
            } else {
                catch any {
                    ctext = (> $compiler.compile_cml(p) <);
                    s.tell(["You submitted the following description:", ""]);
                    s.tell(ctext);
                    s.tell("");
                    if (!(end = s.prompt_yesno("Keep this description? [yes] ")))
                        ctext = 0;
                } with {
                    s.tell(["The following CML compiler error occurred:", "  ", (traceback()[1])[2]]);
                    end = !(s.prompt_yesno(still, 0));
                }
            }
        }
        if (ctext)
            this = (.set_prose(this, ctext)).value();
        set = set.add('described_prose, 1);
    }
    return [this, set];
};

frob method .del_name_template() {
    arg this, template;
    var new;
    
    new = setremove(.name_templates(this), template);
    return .change_data(this, 'name_templates, new);
};

frob method .description() {
    arg this, flags;
    var out;
    
    out = (<$ctext_frob, [[(<$format, ["subj", [], [.name(this)], 'do_subj]>)], #[]]>);
    if ((| flags['prose] |))
        return [out, .prose(this)];
    return [out];
};

frob method .did_move() {
    arg this;
    
    return (<this(), this>);
};

frob method .discard() {
    arg data;
    
    //// just allow anybody to discard for now..
    //  if (data['manager] != sender())
    //      throw(~perm, "You are not the manager of " + .name(data));
    (data['location]).del_frob_from_contents((<this(), data>));
};

frob method .eval_message() {
    arg this, name, definer, vars;
    var eval, msg;
    
    eval = (| definer.get_msg_attr(name, 'evaluator) |) || $bs_eval;
    msg = $message_frob.new_with(.get_msg(this, name, definer));
    vars = dict_add(vars, 'evaluator, eval);
    msg = msg.set_vars(vars);
    vars = dict_add(vars, 'time, 'pre);
    return msg.eval_ctext(vars);
};

frob method .format_setting(): nooverride  {
    arg this, name, definer, value;
    var i, args;
    
    return pass(name, definer, value);
};

frob method .get_command_info() {
    arg this, @args;
    
    return pass(@args);
};

frob method .get_description(): nooverride  {
    arg this, @dflags;
    var flags, f;
    
    flags = #[['prose, 1], ['actor, sender()]];
    if (dflags && (type(dflags[1]) == 'dictionary)) {
        dflags = dflags[1];
        for f in (dflags.keys())
            flags = dict_add(flags, f, dflags[f]);
    }
    return .description(this, flags);
};

frob method .get_lock() {
    arg this, name, definer;
    
    return (| this['lock] |) || (<$true_lock_frob, []>);
};

frob method .get_msg(): nooverride  {
    arg this, name, definer;
    
    return dict_union(definer.get_default_msg(name), (| (this['msgs])[name] |) || #[]);
};

frob method .get_setting(): nooverride  {
    arg this, name, definer;
    var i, settings;
    
    i = definer.setting_info(name);
    if (dict_contains(i, 'access))
        (> .((i['access])[1])(this, name, sender(), caller(), @sublist(i['access], 2.0)) <);
    if (dict_contains(i, 'get))
        return (> .((i['get])[1])(this, name, definer, @sublist(i['get], 2)) <);
    if ((!dict_contains(this, 'settings)) || (!dict_contains(this['settings], name)))
        return (> pass(name, definer) <);
    return (this['settings])[name];
};

frob method .is_obvious_to() {
    arg this, whom;
    
    return 1;
};

frob method .local_commands() {
    arg this;
    
    return pass();
};

frob method .location() {
    arg this;
    
    return (| this['location] |) || $nowhere;
};

frob method .manager() {
    arg this;
    
    return this['manager];
};

frob method .match_name() {
    arg this, str;
    var t, m;
    
    if ((m = match_begin((this['name])[2], str)))
        return 1;
    if (this.contains('name_templates)) {
        for t in (this['name_templates]) {
            if ((m = match_template(str, t)))
                return 1;
        }
    }
    return 0;
};

frob method .move_to() {
    arg data, place;
    var location;
    
    if (!(place.has_ancestor($location)))
        throw(~type, "Argument is not a location.");
    location = data['location];
    if (!valid(location))
        location = $nowhere;
    (> .will_move(data, sender(), place) <);
    return .change_data(data, 'location, place);
};

frob method .msg_definer(): nooverride  {
    arg this, name;
    
    return pass(name);
};

frob method .name() {
    arg dict, @args;
    var name;
    
    name = dict['name];
    if (!name)
        return tostr(this());
    if (!args)
        return name[3];
    switch (args[1]) {
        case 'type:
            return name[1];
        case 'noarticle:
            return name[2];
        default:
            return name;
    }
};

frob method .name_templates() {
    arg this;
    
    return (| this['name_templates] |) || [];
};

frob method .namef() {
    arg dict, @args;
    
    return .name(dict);
};

public method .new() {
    var location;
    
    if (sender().is($location))
        location = sender();
    else if (sender().is($located))
        location = sender().location();
    else
        location = $nowhere;
    return (<this(), #[['prose, []], ['location, location], ['manager, sender()], ['name, .name('literal)]]>);
};

public method .new_with() {
    arg @args;
    var name, prose, data, new;
    
    name = (listlen(args) > 0) && (args[1]);
    prose = (listlen(args) > 1) && (args[2]);
    new = .new();
    if (prose)
        new = new.set_prose(prose);
    if (name)
        new = new.set_name(name);
    return new;
};

frob method .perms() {
    arg this, what, @args;
    
    return (what == (this['manager])) || (> (this['location]).perms(what, @args) <);
};

frob method .prose() {
    arg this, @no_default;
    
    return (| this['prose] |) || (no_default ? 0 : "You see nothing special");
};

frob method .remote_commands() {
    arg this;
    
    return pass();
};

frob method .set_gender(): nooverride  {
    arg name, definer, value;
    
    throw(~perm, "You cannot set the gender on frobs, sorry.");
};

frob method .set_lock() {
    arg this, name, definer, value;
    
    if (class(value) == $true_lock_frob)
        return .change_data(this, 'lock, 0, 'remove);
    else
        return .change_data(this, 'lock, value);
};

frob method .set_msg(): nooverride  {
    arg this, name, branch, definer, value;
    var compiler, branches, msg, definer, msgs;
    
    (> .perms(this, 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.");
    if (dict_contains(this, 'msgs))
        msgs = this['msgs];
    else
        msgs = #[];
    msg = dict_add((| msgs[name] |) || #[], branch, value);
    msgs = dict_add(msgs, name, msg);
    return .change_data(this, 'msgs, msgs);
};

frob method .set_name() {
    arg this, new, @args;
    var type;
    
    if (!new)
        return;
    if (new && ((new[1]) in ["$", "#"]))
        throw(~invname, "Names cannot begin with \"$\" or \"#\".");
    if (match_regexp(new, "^(a|an|the) +"))
        throw(~bad_name, "Do not include articles in name, use +u +n or +p instead.");
    [(type ?= 'normal)] = args;
    switch (type) {
        case 'prop:
            new = [type, new, new];
        case 'uniq:
            new = [type, new, "the " + new];
        case 'normal:
            new = [type, new, ((new.a_or_an()) + " ") + new];
        default:
            throw(~invarg, "Type must be one of: 'prop, 'normal or 'uniq.");
    }
    return .change_data(this, 'name, new);
};

frob method .set_prose() {
    arg this, new;
    
    return .change_data(this, 'prose, new);
};

frob method .set_setting(): nooverride  {
    arg this, name, definer, value;
    var i, args, settings;
    
    (> .perms(this, sender()) <);
    i = (> definer.setting_info(name) <);
    if (dict_contains(i, 'parse)) {
        args = sublist(i['parse], 2);
        catch ~methodnf
            value = (> .((i['parse])[1])(value, @args) <);
        with
            value = (> $settings.((i['parse])[1])(value, @args) <);
    }
    if (dict_contains(i, 'set)) {
        return (> .((i['set])[1])(this, name, definer, value, @sublist(i['set], 2)) <);
    } else {
        settings = dict_add((| this['settings] |) || #[], name, value);
        return .change_data(this, 'settings, settings);
    }
};

frob method .set_visibility() {
    arg this, name, definer, value;
    
    return .change_data(this, 'visibility, value);
};

frob method .setting_definer(): nooverride  {
    arg this, name;
    
    return pass(name);
};

frob method .shortcuts() {
    arg this;
    
    return pass();
};

public method .try_lock() {
    arg this, @args;
    
    return (| this['lock] |) ? ((this['lock]).try(@args)) : 1;
};

frob method .visibility() {
    arg this, @args;
    
    return (| this['visibility] |) || 0;
};

frob method .will_move() {
    arg this, mover, place;
    
    if (!(> .try_lock(this, mover) <))
        throw(~locked, ((((.name()).capitalize()) + " is locked to ") + ((this['lock]).lock_name('thing))) + ".");
    return 1;
};

frob method .writers(): nooverride  {
    arg this, @literal;
    
    if (literal)
        return [];
    return [this['manager]];
};