RhostMUSH Softcode
SharpMUSH reads PennMUSH softcode first. It also understands much of RhostMUSH’s softcode: where RhostMUSH has something that PennMUSH treats as an error, an unknown function or plain text, SharpMUSH does what RhostMUSH does, so RhostMUSH code that uses it runs unchanged and PennMUSH code is not affected. Where RhostMUSH gives the same code a different meaning from PennMUSH, SharpMUSH keeps PennMUSH’s meaning, and a setting switches to RhostMUSH’s for a game whose code was written for it.
These ideas come from RhostMUSH; SharpMUSH’s versions are written from how RhostMUSH behaves, not from its code.
This page covers:
%dand%dL, the element of an@dolist;- bang notation,
!and!!before a function call; - register labels, a second name for a q-register;
%i_<n>,%i_L,%iland%-<n>, more substitutions for loops and arguments;- the functions that come from RhostMUSH;
- RhostMUSH’s spellings of
@switch,@dolistand@lockswitches; - extra arguments to
map(), and the one-argumentsearch(); - the
rhost_edit,rhost_lattr,rhost_printf,rhost_map_args,rhost_listandsidefx_flagsettings; %j, the connection a command came in on;- what is deliberately different from RhostMUSH.
Every example below was run on SharpMUSH. Most are in the game’s help (help @dolist, help bang notation, help setq, help compatibility config and each function’s own entry), where SharpMUSH’s
test suite runs them on every change. The rhost_list section shows the call’s form only.
The @dolist element
Section titled “The @dolist element”%d0 is the element of the @dolist you are in. %d1 is the element of the @dolist around it, and
%dL is the outermost one’s.
%i0 is the element too, but %i counts every loop, iter() included. Inside an iter() in the action
list, %i0 is the iter() element and %d0 is still the @dolist element:
@dolist a b=think iter(x y,%d0:%i0)Output:
a:x a:yb:x b:y%d works in a queued @dolist and in @dolist/inline. Outside any @dolist, %d0 gives
#-1 REGISTER OUT OF RANGE, the same as %i0 outside a loop. The element is never evaluated again:
an element written [add(1,1)] is that text, not 2.
A bare %d, with no number after it, is just the letter d, as in PennMUSH.
Bang notation
Section titled “Bang notation”Put ! or !! before a function’s name and the call gives 1 or 0 about its result instead of the
result:
| Written | Gives 1 when the result |
|---|---|
!name(...) | starts with 0, or with no number |
!!name(...) | starts with a number that is not 0 |
!$name(...) | is empty |
!!$name(...) | is not empty |
!^name(...) | is false, as t() reads it |
!!^name(...) | is true, as t() reads it |
think [!strlen(abc)] [!!strlen(abc)] [!strlen()]Output: 0 1 1
A bang counts only where a function call is recognised: at the start of an argument or a command’s
text, or right after [. It works on any function, global functions made with @function included.
Anywhere else the ! is plain text, and so is a bang before a name that is not a function:
think ![strlen(abc)] x!strlen(abc)Output: !3 x!strlen(abc)
The same bangs work on a register, an iteration element or position, an argument and an @dolist
element: %q<!!$name> is 1 when the register holds something, %i!0 is 1 when the iteration’s element
is 0, and %d!!0 is 1 when the @dolist element is a number other than 0. %i_!0 and %-!0 work the
same way on the substitutions described below.
think [setq(name,)][if(%q<!$name>,No name.,Hello %q<name>.)]Output: No name.
Register labels
Section titled “Register labels”A q-register can carry a label, a second name for it. setq() and setr() with exactly three
arguments set the register and give it the third as its label. From then on %q<label>, r(label)
and setq(label, ...) read and write that same register:
think [setq(0, 15, damage)]%q<damage> %q0Output: 15 15
The register may be +, which picks the register the label already names, or else the first of 0-9
and A-Z with no label and no value. ! picks the same way but may take a register that holds a value.
nameq() reads, sets and searches labels; with a number other than 0 as its third argument it gives
the register a label belongs to:
think [setq(+, north, exit)][nameq(exit, , 1)]: %q<exit>Output: 0: north
setqm() and setrm(), which set registers in order, take <register>><label> as a name:
think [setqm(0>total, 5, total, add(%q<total>, 1))]%q0Output: 6
A label is at least two characters long, is not a number and has no > in it. A three-argument
setq() whose third argument cannot be a label is PennMUSH’s odd-argument error. Labels
are saved and restored with the registers by localize(), ulocal() and the /localize switches.
Loop positions and arguments
Section titled “Loop positions and arguments”| Substitution | Is |
|---|---|
%i_<n> | the position of the element %i<n> names, the same as inum(<n>) |
%i_L | the position of the outermost loop’s element |
%il | %iL, the outermost loop’s element, in either case |
%-<n> | argument <n>, from 0 to 999, the same as %<n>: %-12 is the thirteenth argument |
think iter(a b c,%i_0:%i0)Output: 1:a 2:b 3:c
think iter(a b,iter(x y,%il-%i_L:%i0))Output: a-1:x a-1:y b-2:x b-2:y
&FIRST_LAST me=%-0 and %-12think u(me/FIRST_LAST,a,b,c,d,e,f,g,h,i,j,k,l,m)Output: a and m
Functions from RhostMUSH
Section titled “Functions from RhostMUSH”These functions take the same arguments as on RhostMUSH. Each has its own help entry.
nsiter() is iter() with nothing between the results. citer() loops over the characters of a
string, spaces included. In both, ## is the element and #@ its position.
think nsiter(a b c, ##-#@)Output: a-1b-2c-3
think citer(boo!, ##-#@)Output: b-1 o-2 o-3 !-4
inf() is iter() that can count without end: a list written :<start>:>: counts up from <start>,
and :<start>:<: counts down. The pattern calls ibreak() to stop. A count that never stops is still
cut off by the game’s function invocation, output and time limits.
think inf(:5:>:, [if(gt(##, 8), ibreak())]##)Output: 5 6 7 8 9
while() is map() that stops part way through the list: after each item it runs a second attribute
on the item, and stops once that gives exactly the stop value. The item that stopped it keeps its
result.
&EVAL_FN me=[reverse(%0)]&COND_FN me=[strlen(%0)]think while(EVAL_FN, COND_FN, foo bar meep flibble baz, 4)Output: oof rab peem
u2() and privatize()
Section titled “u2() and privatize()”u2() evaluates an attribute the way u() does, but runs it as the object calling u2(): inside it,
me, %! and %@ are the caller. u2local(), u2default() and u2ldefault() are the same change
to ulocal(), udefault() and uldefault().
@create Widget&RUNS_AS Widget=[strmatch(num(me),%#)]think u(Widget/RUNS_AS) [u2(Widget/RUNS_AS)]Output: 0 1
localize(), ulocal() and the rest start their code with a copy of the caller’s registers.
privatize(1) makes them start with no registers for the rest of the evaluation, and
privatize(<on>, <code>[, <registers>[, <omit>[, <multi>]]]) evaluates <code> that way, for all
registers or only the ones named:
&PAIR me=[setr(0,ONE)]:[r(1)]think [setr(0,TWO)]:[setr(1,CHEESE)], [privatize(1,u(me/PAIR))], %q0:%q1Output: TWO:CHEESE, ONE:, TWO:CHEESE
Lists and characters
Section titled “Lists and characters”listdiff(), listinter() and listunion() are setdiff(), setinter() and setunion() without the
sorting: the result keeps the order the items had. elementpos() picks characters out of a string by
position, as elements() picks words.
| Call | Gives |
|---|---|
listdiff(foo baz gleep bar foo foo, bar moof gleep) | foo baz |
listinter(foo baz gleep bar foo bar, bar moof gleep) | gleep bar |
listunion(foo baz gleep bar foo bar, bar moof gleep) | foo baz gleep bar moof |
elementpos(abcdefg, 1 4) | a d |
ladd(), lsub(), lmul(), ldiv(), lavg(), lmax() and lmin() do arithmetic on a whole list,
and land(), lor(), lxor(), lnor() and lxnor() combine a list of true and false values. Each
item counts as the number it starts with, so they never refuse an item.
| Call | Gives |
|---|---|
ladd(1 2 3 4) | 10 |
lsub(10 2 3 1) | 4 |
lmul(2|2|2|2, |) | 16 |
ldiv(20 2 0 2) | 5 (a zero divisor is passed over) |
lavg(2 4 6 8 10) | 6 |
lmax(1 10 2 4 6) | 10 |
land(1 1 0) | 0 |
lor(0 0 2) | 1 |
lxnor(1 0 1) | 0 |
columns()
Section titled “columns()”columns(<text>, <width>, <columns>, ...) sets the words of <text> out in columns of a fixed width,
running down the first column, then the next. Further arguments set the justification, cropping, the
text before, between and after the columns, the order, the delimiter and the filler.
think columns(this is a test of columns, 10, 3)Output:
this a ofis test columnsCommand switches
Section titled “Command switches”| Written | Is |
|---|---|
@switch/regall | @switch/all/regexp |
@switch/regfirst | @switch/first/regexp |
@switch/clearreg, @dolist/clearreg | /clearregs |
@dolist/space | the default, a space-separated list |
@lock/<type>lock, @unlock/<type>lock | @lock/<type>: @lock/enterlock is @lock/enter, @lock/tportlock is @lock/teleport, @lock/defaultlock is @lock/basic |
The <type>lock spellings work for every lock type SharpMUSH has. A user-defined lock whose name ends
in “lock” keeps its own name.
@dolist/inline with /localize saves the registers before each run of the action list and restores
them after, and /clearregs empties them before each run. A queued @dolist gives each run its own
copy of the registers, so those switches change nothing there.
map() and search()
Section titled “map() and search()”map() passes any arguments after its output separator to the attribute as %1, %2 and so on:
&TAG_ARGS me=<%0:%1:%2>think map(TAG_ARGS,a b,,,x,y)Output: <a:x:y> <b:x:y>
With no extra arguments, %1 is the item’s position, as in PennMUSH, unless rhost_map_args is on.
search(), lsearch() and nsearch() also take RhostMUSH’s one-argument form,
search([<player>] <class>=<restriction>[, <low>[, <high>]]), such as search(type=player) or
search(me th=lamp). A class may be shortened to the start of its name. help lsearch lists the
classes.
The rhost_ settings
Section titled “The rhost_ settings”Each of these is off by default. Turn one on with @config/set, for example
@config/set rhost_printf=yes, or on the web portal’s configuration page, where they are in the
group “RhostMUSH Compatibility”. They take effect on the next call.
rhost_edit
Section titled “rhost_edit”With rhost_edit off, edit() reads the arguments after the string as from/to pairs, as PennMUSH
does. With it on, a fourth and fifth argument are RhostMUSH’s mode arguments: a fourth that starts with
a number other than 0 replaces only the first match.
think edit(abcabc,b,X,1)Output with rhost_edit on: aXcabc
rhost_lattr
Section titled “rhost_lattr”With rhost_lattr on, lattr() and lattrp() take RhostMUSH’s arguments,
lattr(<object>[/<pattern>][, <target>[, <type>[, <flags>[, <regexp>[, <tree>]]]]]), instead of
PennMUSH’s output delimiter. <type> narrows or counts the list: $ keeps attributes holding a
$-command, ^ those holding a listen pattern, and l answers the number of names and of pages.
help compatibility config describes every type.
rhost_printf
Section titled “rhost_printf”With rhost_printf on, printf() reads RhostMUSH’s $ fields instead of SharpMUSH’s % directives.
think printf(|$-5s|$5s|,ab,cd)Output with rhost_printf on: |ab | cd|
rhost_map_args
Section titled “rhost_map_args”With rhost_map_args on, %1 in a map() with no extra arguments is empty, as on RhostMUSH, rather
than the item’s position.
&MAP_TAG me=<%0|%1>think map(me/MAP_TAG,a b)Output with rhost_map_args on: <a|> <b|>
rhost_list
Section titled “rhost_list”PennMUSH’s list() names the game’s functions, commands, flags and so on. RhostMUSH’s
list(<list>, <eval>[, <delimiter>][, <header>][, <target>]) evaluates <eval> for each element, as
iter() does, and tells you each result as its own line instead of returning it. <header> is a
line told before the results, and <target> is an object you control to tell them to, instead of
you. With rhost_list on, list() is RhostMUSH’s, and @list still names the game’s functions,
commands and flags. TinyMUX’s three-argument list() is the same
call, so the one setting serves code from either server.
sidefx_flag
Section titled “sidefx_flag”With sidefx_flag off, side-effect functions such as pemit(), set(), attrib_set() and
create() work for anyone, subject to function_side_effects and their own permission checks, as in
PennMUSH. With it on, they work only for an object that has the SIDEFX flag or holds the
softcode.sidefx permission; anything else gets #-1 FUNCTION DISABLED. Anyone may set SIDEFX on
what they control. The flag has no letter. A function’s reading form, such as name() with one
argument, is never affected.
The wizard role allows softcode.sidefx, so a wizard needs no flag:
think hasflag(me,SIDEFX) [permission(me,softcode.sidefx)]Output for a wizard, with sidefx_flag on: 0 1
The connection handle is %j
Section titled “The connection handle is %j”%j is the connection the command was typed on, the number @pemit/port takes. %d is the
@dolist element, as in RhostMUSH, and no other MUSH server uses %j, so the letter is free for this.
@pemit/port %j=Only this connection sees this line.What is deliberately different
Section titled “What is deliberately different”A few RhostMUSH forms are not taken up, or work differently, because following RhostMUSH would change what PennMUSH code prints or how SharpMUSH’s permissions work:
%+!is not RhostMUSH’s.%+is the number of arguments, as in PennMUSH, so%+!is that number followed by!.- A bare
%-, with no number after it, is just-. RhostMUSH gives%-followed by a letter other meanings; only%-<n>is taken up. edit()with four or five arguments is RhostMUSH’s only underrhost_edit, since PennMUSH reads those arguments as further from/to pairs.- An object whose SEX is unset or not recognised is “they” and “them”, where RhostMUSH and PennMUSH say “it”. Only the first letter of SEX counts: m, f or w, and p or t.
- Wizards hold
softcode.sidefxthrough the wizard role, so they need no SIDEFX flag; on RhostMUSH a wizard needs the flag as well. - A label names one register: giving it to a second register takes it from the first. RhostMUSH lets two registers carry the same label.
setqm()splits a<register>><label>name after evaluating it, so a>that a function in the name returns marks a label too.nameq()with an empty first argument is an error rather than a count of registers, since registers here are named freely.u()runs the attribute as the object it is on, as RhostMUSH’s usual build does; useu2()for the other behaviour.- RhostMUSH lock types that SharpMUSH does not have, such as
teloutlockordarklock, are unknown lock types.