/
CDC-1.2b/
CDC-1.2b/src/
parent $user
object $builder

var $root child_index 0
var $root owners [$builder]
var $root fertile 0
var $has_commands commands [["@par?ents *", 'parents_cmd], ["@dest?roy *", 'destroy_cmd], ["@child?ren|@kids *", 'children_cmd], ["@build *", 'build_cmd], ["@attach * to *", 'attach_cmd], ["@realm?s", 'realms_cmd]]
var $has_commands shortcuts []
var $has_verbs verbs #[]
var $location contents []
var $located location $nowhere
var $user password "*"
var $user connected_at 0
var $user last_command_at 0
var $user connections []
var $root inited 1
var $root owned [$builder]
var $command_aliases command_aliases []
var $user modes #[]
var $mail_list letters #[]
var $mail_list letters_index #[]
var $mail_list senders 1
var $mail_list readers [$core]
var $mail_list notify [$builder]
var $mail_list last_letter 0
var $mail_ui subscribed #[[$builder, 791485891]]
var $gendered gender $gender_neuter
var $located obvious 1
var $described prose #[]
var $user prompt ""
var $root manager $builder
var $root writable [$builder]
var $root readable ['parameters, 'methods, 'code]
var $user parsers [$command_parser, $verb_parser]
var $user tell_traceback ['brief, 0]
var $user context #[]
var $root quota 75000
var $root dbref 'builder
var $named name ['uniq, "Generic Builder"]
var $named name_aliases []
var $user_data user_data #[['real_name, [1, "???"]], ['email, [1, "???"]]]
var $old_command_environment verb_cache #[]
var $old_command_environment command_cache []
var $old_command_environment shortcuts_cache []
var $help_ui current_node $help_node_summary
var $help_ui last_visited #[['pos, 1], ['nodes, [$help_node_summary]]]
var $mail_list mail []
var $mail_ui current #[['location, 0], ['list, $builder]]

method children_cmd
    arg verb, what;
    var line, kid, colx, col, kids, x;
    
    what = .match_env_nice(what);
    kids = what.children();
    if (!kids) {
        .tell(("Children of " + (what.namef('xref))) + ": ** None **");
    } else {
        col = (.linelen()) / 8;
        colx = col * 3;
        line = (listlen(kids) > 1) ? "Children" | "Child";
        .tell(((line + " of ") + (what.namef('ref))) + ":");
        line = pad(" Name", colx + 2) + pad(" Perms", col - 2);
        .tell((line + pad("Size ", -col)) + "Manager");
        for kid in (kids) {
            line = " " + (kid.namef('xref));
            line = pad(line, colx + 2);
            line = line + pad(" " + ($object.see_perms(kid)), col - 2);
            line = line + pad(tostr(kid.size()) + " ", -col);
            line = line + pad($object.get_name(kid.manager(), 'namef, ['xref]), colx);
            .tell(line);
        }
    }
.

method parents_cmd
    arg verb, what;
    var line, par, colx, col, parents, x;
    
    what = .match_env_nice(what);
    parents = what.parents();
    col = (.linelen()) / 8;
    colx = col * 3;
    line = "Parent" + ((listlen(parents) > 1) ? "s" | "");
    .tell(((line + " of ") + (what.namef('ref))) + ":");
    line = pad(" Name", colx + 2) + pad(" Perms", col - 2);
    .tell((line + pad("Size ", -col)) + "Manager");
    for par in (parents) {
        line = " " + (par.namef('xref));
        line = pad(line, colx + 2);
        line = line + pad(" " + ($object.see_perms(par)), col - 2);
        line = line + pad(tostr(par.size()) + " ", -col);
        line = line + pad($object.get_name(par.manager(), 'namef, ['xref]), colx);
        .tell(line);
    }
.

method destroy_cmd
    arg destroy, what;
    var syntax;
    
    if (sender() != this())
        throw(~perm, "Sender not this.");
    syntax = "@destroy <object>";
    what = .match_env_nice(what, syntax);
    catch any {
        what.destroy();
        .tell("Destroyed.");
    } with handler {
        $parse.tell_error((traceback()[1])[2], syntax);
    }
.

method _build_query_coordinates
    arg [returning];
    var radial, azimuth, coord;
    
    (> .perms(sender(), 'this) <);
    ._build_hint(5);
    while (1) {
        coord = .prompt("Exit coordinates (radial,azimuth): ");
        if (coord == "@abort")
            return 0;
        if (coord == "@shortcuts") {
            ._build_shortcuts();
            continue;
        }
        if (!coord) {
            .tell("Invalid Coordinates.");
            continue;
        }
        catch ~coordnf, ~invcoord {
            if (coord.is_numeric()) {
                coord = coord.explode_english_list();
                if (listlen(coord) != 2) {
                    .tell("Seperate coordinates with a comma.");
                    continue;
                }
                if ((!((coord[1]).is_numeric())) || (!((coord[2]).is_numeric()))) {
                    .tell("Invalid coordinates.");
                    continue;
                }
                if ((!((coord[1]).is_numeric())) || (!((coord[2]).is_numeric()))) {
                    .tell("Invalid coordinates.");
                    continue;
                }
                radial = toint(coord[1]);
                azimuth = toint(coord[2]);
            } else {
                coord = $places.coordinates(coord);
                radial = coord[1];
                azimuth = coord[2];
            }
            $places.valid_coordinates(radial, azimuth);
        } with handler {
            .tell((traceback()[1])[2]);
            continue;
        }
        return [radial, azimuth];
    }
.

method build_cmd
    arg cmd, str;
    var there, exit1, exit2, x, name, line, loc, recycle, c, text;
    
    (> .perms(sender(), 'this) <);
    loc = .location();
    if (!(| loc.will_attach('source, this()) |)) {
        .tell("You cannot extend from this room.");
        return;
    }
    catch any {
        ._build_hint(1);
        if (!str) {
            ._build_hint(2);
            name = ._build_loop_name_query("Name of destination room: ");
            if (name == (-1))
                ._build_abort(recycle);
            there = (| ($places.place('default_new)).spawn() |);
            if (!there)
                return .tell("Unable to create room!");
            ._build_set_name(there, @name);
            ._build_hint(4);
            while (1) {
                line = .prompt(("What realm is " + (there.name())) + " in? ");
                if (line == "@abort")
                    ._build_abort(recycle, there);
                if (line == "@realms") {
                    .tell("Known realms:");
                    for x in ($places.known_realms())
                        .tell("  " + (x.name()));
                    continue;
                }
                x = $places.match_realm(line);
                if (!x)
                    continue;
                there.set_realm(x, 'interior);
                break;
            }
        } else if (str in ["-s", "-shortcuts"]) {
            ._build_shortcuts();
            return;
        } else {
            str = explode(str);
            there = .match_env_nice(str[listlen(str)]);
            catch any {
                $places.is_place(there);
            } with handler {
                return .tell((traceback()[1])[2]);
            }
            recycle = 1;
        }
    
        // Ok, we should have a place now as 'there'
        exit1 = ._build_query_exitname(there, loc);
        if ((!exit1) || (exit1 == (-1)))
            ._build_abort(recycle, there);
        c = ._build_query_coordinates();
        if (!c)
            ._build_abort(recycle, there, exit1);
        exit1 = [exit1, c];
        exit2 = ._build_query_exitname(loc, there);
        if (exit2 && (exit2 != (-1))) {
            c = $places.invert_coordinates(@exit1[2]);
            if (!c)
                ._build_abort(recycle, there, exit1[1], exit2);
            exit2 = [exit2, c];
        }
    
        // now we have an exit (or exits), lets try and link everything...
        catch any {
            (exit1[1]).attach(loc, there, @exit1[2]);
        } with handler {
            .tell(("Unable to attach " + ((exit1[1]).name())) + " because: ");
            .tell((traceback()[1])[2]);
            line = .prompt("Continue building? ");
            if (line in ["no", "n"])
                ._build_abort(recycle, there, exit1[1], exit2[1]);
        }
        if (exit2) {
            catch any {
                (exit2[1]).attach(there, loc, @exit2[2]);
            } with handler {
                .tell(("Unable to attach " + ((exit2[1]).name())) + " because: ");
                .tell((traceback()[1])[2]);
                line = .prompt("Continue building? ");
                if (line in ["no", "n"])
                    ._build_abort(recycle, there, exit1[1], exit2[1]);
            }
        }
    
        // Throw in some random pause()'s to reset our tick count.
        pause();
        ._build_query_prose(there);
        ._build_query_prose(exit1[1]);
        ._build_query_prose(exit2[1]);
    } with handler {
        if (error() == ~stop)
            return;
        .tell("Ack, error: " + ((traceback()[1])[2]));
        ._build_abort(recycle, there, (| exit1[1] |), (| exit2[1] |));
    }
    .tell("Finished building extension, do not forget to set exit messages when they are available (you will be notified when they are completed).");
.

method _build_abort
    arg recycle, [objs];
    var obj;
    
    (> .perms(sender(), 'this) <);
    (> .perms(caller(), $builder) <);
    .tell("@build aborted.");
    for obj in (objs) {
        if (valid(obj)) {
            if ((obj.has_ancestor($place)) && recycle)
                continue;
            .tell(("Destroying " + (obj.name())) + "...");
            (| obj.destroy() |);
        }
    }
    throw(~stop, "", 'no_traceback);
.

method _build_shortcuts
    var x;
    
    (> .perms(sender(), 'this) <);
    .tell("Radial/Azimuth Coordinate shortcuts:");
    .tell(" Shortcut            Radial Azimuth");
    for x in ($places.coordinate_shortcuts())
        .tell(((" " + pad(x[1], 20)) + pad(tostr((x[2])[1]), 7)) + tostr((x[2])[2]));
.

method _build_loop_name_query
    arg prompt, [args];
    var invalid, syntax, line, out;
    
    (> .perms(sender(), 'this) <);
    invalid = [@args, "Invalid name."][1];
    syntax = [@args, "", ""][2];
    ._build_hint(3);
    while (1) {
        line = .prompt(prompt);
        if (line == "@abort")
            return -1;
        if (!line) {
            .tell(invalid);
            continue;
        }
        line = (| $code.parse_name(line) |);
        if (!line) {
            .tell("Empty name.");
            continue;
        }
        return line;
    }
.

method _build_set_name
    arg obj, name, aliases;
    var a, x;
    
    (> .perms(sender(), 'this) <);
    catch any {
        obj.set_name(@name);
    } with handler {
        .tell("Unable to set name; " + ((traceback()[1])[2]));
        .tell("Setting name as " + tostr(obj.dbref('symbol)));
        obj.set_name(tostr(obj.dbref('symbol)));
    }
    for a in (aliases)
        obj.add_name_alias(a);
.

method _build_query_exitname
    arg source, dest;
    var exit, line, name;
    
    (> .perms(sender(), 'this) <);
    line = ((("Exit from " + (dest.name())) + " to ") + (source.name())) + ":";
    name = ._build_loop_name_query(line);
    if (name == (-1))
        return -1;
    if (name in ["none", "<none>"])
        return 0;
    exit = (| $exit.spawn() |);
    if (!exit) {
        .tell("Unable to create exit!");
        return 0;
    }
    ._build_set_name(exit, @name);
    return exit;
.

method _build_query_prose
    arg obj;
    var text;
    
    (> .perms(sender(), 'this) <);
    ._build_hint(6);
    while (1) {
        text = .prompt(("Short prose on " + (obj.name())) + ": ");
        if (!text)
            continue;
        if (text == "@abort")
            return 0;
        if (text == "@skip") {
            // do nothing
        } else {
            catch any {
                obj.set_prose('short, [text]);
            } with handler {
                .tell("Unable to set short prose.");
            }
        }
        .tell(("You can change the short prose at a later time with: `@prose [-short] " + (obj.dbref())) + "`.");
        break;
    }
    if (!(obj.has_ancestor($exit))) {
        while (1) {
            text = .read(("Enter text for long prose on " + (obj.name())) + " (end with a period or abort with `@abort`)");
            if (text == 'aborted) {
                text = .prompt("Skip this step or completely abort [skip/abort]? ");
                if (match_template("a?bort", text))
                    return 0;
            } else {
                if (!(text[1]))
                    continue;
                catch any {
                    obj.set_prose(long, text);
                } with handler {
                    .tell(("Unable to set long prose, set it at a later point with `@prose -long " + (obj.dbref())) + "`.");
                }
            }
            .tell(("You can change the long prose at a later time with: `@prose -long " + (obj.dbref())) + "`.");
            break;
        }
    }
.

method _build_hint
    arg hint;
    var hint_text;
    
    (> .perms(sender(), 'this) <);
    
    // This should be default on.
    // if (!.setting("build-hints"))
    //    return;
    hint_text = (| $places.build_hint(hint) |);
    if (!hint_text)
        return;
    .tell([("Build hint #" + tostr(hint)) + ":", @hint_text, "---"]);
.

method attach_cmd
    arg cmd, source_str, prep, dest_str;
    var source, dest, coords, coords_str, exit, ename;
    
    (> .perms(sender(), 'this) <);
    if (!source_str)
        source = .location();
    else
        source = .match_env_nice(source_str);
    dest = .match_env_nice(dest_str);
    exit = ._build_query_exitname(dest, source);
    if (exit == (-1))
        return .tell("Aborted.");
    coords = ._build_query_coordinates();
    if (!coords)
        return .tell("Aborted.");
    ._build_query_prose(exit);
    catch any {
        exit.attach(source, dest, @coords);
    } with handler {
        .tell("Ack, unable to attach exit because:");
        .tell("  " + ((traceback()[1])[2]));
        (| exit.destroy() |);
        return;
    }
    .tell("Successfully attached exit.");
.

method realms_cmd
    arg cmd;
    var x, realms;
    
    (> .perms(sender(), 'this) <);
    
    // realms = $places.known_realms();
    realms = ($places.known_realms()).union($realms_class.descendants());
    .tell("Realms: " + ((realms.map('name)).to_english()));
.