Generic Editor (#51)(an instance of generic room made by Hacker)VERB SOURCE CODE: say:
if ((caller != player) && (caller_perms() != player))
return E_PERM;
endif
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
else
this:insert_line(who, argstr);
endif
.
emote:
if ((caller != player) && (caller_perms() != player))
return E_PERM;
endif
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
else
this:append_line(who, argstr);
endif
.
enter:
if (!this:loaded(player))
player:tell(this:nothing_loaded_msg());
else
lines = $command_utils:read_lines();
if (typeof(lines) == ERR)
player:notify(tostr(lines));
return;
endif
this:insert_line(this:loaded(player), lines, 0);
endif
.
lis*t view:
nonum = 0;
if (verb == "view")
if (!args)
l = {};
for i in [1..length(this.active)]
if (this.readable[i])
l = {@l, this.active[i]};
endif
endfor
if (l)
player:tell("Players having readable texts in this editor: ", $string_utils:names_of(l));
else
player:tell("No one has published anything in this editor.");
endif
return;
elseif ($command_utils:player_match_result(plyr = $string_utils:match_player(args[1]),
args[1])[1])
"...no such player";
return;
elseif ((!(who = this:loaded(plyr))) || (!this:readable(who)))
player:tell(plyr.name, "(", plyr, ") has not published anything in this editor.");
return;
endif
args = listdelete(args, 1);
elseif (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
return;
endif
len = length(this.texts[who]);
ins = this.inserting[who];
window = 8;
if (len < (2 * window))
default = {"1-$"};
elseif (ins <= window)
default = {tostr("1-", 2 * window)};
else
default = {tostr(window, "_-", window, "^"), tostr(2 * window, "$-$")};
endif
if (typeof(range = this:parse_range(who, default, @args)) != LIST)
player:tell(tostr(range));
elseif (range[3] && (!(nonum = "nonum" == $string_utils:trim(range[3]))))
player:tell("Don't understand this: ", range[3]);
elseif (nonum)
player:tell_lines(this.texts[who][range[1]..range[2]]);
else
for line in [range[1]..range[2]]
this:list_line(who, line);
if ($command_utils:running_out_of_time())
suspend(0);
if (!(who = this:loaded(player)))
player:tell("ack! something bad happened during a suspend...");
return;
endif
endif
endfor
if ((ins > len) && (len == range[2]))
player:tell("^^^^");
endif
endif
.
ins*ert n*ext p*revious .:
if (i = index(argstr, "\""))
text = argstr[i + 1..length(argstr)];
argstr = argstr[1..i - 1];
else
text = 0;
endif
spec = $string_utils:trim(argstr);
if (index("next", verb) == 1)
verb = "next";
spec = "+" + (spec || "1");
elseif (index("prev", verb) == 1)
verb = "prev";
spec = "-" + (spec || "1");
else
spec = spec || ".";
endif
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
elseif (ERR == typeof(number = this:parse_insert(who, spec)))
if (verb in {"next", "prev"})
player:tell("Argument must be a number.");
else
player:tell("You must specify an integer or `$' for the last line.");
endif
elseif ((number > (max = length(this.texts[who]) + 1)) || (number < 1))
player:tell("That would take you out of range (to line ", number, "?).");
else
this.inserting[who] = number;
if (typeof(text) == STR)
this:insert_line(who, text);
else
if (verb != "next")
(number > 1) ? this:list_line(who, number - 1) | player:tell("____");
endif
if (verb != "prev")
(number < max) ? this:list_line(who, number) | player:tell("^^^^");
endif
endif
endif
.
del*ete:
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
elseif (typeof(range = this:parse_range(who, {"_", "1"}, @args)) != LIST)
player:tell(range);
elseif (range[3])
player:tell("Junk at end of cmd: ", range[3]);
else
player:tell_lines((text = this.texts[who])[from = range[1]..to = range[2]]);
player:tell("---Line", (to > from) ? "s" | "", " deleted. Insertion point is
before line ", from, ".");
this.texts[who] = {@text[1..from - 1], @text[to + 1..length(text)]};
if (!this.changes[who])
this.changes[who] = 1;
this.times[who] = time();
endif
this.inserting[who] = from;
endif
.
f*ind:
if (callers() && (caller != this))
return E_PERM;
endif
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
elseif (typeof(subst = this:parse_subst(argstr && (argstr[1] + argstr), "c", "Empty
search string?")) != LIST)
player:tell(tostr(subst));
elseif (typeof(start = subst[4] ? this:parse_insert(who, subst[4]) | this.inserting[who])
== ERR)
player:tell("Starting from where?", subst[4] ? (" (can't parse " + subst[4])
+ ")" | "");
else
search = subst[2];
case = !index(subst[3], "c", 1);
text = this.texts[who];
tlen = length(text);
while ((start <= tlen) && (!index(text[start], search, case)))
start = start + 1;
endwhile
if (start > tlen)
player:tell("`", search, "' not found.");
else
this.inserting[who] = start + 1;
this:list_line(who, start);
endif
endif
.
s*ubst:
if (callers() && (caller != this))
return E_PERM;
endif
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
elseif (typeof(subst = this:parse_subst(argstr)) != LIST)
player:tell(tostr(subst));
elseif (typeof(range = this:parse_range(who, {"_", "1"}, @$string_utils:explode(subst[4])))
!= LIST)
player:tell(range);
elseif (range[3])
player:tell("Junk at end of cmd: ", range[3]);
else
fromstr = subst[1];
tostr = subst[2];
global = index(subst[3], "g", 1);
case = !index(subst[3], "c", 1);
munged = {};
text = this.texts[who];
changed = {};
for line in [from = range[1]..to = range[2]]
t = t0 = text[line];
if (!fromstr)
t = tostr + t;
elseif (global)
t = strsub(t, fromstr, tostr, case);
elseif (i = index(t, fromstr, case))
t = (t[1..i - 1] + tostr) + t[i + length(fromstr)..length(t)];
endif
if (strcmp(t0, t))
changed = {@changed, line};
endif
munged = {@munged, t};
endfor
if (!changed)
player:tell("No changes in line", (from == to) ? tostr(" ", from) | tostr("s
", from, "-", to), ".");
else
this.texts[who] = {@text[1..from - 1], @munged, @text[to + 1..length(text)]};
if (!this.changes[who])
this.changes[who] = 1;
this.times[who] = time();
endif
for line in (changed)
this:list_line(who, line);
endfor
endif
endif
.
m*ove c*opy:
verb = (is_move = verb[1] == "m") ? "move" | "copy";
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
return;
endif
wargs = args;
t = to_pos = 0;
while (t = "to" in (wargs = wargs[t + 1..length(wargs)]))
to_pos = to_pos + t;
endwhile
range_args = args[1..to_pos - 1];
if ((!to_pos) || (ERR == typeof(dest = this:parse_insert(who, $string_utils:from_list(wargs,
" ")))))
player:tell(verb, " to where? ");
elseif ((dest < 1) || (dest > ((last = length(this.texts[who])) + 1)))
player:tell("Destination (", dest, ") out of range.");
elseif (("from" in range_args) || ("to" in range_args))
player:tell("Don't use that kind of range specification with this command.");
elseif (typeof(range = this:parse_range(who, {"_", "^"}, @args[1..to_pos - 1])) !=
LIST)
player:tell(range);
elseif (range[3])
player:tell("Junk before `to': ", range[3]);
elseif ((is_move && (dest >= range[1])) && (dest <= (range[2] + 1)))
player:tell("Destination lies inside range of lines to be moved.");
else
from = range[1];
to = range[2];
ins = this.inserting[who];
text = this.texts[who];
if (!is_move)
this.texts[who] = {@text[1..dest - 1], @text[from..to], @text[dest..last]};
if (ins >= dest)
this.inserting[who] = ((ins + to) - from) + 1;
endif
else
"oh shit... it's a move";
if (dest < from)
newtext = {@text[1..dest - 1], @text[from..to], @text[dest..from - 1],
@text[to + 1..last]};
if ((ins >= dest) && (ins <= to))
ins = (ins > from) ? (ins - from) + dest | (((ins + to) - from) +
1);
endif
else
newtext = {@text[1..from - 1], @text[to + 1..dest - 1], @text[from..to],
@text[dest..last]};
if ((ins > from) && (ins < dest))
ins = (ins <= to) ? ((ins + dest) - to) - 1 | (((ins - to) + from)
- 1);
endif
endif
this.texts[who] = newtext;
this.inserting[who] = ins;
endif
if (!this.changes[who])
this.changes[who] = 1;
this.times[who] = time();
endif
player:tell("Lines ", is_move ? "moved." | "copied.");
endif
.
join*literal:
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
elseif (typeof(range = this:parse_range(who, {"_-^", "_", "^"}, @args)) != LIST)
player:tell(range);
elseif (range[3])
player:tell("Junk at end of cmd: ", range[3]);
elseif (!(result = this:join_lines(who, @range[1..2], length(verb) <= 4)))
player:tell((result == 0) ? "Need at least two lines to join." | result);
else
this:list_line(who, range[1]);
endif
.
fill:
fill_column = 70;
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
elseif (typeof(range = this:parse_range(who, {"_", "1"}, @args)) != LIST)
player:tell(range);
elseif (range[3] && ((range[3][1] != "@") || ((fill_column = tonum(range[3][2..length(range[3])]))
< 10)))
player:tell("Usage: fill [
pub*lish perish unpub*lish depub*lish:
if (!(who = this:loaded(player)))
player:tell(this:nothing_loaded_msg());
return;
endif
if (typeof(e = this:set_readable(who, index("publish", verb) == 1)) == ERR)
player:tell(e);
elseif (e)
player:tell("Your text is now globally readable.");
else
player:tell("Your text is read protected.");
endif
.
w*hat:
if (!(this:ok(who = player in this.active) && (typeof(this.texts[who]) == LIST)))
player:tell(this:nothing_loaded_msg());
else
player:tell("You are editing ", this:working_on(who), ".");
player:tell("Your insertion point is ", (this.inserting[who] > length(this.texts[who]))
? "after the last line: next line will be #" | "before line ", this.inserting[who],
".");
player:tell(this.changes[who] ? this:change_msg() | this:no_change_msg());
if (this.readable[who])
player:tell("Your text is globally readable.");
endif
endif
.
abort:
if (!this.changes[who = player in this.active])
player:tell("No changes to throw away. Editor cleared.");
else
player:tell("Throwing away session for ", this:working_on(who), ".");
endif
this:reset_session(who);
if (this.exit_on_abort)
this:done();
endif
.
done q*uit pause:
if (!(caller in {this, player}))
return E_PERM;
elseif (!valid(origin = this.original[who = player in this.active]))
player:tell("I don't know where you came here from.");
else
player:moveto(origin);
if (player.location == this)
player:tell("Hmmm... the place you came from doesn't want you back.");
else
if (msg = this:return_msg())
player.location:announce($string_utils:pronoun_sub(msg));
endif
return;
endif
endif
player:tell("You'll have to use 'home' or a teleporter.");
.
huh2:
"This catches subst and find commands that don't fit into the usual model, e.g.,
s/.../.../ without the space after the s, and find commands without the verb `find'.
Still behaves in annoying ways (e.g., loses if the search string contains multiple
whitespace), but better than before.";
set_task_perms(caller_perms());
if ((c = callers()) && ((c[1][1] != this) || (length(c) > 1)))
return pass(@args);
endif
verb = args[1];
v = 1;
vmax = min(length(verb), 5);
while ((v <= vmax) && (verb[v] == "subst"[v]))
v = v + 1;
endwhile
argstr = $code_utils:argstr(verb, args[2]);
if (((v > 1) && (v <= length(verb))) && (((vl = verb[v]) < "A") || (vl > "Z")))
argstr = (verb[v..length(verb)] + (argstr && " ")) + argstr;
return this:subst();
elseif ("/" == verb[1])
argstr = (verb + (argstr && " ")) + argstr;
return this:find();
else
pass(@args);
endif
.
insertion: return this:ok(who = args[1]) && this.inserting[who]; . set_insertion: return this:ok(who = args[1]) && ((((ins = tonum(args[2])) < 1) ? E_INVARG | ((ins <= (max = length(this.texts[who]) + 1)) || (ins = max))) && (this.inserting[who] = ins)); . changed retain_session_on_exit: return this:ok(who = args[1]) && this.changes[who]; . set_changed: return this:ok(who = args[1]) && (((unchanged = !args[2]) || (this.times[who] = time())) && (this.changes[who] = !unchanged)); . origin: return this:ok(who = args[1]) && this.original[who]; . set_origin: return this:ok(who = args[1]) && (((valid(origin = args[2]) && (origin != this)) || ((origin == $nothing) || E_INVARG)) && (this.original[who] = origin)); . readable: return (((who = args[1]) < 1) || (who > length(this.active))) ? E_RANGE | this.readable[who]; . set_readable: return this:ok(who = args[1]) && (this.readable[who] = !(!args[2])); . text: return (this:readable(who = args[1] || (player in this.active)) || this:ok(who)) && this.texts[who]; . load:
texts = args[2];
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
elseif (typeof(texts) == STR)
texts = {texts};
elseif ((typeof(texts) != LIST) || (length(texts) && (typeof(texts[1]) != STR)))
return E_TYPE;
endif
this.texts[who] = texts;
this.inserting[who] = length(texts) + 1;
this.changes[who] = 0;
this.readable[who] = 0;
this.times[who] = time();
.
working_on:
"Dummy routine. The child editor should provide something informative";
return this:ok(who = args[1]) && (("something [in " + this.name) + "]");
.
ok:
who = args[1];
if ((who < 1) || (who > length(this.active)))
return E_RANGE;
elseif ((length(c = callers()) < 2) ? player == this.active[who] | ((c[2][1] == this)
|| ($perm_utils:controls(c[2][3], this.active[who]) || (c[2][3] == $generic_editor.owner))))
return 1;
else
return E_PERM;
endif
.
loaded: return ((who = args[1] in this.active) && (typeof(this.texts[who]) == LIST)) && who; . list_line:
if (this:ok(who = args[1]))
f = 1 + ((line = args[2]) in {(ins = this.inserting[who]) - 1, ins});
player:tell($string_utils:right(line, 3, " _^"[f]), ":_^"[f], " ", this.texts[who][line]);
endif
.
insert_line:
":insert_line([who,] line or list of lines [,quiet])";
" inserts the given text at the insertion point.";
" returns E_NONE if the session has no text loaded yet.";
if (typeof(who = args[1]) != NUM)
args = {player in this.active, @args};
endif
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
elseif (typeof(text = this.texts[who]) != LIST)
return E_NONE;
else
if (typeof(lines = args[2]) != LIST)
lines = {lines};
endif
p = this.active[who];
quiet = (length(args) >= 3) ? args[3] | p:edit_option("quiet_insert");
insert = this.inserting[who];
this.texts[who] = {@text[1..insert - 1], @lines, @text[insert..length(text)]};
this.inserting[who] = insert + length(lines);
if (lines)
if (!this.changes[who])
this.changes[who] = 1;
this.times[who] = time();
endif
if (!quiet)
if (length(lines) != 1)
p:tell("Lines ", insert, "-", (insert + length(lines)) - 1, " added.");
else
p:tell("Line ", insert, " added.");
endif
endif
else
p:tell("No lines added.");
endif
endif
.
append_line:
":append_line([who,] string)";
" appends the given string to the line before the insertion point.";
" returns E_NONE if the session has no text loaded yet.";
if (typeof(who = args[1]) != NUM)
args = {player in this.active, @args};
endif
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
elseif ((append = this.inserting[who] - 1) < 1)
return this:insert_line(who, {args[2]});
elseif (typeof(text = this.texts[who]) != LIST)
return E_NONE;
else
this.texts[who][append] = text[append] + args[2];
if (!this.changes[who])
this.changes[who] = 1;
this.times[who] = time();
endif
p = this.active[who];
if (!p:edit_option("quiet_insert"))
p:tell("Appended to line ", append, ".");
endif
endif
.
join_lines:
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
elseif ((from = args[2]) >= (to = args[3]))
return 0;
else
nline = "";
for line in ((text = this.texts[who])[from..to])
if (!(english = args[4]))
nline = nline + line;
else
len = length(line) + 1;
while ((len = len - 1) && (line[len] == " "))
endwhile
if (len > 0)
nline = (nline + line) + (index(".:", line[len]) ? " " | " ");
endif
endif
endfor
this.texts[who] = {@text[1..from - 1], nline, @text[to + 1..length(text)]};
if ((insert = this.inserting[who]) > from)
this.inserting[who] = (insert <= to) ? from + 1 | ((insert - to) + from);
endif
if (!this.changes[who])
this.changes[who] = 1;
this.times[who] = time();
endif
return to - from;
endif
.
parse_number:
"parse_number(who,string,before) interprets string as a line number. In the event
that string is `.', `before' tells us which line to use. Return 0 if string is bogus.";
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
endif
last = length(this.texts[who]);
ins = this.inserting[who] - 1;
string = args[2];
after = !args[3];
if (!string)
return 0;
elseif ("." == string)
return ins + after;
elseif (!(i = index("_^$", string[slen = length(string)])))
return tonum(string);
else
start = {ins + 1, ins, last + 1}[i];
n = 1;
if ((slen > 1) && (!(n = tonum(string[1..slen - 1]))))
return 0;
elseif (i % 2)
return start - n;
else
return start + n;
endif
endif
.
parse_range:
"parse_range(who,default,@args) => {from to rest}";
numargs = length(args);
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
elseif (!(last = length(this.texts[who])))
return this:no_text_msg();
endif
default = args[2];
r = 0;
while (default && (LIST != typeof(r = this:parse_range(who, {}, default[1]))))
default = listdelete(default, 1);
endwhile
if (typeof(r) == LIST)
from = r[1];
to = r[2];
else
from = to = 0;
endif
saw_from_to = 0;
not_done = 1;
a = 2;
while (((a = a + 1) <= numargs) && not_done)
if (args[a] == "from")
if ((a == numargs) || (!(from = this:parse_number(who, args[a = a + 1], 0))))
return "from ?";
endif
saw_from_to = 1;
elseif (args[a] == "to")
if ((a == numargs) || (!(to = this:parse_number(who, args[a = a + 1], 1))))
return "to ?";
endif
saw_from_to = 1;
elseif (saw_from_to)
a = a - 1;
not_done = 0;
elseif (i = index(args[a], "-"))
from = this:parse_number(who, args[a][1..i - 1], 0);
to = this:parse_number(who, args[a][i + 1..length(args[a])], 1);
not_done = 0;
elseif (f = this:parse_number(who, args[a], 0))
from = f;
if ((a == numargs) || (!(to = this:parse_number(who, args[a + 1], 1))))
to = from;
else
a = a + 1;
endif
not_done = 0;
else
a = a - 1;
not_done = 0;
endif
endwhile
if (from < 1)
return tostr("from ", from, "? (out of range)");
elseif (to > last)
return tostr("to ", to, "? (out of range)");
elseif (from > to)
return tostr("from ", from, " to ", to, "? (backwards range)");
else
return {from, to, $string_utils:from_list(args[a..numargs], " ")};
endif
.
parse_insert:
"parse_ins(who,string) interprets string as an insertion point, i.e., a position
between lines and returns the number of the following line or 0 if bogus.";
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
endif
who = args[1];
last = length(this.texts[who]) + 1;
ins = this.inserting[who];
string = args[2];
if (i = index("-+", string[1]))
rest = string[2..length(string)];
return ((n = tonum(rest)) || (rest == "0")) ? {ins - n, ins + n}[i] | E_INVARG;
else
if (!(j = index(string, "^") || index(string, "_")))
offset = 0;
else
offset = (j == 1) || tonum(string[1..j - 1]);
if (!offset)
return E_INVARG;
elseif (string[j] == "^")
offset = -offset;
endif
endif
rest = string[j + 1..length(string)];
if (i = rest in {".", "$"})
return offset + {ins, last}[i];
elseif (!(n = tonum(rest)))
return E_INVARG;
else
return (offset + (j && (string[j] == "^"))) + n;
endif
endif
.
parse_subst:
recognized_flags = (length(args) >= 2) ? args[2] | "gc";
null_subst_msg = (length(args) >= 3) ? args[3] | "Null substitution?";
cmd = args[1];
if (!cmd)
return "/xxx/yyy[/[g][c]] [
invoke:
":invoke(...)";
"to find out what arguments this verb expects,";
"see this editor's parse_invoke verb.";
new = args[1];
if ((!(caller in {this, player})) && (!$perm_utils:controls(caller_perms(), player)))
"...non-editor/non-player verb trying to send someone to the editor...";
return E_PERM;
endif
if ((who = this:loaded(player)) && this:changed(who))
if (!new)
if (this:suck_in(player))
player:tell("You are working on ", this:working_on(who));
endif
return;
elseif (player.location == this)
player:tell("You are still working on ", this:working_on(who));
if (msg = this:previous_session_msg())
player:tell(msg);
endif
return;
endif
"... we're not in the editor and we're about to start something new,";
"... but there's still this pending session...";
player:tell("You were working on ", this:working_on(who));
if (!$command_utils:yes_or_no("Do you wish to delete that session?"))
if (this:suck_in(player))
player:tell("Continuing with ", this:working_on(player in this.active));
if (msg = this:previous_session_msg())
player:tell(msg);
endif
endif
return;
endif
"... note session number may have changed => don't trust `who'";
this:kill_session(player in this.active);
endif
spec = this:parse_invoke(@args);
if (typeof(spec) == LIST)
if ((player:edit_option("local") && $object_utils:has_verb(this, "local_editing_info"))
&& (info = this:local_editing_info(@spec)))
this:invoke_local_editor(@info);
elseif (this:suck_in(player))
this:init_session(player in this.active, @spec);
endif
endif
.
suck_in:
"The correct way to move someone into the editor.";
if (((loc = (who_obj = args[1]).location) != this) && (caller == this))
this.invoke_task = task_id();
who_obj:moveto(this);
if (who_obj.location == this)
fork (0)
"...forked, just in case loc:announce is broken...";
if (valid(loc) && (msg = this:depart_msg()))
loc:announce($string_utils:pronoun_sub(msg));
endif
endfork
else
who_obj:tell("For some reason, I can't move you. (?)");
this:exitfunc(who_obj);
endif
this.invoke_task = 0;
endif
return who_obj.location == this;
.
new_session:
"WIZARDLY";
who_obj = args[1];
from = args[2];
if ($object_utils:isa(from, $generic_editor))
"... never put an editor in .original, ...";
if (w = who_obj in from.active)
from = from.original[w];
else
from = #-1;
endif
endif
if (caller != this)
return E_PERM;
elseif (who = (who_obj = args[1]) in this.active)
"... edit in progress here...";
if (valid(from))
this.original[who] = from;
endif
return -1;
else
for p in ({{"active", who_obj}, {"original", valid(from) ? from | $nothing},
{"times", time()}, @this.stateprops})
this.(p[1]) = {@this.(p[1]), p[2]};
endfor
return length(this.active);
endif
.
kill_session:
"WIZARDLY";
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
else
for p in ({@this.stateprops, {"original"}, {"active"}, {"times"}})
this.(p[1]) = listdelete(this.(p[1]), who);
endfor
return who;
endif
.
reset_session:
"WIZARDLY";
if (!(fuckup = this:ok(who = args[1])))
return fuckup;
else
for p in (this.stateprops)
this.(p[1])[who] = p[2];
endfor
this.times[who] = time();
return who;
endif
.
kill_all_sessions:
"WIZARDLY";
if ((caller != this) && (!caller_perms().wizard))
return E_PERM;
else
for victim in (this.contents)
victim:tell("Sorry, ", this.name, " is going down. Your editing session
is hosed.");
victim:moveto(((who = victim in this.active) && valid(origin = this.original[who]))
? origin | (valid(victim.home) ? victim.home | $player_start));
endfor
for p in ({@this.stateprops, {"original"}, {"active"}, {"times"}})
this.(p[1]) = {};
endfor
return 1;
endif
.
acceptable: return is_player(who_obj = args[1]) && (who_obj.wizard || pass(@args)); . enterfunc:
who_obj = args[1];
if (who_obj.wizard && (!(who_obj in this.active)))
this:accept(who_obj);
endif
pass(@args);
if (this.invoke_task == task_id())
"Means we're about to load something, so be quiet.";
this.invoke_task = 0;
elseif (who = this:loaded(who_obj))
who_obj:tell("You are working on ", this:working_on(who), ".");
elseif (msg = this:nothing_loaded_msg())
who_obj:tell(msg);
endif
.
exitfunc:
if (!(who = (who_obj = args[1]) in this.active))
elseif (this:retain_session_on_exit(who))
if (msg = this:no_littering_msg())
who_obj:tell_lines(msg);
endif
else
this:kill_session(who);
endif
pass(@args);
.
@flush: "@flush @stateprop:
if (!$perm_utils:controls(player, this))
player:tell(E_PERM);
return;
endif
if (i = index(dobjstr, "="))
default = dobjstr[i + 1..length(dobjstr)];
prop = dobjstr[1..i - 1];
if (argstr[1 + index(argstr, "=")] == "\"")
elseif (default[1] == "#")
default = toobj(default);
elseif (index("0123456789", default[1]))
default = tonum(default);
elseif (default == "{}")
default = {};
endif
else
default = 0;
prop = dobjstr;
endif
if (typeof(result = this:set_stateprops(prop, default)) == ERR)
player:tell((result == E_RANGE) ? tostr(".", prop, " needs to hold a list of
the same length as .active (", length(this.active), ").") | ((result != E_NACC) ?
result | (prop + " is already a property on an ancestral editor.")));
else
player:tell("Property added.");
endif
.
@rmstateprop:
if (!$perm_utils:controls(player, this))
player:tell(E_PERM);
elseif (typeof(result = this:set_stateprops(dobjstr)) == ERR)
player:tell((result != E_NACC) ? result | (dobjstr + " is already a property
on an ancestral editor."));
else
player:tell("Property removed.");
endif
.
initialize:
if ($perm_utils:controls(caller_perms(), this))
pass(@args);
this:kill_all_sessions();
endif
.
init_for_core:
if (caller_perms().wizard)
pass();
this:kill_all_sessions();
this.help = $editor_help;
endif
.
set_stateprops:
remove = length(args) < 2;
if ((caller != this) && (!$perm_utils:controls(caller_perms(), this)))
return E_PERM;
elseif (!(length(args) in {1, 2}))
return E_ARGS;
elseif (typeof(prop = args[1]) != STR)
return E_TYPE;
elseif (i = $list_utils:iassoc(prop, this.stateprops))
if (!remove)
this.stateprops[i] = {prop, args[2]};
elseif ($object_utils:has_property(parent(this), prop))
return E_NACC;
else
this.stateprops = listdelete(this.stateprops, i);
endif
elseif (remove)
elseif (prop in properties(this))
if (this:_stateprop_length(prop) != length(this.active))
return E_RANGE;
endif
this.stateprops = {{prop, args[2]}, @this.stateprops};
else
return $object_utils:has_property(this, prop) ? E_NACC | E_PROPNF;
endif
return 0;
.
description:
is_look_self = 1;
for c in (callers())
if (is_look_self && (c[2] in {"enterfunc", "confunc"}))
return {"", "Do a 'look' to get the list of commands, or 'help' for assistance.",
"", @this.description};
elseif (c[2] != "look_self")
is_look_self = 0;
endif
endfor
d = {"Commands:", ""};
col = {{}, {}};
for c in [1..2]
for cmd in (this.commands2[c])
cmd = this:commands_info(cmd);
col[c] = {cmdargs = $string_utils:left(cmd[1] + " ", 12) + cmd[2], @col[c]};
endfor
endfor
i1 = length(col[1]);
i2 = length(col[2]);
right = 0;
while (i1 || i2)
if (!((i1 && (length(col[1][i1]) > 35)) || (i2 && (length(col[2][i2]) > 35))))
d = {@d, $string_utils:left(i1 ? col[1][i1] | "", 40) + (i2 ? col[2][i2]
| "")};
i1 && (i1 = i1 - 1);
i2 && (i2 = i2 - 1);
right = 0;
elseif (right && i2)
d = {@d, (length(col[2][i2]) > 35) ? $string_utils:right(col[2][i2], 75)
| ($string_utils:space(40) + col[2][i2])};
i2 = i2 - 1;
right = 0;
elseif (i1)
d = {@d, col[1][i1]};
i1 = i1 - 1;
right = 1;
else
right = 1;
endif
endwhile
return {@d, "", "---- Do `help
commands_info:
cmd = args[1];
if (pc = $list_utils:assoc(cmd, this.commands))
return pc;
elseif (this == $generic_editor)
return {cmd, "<<<<<======= Need to add this to .commands"};
else
return parent(this):commands_info(cmd);
endif
.
match_object:
who = {@args, player}[2];
objstr = args[1];
origin = this;
while ((where = player in origin.active) && ($recycler:valid(origin = origin.original[where])
&& (origin != this)))
if (!$object_utils:isa(origin, $generic_editor))
return origin:match_object(args[1], who);
endif
endwhile
return who:my_match_object(objstr, #-1);
.
who_location_msg:
who = args[1];
where = {#-1, @this.original}[1 + (who in this.active)];
return strsub(this.who_location_msg, "%L", where:who_location_msg(who));
return $string_utils:pronoun_sub(this.who_location_msg, who, this, where);
.
nothing_loaded_msg no_text_msg change_msg no_change_msg no_littering_msg depart_msg return_msg previous_session_msg: return this.(verb); . announce announce_all announce_all_but tell_contents: return; . fill_string: "fill(string,width[,prefix])"; "tries to cut here_huh:
"This catches subst and find commands that don't fit into the usual model, e.g.,
s/.../.../ without the space after the s, and find commands without the verb `find'.
Still behaves in annoying ways (e.g., loses if the search string contains multiple
whitespace), but better than before.";
if ((caller != this) && (caller_perms() != player))
return E_PERM;
endif
verb = args[1];
args = args[2];
v = 1;
vmax = min(length(verb), 5);
while ((v <= vmax) && (verb[v] == "subst"[v]))
v = v + 1;
endwhile
argstr = $code_utils:argstr(verb, args);
if ((v > 1) && ((v <= length(verb)) && (((vl = verb[v]) < "A") || (vl > "Z"))))
argstr = (verb[v..length(verb)] + (argstr && " ")) + argstr;
this:subst();
return 1;
elseif ("/" == verb[1])
argstr = (verb + (argstr && " ")) + argstr;
this:find();
return 1;
else
return 0;
endif
.
match: return $failed_match; . get_room:
":get_room([player]) => correct room to match in on invocation.";
who = {@args, player}[1];
if (who.location != this)
return who.location;
else
origin = this;
while ((where = player in origin.active) && (valid(origin = origin.original[where])
&& (origin != this)))
if (!$object_utils:isa(origin, $generic_editor))
return origin;
endif
endwhile
return this;
endif
.
invoke_local_editor:
":invoke_local_editor(name, text, upload)";
"Spits out the magic text that invokes the local editor in the player's client.";
"NAME is a good human-readable name for the local editor to use for this particular
piece of text.";
"TEXT is a string or list of strings, the initial body of the text being edited.";
"UPLOAD, a string, is a MOO command that the local editor can use to save the text
when the user is done editing. The local editor is going to send that command on
a line by itself, followed by the new text lines, followed by a line containing only
`.'. The UPLOAD command should therefore call $command_utils:read_lines() to get
the new text as a list of strings.";
if (caller != this)
return;
endif
name = args[1];
text = args[2];
upload = args[3];
if (typeof(text) == STR)
text = {text};
endif
notify(player, tostr("#$# edit name: ", name, " upload: ", upload));
":dump_lines() takes care of the final `.' ...";
for line in ($command_utils:dump_lines(text))
notify(player, line);
endfor
.
_stateprop_length:
"+c properties on children cannot necessarily be read, so we need this silliness...";
if (caller != this)
return E_PERM;
else
return length(this.(args[1]));
endif
.
print:
txt = this:text(player in this.active);
if (typeof(txt) == LIST)
player:tell_lines(txt);
else
player:tell("Text unreadable: ", txt);
endif
player:tell("--------------------------");
.
accept: return this:acceptable(who_obj = args[1]) && this:new_session(who_obj, who_obj.location); . PROPERTY DATA:       readable       times       commands2       help       no_text_msg       commands       invoke_task       exit_on_abort       previous_session_msg       stateprops       depart_msg       return_msg       no_littering_msg       no_change_msg       change_msg       nothing_loaded_msg       texts       active       changes       inserting       original CHILDREN: Verb Editor Note Editor Mail Room |