command utilities #56

Parent #79Owner #2Flags readSource QuestCore.db

Aliases: command utilities

16 verbs · 7 properties · 0 children

Verbs

VerbSpecFlagsDefinerLines
object_match_failedthis none thisrxd#5622
player_match_result player_match_failedthis none thisrxd#5645
readthis none thisrxd#5618
read_linesthis none thisrxd#5629
yes_or_nothis none thisrxd#5620
read_lines_escapethis none thisrxd#5643
suspendthis none thisrxd#5649
running_out_of_timethis none thisrxd#563
suspend_if_neededthis none thisrxd#5614
dump_linesthis none thisrxd#5618
explain_syntaxthis none thisrxd#5618
do_huhthis none thisrx#5630
task_infothis none thisrxd#5612
init_for_corethis none thisrxd#564
kill_if_laggythis none thisrxd#566
validate_featurethis none thisrxd#565

Properties

PropertyDefinerFlagsOwnerValue
lag_samples#56r#2{}
feature_task#56#36
list of 9{1670993250, "@scheduler", {}, "", #-1, "", "", #-1, ""}
help_msg#79rc#2
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."}
key#1c#2<clear>
aliases#1rc#2{"command utilities"}
description#1rc#2{"This is the command utilities utility package. See `help $command_utils' for more details."}
object_size#1r#36{19021, 1539462952}

Ancestry

Ancestors (nearest first): #79 Generic Utilities Package#1 Root Class

Children: none

Call graph

calls n56_0 #56:object_match_failed n42_0 #42:controls n56_0->n42_0 n59_2 #59:toobj n56_0->n59_2 n56_1 #56:player_match_result n56_1->n42_0 n37_2 #37:find_all n56_1->n37_2 n20_6 #20:english_list n56_1->n20_6 n55_4 #55:map_arg n56_1->n55_4 n56_2 #56:read n20_9 #20:trim n56_2->n20_9 n56_3 #56:read_lines n20_71 #20:redirect_ansi n56_3->n20_71 n56_4 #56:yes_or_no n56_4->n42_0 n56_4->n20_9 n56_5 #56:read_lines_escape n56_5->n20_6 n20_11 #20:trimr n56_5->n20_11 n56_6 #56:suspend n6_18 #6:tell n56_6->n6_18 n56_8 #56:suspend_if_needed n56_8->n6_18 n10_30 #10:current_lag n56_8->n10_30 n56_10 #56:explain_syntax n56_10->n6_18 n52_2 #52:has_verb n56_10->n52_2 n59_21 #59:find_verb_named n56_10->n59_21 n59_8 #59:explain_verb_syntax n56_10->n59_8 n56_11 #56:do_huh n56_11->n42_0 n56_11->n56_10 n6_5 #6:my_huh n56_11->n6_5 n6_6 #6:last_huh n56_11->n6_6 n56_14 #56:kill_if_laggy n56_14->n6_18 n56_14->n10_30

Source

object_match_failed

Spec this none thisFlags rxdOwner #2Definer #56

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 #2Definer #56

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 #2Definer #56

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(tostr("[Enter ", prompt, ", or `@abort' to abort the command.]"));
9try
10ans = read();
11if ($string_utils:trim(ans) == "@abort")
12p:notify(">> Command Aborted <<");
13kill_task(task_id());
14endif
15return ans;
16except error (ANY)
17return error[1];
18endtry

read_lines

Spec this none thisFlags rxdOwner #2Definer #56

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 #2Definer #56

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] + " " | "", "[Enter `yes' or `no']"));
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 #2Definer #56

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 #2Definer #56

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 #36Definer #56

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

Spec this none thisFlags rxdOwner #2Definer #56

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() < 4000) || (seconds_left() < 2))
4"Note: above computation should be the same as :running_out_of_time.";
5{?time = 10, @ann} = args;
6if (ann && valid(player))
7player:tell(tostr(@ann));
8endif
9amount = max(time, min($login:current_lag(), 10));
10set_task_perms(caller_perms());
11"this is trying to back off according to lag...";
12suspend(amount);
13return 1;
14endif

dump_lines

Spec this none thisFlags rxdOwner #36Definer #56

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 #2Definer #56

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 rxOwner #2Definer #56

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)("[bold]What?[normal]");
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("[bold]What?[normal] (\"", dobjstr, "\" and \"", iobjstr, "\" are both ambiguous names)."));
22else
23player:(notify)(tostr("[bold]What?[normal] (\"", dobjstr, "\" is an ambiguous name)."));
24endif
25elseif (iobj == $ambiguous_match)
26player:(notify)(tostr("[bold]What?[normal] (\"", iobjstr, "\" is an ambiguous name)."));
27else
28player:(notify)("[bold]What?[normal]");
29player:my_explain_syntax(caller, verb, args) || (caller:here_explain_syntax(caller, verb, args) || this:explain_syntax(caller, verb, args));
30endif

task_info

Spec this none thisFlags rxdOwner #2Definer #56

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 #2Definer #56

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 #36Definer #56

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 #36Definer #56

Referenced by

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;