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 |