command utilities #48

Parent #72Owner #361Flags readSource hellcore/hellcore.db

Aliases: Generic Utilities Package

19 verbs · 16 properties · 0 children

Verbs

VerbSpecFlagsDefinerLines
object_match_failedthis none thisrxd#4822
player_match_result player_match_failedthis none thisrxd#4845
readthis none thisrxd#4819
read_linesthis none thisrxd#4829
yes_or_nothis none thisrxd#4820
read_lines_escapethis none thisrxd#4843
suspendthis none thisrxd#4849
running_out_of_timethis none thisrxd#483
suspend_if_needed sinthis none thisrxd#4817
dump_linesthis none thisrxd#4818
explain_syntaxthis none thisrxd#4818
do_huhthis none thisrxd#4835
task_infothis none thisrxd#4812
init_for_corethis none thisrxd#484
kill_if_laggythis none thisrxd#486
validate_featurethis none thisrxd#485
sin_onthis none thisrxd#4817
sin_offthis none thisrxd#481
tell_etathis none thisrxd#4818

Properties

PropertyDefinerFlagsOwnerValue
lag_samples#48r#361{}
feature_task#48#29
list of 9{610622534, "prognet", {"who"}, "who", #-3, "who", "", #-1, ""}
sin_notify#48rc#361{#35757}
megatrace#48rc#361{}
run_megatrace#48rc#3610
help_msg#72rc#361
list of 38{"$command_utils is the repository for verbs that are of general usefulness to authors of all sorts of commands. For more details about any of these verbs, use `help $command_utils:<verb-name>'.", "", "Detecting and Handling Failures in Matching", "-------------------------------------------", ":object_match_failed(match_result, name)", " Test whether or not a :match_object() call failed and print messages if so.", ":player_match_failed(match_result, name)", " Test whether or not a :match_player() call failed and print messages if so.", ":player_match_result(match_results, names)", " ...similar to :player_match_failed, but does a whole list at once.", "", "Reading Input from the Player", "-----------------------------", ":read() -- Read one line of input from the player and return it.", ":yes_or_no([prompt])", " -- Prompt for and read a `yes' or `no' answer.", ":read_lines() -- Read zero or more lines of input from the player.", ":dump_lines(lines) ", " -- Return list of lines quoted so that feeding them to ", " :read_lines() will reproduce the original lines.", ":read_lines_escape(escapes[,help])", " -- Like read_lines, except you can provide more escapes", " to terminate the read.", "", "Feature Objects", "---------------", ":validate_feature -- compare command line against feature verb argument spec", "", "Utilities for Suspending", "------------------------", ":running_out_of_time()", " -- Return true if we're low on ticks or seconds.", ":suspend_if_needed(time)", " -- Suspend (and return true) if we're running out of time.", "", "Client Support for Lengthy Commands", "-----------------------------------", ":suspend(args) -- Handle PREFIX and SUFFIX for clients in long commands."}
aliases#1rc#361<clear>
description#1rc#361{"This is the command utilities utility package. See `help $command_utils' for more details."}
object_size#1r#29{22112, 1298433815}
hidden_verbs#1rc#361<clear>
phelp_msg#1rc#361<clear>
weight#1rc#361<clear>
owner_verbs#1rc#361<clear>
plural_name#1rc#361<clear>
client_image#1rc#361<clear>
listening#1rc#361<clear>

Ancestry

Ancestors (nearest first): #72 Generic Utilities Package#1 root

Children: none

Call graph

calls n48_0 #48:object_match_failed n42_0 #42:controls n48_0->n42_0 n51_2 #51:toobj n48_0->n51_2 n48_1 #48:player_match_result n48_1->n42_0 n30_2 #30:find_all n48_1->n30_2 n20_6 #20:english_list n48_1->n20_6 n48_2 #48:read n122_8 #122:strip n48_2->n122_8 n20_9 #20:trim n48_2->n20_9 n48_3 #48:read_lines n20_0 #20:space n48_3->n20_0 n48_4 #48:yes_or_no n48_4->n42_0 n48_4->n20_9 n48_5 #48:read_lines_escape n48_5->n20_6 n20_11 #20:trimr n48_5->n20_11 n48_6 #48:suspend n107_43 #107:tell n48_6->n107_43 n48_8 #48:suspend_if_needed n48_8->n107_43 n48_10 #48:explain_syntax n48_10->n107_43 n45_2 #45:has_verb n48_10->n45_2 n51_21 #51:find_verb_named n48_10->n51_21 n51_8 #51:explain_verb_syntax n48_10->n51_8 n48_11 #48:do_huh n48_11->n42_0 n48_11->n48_10 n48_11->n45_2 n6_4 #6:my_huh n48_11->n6_4 n6_5 #6:last_huh n48_11->n6_5 n48_14 #48:kill_if_laggy n48_14->n107_43 n4_31 #4:current_lag n48_14->n4_31 n48_16 #48:sin_on n48_16->n107_43 n48_18 #48:tell_eta n35_6 #35:dhms n48_18->n35_6 n103_23 #103:gbar n48_18->n103_23

Source

object_match_failed

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1"Usage: object_match_failed(object, string)";
2"Prints a message if string does not match object.  Generally used after object is derived from a :match_object(string).";
3{match_result, string} = args;
4tell = $perm_utils:controls(caller_perms(), player) ? "notify" | "tell";
5if ((index(string, "#") == 1) && ($code_utils:toobj(string) != E_TYPE))
6"...avoid the `I don't know which `#-2' you mean' message...";
7if (!valid(match_result))
8player:(tell)(tostr(string, " does not exist."));
9endif
10return !valid(match_result);
11elseif (match_result == $nothing)
12player:(tell)("You must give the name of some object.");
13elseif (match_result == $failed_match)
14player:(tell)(tostr("I see no \"", string, "\" here."));
15elseif (match_result == $ambiguous_match)
16player:(tell)(tostr("I don't know which \"", string, "\" you mean."));
17elseif (!valid(match_result))
18player:(tell)(tostr(match_result, " does not exist."));
19else
20return 0;
21endif
22return 1;

player_match_result player_match_failed

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1":player_match_failed(result,string)";
2"  is exactly like :object_match_failed(result,string)";
3"  except that its messages are more suitable for player searches.";
4":player_match_result(results,strings)";
5"  handles a list of results, also presumably from $string_utils:match_player(strings), printing messages to player for *each* of the nonmatching strings.  It returns a list, an overall result (true if some string didn't match --- just like player_match_failed), followed by the list players that matched.";
6"";
7"An optional 3rd arg gives an identifying string to prefix to each of the nasty messages.";
8if (valid(player))
9tell = $perm_utils:controls(caller_perms(), player) ? "notify" | "tell";
10plyr = player;
11else
12tell = "notify";
13plyr = $login;
14endif
15"...";
16{match_results, strings, ?cmdid = ""} = args;
17pmf = verb == "player_match_failed";
18if (typeof(match_results) == OBJ)
19match_results = {match_results};
20strings = {strings};
21endif
22pset = {};
23bombed = 0;
24for i in [1..length(match_results)]
25if (valid(result = match_results[i]))
26pset = setadd(pset, match_results[i]);
27elseif (result == $nothing)
28"... player_match_result quietly skips over blank strings";
29if (pmf)
30plyr:(tell)("You must give the name of some player.");
31bombed = 1;
32endif
33elseif (result == $failed_match)
34plyr:(tell)(tostr(cmdid, "\"", strings[i], "\" is not the name of any player."));
35bombed = 1;
36elseif (result == $ambiguous_match)
37lst = $player_db:find_all(strings[i]);
38plyr:(tell)(tostr(cmdid, "\"", strings[i], "\" could refer to ", (length(lst) > 20) ? tostr("any of ", length(lst), " players") | $string_utils:english_list($list_utils:map_arg(2, $string_utils, "pronoun_sub", "%n (%#)", lst), "no one", " or "), "."));
39bombed = 1;
40else
41plyr:(tell)(tostr(result, " does not exist."));
42bombed = 1;
43endif
44endfor
45return pmf ? bombed | {bombed, @pset};

read

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1"$command_utils:read() -- read a line of input from the player and return it";
2"Optional argument is a prompt portion to replace `a line of input' in the prompt.";
3"";
4"Returns E_PERM if the current task is not a command task that has never called suspend().";
5{?prompt = "a line of input"} = args;
6c = callers();
7p = c[$][5];
8p:notify(((((($ansi.cyan + $ansi.bold_on) + prompt) + " ") + $ansi.bold_off) + "[or `@abort' to abort.]") + $ansi.reset);
9try
10ans = read();
11(!p.programmer) && (ans = $ansi:strip(ans));
12if ($string_utils:trim(ans) == "@abort")
13p:notify(">> Command Aborted <<");
14kill_task(task_id());
15endif
16return ans;
17except error (ANY)
18return error[1];
19endtry

read_lines

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1"$command_utils:read_lines([max]) -- read zero or more lines of input";
2"";
3"Returns a list of strings, the (up to MAX, if given) lines typed by the player.  Returns E_PERM if the current task is not a command task that has never called suspend().";
4"In order that one may enter arbitrary lines, including \"@abort\" or \".\", if the first character in an input line is `.' and there is some nonwhitespace afterwords, the `.' is dropped and the rest of the line is taken verbatim, so that, e.g., \".@abort\" enters as \"@abort\" and \"..\" enters as \".\".";
5{?max = 0} = args;
6c = callers();
7p = c[$][5];
8p:notify(tostr("[Type", max ? tostr(" up to ", max) | "", " lines of input; use `.' to end or `@abort' to abort the command.]"));
9ans = {};
10while (1)
11try
12line = read();
13if ((line[1..min(6, $)] == "@abort") && ((tail = line[7..$]) == $string_utils:space(tail)))
14p:notify(">> Command Aborted <<");
15kill_task(task_id());
16elseif ((!line) || (line[1] != "."))
17ans = {@ans, line};
18elseif ((tail = line[2..$]) == $string_utils:space(tail))
19return ans;
20else
21ans = {@ans, tail};
22endif
23if (max && (length(ans) >= max))
24return ans;
25endif
26except error (ANY)
27return error[1];
28endtry
29endwhile

yes_or_no

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1":yes-or-no([prompt]) -- prompts the player for a yes or no answer and returns a true value iff the player enters a line of input that is some prefix of \"yes\"";
2"";
3"Returns E_NONE if the player enters a blank line, E_INVARG, if the player enters something that isn't a prefix of \"yes\" or \"no\", and E_PERM if the current task is not a command task that has never called suspend().";
4c = callers();
5p = c[$][5];
6p:notify(tostr(args ? args[1] + " " | "", ($ansi.cyan + "[ Enter 'yes' or 'no': ]") + $ansi.reset));
7try
8ans = read(@((caller == p) || $perm_utils:controls(caller_perms(), p)) ? {p} | {});
9if (ans = $string_utils:trim(ans))
10if (ans == "@abort")
11p:notify(">> Command Aborted <<");
12kill_task(task_id());
13endif
14return (index("yes", ans) == 1) || ((index("no", ans) != 1) && E_INVARG);
15else
16return E_NONE;
17endif
18except error (ANY)
19return error[1];
20endtry

read_lines_escape

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1"$command_utils:read_lines_escape(escapes[,help]) -- read zero or more lines of input";
2"";
3"Similar to :read_lines() except that help is available and one may specify other escape sequences to terminate the read.";
4"  escapes should be either a string or list of strings; this specifies which inputs other from `.' or `@abort' should terminate the read (... don't use anything beginning with a `.').";
5"  help should be a string or list of strings to be printed in response to the player typing `?'; the first line of the help text should be a general comment about what the input text should be used for.  Successive lines should describe the effects of the alternative escapes.";
6"Returns {end,list-of-strings-input} where end is the particular line that terminated this input or 0 if input terminated normally with `.'.  Returns E_PERM if the current task is not a command task that has never called suspend().  ";
7"@abort and lines beginning with `.' are treated exactly as with :read_lines()";
8{escapes, ?help = "You are currently in a read loop."} = args;
9c = callers();
10p = c[$][5];
11escapes = {".", "@abort", @(typeof(escapes) == LIST) ? escapes | {escapes}};
12p:notify(tostr("[Type lines of input; `?' for help; end with `", $string_utils:english_list(escapes, "", "' or `", "', `", ""), "'.]"));
13ans = {};
14escapes[1..0] = {"?"};
15"... set up the help text...";
16if (typeof(help) != LIST)
17help = {help};
18endif
19help[2..1] = {"Type `.' on a line by itself to finish.", "Anything else with a leading period is entered with the period removed.", "Type `@abort' to abort the command completely."};
20while (1)
21try
22line = read();
23if ((trimline = $string_utils:trimr(line)) in escapes)
24if (trimline == ".")
25return {0, ans};
26elseif (trimline == "@abort")
27p:notify(">> Command Aborted <<");
28kill_task(task_id());
29elseif (trimline == "?")
30p:notify_lines(help);
31else
32return {trimline, ans};
33endif
34else
35if (line && (line[1] == "."))
36line[1..1] = "";
37endif
38ans = {@ans, line};
39endif
40except error (ANY)
41return error[1];
42endtry
43endwhile

suspend

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

none

Source

1"Suspend, using output_delimiters() in case a client needs to keep track";
2"of the output of the current command.";
3"Args are TIME, amount of time to suspend, and optional (misnamed) OUTPUT.";
4"If given no OUTPUT, just do a suspend.";
5"If OUTPUT is neither list nor string, suspend and return output_delimiters";
6"If OUTPUT is a list, it should be in the output_delimiters() format:";
7"  {PREFIX, SUFFIX}.  Use these to handle that client stuff.";
8"If OUTPUT is a string, it should be SUFFIX (output_delimiters[2])";
9"";
10"Proper usage:";
11"The first time you want to suspend, use";
12"  output_delimiters = $command_utils:suspend(time, x);";
13"where x is some non-zero number.";
14"Following, use";
15"  $command_utils:suspend(time, output_delimiters);";
16"To wrap things up, use";
17"  $command_utils:suspend(time, output_delimiters[2]);";
18"You'll probably want time == 0 most of the time.";
19"Note: Using this from verbs called by other verbs could get pretty weird.";
20{time, ?output = 0} = args;
21set_task_perms(caller_perms());
22value = 0;
23if (!output)
24suspend(time);
25else
26if (typeof(output) == LIST)
27PREFIX = output[1];
28SUFFIX = output[2];
29if (PREFIX)
30player:tell(output[2]);
31endif
32suspend(time);
33if (SUFFIX)
34player:tell(output[1]);
35endif
36elseif (typeof(output) == STR)
37if (output)
38player:tell(output);
39endif
40else
41output = output_delimiters(player);
42suspend(time);
43if (output != {"", ""})
44player:tell(output[1]);
45endif
46value = output;
47endif
48endif
49return output;

running_out_of_time

Spec this none thisFlags rxdOwner #29Definer #48

Referenced by

Source

1"Return true if we're running out of ticks or seconds.";
2return (ticks_left() < 4000) || (seconds_left() < 2);
3"If this verb is changed make sure to change :suspend_if_needed as well.";

suspend_if_needed sin

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1"Usage:  $command_utils:suspend_if_needed(<time>[, @<announcement>])";
2"See if we're running out of ticks or seconds, and if so suspend(<time>) and return true.  If more than one arg is given, print the remainder with player:tell.";
3if ((ticks_left() < 10000) || (seconds_left() < 2))
4"Note: above computation should be the same as :running_out_of_time.";
5{?time = 1, @ann} = args;
6if (ann && valid(player))
7player:tell(tostr(@ann));
8endif
9amount = max(time, min(toint($flywheel.ema), 10));
10set_task_perms(caller_perms());
11"this is trying to back off according to lag...";
12suspend(amount);
13for x in (this.sin_notify)
14`x:sin_notify(amount) ! ANY => 0';
15endfor
16return 1;
17endif

dump_lines

Spec this none thisFlags rxdOwner #29Definer #48

Referenced by

Source

1":dump_lines(text) => text `.'-quoted for :read_lines()";
2"  text is assumed to be a list of strings";
3"Returns a corresponding list of strings which, when read via :read_lines, ";
4"produces the original list of strings (essentially, any strings beginning ";
5"with a period \".\" have the period doubled).";
6"The list returned includes a final \".\"";
7text = args[1];
8newtext = {};
9i = lasti = 0;
10for line in (text)
11if (match(line, "^%(%.%| *@abort *$%)"))
12newtext = {@newtext, @(i > lasti) ? text[lasti + 1..i] | {}, "." + line};
13lasti = i = i + 1;
14else
15i = i + 1;
16endif
17endfor
18return {@newtext, @(i > lasti) ? text[lasti + 1..i] | {}, "."};

explain_syntax

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1":explain_syntax(here,verb,args)";
2verb = args[2];
3for x in ({player, args[1], @valid(dobj) ? {dobj} | {}, @valid(iobj) ? {iobj} | {}})
4what = x;
5while (hv = $object_utils:has_verb(what, verb))
6what = hv[1];
7i = 1;
8while (i = $code_utils:find_verb_named(what, verb, i))
9if (evs = $code_utils:explain_verb_syntax(x, verb, @verb_args(what, i)))
10player:tell("Try this instead:  ", evs);
11return 1;
12endif
13i = i + 1;
14endwhile
15what = parent(what);
16endwhile
17endfor
18return 0;

do_huh

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

Source

1":do_huh(verb,args)  what :huh should do by default.";
2{verb, args} = args;
3if ($perm_utils:controls(caller_perms(), player) || (caller_perms() == player))
4this.feature_task = {task_id(), verb, args, argstr, dobj, dobjstr, prepstr, iobj, iobjstr};
5endif
6set_task_perms(cp = caller_perms());
7notify = $perm_utils:controls(cp, player) ? "notify" | "tell";
8if (verb == "")
9"should only happen if a player types backslash";
10player:(notify)("I don't understand that.");
11return;
12endif
13if (player:my_huh(verb, args))
14"... the player found something funky to do ...";
15elseif (caller:here_huh(verb, args))
16"... the room found something funky to do ...";
17elseif (player:last_huh(verb, args))
18"... player's second round found something to do ...";
19elseif (dobj == $ambiguous_match)
20if (iobj == $ambiguous_match)
21player:(notify)(tostr("I don't understand that (\"", dobjstr, "\" and \"", iobjstr, "\" are both ambiguous names)."));
22else
23player:(notify)(tostr("I don't understand that (\"", dobjstr, "\" is an ambiguous name)."));
24endif
25elseif (iobj == $ambiguous_match)
26player:(notify)(tostr("I don't understand that (\"", iobjstr, "\" is an ambiguous name)."));
27else
28player:(notify)("I don't understand that.");
29"  player:my_explain_syntax(caller, verb, args) || (caller:here_explain_syntax(caller, verb, args) || this:explain_syntax(caller, verb, args));";
30if (!($ou:has_verb(player, "my_explain_syntax") && player:my_explain_syntax(caller, verb, args)))
31if (!($ou:has_verb(caller, "here_explain_syntax") && caller:here_explain_syntax(caller, verb, args)))
32this:explain_syntax(caller, verb, args);
33endif
34endif
35endif

task_info

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

none

Source

1"task_info(task id)";
2"Return info (the same info supplied by queued_tasks()) about a given task id, or E_INVARG if there's no such task queued.";
3"WIZARDLY";
4set_task_perms(caller_perms());
5tasks = queued_tasks();
6task_id = args[1];
7for task in (tasks)
8if (task[1] == task_id)
9return task;
10endif
11endfor
12return E_INVARG;

init_for_core

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

none

Source

1if (caller_perms().wizard)
2this.lag_samples = {};
3this.feature_task = "hey, neat, no feature verbs have been run yet!";
4endif

kill_if_laggy

Spec this none thisFlags rxdOwner #29Definer #48

Referenced by

Source

1"Kills this task if the current lag is greater than args[1].  Args[2..n] will be passed to player:tell.";
2cutoff = args[1];
3if ($login:current_lag() > cutoff)
4player:tell(@listdelete(args, 1));
5kill_task(task_id());
6endif

validate_feature

Spec this none thisFlags rxdOwner #29Definer #48

Referenced by

none

Source

1":validate_feature(verb, args)";
2"  (where `verb' and `args' are the arguments passed to :my_huh)";
3"  returns true or false based on whether this is the same command typed by the user (comparing it against $command_utils.feature_task, set by $command_utils:do_huh).";
4"  assumes that the :my_huh parsing has not suspended";
5return {task_id(), @args, argstr, dobj, dobjstr, prepstr, iobj, iobjstr} == this.feature_task;

sin_on

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

none

Source

1"Usage:  $command_utils:suspend_if_needed(<time>[, @<announcement>])";
2"See if we're running out of ticks or seconds, and if so suspend(<time>) and return true.  If more than one arg is given, print the remainder with player:tell.";
3if ((ticks_left() < 10000) || (seconds_left() < 2))
4"Note: above computation should be the same as :running_out_of_time.";
5{?time = 1, @ann} = args;
6if (ann && valid(player))
7player:tell(tostr(@ann));
8endif
9amount = max(time, min(toint($flywheel.ema), 10));
10set_task_perms(caller_perms());
11"this is trying to back off according to lag...";
12suspend(amount);
13for x in (this.sin_notify)
14`x:sin_notify(amount) ! ANY => 0';
15endfor
16return 1;
17endif

sin_off

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

none

Source

1return 0;

tell_eta

Spec this none thisFlags rxdOwner #361Definer #48

Referenced by

none

Source

1"$cu:tell_eta(FLOAT pct_done, INT time_started [, STR what, [, OBJ who|net]]) => 0";
2"tells 'who' how much is done, and when this will end. who defaults to player, what defaults to the name of the calling verb.";
3{pct, start, ?what = callers()[1][2], ?who = player} = args;
4elapsed = time() - start;
5if (elapsed > 0)
6pct_per_sec = pct / tofloat(elapsed);
7total = toint(100.0 / pct_per_sec);
8est_remain = $tu:dhms(total - elapsed);
9else
10est_remain = "???";
11endif
12bar = `$rpg:gbar(toint(pct), 100, 20, 0, $ansi.magenta) ! ANY => ""';
13msg = tostr($ansi.magenta, " | ", bar, $ansi.magenta, " ", what, "   ", floatstr(pct, 1), "%   [ETA ", est_remain, "]", $ansi.reset);
14if (is_a(who, $net))
15who:announce(this, msg, 1);
16else
17who:tell(msg);
18endif