This is patch 0 for PennMUSH 1.8.4. After applying this patch, you will have version 1.8.4p0 To apply this patch, save it to a file in your top-level 1.8.3p13 MUSH directory, and do the following: patch -p0 < 1.8.4-patch00 ./configure make install If you use GNU patch 2.2, you probably want the above to be 'patch -b -p0', not just 'patch -p0'. Unix (or cygwin) users need not worry about failed hunks in src/switchinc.c, hdrs/switches.h, hdrs/cmds.h, or hdrs/funs.h. These files are automatically rebuilt on compile. On the off chance they appear not to be, simply rm them and re-run make. Then @shutdown/reboot your MUSH. - Shawn/Raevnos In this patch: Major Changes: * Commands can now be restricted with an @lock-style lock in restrict.cnf and @command/restrict, allowing more complex restrictions. [MG] Minor Changes: * @shutdown/reboot logs who was responsible. Suggested by Kitai. [SW] * Rewrite of help @lock to improve clarity, by Sketch. * New NO_LOG flag to disable command logging on a per-object basis. Based on code by Teal. [SW] * mindb+maxdb classes for lsearch/@search no longer reset to default values when > db_top or < 0 is given: Instead treated as an integer comparison. [GM] * @open can now open exits in remove locations, as well as your current location. Suggested by Bane. [MG] * New OPEN_OK flag allows anyone to open exits in a room, and @lock/open to restrict who can. Based on patch by ranmir@M*U*S*H. [MG] * Master Room exits and ZMR exits now run the "goto" command, and @ealias and @lalias run the "enter"/"leave" commands, so @hooks get run, command restrictions checked, etc. [MG] * New @lock/from and @lock/receive locks, to control who can give to an object, and what objects can be given to them, respectively. From a suggestion by Nammyung@M*U*S*H, based on locks on ElendorMUSH. [MG] * Changed the restrictions for valid @function names to match what was reported by valid(). [MG] Commands: * New @include / command, which inserts into the current action list. Patch by Javelin. * @scan can now take multiple switches at the same time. [MG] * @version now reports the SVN revision of the current version, when available. Suggested by Paige. [MG] * @clone can take a garbage dbref for the new object, the same as @create. Suggested by Dan. [MG] * 'look' now supports more english-matching (look this foo's 1st bar). [MG] * You can now look at objects on the other side of transparent exits, with "look [toward] 's ". Suggested by Trinsec. [MG] * All wizards can now use @command/add. Suggested by qa'toq. [MG] * function_alias in alias.cnf now creates a proper alias, not a clone, of functions. @function/alias added, which does the same in-game. [MG] * New @command/clone and @function/clone commands, which create copies of a command/function which initially work the same as, but are independant of, the originals. Based on suggestion by Bane. [MG] * Added a comment line to the beginning of @decompile's output showing the object name and dbref. [MG] Functions: * Added strfirstof() and strallof(), which return the first arg/all args which are non-empty strings. [MG] * Added reglattr[p](), regxattr[p]() and regnattr[p](), regexp variants of lattr[p](), xattr[p]() and nattr[p](). Suggested by Trinsec. [MG] * The *emit() functions, and cbufferadd(), are now disabled when function_side_effects are off. Suggested by Cheetah. [MG] * round() now takes an optional third argument to 0-pad the results if needed. Suggested by Trinsec. [SW] * Many functions (particularly ones which take only numbers, dbrefs or attribute names as arguments) now ignore ANSI in their arguments, rather than throwing an error. [MG] * nattr()'s now defaults to *, not **, the same as lattr() and other attribute functions. [MG] * clone() can now take a and , as per @clone. [MG] * cwho() now takes an optional 3rd argument to omit gagged objects. Suggested by Trinsec. [MG] Attributes: * @outpageformat lets you alter how you view pages that you send. Fixes: * isprint() bug in ord() fixed. [GM] * Possible crashbug in @destroy fixed. Reported by Dan. [MG] * Minor bug in benchmark() fixed. [MG] * channels() was incorrectly sorted for channel names containing ansi. Reported by Trelane. [MG] * Help fixes by Teal and others. [MG] * Minor updates to some README files. [MG] * Some typos and translation errors fixed by Stoko. * namelist() now ignores null items. Reported by Minion. [MG] * The matching code would always perform absolute (dbref) matches, even when it wasn't told to. [MG] * Improvements to the match flags used by many pieces of code, hopefully fixing a number of minor bugs. [MG] * Paranoid dumps no longer treat ANSI tags as invalid characters in attrs. Reported by Trelane. [MG] * The /silent switch for @lemit didn't work. [MG] * @decompile/db showed '@create ' for THINGs, not '@create ', and @decomp/name could break. Reported by Paige. [MG] * Crash bug in locks fixed. Reported by Tanaku. [SW] CHANGES.182 | 6 CHANGES.183 | 6 CHANGES.184 | 107 + FAQ | 43 I18N | 5 INSTALL | 2 Makefile.in | 4 Patchlevel | 2 README.SQL | 2 README.SSL | 6 UPGRADING | 24 game/README | 27 game/aliascnf.dst | 6 game/mushcnf.dst | 9 game/restrictcnf.dst | 4 game/txt/hlp/index.hlp | 639 ++++---- game/txt/hlp/pennattr.hlp | 87 - game/txt/hlp/pennchat.hlp | 195 +- game/txt/hlp/penncmd.hlp | 1378 ++++++++++--------- game/txt/hlp/pennflag.hlp | 891 ++++++------ game/txt/hlp/pennfunc.hlp | 295 ++-- game/txt/hlp/penntop.hlp | 296 ++-- game/txt/hlp/pennv183.hlp | 12 game/txt/hlp/pennv184.hlp | 102 + game/txt/hlp/pennvOLD.hlp | 1 hdrs/atr_tab.h | 1 hdrs/attrib.h | 7 hdrs/command.h | 30 hdrs/dbdefs.h | 1 hdrs/externs.h | 15 hdrs/flags.h | 5 hdrs/function.h | 6 hdrs/game.h | 2 hdrs/lock.h | 3 hdrs/mushdb.h | 12 hdrs/svninfo.h | 3 hdrs/switches.h | 300 ++-- hdrs/version.h | 8 po/bg_BG.pox | 303 +--- po/da_DK.pox | 481 ++---- po/de_DE.pox | 243 +-- po/eo.pox | 2 po/es_ES.pox | 107 - po/fr_FR.pox | 1222 +++++++--------- po/hr_HR.pox | 1964 ++++++++++++--------------- po/hu_HU.pox | 128 - po/nl_NL.pox | 610 +++++--- po/no_NO.pox | 3307 ++++++++++++++++++++++++++++++++++++++++------ po/pennmush.pot | 2528 +++++++++++++++++------------------ po/pl_PL.pox | 191 -- po/pt_BR.pox | 504 +++---- po/pt_PT.pox | 104 - po/ru_RU.pox | 104 - po/sv_SE.pox | 1363 ++++++++---------- po/zh_CN.pox | 323 ---- src/Makefile.in | 9 src/SWITCHES | 2 src/attrib.c | 57 src/bsd.c | 26 src/chunk.c | 254 ++- src/cmds.c | 60 src/command.c | 558 ++++--- src/conf.c | 16 src/cque.c | 204 ++ src/create.c | 65 src/db.c | 28 src/destroy.c | 55 src/extchat.c | 65 src/extmail.c | 85 - src/flags.c | 94 - src/function.c | 720 +++++----- src/fundb.c | 73 - src/funlist.c | 19 src/funmath.c | 26 src/funmisc.c | 90 - src/funstr.c | 89 - src/game.c | 80 - src/help.c | 1 src/lock.c | 8 src/log.c | 20 src/look.c | 51 src/malias.c | 7 src/match.c | 34 src/move.c | 33 src/myrlimit.c | 2 src/myssl.c | 3 src/parse.c | 38 src/pcre.c | 9 src/player.c | 17 src/predicat.c | 24 src/rob.c | 151 +- src/services.c | 16 src/set.c | 66 src/sort.c | 10 src/speech.c | 60 src/switchinc.c | 2 src/utils.c | 16 src/version.c | 29 src/wiz.c | 47 test/MUSHConnection.pm | 6 test/TestHarness.pm | 11 test/testalias.pl | 1 test/testansi.pl | 8 test/testdigest.pl | 13 test/testmath.pl | 3 utils/README.txt | 19 utils/cscope.sh | 6 107 files changed, 11927 insertions(+), 9485 deletions(-) Prereq: 1.8.3p13 =================================================================== --- Patchlevel (.../183p13) (revision 469) +++ Patchlevel (.../184p0) (revision 469) @@ -1,3 +1,3 @@ Do not edit this file. It is maintained by the official PennMUSH patches. -This is PennMUSH 1.8.3p13 +This is PennMUSH 1.8.4.0 Index: Makefile.in =================================================================== --- Makefile.in (.../183p13) (revision 469) +++ Makefile.in (.../184p0) (revision 469) @@ -2,8 +2,8 @@ # - System configuration - # -VERSION=1.8.3 -PATCHLEVEL=13 +VERSION=1.8.4 +PATCHLEVEL=0 # # This section of the file should be automatically configured by the Index: src/fundb.c =================================================================== --- src/fundb.c (.../183p13) (revision 469) +++ src/fundb.c (.../184p0) (revision 469) @@ -108,14 +108,25 @@ { dbref thing; int doparent; - static const char *matchall = "**"; /* count atrees by default too */ - char *pattern; + const char *pattern; + int regexp = 0; + int matchall = 0; + + if (*called_as == 'R') + regexp = 1; + doparent = strchr(called_as, 'P') ? 1 : 0; pattern = strchr(args[0], '/'); - if (pattern) - *pattern++ = '\0'; - else - pattern = (char *) matchall; /* match anything */ + if (pattern) { + args[0][pattern - args[0]] = '\0'; + pattern++; + } else { + pattern = (regexp ? "**" : "*"); + } + if (!strcmp(pattern, "**") || !strlen(pattern)) { + regexp = 0; + matchall = 1; + } thing = match_thing(executor, args[0]); if (!GoodObject(thing)) { @@ -123,14 +134,9 @@ return; } - doparent = strchr(called_as, 'P') ? 1 : 0; - - if (!doparent && pattern == matchall && Can_Examine(executor, thing)) { - safe_integer(AttrCount(thing), buff, bp); - } else { - safe_integer(atr_pattern_count(executor, thing, pattern, doparent, - !Can_Examine(executor, thing)), buff, bp); - } + safe_integer(atr_pattern_count(executor, thing, pattern, doparent, + !Can_Examine(executor, thing), regexp), buff, + bp); } /* ARGSUSED */ @@ -140,10 +146,11 @@ char *pattern; struct lh_args lh; char delim; + int regexp = 0; lh.nattr = lh.start = lh.count = 0; - if (*called_as == 'X') { + if (strchr(called_as, 'X')) { if (!is_strict_integer(args[1]) || !is_strict_integer(args[2])) { safe_str(T(e_int), buff, bp); return; @@ -164,12 +171,17 @@ if (!delim_check(buff, bp, nargs, args, 2, &delim)) return; } + if (*called_as == 'R') + regexp = 1; pattern = strchr(args[0], '/'); if (pattern) *pattern++ = '\0'; - else - pattern = (char *) "*"; /* match anything */ + else if (regexp) { + regexp = 0; + pattern = (char *) "**"; + } else + pattern = (char *) "*"; thing = match_thing(executor, args[0]); if (!GoodObject(thing)) { @@ -183,11 +195,12 @@ if (strchr(called_as, 'P')) { (void) atr_iter_get_parent(executor, thing, pattern, - !Can_Examine(executor, thing), lattr_helper, - &lh); + !Can_Examine(executor, thing), regexp, + lattr_helper, &lh); } else { (void) atr_iter_get(executor, thing, pattern, - !Can_Examine(executor, thing), lattr_helper, &lh); + !Can_Examine(executor, thing), regexp, lattr_helper, + &lh); } } @@ -590,7 +603,9 @@ if ((place != NOTHING) && (Can_Examine(executor, place) || (Location(executor) == place) || (enactor == place))) { - switch (thing = match_result(place, name, NOTYPE, MAT_REMOTE)) { + switch (thing = + match_result(place, name, NOTYPE, + MAT_POSSESSION | MAT_CARRIED_EXIT)) { case NOTHING: safe_str(T(e_match), buff, bp); break; @@ -1684,10 +1699,6 @@ safe_str("#-1", buff, bp); } return; - } else if (!GoodObject(it)) { - /* Catch ambiguous matches */ - safe_str("#-1", buff, bp); - return; } /* If the thing in question has unlimited money, respond with the * max money possible. We don't use the NoPay macro, though, because @@ -1695,7 +1706,7 @@ * if its owner is no_pay. Softcode can check money(owner(XX)) if * they want to allow objects to pay like their owners. */ - if (has_power_by_name(it, "NO_PAY", NOTYPE)) + if (NoPay(it)) safe_integer(MAX_PENNIES, buff, bp); else safe_integer(Pennies(it), buff, bp); @@ -1858,7 +1869,7 @@ int first = 1; char *current; dbref target; - const char *start; + char *start; int report = 0; ufun_attrib ufun; char *wenv[2]; @@ -1872,12 +1883,12 @@ } } - start = args[0]; + start = trim_space_sep(args[0], ' '); while (start && *start) { if (!first) - safe_str(" ", buff, bp); + safe_chr(' ', buff, bp); first = 0; - current = next_in_list(&start); + current = split_token(&start, ' '); if (*current == '*') current = current + 1; target = lookup_player(current); @@ -2108,7 +2119,7 @@ safe_str(T(e_perm), buff, bp); return; } - safe_dbref(do_clone(executor, args[0], NULL, 0), buff, bp); + safe_dbref(do_clone(executor, args[0], args[1], 0, args[2]), buff, bp); } Index: src/utils.c =================================================================== --- src/utils.c (.../183p13) (revision 469) +++ src/utils.c (.../184p0) (revision 469) @@ -701,15 +701,17 @@ if (IsRoom(it)) return it; room = IsExit(it) ? Home(it) : Location(it); - if (!GoodObject(room)) - return NOTHING; - while (!IsRoom(room)) { - room = Location(room); + while (rec <= 20) { + if (!GoodObject(room) || IsGarbage(room)) { + return NOTHING; + } + if (IsRoom(room)) { + return room; + } rec++; - if (rec > 20) - return AMBIGUOUS; + room = Location(room); } - return room; + return AMBIGUOUS; } Index: src/extchat.c =================================================================== --- src/extchat.c (.../183p13) (revision 469) +++ src/extchat.c (.../184p0) (revision 469) @@ -556,8 +556,8 @@ if (!ch || !*ch) return; - /* If there's no users on the list, or if the first user is already - * alphabetically greater, user should be the first entry on the list */ + /* If there's no channels on the list, or if the first channel is already + * alphabetically greater, ch should be the first entry on the list */ /* No channels? */ if (!channels) { channels = *ch; @@ -617,6 +617,8 @@ { CHANLIST *p; CHANLIST *tmp; + char cleanname[CHAN_NAME_LEN]; + char cleanp[CHAN_NAME_LEN]; if (!ch || !*ch) return; @@ -625,6 +627,7 @@ if (!tmp) return; tmp->chan = *ch; + strcpy(cleanname, remove_markup(ChanName(*ch), NULL)); /* If there's no channels on the list, or if the first channel is already * alphabetically greater, chan should be the first entry on the list */ /* No channels? */ @@ -635,20 +638,23 @@ } p = Chanlist(who); /* First channel? */ - if (strcasecoll(ChanName(p->chan), ChanName(*ch)) > 0) { + strcpy(cleanp, remove_markup(ChanName(p->chan), NULL)); + if (strcasecoll(cleanp, cleanname) > 0) { tmp->next = p; s_Chanlist(who, tmp); return; - } else if (!strcasecmp(ChanName(p->chan), ChanName(*ch))) { + } else if (!strcasecmp(cleanp, cleanname)) { /* Don't add the same channel twice! */ free_chanlist(tmp); } else { /* Otherwise, find which channel this channel should be inserted after */ - for (; - p->next - && (strcasecoll(ChanName(p->next->chan), ChanName(*ch)) < 0); - p = p->next) ; - if (p->next && !strcasecmp(ChanName(p->next->chan), ChanName(*ch))) { + while (p->next) { + strcpy(cleanp, remove_markup(ChanName(p->next->chan), NULL)); + if (strcasecoll(cleanp, cleanname) >= 0) + break; + p = p->next; + } + if (p->next && !strcasecmp(cleanp, cleanname)) { /* Don't add the same channel twice! */ free_chanlist(tmp); } else { @@ -1168,7 +1174,7 @@ return; } if (!com || !*com) { - notify(player, T("What do you want to do with that channel?")); + notify(player, T("What do you want to do with the channel?")); return; } @@ -1322,7 +1328,7 @@ switch (find_channel_partial_off(name, &chan, player)) { case CMATCH_NONE: if (find_channel_partial_on(name, &chan, player)) - notify_format(player, T("CHAT: You are already on channel <%s>"), + notify_format(player, T("CHAT: You are already on channel <%s>."), ChanName(chan)); else notify(player, T("CHAT: I don't recognize that channel.")); @@ -2269,6 +2275,11 @@ CHAN *c; dbref victim; + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + /* Person must be able to do nospoof cemits. */ if (!command_check_byname(executor, "@cemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -2289,7 +2300,7 @@ /* Do we spoof somebody else? */ if (nargs == 3 && parse_boolean(args[2])) { /* Person must be able to do nospoof cemits. */ - if (!command_check_byname(executor, "@nscemit") || fun->flags & FN_NOSIDEFX) { + if (!command_check_byname(executor, "@nscemit")) { safe_str(T(e_perm), buff, bp); return; } @@ -2866,6 +2877,7 @@ int first = 1; int matchcond = 0; int priv = 0; + int skip_gagged = 0; int show; CHAN *chan = NULL; CHANUSER *u; @@ -2882,7 +2894,7 @@ break; } - if (nargs == 2) { + if (nargs > 1 && args[1] && *args[1]) { if (!strcasecmp(args[1], "on")) matchcond = 0; else if (!strcasecmp(args[1], "off")) @@ -2895,6 +2907,9 @@ } } + if (nargs > 2 && parse_boolean(args[2])) + skip_gagged = 1; + /* Feh. We need to do some sort of privilege checking, so that * if mortals can't do '@channel/who wizard', they can't do * 'think cwho(wizard)' either. The first approach that comes to @@ -2926,6 +2941,8 @@ } if (!show) continue; + if (Chanuser_Gag(u) && skip_gagged) + continue; if (first) first = 0; else @@ -3320,10 +3337,10 @@ char *nsmsg = ns_esnotify(speaker, na_one, &executor, Paranoid(executor) ? 1 : 0); if (!showstamp) - safe_format(buff, bp, T("%s %s"), nsmsg, buf); + safe_format(buff, bp, "%s %s", nsmsg, buf); else { stamp = show_time(timestamp, 0); - safe_format(buff, bp, T("[%s] %s %s"), stamp, nsmsg, buf); + safe_format(buff, bp, "[%s] %s %s", stamp, nsmsg, buf); } mush_free(nsmsg, "string"); } else { @@ -3331,7 +3348,7 @@ safe_str(buf, buff, bp); else { stamp = show_time(timestamp, 0); - safe_format(buff, bp, T("[%s] %s"), stamp, buf); + safe_format(buff, bp, "[%s] %s", stamp, buf); } } num_lines--; @@ -3463,8 +3480,8 @@ */ char * -mogrify(dbref mogrifier, char *attrname, - dbref player, int numargs, char *argv[], char *orig) +mogrify(dbref mogrifier, const char *attrname, + dbref player, int numargs, const char *argv[], const char *orig) { static char buff[BUFFER_LEN]; const char *wenv[10] = { 0 }; @@ -3513,12 +3530,12 @@ CHANUSER *speaker; dbref current; char *bp; - char *blockstr = ""; + const char *blockstr = ""; int na_flags = NA_INTER_LOCK; const char *someone = "Someone"; dbref mogrifier = NOTHING; - char *ctype = NULL; - char *argv[10]; + const char *ctype = NULL; + const char *argv[10]; int override_chatformat = 0; memset(argv, 0, sizeof(argv)); @@ -3810,10 +3827,10 @@ char *nsmsg = ns_esnotify(speaker, na_one, &player, Paranoid(player) ? 1 : 0); if (quiet) - notify_format(player, T("%s %s"), nsmsg, buf); + notify_format(player, "%s %s", nsmsg, buf); else { stamp = show_time(timestamp, 0); - notify_format(player, T("[%s] %s %s"), stamp, nsmsg, buf); + notify_format(player, "[%s] %s %s", stamp, nsmsg, buf); } mush_free(nsmsg, "string"); } else { @@ -3821,7 +3838,7 @@ notify(player, buf); else { stamp = show_time(timestamp, 0); - notify_format(player, T("[%s] %s"), stamp, buf); + notify_format(player, "[%s] %s", stamp, buf); } } num_lines--; Index: src/Makefile.in =================================================================== --- src/Makefile.in (.../183p13) (revision 469) +++ src/Makefile.in (.../184p0) (revision 469) @@ -75,6 +75,15 @@ @echo "#define BUILDDATE \"`date`\"" >> ../hdrs/buildinf.h @echo "#define COMPILER \"$(CC)\"" >> ../hdrs/buildinf.h @echo "#define CCFLAGS \"$(CFLAGS)\"" >> ../hdrs/buildinf.h + @if [ ! -f ../hdrs/svninfo.h ]; then \ + echo '#define SVNREVISION "$$Rev$$"' > ../hdrs/svninfo.h; \ + echo '#define SVNDATE "$$Date$$"' >> ../hdrs/svninfo.h; \ + else \ + echo `egrep "#define SVNREVISION \".+?\"" ../hdrs/svninfo.h` > ../hdrs/svninfo2.h; \ + echo `egrep "#define SVNDATE \".+?\"" ../hdrs/svninfo.h` >> ../hdrs/svninfo2.h; \ + mv -f ../hdrs/svninfo2.h ../hdrs/svninfo.h; \ + fi + @echo "/* Built at `date +%Y%m%d%H%M%S` */" >> ../hdrs/svninfo.h # If funlocal.c doesn't exist, we want to build it from # funlocal.dst. Index: src/malias.c =================================================================== --- src/malias.c (.../183p13) (revision 469) +++ src/malias.c (.../184p0) (revision 469) @@ -500,9 +500,10 @@ struct mail_alias *m; m = get_malias(player, alias); if (!m) { - notify(player, - T - ("MAIL: Not a valid alias. Remember to prefix the alias name with *.")); + notify_format(player, + T + ("MAIL: Not a valid alias. Remember to prefix the alias name with %c."), + MALIAS_TOKEN); return; } if (Wizard(player) || (m->owner == player)) { Index: src/myssl.c =================================================================== --- src/myssl.c (.../183p13) (revision 469) +++ src/myssl.c (.../184p0) (revision 469) @@ -114,7 +114,8 @@ SSL_CTX * ssl_init(char *private_key_file, char *ca_file, int req_client_cert) { - SSL_METHOD *meth; + const SSL_METHOD *meth; /* If this const gives you a warning, you're + using an old version of OpenSSL. */ unsigned char context[128]; DH *dh; unsigned int reps = 1; Index: src/wiz.c =================================================================== --- src/wiz.c (.../183p13) (revision 469) +++ src/wiz.c (.../184p0) (revision 469) @@ -109,7 +109,7 @@ */ dbref do_pcreate(dbref creator, const char *player_name, const char *player_password, - const char *try_dbref) + char *try_dbref) { dbref player; @@ -120,12 +120,11 @@ if (!can_pay_fees(creator, 0)) return NOTHING; - if (try_dbref && *try_dbref) - player = parse_dbref(try_dbref); - else - player = NOTHING; + if (!make_first_free_wrapper(creator, try_dbref)) { + return NOTHING; + } - player = create_player(player_name, player_password, "None", "None", player); + player = create_player(player_name, player_password, "None", "None"); if (player == NOTHING) { notify_format(creator, T("Failure creating '%s' (bad name)"), player_name); return NOTHING; @@ -438,8 +437,8 @@ /* Unlike normal teleport, you must control the destination * or have the open_anywhere power */ - if (!(tport_control_ok(player, victim, loc) && - (controls(player, destination) || Open_Anywhere(player)))) { + if (!tport_control_ok(player, victim, loc) || + !can_open_from(player, destination)) { notify(player, T("Permission denied.")); return; } @@ -815,7 +814,7 @@ switch (flag) { case BOOT_NAME: victim = noisy_match_result(player, name, TYPE_PLAYER, - MAT_PMATCH | MAT_PLAYER | MAT_ME); + MAT_PMATCH | MAT_TYPE | MAT_ME); if (victim == NOTHING) { notify(player, T("No such connected player.")); return; @@ -912,7 +911,8 @@ notify(player, T("Try asking them first!")); return; } - if ((victim = noisy_match_result(player, name, TYPE_PLAYER, MAT_LIMITED)) + if ((victim = + noisy_match_result(player, name, TYPE_PLAYER, MAT_LIMITED | MAT_TYPE)) == NOTHING) return; @@ -921,7 +921,7 @@ } else { if ((n_target = noisy_match_result(player, target, TYPE_PLAYER, - MAT_LIMITED)) == NOTHING) + MAT_LIMITED | MAT_TYPE)) == NOTHING) return; } @@ -962,7 +962,8 @@ notify(player, T("You do not have the power to change reality.")); return; } - if ((victim = noisy_match_result(player, name, TYPE_PLAYER, MAT_LIMITED)) + if ((victim = + noisy_match_result(player, name, TYPE_PLAYER, MAT_LIMITED | MAT_TYPE)) == NOTHING) return; @@ -1745,7 +1746,7 @@ strcpy(spec->eval, ""); strcpy(spec->name, ""); spec->low = 0; - spec->high = db_top - 1; + spec->high = INT_MAX; spec->start = 1; /* 1-indexed */ spec->count = 0; spec->lock = TRUE_BOOLEXP; @@ -1782,8 +1783,6 @@ if (*restriction == '#') offset = 1; spec->high = parse_integer(restriction + offset); - if (!GoodObject(spec->high)) - spec->high = db_top - 1; continue; } } @@ -1796,8 +1795,6 @@ if (*class == '#') offset = 1; spec->low = parse_integer(class + offset); - if (!GoodObject(spec->low)) - spec->low = 0; if (isdigit((unsigned char) *restriction) || ((*restriction == '#') && *(restriction + 1) && isdigit((unsigned char) *(restriction + 1)))) { @@ -1805,9 +1802,6 @@ if (*restriction == '#') offset = 1; spec->high = parse_integer(restriction + offset); - if (!GoodObject(spec->high)) - spec->high = db_top - 1; - } continue; } @@ -1820,16 +1814,12 @@ if (*restriction == '#') offset = 1; spec->low = parse_integer(restriction + offset); - if (!GoodObject(spec->low)) - spec->low = 0; continue; } else if (string_prefix("maxdb", class)) { size_t offset = 0; if (*restriction == '#') offset = 1; spec->high = parse_integer(restriction + offset); - if (!GoodObject(spec->high)) - spec->low = db_top - 1; continue; } @@ -1996,7 +1986,7 @@ !(is_wiz || (spec.type == TYPE_PLAYER) || (ZMaster(spec.owner) && eval_lock(player, spec.owner, Zone_Lock)))) { giveto(player, FIND_COST); - notify(player, T("You need a search warrant to do that.")); + notify(player, T("You need a search warrant to do that!")); if (spec.lock != TRUE_BOOLEXP) free_boolexp(spec.lock); return -1; @@ -2007,7 +1997,12 @@ if (!*result) mush_panic("Couldn't allocate memory in search!"); - for (n = spec.low; n <= spec.high; n++) { + if (spec.low < 0) { + spec.low = 0; + } + if (spec.high >= db_top) + spec.high = db_top - 1; + for (n = spec.low; n <= spec.high && n < db_top; n++) { if (IsGarbage(n) && spec.type != TYPE_GARBAGE) continue; if (spec.owner != ANY_OWNER && Owner(n) != spec.owner) Index: src/services.c =================================================================== --- src/services.c (.../183p13) (revision 469) +++ src/services.c (.../184p0) (revision 469) @@ -755,28 +755,28 @@ switch (svcstatus.dwCurrentState) { case SERVICE_STOPPED: - p = T("The service is not running."); + p = "The service is not running."; break; case SERVICE_START_PENDING: - p = T("The service is starting."); + p = "The service is starting."; break; case SERVICE_STOP_PENDING: - p = T("The service is stopping."); + p = "The service is stopping."; break; case SERVICE_RUNNING: - p = T("The service is running."); + p = "The service is running."; break; case SERVICE_CONTINUE_PENDING: - p = T("The service continue is pending."); + p = "The service continue is pending."; break; case SERVICE_PAUSE_PENDING: - p = T("The service pause is pending."); + p = "The service pause is pending."; break; case SERVICE_PAUSED: - p = T("The service is paused."); + p = "The service is paused."; break; default: - p = T("Unrecognised status."); + p = "Unrecognised status."; break; } /* end of switch */ Index: src/conf.c =================================================================== --- src/conf.c (.../183p13) (revision 469) +++ src/conf.c (.../184p0) (revision 469) @@ -930,6 +930,7 @@ config_set(const char *opt, char *val, int source, int restrictions) { PENNCONF *cp; + COMMAND_INFO *command; char *p; if (!val) @@ -942,7 +943,14 @@ for (p = val; *p && !isspace((unsigned char) *p); p++) ; if (*p) { *p++ = '\0'; - if (!restrict_command(val, p)) { + command = command_find(val); + if (!command) { + if (source == 0) { + do_rawlog(LT_ERR, + "CONFIG: Invalid command or restriction for %s.", val); + } + return 0; + } else if (!restrict_command(NOTHING, command, p)) { if (source == 0) { do_rawlog(LT_ERR, "CONFIG: Invalid command or restriction for %s.", val); @@ -1037,7 +1045,7 @@ for (p = val; *p && !isspace((unsigned char) *p); p++) ; if (*p) { *p++ = '\0'; - if (!alias_function(val, p)) { + if (!alias_function(NOTHING, val, p)) { if (source == 0) { do_rawlog(LT_ERR, "CONFIG: Couldn't alias %s to %s.", p, val); } @@ -1688,9 +1696,9 @@ else notify(player, T("Enabled.")); do_log(LT_WIZ, player, NOTHING, "%s %s", - cp->name, (state) ? T("ENABLED") : T("DISABLED")); + cp->name, (state) ? "ENABLED" : "DISABLED"); } else - notify(player, T("That isn't a on/off option.")); + notify(player, T("That isn't an on/off option.")); return; } } Index: src/attrib.c =================================================================== --- src/attrib.c (.../183p13) (revision 469) +++ src/attrib.c (.../184p0) (revision 469) @@ -1087,24 +1087,31 @@ * \param thing the object containing the attribute. * \param name the pattern to match against the attribute name. * \param mortal only fetch mortal-visible attributes? + * \param regexp is name a regexp, rather than a glob pattern? * \param func the function to call for each matching attribute. * \param args additional arguments to pass to the function. * \return the sum of the return values of the functions called. */ int atr_iter_get(dbref player, dbref thing, const char *name, int mortal, - aig_func func, void *args) + int regexp, aig_func func, void *args) { ATTR *ptr, **indirect; int result; size_t len; result = 0; - if (!name || !*name) - name = "*"; + if (!name || !*name) { + if (regexp) { + regexp = 0; + name = "**"; + } else { + name = "*"; + } + } len = strlen(name); - if (!wildcard(name) && name[len - 1] != '`') { + if (!regexp && !wildcard(name) && name[len - 1] != '`') { ptr = atr_get_noparent(thing, strupper(name)); if (ptr && (mortal ? Is_Visible_Attr(thing, ptr) : Can_Read_Attr(player, thing, ptr))) @@ -1114,7 +1121,9 @@ while (*indirect) { ptr = *indirect; if ((mortal ? Is_Visible_Attr(thing, ptr) - : Can_Read_Attr(player, thing, ptr)) && atr_wild(name, AL_NAME(ptr))) + : Can_Read_Attr(player, thing, ptr)) + && (regexp ? quick_regexp_match(name, AL_NAME(ptr), 0) : + atr_wild(name, AL_NAME(ptr)))) result += func(player, thing, NOTHING, name, ptr, args); if (ptr == *indirect) indirect = &AL_NEXT(ptr); @@ -1130,13 +1139,14 @@ * \param player the enactor. * \param thing the object containing the attribute. * \param name the pattern to match against the attribute name. - * \param mortal only fetch mortal-visible attributes? * \param doparent count parent attrbutes as well? + * \param mortal only fetch mortal-visible attributes? + * \param regexp is name a regexp, rather than a glob pattern? * \return the count of matching attributes */ int atr_pattern_count(dbref player, dbref thing, const char *name, - int doparent, int mortal) + int doparent, int mortal, int regexp) { ATTR *ptr, **indirect; int result; @@ -1144,11 +1154,17 @@ dbref parent = NOTHING; result = 0; - if (!name || !*name) - name = "*"; + if (!name || !*name) { + if (regexp) { + regexp = 0; + name = "**"; + } else { + name = "*"; + } + } len = strlen(name); - if (!wildcard(name) && name[len - 1] != '`') { + if (!regexp && !wildcard(name) && name[len - 1] != '`') { parent = thing; if (doparent) ptr = atr_get_with_parent(thing, strupper(name), &parent); @@ -1172,7 +1188,8 @@ if ((parent == thing) || !AF_Private(ptr)) { if ((mortal ? Is_Visible_Attr(parent, ptr) : Can_Read_Attr(player, parent, ptr)) - && atr_wild(name, AL_NAME(ptr))) + && (regexp ? quick_regexp_match(name, AL_NAME(ptr), 0) : + atr_wild(name, AL_NAME(ptr)))) result += 1; } } @@ -1194,6 +1211,7 @@ * \param thing the object containing the attribute. * \param name the pattern to match against the attribute name. * \param mortal only fetch mortal-visible attributes? + * \param regexp is name a regexp pattern, rather than a glob pattern? * \param func the function to call for each matching attribute, with * a pointer to the dbref of the object the attribute is really on passed * as the function's args argument. @@ -1201,7 +1219,7 @@ */ int atr_iter_get_parent(dbref player, dbref thing, const char *name, int mortal, - aig_func func, void *args) + int regexp, aig_func func, void *args) { ATTR *ptr, **indirect; int result; @@ -1209,11 +1227,17 @@ dbref parent = NOTHING; result = 0; - if (!name || !*name) - name = "*"; + if (!name || !*name) { + if (regexp) { + regexp = 0; + name = "**"; + } else { + name = "*"; + } + } len = strlen(name); - if (!wildcard(name) && name[len - 1] != '`') { + if (!regexp && !wildcard(name) && name[len - 1] != '`') { ptr = atr_get_with_parent(thing, strupper(name), &parent); if (ptr && (mortal ? Is_Visible_Attr(parent, ptr) : Can_Read_Attr(player, parent, ptr))) @@ -1232,7 +1256,8 @@ if ((parent == thing) || !AF_Private(ptr)) { if ((mortal ? Is_Visible_Attr(parent, ptr) : Can_Read_Attr(player, parent, ptr)) - && atr_wild(name, AL_NAME(ptr))) + && (regexp ? quick_regexp_match(name, AL_NAME(ptr), 0) : + atr_wild(name, AL_NAME(ptr)))) result += func(player, thing, parent, name, ptr, args); } } Index: src/db.c =================================================================== --- src/db.c (.../183p13) (revision 469) +++ src/db.c (.../184p0) (revision 469) @@ -246,7 +246,7 @@ } /** Output a string to a file. - * This function writes a string to a file, double-quoted, + * This function writes a string to a file, double-quoted, * appropriately escaping quotes and backslashes (the escape character). * \param f file pointer to write to. * \param s value to write. @@ -404,7 +404,7 @@ } /** Read a string with a given label. - * If the label read is different than the one being checked, the + * If the label read is different than the one being checked, the * database load will abort with an error. * \param f the file to read from. * \param label the label that should be read. @@ -427,7 +427,7 @@ } /** Read an int with a given label. - * If the label read is different than the one being checked, the + * If the label read is different than the one being checked, the * database load will abort with an error. * \param f the file to read from. * \param label the label that should be read. @@ -467,7 +467,7 @@ /** Read a uint32_t with a given label. - * If the label read is different than the one being checked, the + * If the label read is different than the one being checked, the * database load will abort with an error. * \param f the file to read from. * \param label the label that should be read. @@ -507,7 +507,7 @@ /** Read a dbref with a given label. - * If the label read is different than the one being checked, the + * If the label read is different than the one being checked, the * database load will abort with an error. * \param f the file to read from. * \param label the label that should be read. @@ -841,11 +841,11 @@ /* get rid of unprintables and hard newlines */ lastp = '\0'; for (p = tbuf1; *p; p++) { - if (!isprint((unsigned char) *p)) { - if (!isspace((unsigned char) *p)) { - *p = '!'; - err = 1; - } + if (!isprint((unsigned char) *p) && !isspace((unsigned char) *p) && + *p != TAG_START && *p != TAG_END && *p != ESC_CHAR + && *p != BEEP_CHAR) { + *p = '!'; + err = 1; } lastp = *p; } @@ -872,7 +872,7 @@ /** Write out the object database to disk, in paranoid mode. * \verbatim - * This function writes the databsae out to disk, in paranoid mode. + * This function writes the databsae out to disk, in paranoid mode. * The database structure currently looks something like this: * +V
* +FLAGS LIST @@ -1216,7 +1216,7 @@ derefs = 0; /* We add the attribute assuming that atoi(p) is an ok dbref * since we haven't loaded the whole db and can't really tell - * if it is or not. We'll fix this up at the end of the load + * if it is or not. We'll fix this up at the end of the load */ tb2 = getstring_noalloc(f); if (strchr(tb2, TAG_START) || strchr(tb2, ESC_CHAR)) { @@ -1322,7 +1322,7 @@ } -/** Read a non-labeled database from a file. +/** Read a non-labeled database from a file. * \param f the file to read from * \return number of objects in the database */ @@ -1816,7 +1816,7 @@ hashinit(&htab_objdata_keys, 8); } -/** Add data to the object data hashtable. +/** Add data to the object data hashtable. * This hash table is typically used to store transient object data * that is built at database load and isn't saved to disk, but it * can be used for other purposes as well - it's a good general Index: src/function.c =================================================================== --- src/function.c (.../183p13) (revision 469) +++ src/function.c (.../184p0) (revision 469) @@ -34,6 +34,8 @@ extern void local_functions(void); static int apply_restrictions(unsigned int result, const char *restriction); static char *build_function_report(dbref player, FUN *fp); +static FUN *user_func_hash_lookup(const char *name); +static FUN *any_func_hash_lookup(const char *name); HASHTAB htab_function; /**< Function hash table */ HASHTAB htab_user_function; /**< User-defined function hash table */ @@ -303,48 +305,64 @@ int flags; /**< Flags to control how the function is parsed. */ } FUNTAB; +typedef struct fun_alias { + const char *name; /**< Name of function to alias */ + const char *alias; /**< Name of alias to create */ +} FUNALIAS; + +/* Table of hardcoded function aliases. Aliases can also be added with + * @function/alias or a function_alias directive in alias.cnf, both of + * which call the alias_function() function + */ +FUNALIAS faliases[] = { + {"UFUN", "U"}, + {"IDLE", "IDLESECS"}, + {"HOST", "HOSTNAME"}, + {NULL, NULL} +}; + /** The function table. Functions can also be added at runtime with * add_function(). */ FUNTAB flist[] = { - {"@@", fun_atat, 1, -1, FN_NOPARSE}, - {"ABS", fun_abs, 1, 1, FN_REG}, + {"@@", fun_null, 1, -1, FN_NOPARSE}, + {"ABS", fun_abs, 1, 1, FN_REG | FN_STRIPANSI}, {"ACCENT", fun_accent, 2, 2, FN_REG}, {"ACCNAME", fun_accname, 1, 1, FN_REG}, - {"ADD", fun_add, 2, INT_MAX, FN_REG}, + {"ADD", fun_add, 2, INT_MAX, FN_REG | FN_STRIPANSI}, {"AFTER", fun_after, 2, 2, FN_REG}, {"ALIAS", fun_alias, 1, 2, FN_REG}, {"ALIGN", fun_align, 2, INT_MAX, FN_REG}, {"LALIGN", fun_align, 2, 6, FN_REG}, {"ALLOF", fun_allof, 2, INT_MAX, FN_NOPARSE}, - {"ALPHAMAX", fun_alphamax, 1, INT_MAX, FN_REG}, - {"ALPHAMIN", fun_alphamin, 1, INT_MAX, FN_REG}, - {"AND", fun_and, 2, INT_MAX, FN_REG}, - {"ANDFLAGS", fun_andflags, 2, 2, FN_REG}, - {"ANDLFLAGS", fun_andlflags, 2, 2, FN_REG}, - {"ANDLPOWERS", fun_andlflags, 2, 2, FN_REG}, + {"ALPHAMAX", fun_alphamax, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"ALPHAMIN", fun_alphamin, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"AND", fun_and, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"ANDFLAGS", fun_andflags, 2, 2, FN_REG | FN_STRIPANSI}, + {"ANDLFLAGS", fun_andlflags, 2, 2, FN_REG | FN_STRIPANSI}, + {"ANDLPOWERS", fun_andlflags, 2, 2, FN_REG | FN_STRIPANSI}, {"ANSI", fun_ansi, 2, -2, FN_REG}, #ifdef ANSI_DEBUG {"ANSIINSPECT", fun_ansiinspect, 1, 2, FN_REG}, #endif - {"APOSS", fun_aposs, 1, 1, FN_REG}, - {"ART", fun_art, 1, 1, FN_REG}, - {"ATRLOCK", fun_atrlock, 1, 2, FN_REG}, + {"APOSS", fun_aposs, 1, 1, FN_REG | FN_STRIPANSI}, + {"ART", fun_art, 1, 1, FN_REG | FN_STRIPANSI}, + {"ATRLOCK", fun_atrlock, 1, 2, FN_REG | FN_STRIPANSI}, {"ATTRIB_SET", fun_attrib_set, 1, -2, FN_REG}, - {"BAND", fun_band, 1, INT_MAX, FN_REG}, - {"BASECONV", fun_baseconv, 3, 3, FN_REG}, - {"BEEP", fun_beep, 0, 1, FN_REG}, + {"BAND", fun_band, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"BASECONV", fun_baseconv, 3, 3, FN_REG | FN_STRIPANSI}, + {"BEEP", fun_beep, 0, 1, FN_REG | FN_STRIPANSI}, {"BEFORE", fun_before, 2, 2, FN_REG}, {"BENCHMARK", fun_benchmark, 2, 3, FN_NOPARSE}, - {"BNAND", fun_bnand, 2, 2, FN_REG}, - {"BNOT", fun_bnot, 1, 1, FN_REG}, - {"BOR", fun_bor, 1, INT_MAX, FN_REG}, - {"BOUND", fun_bound, 2, 3, FN_REG}, - {"BRACKETS", fun_brackets, 1, 1, FN_REG}, - {"BXOR", fun_bxor, 1, INT_MAX, FN_REG}, - {"CAND", fun_cand, 2, INT_MAX, FN_NOPARSE}, - {"NCAND", fun_cand, 1, INT_MAX, FN_NOPARSE}, + {"BNAND", fun_bnand, 2, 2, FN_REG | FN_STRIPANSI}, + {"BNOT", fun_bnot, 1, 1, FN_REG | FN_STRIPANSI}, + {"BOR", fun_bor, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"BOUND", fun_bound, 2, 3, FN_REG | FN_STRIPANSI}, + {"BRACKETS", fun_brackets, 1, 1, FN_REG | FN_STRIPANSI}, + {"BXOR", fun_bxor, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"CAND", fun_cand, 2, INT_MAX, FN_NOPARSE | FN_STRIPANSI}, + {"NCAND", fun_cand, 1, INT_MAX, FN_NOPARSE | FN_STRIPANSI}, {"CAPSTR", fun_capstr, 1, -1, FN_REG}, {"CASE", fun_switch, 3, INT_MAX, FN_NOPARSE}, {"CASEALL", fun_switch, 3, INT_MAX, FN_NOPARSE}, @@ -353,117 +371,115 @@ {"CBUFFERADD", fun_cbufferadd, 2, 3, FN_REG}, {"CDESC", fun_cinfo, 1, 1, FN_REG}, {"CEMIT", fun_cemit, 2, 3, FN_REG}, - {"CFLAGS", fun_cflags, 1, 2, FN_REG}, - {"CHANNELS", fun_channels, 0, 2, FN_REG}, - {"CLFLAGS", fun_cflags, 1, 2, FN_REG}, - {"CLOCK", fun_clock, 1, 2, FN_REG}, - {"CMSGS", fun_cinfo, 1, 1, FN_REG}, - {"COWNER", fun_cowner, 1, 1, FN_REG}, - {"CRECALL", fun_crecall, 1, 5, FN_REG}, - {"CSTATUS", fun_cstatus, 2, 2, FN_REG}, - {"CTITLE", fun_ctitle, 2, 2, FN_REG}, - {"CUSERS", fun_cinfo, 1, 1, FN_REG}, - {"CWHO", fun_cwho, 1, 2, FN_REG}, + {"CFLAGS", fun_cflags, 1, 2, FN_REG | FN_STRIPANSI}, + {"CHANNELS", fun_channels, 0, 2, FN_REG | FN_STRIPANSI}, + {"CLFLAGS", fun_cflags, 1, 2, FN_REG | FN_STRIPANSI}, + {"CLOCK", fun_clock, 1, 2, FN_REG | FN_STRIPANSI}, + {"CMSGS", fun_cinfo, 1, 1, FN_REG | FN_STRIPANSI}, + {"COWNER", fun_cowner, 1, 1, FN_REG | FN_STRIPANSI}, + {"CRECALL", fun_crecall, 1, 5, FN_REG | FN_STRIPANSI}, + {"CSTATUS", fun_cstatus, 2, 2, FN_REG | FN_STRIPANSI}, + {"CTITLE", fun_ctitle, 2, 2, FN_REG | FN_STRIPANSI}, + {"CUSERS", fun_cinfo, 1, 1, FN_REG | FN_STRIPANSI}, + {"CWHO", fun_cwho, 1, 3, FN_REG | FN_STRIPANSI}, {"CENTER", fun_center, 2, 4, FN_REG}, - {"CHILDREN", fun_lsearch, 1, 1, FN_REG}, - {"CHR", fun_chr, 1, 1, FN_REG}, - {"CHECKPASS", fun_checkpass, 2, 2, FN_REG | FN_WIZARD}, - {"CLONE", fun_clone, 1, 1, FN_REG}, - {"CMDS", fun_cmds, 1, 1, FN_REG}, - {"COMP", fun_comp, 2, 3, FN_REG}, - {"CON", fun_con, 1, 1, FN_REG}, + {"CHILDREN", fun_lsearch, 1, 1, FN_REG | FN_STRIPANSI}, + {"CHR", fun_chr, 1, 1, FN_REG | FN_STRIPANSI}, + {"CHECKPASS", fun_checkpass, 2, 2, FN_REG | FN_WIZARD | FN_STRIPANSI}, + {"CLONE", fun_clone, 1, 3, FN_REG}, + {"CMDS", fun_cmds, 1, 1, FN_REG | FN_STRIPANSI}, + {"COMP", fun_comp, 2, 3, FN_REG | FN_STRIPANSI}, + {"CON", fun_con, 1, 1, FN_REG | FN_STRIPANSI}, {"COND", fun_if, 2, INT_MAX, FN_NOPARSE}, {"CONDALL", fun_if, 2, INT_MAX, FN_NOPARSE}, - {"CONFIG", fun_config, 1, 1, FN_REG}, - {"CONN", fun_conn, 1, 1, FN_REG}, - {"CONTROLS", fun_controls, 2, 2, FN_REG}, - {"CONVSECS", fun_convsecs, 1, 2, FN_REG}, - {"CONVUTCSECS", fun_convsecs, 1, 1, FN_REG}, - {"CONVTIME", fun_convtime, 1, 1, FN_REG}, - {"COR", fun_cor, 2, INT_MAX, FN_NOPARSE}, - {"NCOR", fun_cor, 1, INT_MAX, FN_NOPARSE}, + {"CONFIG", fun_config, 1, 1, FN_REG | FN_STRIPANSI}, + {"CONN", fun_conn, 1, 1, FN_REG | FN_STRIPANSI}, + {"CONTROLS", fun_controls, 2, 2, FN_REG | FN_STRIPANSI}, + {"CONVSECS", fun_convsecs, 1, 2, FN_REG | FN_STRIPANSI}, + {"CONVUTCSECS", fun_convsecs, 1, 1, FN_REG | FN_STRIPANSI}, + {"CONVTIME", fun_convtime, 1, 1, FN_REG | FN_STRIPANSI}, + {"COR", fun_cor, 2, INT_MAX, FN_NOPARSE | FN_STRIPANSI}, + {"NCOR", fun_cor, 1, INT_MAX, FN_NOPARSE | FN_STRIPANSI}, {"CREATE", fun_create, 1, 3, FN_REG}, - {"CSECS", fun_csecs, 1, 1, FN_REG}, - {"CTIME", fun_ctime, 1, 2, FN_REG}, - {"DEC", fun_dec, 1, 1, FN_REG}, + {"CSECS", fun_csecs, 1, 1, FN_REG | FN_STRIPANSI}, + {"CTIME", fun_ctime, 1, 2, FN_REG | FN_STRIPANSI}, + {"DEC", fun_dec, 1, 1, FN_REG | FN_STRIPANSI}, {"DECODE64", fun_decode64, 1, -1, FN_REG}, {"DECOMPOSE", fun_decompose, 1, -1, FN_REG}, {"DECRYPT", fun_decrypt, 2, 3, FN_REG}, {"DEFAULT", fun_default, 2, INT_MAX, FN_NOPARSE}, {"DELETE", fun_delete, 3, 3, FN_REG}, - {"DIE", fun_die, 2, 3, FN_REG}, + {"DIE", fun_die, 2, 3, FN_REG | FN_STRIPANSI}, {"DIG", fun_dig, 1, 3, FN_REG}, {"DIGEST", fun_digest, 2, -2, FN_REG}, - {"DIST2D", fun_dist2d, 4, 4, FN_REG}, - {"DIST3D", fun_dist3d, 6, 6, FN_REG}, - {"DIV", fun_div, 2, 2, FN_REG}, - {"DOING", fun_doing, 1, 1, FN_REG}, + {"DIST2D", fun_dist2d, 4, 4, FN_REG | FN_STRIPANSI}, + {"DIST3D", fun_dist3d, 6, 6, FN_REG | FN_STRIPANSI}, + {"DIV", fun_div, 2, 2, FN_REG | FN_STRIPANSI}, + {"DOING", fun_doing, 1, 1, FN_REG | FN_STRIPANSI}, {"EDEFAULT", fun_edefault, 2, 2, FN_NOPARSE}, {"EDIT", fun_edit, 3, INT_MAX, FN_REG}, {"ELEMENT", fun_element, 3, 3, FN_REG}, {"ELEMENTS", fun_elements, 2, 4, FN_REG}, {"ELIST", fun_itemize, 1, 5, FN_REG}, - {"ELOCK", fun_elock, 2, 2, FN_REG}, + {"ELOCK", fun_elock, 2, 2, FN_REG | FN_STRIPANSI}, {"EMIT", fun_emit, 1, -1, FN_REG}, {"ENCODE64", fun_encode64, 1, -1, FN_REG}, {"ENCRYPT", fun_encrypt, 2, 3, FN_REG}, - {"ENTRANCES", fun_entrances, 0, 4, FN_REG}, + {"ENTRANCES", fun_entrances, 0, 4, FN_REG | FN_STRIPANSI}, {"ETIMEFMT", fun_etimefmt, 2, 2, FN_REG}, - {"EQ", fun_eq, 2, INT_MAX, FN_REG}, + {"EQ", fun_eq, 2, INT_MAX, FN_REG | FN_STRIPANSI}, {"EVAL", fun_eval, 2, 2, FN_REG}, {"ESCAPE", fun_escape, 1, -1, FN_REG}, - {"EXIT", fun_exit, 1, 1, FN_REG}, + {"EXIT", fun_exit, 1, 1, FN_REG | FN_STRIPANSI}, {"EXTRACT", fun_extract, 1, 4, FN_REG}, {"FILTER", fun_filter, 2, 4, FN_REG}, {"FILTERBOOL", fun_filter, 2, 4, FN_REG}, - {"FINDABLE", fun_findable, 2, 2, FN_REG}, + {"FINDABLE", fun_findable, 2, 2, FN_REG | FN_STRIPANSI}, {"FIRST", fun_first, 1, 2, FN_REG}, {"FIRSTOF", fun_firstof, 0, INT_MAX, FN_NOPARSE}, - {"FLAGS", fun_flags, 0, 1, FN_REG}, + {"FLAGS", fun_flags, 0, 1, FN_REG | FN_STRIPANSI}, {"FLIP", fun_flip, 1, -1, FN_REG}, {"FLOORDIV", fun_floordiv, 2, 2, FN_REG}, {"FN", fun_fn, 1, INT_MAX, FN_NOPARSE}, {"FOLD", fun_fold, 2, 4, FN_REG}, - {"FOLDERSTATS", fun_folderstats, 0, 2, FN_REG}, - {"FOLLOWERS", fun_followers, 1, 1, FN_REG}, - {"FOLLOWING", fun_following, 1, 1, FN_REG}, + {"FOLDERSTATS", fun_folderstats, 0, 2, FN_REG | FN_STRIPANSI}, + {"FOLLOWERS", fun_followers, 1, 1, FN_REG | FN_STRIPANSI}, + {"FOLLOWING", fun_following, 1, 1, FN_REG | FN_STRIPANSI}, {"FOREACH", fun_foreach, 2, 4, FN_REG}, - {"FRACTION", fun_fraction, 1, 1, FN_REG}, - {"FUNCTIONS", fun_functions, 0, 1, FN_REG}, - {"FULLALIAS", fun_fullalias, 1, 1, FN_REG}, - {"FULLNAME", fun_fullname, 1, 1, FN_REG}, - {"GET", fun_get, 1, 1, FN_REG}, - {"GETPIDS", fun_lpids, 1, 1, FN_REG}, + {"FRACTION", fun_fraction, 1, 1, FN_REG | FN_STRIPANSI}, + {"FUNCTIONS", fun_functions, 0, 1, FN_REG | FN_STRIPANSI}, + {"FULLALIAS", fun_fullalias, 1, 1, FN_REG | FN_STRIPANSI}, + {"FULLNAME", fun_fullname, 1, 1, FN_REG | FN_STRIPANSI}, + {"GET", fun_get, 1, 1, FN_REG | FN_STRIPANSI}, + {"GETPIDS", fun_lpids, 1, 1, FN_REG | FN_STRIPANSI}, {"GET_EVAL", fun_get_eval, 1, 1, FN_REG}, {"GRAB", fun_grab, 2, 3, FN_REG}, {"GRABALL", fun_graball, 2, 4, FN_REG}, {"GREP", fun_grep, 3, 3, FN_REG}, {"GREPI", fun_grep, 3, 3, FN_REG}, - {"GT", fun_gt, 2, INT_MAX, FN_REG}, - {"GTE", fun_gte, 2, INT_MAX, FN_REG}, - {"HASATTR", fun_hasattr, 1, 2, FN_REG}, - {"HASATTRP", fun_hasattr, 1, 2, FN_REG}, - {"HASATTRPVAL", fun_hasattr, 1, 2, FN_REG}, - {"HASATTRVAL", fun_hasattr, 1, 2, FN_REG}, - {"HASFLAG", fun_hasflag, 2, 2, FN_REG}, - {"HASPOWER", fun_haspower, 2, 2, FN_REG}, - {"HASTYPE", fun_hastype, 2, 2, FN_REG}, - {"HEIGHT", fun_height, 1, 2, FN_REG}, - {"HIDDEN", fun_hidden, 1, 1, FN_REG}, - {"HOME", fun_home, 1, 1, FN_REG}, - {"HOST", fun_hostname, 1, 1, FN_REG}, - {"HOSTNAME", fun_hostname, 1, 1, FN_REG}, - {"IDLE", fun_idlesecs, 1, 1, FN_REG}, - {"IDLESECS", fun_idlesecs, 1, 1, FN_REG}, + {"GT", fun_gt, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"GTE", fun_gte, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"HASATTR", fun_hasattr, 1, 2, FN_REG | FN_STRIPANSI}, + {"HASATTRP", fun_hasattr, 1, 2, FN_REG | FN_STRIPANSI}, + {"HASATTRPVAL", fun_hasattr, 1, 2, FN_REG | FN_STRIPANSI}, + {"HASATTRVAL", fun_hasattr, 1, 2, FN_REG | FN_STRIPANSI}, + {"HASFLAG", fun_hasflag, 2, 2, FN_REG | FN_STRIPANSI}, + {"HASPOWER", fun_haspower, 2, 2, FN_REG | FN_STRIPANSI}, + {"HASTYPE", fun_hastype, 2, 2, FN_REG | FN_STRIPANSI}, + {"HEIGHT", fun_height, 1, 2, FN_REG | FN_STRIPANSI}, + {"HIDDEN", fun_hidden, 1, 1, FN_REG | FN_STRIPANSI}, + {"HOME", fun_home, 1, 1, FN_REG | FN_STRIPANSI}, + {"HOST", fun_hostname, 1, 1, FN_REG | FN_STRIPANSI}, + {"IDLE", fun_idlesecs, 1, 1, FN_REG | FN_STRIPANSI}, {"IF", fun_if, 2, 3, FN_NOPARSE}, {"IFELSE", fun_if, 3, 3, FN_NOPARSE}, - {"ILEV", fun_ilev, 0, 0, FN_REG}, - {"INAME", fun_iname, 1, 1, FN_REG}, - {"INC", fun_inc, 1, 1, FN_REG}, + {"ILEV", fun_ilev, 0, 0, FN_REG | FN_STRIPANSI}, + {"INAME", fun_iname, 1, 1, FN_REG | FN_STRIPANSI}, + {"INC", fun_inc, 1, 1, FN_REG | FN_STRIPANSI}, {"INDEX", fun_index, 4, 4, FN_REG}, {"INSERT", fun_insert, 3, 4, FN_REG}, - {"INUM", fun_inum, 1, 1, FN_REG}, - {"IPADDR", fun_ipaddr, 1, 1, FN_REG}, + {"INUM", fun_inum, 1, 1, FN_REG | FN_STRIPANSI}, + {"IPADDR", fun_ipaddr, 1, 1, FN_REG | FN_STRIPANSI}, {"ISDAYLIGHT", fun_isdaylight, 0, 0, FN_REG}, {"ISDBREF", fun_isdbref, 1, 1, FN_REG}, {"ISINT", fun_isint, 1, 1, FN_REG}, @@ -471,107 +487,107 @@ {"ISOBJID", fun_isobjid, 1, 1, FN_REG}, {"ISWORD", fun_isword, 1, 1, FN_REG}, {"ITER", fun_iter, 2, 4, FN_NOPARSE}, - {"ITEMS", fun_items, 2, 2, FN_REG}, + {"ITEMS", fun_items, 2, 2, FN_REG | FN_STRIPANSI}, {"ITEMIZE", fun_itemize, 1, 4, FN_REG}, - {"ITEXT", fun_itext, 1, 1, FN_REG}, + {"ITEXT", fun_itext, 1, 1, FN_REG | FN_STRIPANSI}, {"LAST", fun_last, 1, 2, FN_REG}, - {"LATTR", fun_lattr, 1, 2, FN_REG}, - {"LATTRP", fun_lattr, 1, 2, FN_REG}, - {"LCON", fun_dbwalker, 1, 1, FN_REG}, + {"LATTR", fun_lattr, 1, 2, FN_REG | FN_STRIPANSI}, + {"LATTRP", fun_lattr, 1, 2, FN_REG | FN_STRIPANSI}, + {"LCON", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, {"LCSTR", fun_lcstr, 1, -1, FN_REG}, {"LDELETE", fun_ldelete, 2, 3, FN_REG}, {"LEFT", fun_left, 2, 2, FN_REG}, {"LEMIT", fun_lemit, 1, -1, FN_REG}, {"LETQ", fun_letq, 1, INT_MAX, FN_NOPARSE}, - {"LEXITS", fun_dbwalker, 1, 1, FN_REG}, - {"LFLAGS", fun_lflags, 0, 1, FN_REG}, - {"LINK", fun_link, 2, 3, FN_REG}, - {"LIST", fun_list, 1, 1, FN_REG}, + {"LEXITS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"LFLAGS", fun_lflags, 0, 1, FN_REG | FN_STRIPANSI}, + {"LINK", fun_link, 2, 3, FN_REG | FN_STRIPANSI}, + {"LIST", fun_list, 1, 1, FN_REG | FN_STRIPANSI}, {"LIT", fun_lit, 1, -1, FN_LITERAL}, {"LJUST", fun_ljust, 2, 3, FN_REG}, - {"LLOCKFLAGS", fun_lockflags, 0, 1, FN_REG}, - {"LLOCKS", fun_locks, 0, 1, FN_REG}, - {"LMATH", fun_lmath, 2, 3, FN_REG}, - {"LNUM", fun_lnum, 1, 4, FN_REG}, - {"LOC", fun_loc, 1, 1, FN_REG}, + {"LLOCKFLAGS", fun_lockflags, 0, 1, FN_REG | FN_STRIPANSI}, + {"LLOCKS", fun_locks, 0, 1, FN_REG | FN_STRIPANSI}, + {"LMATH", fun_lmath, 2, 3, FN_REG | FN_STRIPANSI}, + {"LNUM", fun_lnum, 1, 4, FN_REG | FN_STRIPANSI}, + {"LOC", fun_loc, 1, 1, FN_REG | FN_STRIPANSI}, {"LOCALIZE", fun_localize, 1, 1, FN_NOPARSE}, - {"LOCATE", fun_locate, 3, 3, FN_REG}, - {"LOCK", fun_lock, 1, 2, FN_REG}, - {"LOCKFLAGS", fun_lockflags, 0, 1, FN_REG}, - {"LOCKOWNER", fun_lockowner, 1, 1, FN_REG}, - {"LOCKS", fun_locks, 1, 1, FN_REG}, - {"LPARENT", fun_lparent, 1, 1, FN_REG}, - {"LPIDS", fun_lpids, 0, 2, FN_REG}, - {"LPLAYERS", fun_dbwalker, 1, 1, FN_REG}, - {"LPORTS", fun_lports, 0, 2, FN_REG}, - {"LPOS", fun_lpos, 2, 2, FN_REG}, + {"LOCATE", fun_locate, 3, 3, FN_REG | FN_STRIPANSI}, + {"LOCK", fun_lock, 1, 2, FN_REG | FN_STRIPANSI}, + {"LOCKFLAGS", fun_lockflags, 0, 1, FN_REG | FN_STRIPANSI}, + {"LOCKOWNER", fun_lockowner, 1, 1, FN_REG | FN_STRIPANSI}, + {"LOCKS", fun_locks, 1, 1, FN_REG | FN_STRIPANSI}, + {"LPARENT", fun_lparent, 1, 1, FN_REG | FN_STRIPANSI}, + {"LPIDS", fun_lpids, 0, 2, FN_REG | FN_STRIPANSI}, + {"LPLAYERS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"LPORTS", fun_lports, 0, 2, FN_REG | FN_STRIPANSI}, + {"LPOS", fun_lpos, 2, 2, FN_REG | FN_STRIPANSI}, {"LSEARCH", fun_lsearch, 1, INT_MAX, FN_REG}, {"LSEARCHR", fun_lsearch, 1, INT_MAX, FN_REG}, - {"LSET", fun_lset, 2, 2, FN_REG}, - {"LSTATS", fun_lstats, 0, 1, FN_REG}, - {"LT", fun_lt, 2, INT_MAX, FN_REG}, - {"LTE", fun_lte, 2, INT_MAX, FN_REG}, - {"LTHINGS", fun_dbwalker, 1, 1, FN_REG}, - {"LVCON", fun_dbwalker, 1, 1, FN_REG}, - {"LVEXITS", fun_dbwalker, 1, 1, FN_REG}, - {"LVPLAYERS", fun_dbwalker, 1, 1, FN_REG}, - {"LVTHINGS", fun_dbwalker, 1, 1, FN_REG}, - {"LWHO", fun_lwho, 0, 2, FN_REG}, - {"LWHOID", fun_lwho, 0, 1, FN_REG}, - {"MAIL", fun_mail, 0, 2, FN_REG}, - {"MAILFROM", fun_mailfrom, 1, 2, FN_REG}, + {"LSET", fun_lset, 2, 2, FN_REG | FN_STRIPANSI}, + {"LSTATS", fun_lstats, 0, 1, FN_REG | FN_STRIPANSI}, + {"LT", fun_lt, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"LTE", fun_lte, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"LTHINGS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"LVCON", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"LVEXITS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"LVPLAYERS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"LVTHINGS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"LWHO", fun_lwho, 0, 2, FN_REG | FN_STRIPANSI}, + {"LWHOID", fun_lwho, 0, 1, FN_REG | FN_STRIPANSI}, + {"MAIL", fun_mail, 0, 2, FN_REG | FN_STRIPANSI}, + {"MAILFROM", fun_mailfrom, 1, 2, FN_REG | FN_STRIPANSI}, {"MAILSEND", fun_mailsend, 2, 2, FN_REG}, - {"MAILSTATS", fun_mailstats, 1, 1, FN_REG}, - {"MAILDSTATS", fun_mailstats, 1, 1, FN_REG}, - {"MAILFSTATS", fun_mailstats, 1, 1, FN_REG}, - {"MAILSTATUS", fun_mailstatus, 1, 2, FN_REG}, - {"MAILSUBJECT", fun_mailsubject, 1, 2, FN_REG}, - {"MAILTIME", fun_mailtime, 1, 2, FN_REG}, - {"MALIAS", fun_malias, 0, 2, FN_REG}, + {"MAILSTATS", fun_mailstats, 1, 1, FN_REG | FN_STRIPANSI}, + {"MAILDSTATS", fun_mailstats, 1, 1, FN_REG | FN_STRIPANSI}, + {"MAILFSTATS", fun_mailstats, 1, 1, FN_REG | FN_STRIPANSI}, + {"MAILSTATUS", fun_mailstatus, 1, 2, FN_REG | FN_STRIPANSI}, + {"MAILSUBJECT", fun_mailsubject, 1, 2, FN_REG | FN_STRIPANSI}, + {"MAILTIME", fun_mailtime, 1, 2, FN_REG | FN_STRIPANSI}, + {"MALIAS", fun_malias, 0, 2, FN_REG | FN_STRIPANSI}, {"MAP", fun_map, 2, 4, FN_REG}, {"MAPSQL", fun_mapsql, 2, 4, FN_REG}, - {"MATCH", fun_match, 2, 3, FN_REG}, - {"MATCHALL", fun_matchall, 2, 4, FN_REG}, - {"MAX", fun_max, 1, INT_MAX, FN_REG}, - {"MEAN", fun_mean, 1, INT_MAX, FN_REG}, - {"MEDIAN", fun_median, 1, INT_MAX, FN_REG}, - {"MEMBER", fun_member, 2, 3, FN_REG}, + {"MATCH", fun_match, 2, 3, FN_REG | FN_STRIPANSI}, + {"MATCHALL", fun_matchall, 2, 4, FN_REG | FN_STRIPANSI}, + {"MAX", fun_max, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"MEAN", fun_mean, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"MEDIAN", fun_median, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"MEMBER", fun_member, 2, 3, FN_REG | FN_STRIPANSI | FN_STRIPANSI}, {"MERGE", fun_merge, 3, 3, FN_REG}, {"MESSAGE", fun_message, 3, 13, FN_REG}, {"MID", fun_mid, 3, 3, FN_REG}, - {"MIN", fun_min, 1, INT_MAX, FN_REG}, + {"MIN", fun_min, 1, INT_MAX, FN_REG | FN_STRIPANSI}, {"MIX", fun_mix, 3, 12, FN_REG}, - {"MODULO", fun_modulo, 2, 2, FN_REG}, - {"MONEY", fun_money, 1, 1, FN_REG}, - {"MSECS", fun_msecs, 1, 1, FN_REG}, - {"MTIME", fun_mtime, 1, 2, FN_REG}, + {"MODULO", fun_modulo, 2, 2, FN_REG | FN_STRIPANSI}, + {"MONEY", fun_money, 1, 1, FN_REG | FN_STRIPANSI}, + {"MSECS", fun_msecs, 1, 1, FN_REG | FN_STRIPANSI}, + {"MTIME", fun_mtime, 1, 2, FN_REG | FN_STRIPANSI}, {"MUDNAME", fun_mudname, 0, 0, FN_REG}, {"MUDURL", fun_mudurl, 0, 0, FN_REG}, - {"MUL", fun_mul, 2, INT_MAX, FN_REG}, + {"MUL", fun_mul, 2, INT_MAX, FN_REG | FN_STRIPANSI}, {"MUNGE", fun_munge, 3, 5, FN_REG}, - {"MWHO", fun_lwho, 0, 0, FN_REG}, - {"MWHOID", fun_lwho, 0, 0, FN_REG}, - {"NAME", fun_name, 0, 2, FN_REG}, + {"MWHO", fun_lwho, 0, 0, FN_REG | FN_STRIPANSI}, + {"MWHOID", fun_lwho, 0, 0, FN_REG | FN_STRIPANSI}, + {"NAME", fun_name, 0, 2, FN_REG | FN_STRIPANSI}, {"NAMELIST", fun_namelist, 1, 2, FN_REG}, {"NAMEGRAB", fun_namegrab, 2, 3, FN_REG}, {"NAMEGRABALL", fun_namegraball, 2, 3, FN_REG}, - {"NAND", fun_nand, 1, INT_MAX, FN_REG}, - {"NATTR", fun_nattr, 1, 1, FN_REG}, - {"NATTRP", fun_nattr, 1, 1, FN_REG}, - {"NCHILDREN", fun_lsearch, 1, 1, FN_REG}, - {"NCON", fun_dbwalker, 1, 1, FN_REG}, + {"NAND", fun_nand, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"NATTR", fun_nattr, 1, 1, FN_REG | FN_STRIPANSI}, + {"NATTRP", fun_nattr, 1, 1, FN_REG | FN_STRIPANSI}, + {"NCHILDREN", fun_lsearch, 1, 1, FN_REG | FN_STRIPANSI}, + {"NCON", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, {"NCOND", fun_if, 2, INT_MAX, FN_NOPARSE}, {"NCONDALL", fun_if, 2, INT_MAX, FN_NOPARSE}, - {"NEXITS", fun_dbwalker, 1, 1, FN_REG}, - {"NPLAYERS", fun_dbwalker, 1, 1, FN_REG}, - {"NEARBY", fun_nearby, 2, 2, FN_REG}, - {"NEQ", fun_neq, 2, INT_MAX, FN_REG}, - {"NEXT", fun_next, 1, 1, FN_REG}, + {"NEXITS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"NPLAYERS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"NEARBY", fun_nearby, 2, 2, FN_REG | FN_STRIPANSI}, + {"NEQ", fun_neq, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"NEXT", fun_next, 1, 1, FN_REG | FN_STRIPANSI}, {"NEXTDBREF", fun_nextdbref, 0, 0, FN_REG}, {"NLSEARCH", fun_lsearch, 1, INT_MAX, FN_REG}, {"NMWHO", fun_nwho, 0, 0, FN_REG}, - {"NOR", fun_nor, 1, INT_MAX, FN_REG}, - {"NOT", fun_not, 1, 1, FN_REG}, + {"NOR", fun_nor, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"NOT", fun_not, 1, 1, FN_REG | FN_STRIPANSI}, {"NSCEMIT", fun_cemit, 2, 3, FN_REG}, {"NSEARCH", fun_lsearch, 1, INT_MAX, FN_REG}, {"NSEMIT", fun_emit, 1, -1, FN_REG}, @@ -581,47 +597,47 @@ {"NSPROMPT", fun_prompt, 2, -2, FN_REG}, {"NSREMIT", fun_remit, 2, -2, FN_REG}, {"NSZEMIT", fun_zemit, 2, -2, FN_REG}, - {"NTHINGS", fun_dbwalker, 1, 1, FN_REG}, - {"NUM", fun_num, 1, 1, FN_REG}, + {"NTHINGS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"NUM", fun_num, 1, 1, FN_REG | FN_STRIPANSI}, {"NUMVERSION", fun_numversion, 0, 0, FN_REG}, {"NULL", fun_null, 1, INT_MAX, FN_REG}, - {"NVCON", fun_dbwalker, 1, 1, FN_REG}, - {"NVEXITS", fun_dbwalker, 1, 1, FN_REG}, - {"NVPLAYERS", fun_dbwalker, 1, 1, FN_REG}, - {"NVTHINGS", fun_dbwalker, 1, 1, FN_REG}, - {"NWHO", fun_nwho, 0, 1, FN_REG}, - {"OBJ", fun_obj, 1, 1, FN_REG}, + {"NVCON", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"NVEXITS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"NVPLAYERS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"NVTHINGS", fun_dbwalker, 1, 1, FN_REG | FN_STRIPANSI}, + {"NWHO", fun_nwho, 0, 1, FN_REG | FN_STRIPANSI}, + {"OBJ", fun_obj, 1, 1, FN_REG | FN_STRIPANSI}, {"OBJEVAL", fun_objeval, 2, -2, FN_NOPARSE}, - {"OBJID", fun_objid, 1, 1, FN_REG}, - {"OBJMEM", fun_objmem, 1, 1, FN_REG}, + {"OBJID", fun_objid, 1, 1, FN_REG | FN_STRIPANSI}, + {"OBJMEM", fun_objmem, 1, 1, FN_REG | FN_STRIPANSI}, {"OEMIT", fun_oemit, 2, -2, FN_REG}, {"OPEN", fun_open, 2, 2, FN_REG}, - {"OR", fun_or, 2, INT_MAX, FN_REG}, - {"ORD", fun_ord, 1, 1, FN_REG}, - {"ORDINAL", fun_spellnum, 1, 1, FN_REG}, - {"ORFLAGS", fun_orflags, 2, 2, FN_REG}, - {"ORLFLAGS", fun_orlflags, 2, 2, FN_REG}, - {"ORLPOWERS", fun_orlflags, 2, 2, FN_REG}, - {"OWNER", fun_owner, 1, 1, FN_REG}, - {"PARENT", fun_parent, 1, 2, FN_REG}, + {"OR", fun_or, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"ORD", fun_ord, 1, 1, FN_REG | FN_STRIPANSI}, + {"ORDINAL", fun_spellnum, 1, 1, FN_REG | FN_STRIPANSI}, + {"ORFLAGS", fun_orflags, 2, 2, FN_REG | FN_STRIPANSI}, + {"ORLFLAGS", fun_orlflags, 2, 2, FN_REG | FN_STRIPANSI}, + {"ORLPOWERS", fun_orlflags, 2, 2, FN_REG | FN_STRIPANSI}, + {"OWNER", fun_owner, 1, 1, FN_REG | FN_STRIPANSI}, + {"PARENT", fun_parent, 1, 2, FN_REG | FN_STRIPANSI}, {"PCREATE", fun_pcreate, 2, 3, FN_REG}, {"PEMIT", fun_pemit, 2, -2, FN_REG}, - {"PIDINFO", fun_pidinfo, 1, 3, FN_REG}, - {"PLAYERMEM", fun_playermem, 1, 1, FN_REG}, - {"PLAYER", fun_player, 1, 1, FN_REG}, - {"PMATCH", fun_pmatch, 1, 1, FN_REG}, + {"PIDINFO", fun_pidinfo, 1, 3, FN_REG | FN_STRIPANSI}, + {"PLAYERMEM", fun_playermem, 1, 1, FN_REG | FN_STRIPANSI}, + {"PLAYER", fun_player, 1, 1, FN_REG | FN_STRIPANSI}, + {"PMATCH", fun_pmatch, 1, 1, FN_REG | FN_STRIPANSI}, {"POLL", fun_poll, 0, 0, FN_REG}, - {"PORTS", fun_ports, 1, 1, FN_REG}, - {"POS", fun_pos, 2, 2, FN_REG}, - {"POSS", fun_poss, 1, 1, FN_REG}, - {"POWERS", fun_powers, 1, 2, FN_REG}, + {"PORTS", fun_ports, 1, 1, FN_REG | FN_STRIPANSI}, + {"POS", fun_pos, 2, 2, FN_REG | FN_STRIPANSI}, + {"POSS", fun_poss, 1, 1, FN_REG | FN_STRIPANSI}, + {"POWERS", fun_powers, 1, 2, FN_REG | FN_STRIPANSI}, {"PROMPT", fun_prompt, 2, -2, FN_REG}, - {"PUEBLO", fun_pueblo, 1, 1, FN_REG}, - {"QUOTA", fun_quota, 1, 1, FN_REG}, - {"R", fun_r, 1, 1, FN_REG}, - {"RAND", fun_rand, 1, 2, FN_REG}, + {"PUEBLO", fun_pueblo, 1, 1, FN_REG | FN_STRIPANSI}, + {"QUOTA", fun_quota, 1, 1, FN_REG | FN_STRIPANSI}, + {"R", fun_r, 1, 1, FN_REG | FN_STRIPANSI}, + {"RAND", fun_rand, 1, 2, FN_REG | FN_STRIPANSI}, {"RANDWORD", fun_randword, 1, 2, FN_REG}, - {"RECV", fun_recv, 1, 1, FN_REG}, + {"RECV", fun_recv, 1, 1, FN_REG | FN_STRIPANSI}, {"REGEDIT", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, {"REGEDITALL", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, {"REGEDITALLI", fun_regreplace, 3, INT_MAX, FN_NOPARSE}, @@ -634,6 +650,12 @@ {"REGRABI", fun_regrab, 2, 3, FN_REG}, {"REGREP", fun_regrep, 3, 3, FN_REG}, {"REGREPI", fun_regrep, 3, 3, FN_REG}, + {"REGLATTR", fun_lattr, 1, 2, FN_REG}, + {"REGLATTRP", fun_lattr, 1, 2, FN_REG}, + {"REGNATTR", fun_nattr, 1, 1, FN_REG}, + {"REGNATTRP", fun_nattr, 1, 1, FN_REG}, + {"REGXATTR", fun_lattr, 3, 4, FN_REG}, + {"REGXATTRP", fun_lattr, 3, 4, FN_REG}, {"RESWITCH", fun_reswitch, 3, INT_MAX, FN_NOPARSE}, {"RESWITCHALL", fun_reswitch, 3, INT_MAX, FN_NOPARSE}, {"RESWITCHALLI", fun_reswitch, 3, INT_MAX, FN_NOPARSE}, @@ -650,16 +672,16 @@ {"REVWORDS", fun_revwords, 1, 3, FN_REG}, {"RIGHT", fun_right, 2, 2, FN_REG}, {"RJUST", fun_rjust, 2, 3, FN_REG}, - {"RLOC", fun_rloc, 2, 2, FN_REG}, - {"RNUM", fun_rnum, 2, 2, FN_REG}, - {"ROOM", fun_room, 1, 1, FN_REG}, - {"ROOT", fun_root, 2, 2, FN_REG}, + {"RLOC", fun_rloc, 2, 2, FN_REG | FN_STRIPANSI}, + {"RNUM", fun_rnum, 2, 2, FN_REG | FN_STRIPANSI}, + {"ROOM", fun_room, 1, 1, FN_REG | FN_STRIPANSI}, + {"ROOT", fun_root, 2, 2, FN_REG | FN_STRIPANSI}, {"S", fun_s, 1, -1, FN_REG}, - {"SCAN", fun_scan, 1, -2, FN_REG}, + {"SCAN", fun_scan, 1, -2, FN_REG | FN_STRIPANSI}, {"SCRAMBLE", fun_scramble, 1, -1, FN_REG}, {"SECS", fun_secs, 0, 0, FN_REG}, {"SECURE", fun_secure, 1, -1, FN_REG}, - {"SENT", fun_sent, 1, 1, FN_REG}, + {"SENT", fun_sent, 1, 1, FN_REG | FN_STRIPANSI}, {"SET", fun_set, 2, 2, FN_REG}, {"SETQ", fun_setq, 2, INT_MAX, FN_REG}, {"SETR", fun_setq, 2, INT_MAX, FN_REG}, @@ -667,58 +689,59 @@ {"SETINTER", fun_setinter, 2, 5, FN_REG}, {"SETUNION", fun_setunion, 2, 5, FN_REG}, {"SHA0", fun_sha0, 1, 1, FN_REG}, - {"SHL", fun_shl, 2, 2, FN_REG}, - {"SHR", fun_shr, 2, 2, FN_REG}, + {"SHL", fun_shl, 2, 2, FN_REG | FN_STRIPANSI}, + {"SHR", fun_shr, 2, 2, FN_REG | FN_STRIPANSI}, {"SHUFFLE", fun_shuffle, 1, 3, FN_REG}, - {"SIGN", fun_sign, 1, 1, FN_REG}, + {"SIGN", fun_sign, 1, 1, FN_REG | FN_STRIPANSI}, {"SORT", fun_sort, 1, 4, FN_REG}, {"SORTBY", fun_sortby, 2, 4, FN_REG}, {"SORTKEY", fun_sortkey, 2, 5, FN_REG}, - {"SOUNDEX", fun_soundex, 1, 1, FN_REG}, - {"SOUNDSLIKE", fun_soundlike, 2, 2, FN_REG}, - {"SPACE", fun_space, 1, 1, FN_REG}, + {"SOUNDEX", fun_soundex, 1, 1, FN_REG | FN_STRIPANSI}, + {"SOUNDSLIKE", fun_soundlike, 2, 2, FN_REG | FN_STRIPANSI}, + {"SPACE", fun_space, 1, 1, FN_REG | FN_STRIPANSI}, {"SPEAK", fun_speak, 2, 7, FN_REG}, {"SPEAKPENN", fun_speak, 2, 7, FN_REG}, - {"SPELLNUM", fun_spellnum, 1, 1, FN_REG}, + {"SPELLNUM", fun_spellnum, 1, 1, FN_REG | FN_STRIPANSI}, {"SPLICE", fun_splice, 3, 4, FN_REG}, {"SQL", fun_sql, 1, 4, FN_REG}, {"SQLESCAPE", fun_sql_escape, 1, 1, FN_REG}, {"SQUISH", fun_squish, 1, 2, FN_REG}, - {"SSL", fun_ssl, 1, 1, FN_REG}, + {"SSL", fun_ssl, 1, 1, FN_REG | FN_STRIPANSI}, {"STARTTIME", fun_starttime, 0, 0, FN_REG}, {"STEP", fun_step, 3, 5, FN_REG}, + {"STRFIRSTOF", fun_firstof, 2, INT_MAX, FN_NOPARSE}, + {"STRALLOF", fun_allof, 2, INT_MAX, FN_NOPARSE}, {"STRCAT", fun_strcat, 1, INT_MAX, FN_REG}, - {"STRINGSECS", fun_stringsecs, 1, 1, FN_REG}, + {"STRINGSECS", fun_stringsecs, 1, 1, FN_REG | FN_STRIPANSI}, {"STRINSERT", fun_strinsert, 3, -3, FN_REG}, {"STRIPACCENTS", fun_stripaccents, 1, 1, FN_REG}, - {"STRIPANSI", fun_stripansi, 1, -1, FN_REG}, + {"STRIPANSI", fun_stripansi, 1, -1, FN_REG | FN_STRIPANSI}, {"STRLEN", fun_strlen, 1, -1, FN_REG}, {"STRMATCH", fun_strmatch, 2, 3, FN_REG}, {"STRREPLACE", fun_strreplace, 4, 4, FN_REG}, - {"SUB", fun_sub, 2, 2, FN_REG}, - {"SUBJ", fun_subj, 1, 1, FN_REG}, + {"SUB", fun_sub, 2, 2, FN_REG | FN_STRIPANSI}, + {"SUBJ", fun_subj, 1, 1, FN_REG | FN_STRIPANSI}, {"SWITCH", fun_switch, 3, INT_MAX, FN_NOPARSE}, {"SWITCHALL", fun_switch, 3, INT_MAX, FN_NOPARSE}, - {"T", fun_t, 1, 1, FN_REG}, + {"T", fun_t, 1, 1, FN_REG | FN_STRIPANSI}, {"TABLE", fun_table, 1, 5, FN_REG}, - {"TEL", fun_tel, 2, 4, FN_REG}, - {"TERMINFO", fun_terminfo, 1, 1, FN_REG}, - {"TESTLOCK", fun_testlock, 2, 2, FN_REG}, - {"TEXTENTRIES", fun_textentries, 2, 3, FN_REG}, - {"TEXTFILE", fun_textfile, 2, 2, FN_REG}, - {"TIME", fun_time, 0, 1, FN_REG}, + {"TEL", fun_tel, 2, 4, FN_REG | FN_STRIPANSI}, + {"TERMINFO", fun_terminfo, 1, 1, FN_REG | FN_STRIPANSI}, + {"TESTLOCK", fun_testlock, 2, 2, FN_REG | FN_STRIPANSI}, + {"TEXTENTRIES", fun_textentries, 2, 3, FN_REG | FN_STRIPANSI}, + {"TEXTFILE", fun_textfile, 2, 2, FN_REG | FN_STRIPANSI}, + {"TIME", fun_time, 0, 1, FN_REG | FN_STRIPANSI}, {"TIMEFMT", fun_timefmt, 1, 2, FN_REG}, - {"TIMESTRING", fun_timestring, 1, 2, FN_REG}, + {"TIMESTRING", fun_timestring, 1, 2, FN_REG | FN_STRIPANSI}, {"TR", fun_tr, 3, 3, FN_REG}, {"TRIM", fun_trim, 1, 3, FN_REG}, {"TRIMPENN", fun_trim, 1, 3, FN_REG}, {"TRIMTINY", fun_trim, 1, 3, FN_REG}, {"TRUNC", fun_trunc, 1, 1, FN_REG}, - {"TYPE", fun_type, 1, 1, FN_REG}, + {"TYPE", fun_type, 1, 1, FN_REG | FN_STRIPANSI}, {"UCSTR", fun_ucstr, 1, -1, FN_REG}, {"UDEFAULT", fun_udefault, 2, 12, FN_NOPARSE}, {"UFUN", fun_ufun, 1, 11, FN_REG}, - {"U", fun_ufun, 1, 11, FN_REG}, {"PFUN", fun_pfun, 1, 11, FN_REG}, {"ULAMBDA", fun_ufun, 1, 11, FN_REG}, {"ULDEFAULT", fun_udefault, 1, 12, FN_NOPARSE | FN_LOCALIZE}, @@ -726,70 +749,70 @@ {"UNIQUE", fun_unique, 1, 4, FN_REG}, {"UNSETQ", fun_unsetq, 0, 1, FN_REG}, {"UTCTIME", fun_time, 0, 0, FN_REG}, - {"V", fun_v, 1, 1, FN_REG}, + {"V", fun_v, 1, 1, FN_REG | FN_STRIPANSI}, {"VALID", fun_valid, 2, 2, FN_REG}, {"VERSION", fun_version, 0, 0, FN_REG}, - {"VISIBLE", fun_visible, 2, 2, FN_REG}, - {"WHERE", fun_where, 1, 1, FN_REG}, - {"WIDTH", fun_width, 1, 2, FN_REG}, + {"VISIBLE", fun_visible, 2, 2, FN_REG | FN_STRIPANSI}, + {"WHERE", fun_where, 1, 1, FN_REG | FN_STRIPANSI}, + {"WIDTH", fun_width, 1, 2, FN_REG | FN_STRIPANSI}, {"WILDGREP", fun_grep, 3, 3, FN_REG}, {"WILDGREPI", fun_grep, 3, 3, FN_REG}, {"WIPE", fun_wipe, 1, 1, FN_REG}, {"WORDPOS", fun_wordpos, 2, 3, FN_REG}, - {"WORDS", fun_words, 1, 2, FN_REG}, + {"WORDS", fun_words, 1, 2, FN_REG | FN_STRIPANSI}, {"WRAP", fun_wrap, 2, 4, FN_REG}, - {"XATTR", fun_lattr, 3, 4, FN_REG}, - {"XATTRP", fun_lattr, 3, 4, FN_REG}, - {"XCON", fun_dbwalker, 3, 3, FN_REG}, - {"XEXITS", fun_dbwalker, 3, 3, FN_REG}, - {"XMWHO", fun_xwho, 2, 2, FN_REG}, - {"XMWHOID", fun_xwho, 2, 2, FN_REG}, - {"XPLAYERS", fun_dbwalker, 3, 3, FN_REG}, - {"XGET", fun_xget, 2, 2, FN_REG}, - {"XOR", fun_xor, 2, INT_MAX, FN_REG}, - {"XTHINGS", fun_dbwalker, 3, 3, FN_REG}, - {"XVCON", fun_dbwalker, 3, 3, FN_REG}, - {"XVEXITS", fun_dbwalker, 3, 3, FN_REG}, - {"XVPLAYERS", fun_dbwalker, 3, 3, FN_REG}, - {"XVTHINGS", fun_dbwalker, 3, 3, FN_REG}, - {"XWHO", fun_xwho, 2, 2, FN_REG}, - {"XWHOID", fun_xwho, 2, 2, FN_REG}, + {"XATTR", fun_lattr, 3, 4, FN_REG | FN_STRIPANSI}, + {"XATTRP", fun_lattr, 3, 4, FN_REG | FN_STRIPANSI}, + {"XCON", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XEXITS", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XMWHO", fun_xwho, 2, 2, FN_REG | FN_STRIPANSI}, + {"XMWHOID", fun_xwho, 2, 2, FN_REG | FN_STRIPANSI}, + {"XPLAYERS", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XGET", fun_xget, 2, 2, FN_REG | FN_STRIPANSI}, + {"XOR", fun_xor, 2, INT_MAX, FN_REG | FN_STRIPANSI}, + {"XTHINGS", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XVCON", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XVEXITS", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XVPLAYERS", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XVTHINGS", fun_dbwalker, 3, 3, FN_REG | FN_STRIPANSI}, + {"XWHO", fun_xwho, 2, 2, FN_REG | FN_STRIPANSI}, + {"XWHOID", fun_xwho, 2, 2, FN_REG | FN_STRIPANSI}, {"ZEMIT", fun_zemit, 2, -2, FN_REG}, {"ZFUN", fun_zfun, 1, 11, FN_REG}, - {"ZONE", fun_zone, 1, 2, FN_REG}, - {"ZMWHO", fun_zwho, 1, 1, FN_REG}, - {"ZWHO", fun_zwho, 1, 2, FN_REG}, - {"VADD", fun_vadd, 2, 3, FN_REG}, - {"VCROSS", fun_vcross, 2, 3, FN_REG}, - {"VSUB", fun_vsub, 2, 3, FN_REG}, - {"VMAX", fun_vmax, 2, 3, FN_REG}, - {"VMIN", fun_vmin, 2, 3, FN_REG}, - {"VMUL", fun_vmul, 2, 3, FN_REG}, - {"VDOT", fun_vdot, 2, 3, FN_REG}, - {"VMAG", fun_vmag, 1, 2, FN_REG}, - {"VDIM", fun_words, 1, 2, FN_REG}, - {"VUNIT", fun_vunit, 1, 2, FN_REG}, - {"ACOS", fun_acos, 1, 2, FN_REG}, - {"ASIN", fun_asin, 1, 2, FN_REG}, - {"ATAN", fun_atan, 1, 2, FN_REG}, - {"ATAN2", fun_atan2, 2, 3, FN_REG}, - {"CEIL", fun_ceil, 1, 1, FN_REG}, - {"COS", fun_cos, 1, 2, FN_REG}, - {"CTU", fun_ctu, 3, 3, FN_REG}, + {"ZONE", fun_zone, 1, 2, FN_REG | FN_STRIPANSI}, + {"ZMWHO", fun_zwho, 1, 1, FN_REG | FN_STRIPANSI}, + {"ZWHO", fun_zwho, 1, 2, FN_REG | FN_STRIPANSI}, + {"VADD", fun_vadd, 2, 3, FN_REG | FN_STRIPANSI}, + {"VCROSS", fun_vcross, 2, 3, FN_REG | FN_STRIPANSI}, + {"VSUB", fun_vsub, 2, 3, FN_REG | FN_STRIPANSI}, + {"VMAX", fun_vmax, 2, 3, FN_REG | FN_STRIPANSI}, + {"VMIN", fun_vmin, 2, 3, FN_REG | FN_STRIPANSI}, + {"VMUL", fun_vmul, 2, 3, FN_REG | FN_STRIPANSI}, + {"VDOT", fun_vdot, 2, 3, FN_REG | FN_STRIPANSI}, + {"VMAG", fun_vmag, 1, 2, FN_REG | FN_STRIPANSI}, + {"VDIM", fun_words, 1, 2, FN_REG | FN_STRIPANSI}, + {"VUNIT", fun_vunit, 1, 2, FN_REG | FN_STRIPANSI}, + {"ACOS", fun_acos, 1, 2, FN_REG | FN_STRIPANSI}, + {"ASIN", fun_asin, 1, 2, FN_REG | FN_STRIPANSI}, + {"ATAN", fun_atan, 1, 2, FN_REG | FN_STRIPANSI}, + {"ATAN2", fun_atan2, 2, 3, FN_REG | FN_STRIPANSI}, + {"CEIL", fun_ceil, 1, 1, FN_REG | FN_STRIPANSI}, + {"COS", fun_cos, 1, 2, FN_REG | FN_STRIPANSI}, + {"CTU", fun_ctu, 3, 3, FN_REG | FN_STRIPANSI}, {"E", fun_e, 0, 0, FN_REG}, - {"EXP", fun_exp, 1, 1, FN_REG}, - {"FDIV", fun_fdiv, 2, 2, FN_REG}, - {"FMOD", fun_fmod, 2, 2, FN_REG}, - {"FLOOR", fun_floor, 1, 1, FN_REG}, - {"LOG", fun_log, 1, 2, FN_REG}, - {"LN", fun_ln, 1, 1, FN_REG}, + {"EXP", fun_exp, 1, 1, FN_REG | FN_STRIPANSI}, + {"FDIV", fun_fdiv, 2, 2, FN_REG | FN_STRIPANSI}, + {"FMOD", fun_fmod, 2, 2, FN_REG | FN_STRIPANSI}, + {"FLOOR", fun_floor, 1, 1, FN_REG | FN_STRIPANSI}, + {"LOG", fun_log, 1, 2, FN_REG | FN_STRIPANSI}, + {"LN", fun_ln, 1, 1, FN_REG | FN_STRIPANSI}, {"PI", fun_pi, 0, 0, FN_REG}, - {"POWER", fun_power, 2, 2, FN_REG}, - {"ROUND", fun_round, 2, 2, FN_REG}, - {"SIN", fun_sin, 1, 2, FN_REG}, - {"SQRT", fun_sqrt, 1, 1, FN_REG}, - {"STDDEV", fun_stddev, 1, INT_MAX, FN_REG}, - {"TAN", fun_tan, 1, 2, FN_REG}, + {"POWER", fun_power, 2, 2, FN_REG | FN_STRIPANSI}, + {"ROUND", fun_round, 2, 3, FN_REG | FN_STRIPANSI}, + {"SIN", fun_sin, 1, 2, FN_REG | FN_STRIPANSI}, + {"SQRT", fun_sqrt, 1, 1, FN_REG | FN_STRIPANSI}, + {"STDDEV", fun_stddev, 1, INT_MAX, FN_REG | FN_STRIPANSI}, + {"TAN", fun_tan, 1, 2, FN_REG | FN_STRIPANSI}, {"HTML", fun_html, 1, 1, FN_REG}, {"TAG", fun_tag, 1, INT_MAX, FN_REG}, {"ENDTAG", fun_endtag, 1, 1, FN_REG}, @@ -869,8 +892,10 @@ if (nptrs > 0) { safe_str(ptrs[0], buff, &bp); for (i = 1; i < nptrs; i++) { - safe_chr(' ', buff, &bp); - safe_str(ptrs[i], buff, &bp); + if (strcmp(ptrs[i], ptrs[i - 1])) { + safe_chr(' ', buff, &bp); + safe_str(ptrs[i], buff, &bp); + } } } *bp = '\0'; @@ -891,12 +916,31 @@ func_hash_lookup(const char *name) { FUN *f; - f = (FUN *) hashfind(strupper(name), &htab_function); - if (!f || f->flags & FN_OVERRIDE) - f = (FUN *) hashfind(strupper(name), &htab_user_function); + f = builtin_func_hash_lookup(name); + if (!f) + f = user_func_hash_lookup(name); + else if (f->flags & FN_OVERRIDE) + f = user_func_hash_lookup(name); return f; } +static FUN * +any_func_hash_lookup(const char *name) +{ + + FUN *f; + f = builtin_func_hash_lookup(name); + if (!f) + f = user_func_hash_lookup(name); + return f; +} + +static FUN * +user_func_hash_lookup(const char *name) +{ + return (FUN *) hashfind(strupper(name), &htab_user_function); +} + /** Look up a function by name, builtins only. * \param name name of function to look up. * \return pointer to function data, or NULL. @@ -923,6 +967,7 @@ init_func_hashtab(void) { FUNTAB *ftp; + FUNALIAS *fa; hashinit(&htab_function, 512); hash_init(&htab_user_function, 32, delete_function); @@ -930,6 +975,9 @@ for (ftp = flist; ftp->name; ftp++) { function_add(ftp->name, ftp->fun, ftp->minargs, ftp->maxargs, ftp->flags); } + for (fa = faliases; fa->name; fa++) { + alias_function(NOTHING, fa->name, fa->alias); + } local_functions(); } @@ -973,33 +1021,91 @@ return 1; } +/** @function/clone, for creating a copy of a function. + * \param player the enactor + * \param name name of function to clone + * \param clone name of the cloned function + */ +void +do_function_clone(dbref player, const char *function, const char *clone) +{ + FUN *fp; + char *realclone = strupper(clone); + + if (!Wizard(player)) { + notify(player, T("Permission denied.")); + return; + } + + if (any_func_hash_lookup(realclone)) { + notify(player, T("There's already a function with that name.")); + return; + } + + if (!ok_function_name(realclone)) { + notify(player, T("Invalid function name.")); + return; + } + + fp = builtin_func_hash_lookup(function); + if (!fp) { + notify(player, T("That's not a builtin function.")); + return; + } + + function_add(realclone, fp->where.fun, fp->minargs, fp->maxargs, fp->flags); + + notify(player, T("Function cloned.")); +} + /** Add an alias to a function. * This function adds an alias to a function in the hash table. + * \param player dbref of player to notify with errors, or NOTHING to skip * \param function name of function to alias. * \param alias name of the alias to add. * \retval 0 failure (alias exists, or function doesn't, or is a user fun). * \retval 1 success. */ int -alias_function(const char *function, const char *alias) +alias_function(dbref player, const char *function, const char *alias) { FUN *fp; + char realalias[BUFFER_LEN]; + strcpy(realalias, strupper(alias)); /* Make sure the alias doesn't exist already */ - if (func_hash_lookup(alias)) + if (any_func_hash_lookup(realalias)) { + if (player != NOTHING) + notify(player, T("There's already a function with that name.")); return 0; + } + + if (!ok_function_name(realalias)) { + if (player != NOTHING) + notify(player, T("Invalid function name.")); + return 0; + } /* Look up the original */ fp = func_hash_lookup(function); - if (!fp) + if (!fp) { + if (player != NOTHING) + notify(player, T("No such function.")); return 0; + } /* We can't alias @functions. Just use another @function for these */ - if (!(fp->flags & FN_BUILTIN)) + if (!(fp->flags & FN_BUILTIN)) { + if (player != NOTHING) + notify(player, T("You cannot alias @functions.")); return 0; + } + + func_hash_insert(realalias, fp); + + if (player != NOTHING) + notify(player, T("Alias added.")); - function_add(strdup(strupper(alias)), fp->where.fun, - fp->minargs, fp->maxargs, fp->flags); return 1; } @@ -1202,7 +1308,7 @@ if (fp->flags & FN_BUILTIN) safe_format(tbuf1, &bp, "%s %s - ", T("Builtin function"), fp->name); else - safe_format(tbuf1, &bp, "%s #%d/%s - ", T("@function"), + safe_format(tbuf1, &bp, "%s #%d/%s - ", "@function", fp->where.ufun->thing, fp->where.ufun->name); if (fp->flags == flags) safe_str(T("Restrictions unchanged."), tbuf1, &bp); @@ -1324,8 +1430,9 @@ return; } /* make sure the function name length is okay */ - if (strlen(name) >= SBUF_LEN) { - notify(player, T("Function name too long.")); + upcasestr(name); + if (!ok_function_name(name)) { + notify(player, T("Invalid function name.")); return; } /* find the object. For some measure of security, the player must @@ -1351,7 +1458,7 @@ * to replace a built-in function. */ - fp = func_hash_lookup(upcasestr(name)); + fp = func_hash_lookup(name); if (!fp) { if (argv[6] && *argv[6]) { notify(player, T("Expected between 1 and 5 arguments.")); @@ -1393,19 +1500,11 @@ notify(player, T("Function added.")); return; } else { - /* we are modifying an old entry */ - if ((fp->flags & FN_BUILTIN) && !(fp->flags & FN_OVERRIDE)) { + if ((fp->flags & FN_BUILTIN)) { notify(player, T("You cannot change that built-in function.")); return; } - if (fp->flags & FN_BUILTIN) { /* Overriding a built in function */ - fp = slab_malloc(function_slab, NULL); - fp->name = mush_strdup(name, "func_hash.name"); - fp->where.ufun = mush_malloc(sizeof(USERFN_ENTRY), "userfn"); - fp->flags = 0; - hashadd(name, fp, &htab_user_function); - } fp->where.ufun->thing = thing; if (fp->where.ufun->name) mush_free(fp->where.ufun->name, "userfn.name"); @@ -1477,7 +1576,7 @@ return; } - fp = (FUN *) hashfind(strupper(name), &htab_function); + fp = builtin_func_hash_lookup(name); if (!fp) { notify(player, T("That's not a builtin function.")); @@ -1523,6 +1622,12 @@ return; } if (fp->flags & FN_BUILTIN) { + if (strcasecmp(name, fp->name)) { + /* Function alias */ + hashdelete(strupper(name), &htab_function); + notify(player, T("Function alias deleted.")); + return; + } if (!Wizard(player)) { notify(player, T("You can't delete that @function.")); return; @@ -1565,6 +1670,11 @@ return; } + if (strcasecmp(fp->name, strupper(name))) { + notify(player, T("You can't disable aliases.")); + return; + } + if (toggle) { fp->flags &= ~FN_DISABLED; notify(player, T("Enabled.")); @@ -1660,6 +1770,13 @@ first = 0; } + if (fp->flags & FN_STRIPANSI) { + if (first == 0) + safe_strl(", ", 2, tbuf, &tp); + safe_str("Stripansi", tbuf, &tp); + first = 0; + } + if (fp->flags & FN_LOGARGS) { if (first == 0) safe_strl(", ", 2, tbuf, &tp); @@ -1672,7 +1789,6 @@ first = 0; } - if (fp->flags & FN_NOGAGGED) { if (first == 0) safe_strl(", ", 2, tbuf, &tp); Index: src/cmds.c =================================================================== --- src/cmds.c (.../183p13) (revision 469) +++ src/cmds.c (.../184p0) (revision 469) @@ -48,6 +48,8 @@ void do_uptime(dbref player, int mortal); extern int config_set(const char *opt, char *val, int source, int restrictions); +void do_list_allocations(dbref player); + /** Is there a right-hand side of the equal sign? From command.c */ extern int rhs_present; @@ -179,7 +181,7 @@ } if (!config_set(arg_left, arg_right, source, 0) && !config_set(arg_left, arg_right, source, 1)) - notify(player, T("Couldn't set that option")); + notify(player, T("Couldn't set that option.")); else { if (source == 2) { #ifdef HAVE_ED @@ -220,9 +222,9 @@ COMMAND(cmd_clone) { if (SW_ISSET(sw, SWITCH_PRESERVE)) - do_clone(player, arg_left, arg_right, SWITCH_PRESERVE); + do_clone(player, arg_left, args_right[1], SWITCH_PRESERVE, args_right[2]); else - do_clone(player, arg_left, arg_right, SWITCH_NONE); + do_clone(player, arg_left, args_right[1], SWITCH_NONE, args_right[2]); } COMMAND(cmd_dbck) @@ -234,7 +236,6 @@ { char prefix[BUFFER_LEN]; int flags = 0, dbflags = 0; - //int sd = SW_ISSET(sw, SWITCH_SKIPDEFAULTS); *prefix = '\0'; if (SW_ISSET(sw, SWITCH_SKIPDEFAULTS)) flags |= DEC_SKIPDEF; @@ -254,7 +255,7 @@ if (SW_ISSET(sw, SWITCH_DB) || SW_ISSET(sw, SWITCH_TF)) flags |= DEC_DB; if (SW_ISSET(sw, SWITCH_NAME)) - flags = ~DEC_DB; + flags &= ~DEC_DB; if (SW_ISSET(sw, SWITCH_FLAGS)) dbflags |= DEC_FLAG; if (SW_ISSET(sw, SWITCH_ATTRIBS)) @@ -333,7 +334,7 @@ if (SW_ISSET(sw, SWITCH_ROOM)) do_lemit(player, arg_left, - (SW_ISSET(sw, SWITCH_SILENT) * PEMIT_SILENT) | spflags); + (SW_ISSET(sw, SWITCH_SILENT) ? PEMIT_SILENT : 0) | spflags); else do_emit(player, arg_left, spflags); } @@ -417,6 +418,10 @@ SW_ISSET(sw, SWITCH_BUILTIN)); else if (SW_ISSET(sw, SWITCH_RESTORE)) do_function_restore(player, arg_left); + else if (SW_ISSET(sw, SWITCH_ALIAS)) + alias_function(player, arg_left, args_right[1]); + else if (SW_ISSET(sw, SWITCH_CLONE)) + do_function_clone(player, arg_left, args_right[1]); else { int split; char *saved; @@ -474,11 +479,6 @@ { enum hook_type flags; - if (!(Wizard(player) || has_power_by_name(player, "HOOK", NOTYPE))) { - notify(player, T("You need a fishing license to use that hook.")); - return; - } - if (SW_ISSET(sw, SWITCH_AFTER)) flags = HOOK_AFTER; else if (SW_ISSET(sw, SWITCH_BEFORE)) @@ -520,7 +520,7 @@ && Can_Nspemit(player) ? PEMIT_SPOOF : 0); SPOOF(player, cause, sw); do_lemit(player, arg_left, - (SW_ISSET(sw, SWITCH_SILENT) * PEMIT_SILENT) | spflags); + (SW_ISSET(sw, SWITCH_SILENT) ? PEMIT_SILENT : 0) | spflags); } COMMAND(cmd_link) @@ -551,6 +551,8 @@ do_list_flags("FLAG", player, arg_left, lc, T("Flags")); else if (SW_ISSET(sw, SWITCH_POWERS)) do_list_flags("POWER", player, arg_left, lc, T("Powers")); + else if (SW_ISSET(sw, SWITCH_ALLOCATIONS)) + do_list_allocations(player); else do_list(player, arg_left, lc); } @@ -794,7 +796,7 @@ COMMAND(cmd_pcreate) { - const char *newdbref; + char *newdbref; if (args_right[2] && *args_right[2]) newdbref = args_right[2]; @@ -951,17 +953,20 @@ COMMAND(cmd_scan) { + int check = 0; + if (SW_ISSET(sw, SWITCH_ROOM)) - do_scan(player, arg_left, CHECK_NEIGHBORS | CHECK_HERE); - else if (SW_ISSET(sw, SWITCH_SELF)) - do_scan(player, arg_left, CHECK_INVENTORY | CHECK_SELF); - else if (SW_ISSET(sw, SWITCH_ZONE)) - do_scan(player, arg_left, CHECK_ZONE); - else if (SW_ISSET(sw, SWITCH_GLOBALS)) - do_scan(player, arg_left, CHECK_GLOBAL); - else - do_scan(player, arg_left, CHECK_INVENTORY | CHECK_NEIGHBORS | - CHECK_SELF | CHECK_HERE | CHECK_ZONE | CHECK_GLOBAL); + check |= CHECK_NEIGHBORS | CHECK_HERE; + if (SW_ISSET(sw, SWITCH_SELF)) + check |= CHECK_INVENTORY | CHECK_SELF; + if (SW_ISSET(sw, SWITCH_ZONE)) + check |= CHECK_ZONE; + if (SW_ISSET(sw, SWITCH_GLOBALS)) + check |= CHECK_GLOBAL; + if (check == 0) + check = CHECK_INVENTORY | CHECK_NEIGHBORS | + CHECK_SELF | CHECK_HERE | CHECK_ZONE | CHECK_GLOBAL; + do_scan(player, arg_left, check); } COMMAND(cmd_search) @@ -983,10 +988,6 @@ COMMAND(cmd_shutdown) { enum shutdown_type paranoid; - if (!Wizard(player)) { - notify(player, T("You don't have the authority to do that!")); - return; - } paranoid = SW_ISSET(sw, SWITCH_PARANOID) ? SHUT_PARANOID : SHUT_NORMAL; if (SW_ISSET(sw, SWITCH_REBOOT)) do_reboot(player, paranoid == SHUT_PARANOID); @@ -1068,6 +1069,11 @@ (SW_ISSET(sw, SWITCH_INSIDE))); } +COMMAND(cmd_include) +{ + do_include(player, arg_left, args_right); +} + COMMAND(cmd_trigger) { do_trigger(player, arg_left, args_right); Index: src/funmisc.c =================================================================== --- src/funmisc.c (.../183p13) (revision 469) +++ src/funmisc.c (.../184p0) (revision 469) @@ -73,6 +73,12 @@ int ns = (string_prefix(called_as, "NS") && Can_Nspemit(executor)); int flags = PEMIT_LIST | PEMIT_SILENT; dbref saved_orator = orator; + + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, ns ? "@nspemit" : "@pemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -105,6 +111,12 @@ { int ns = (string_prefix(called_as, "NS") && Can_Nspemit(executor)); int flags = ns ? PEMIT_SPOOF : 0; + + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, ns ? "@nsoemit" : "@oemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -119,6 +131,12 @@ { int ns = (string_prefix(called_as, "NS") && Can_Nspemit(executor)); int flags = ns ? PEMIT_SPOOF : 0; + + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, ns ? "@nsemit" : "@emit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -133,6 +151,12 @@ { int ns = (string_prefix(called_as, "NS") && Can_Nspemit(executor)); int flags = ns ? PEMIT_SPOOF : 0; + + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, ns ? "@nsremit" : "@remit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -147,6 +171,12 @@ { int ns = (string_prefix(called_as, "NS") && Can_Nspemit(executor)); int flags = ns ? PEMIT_SPOOF : 0; + + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, ns ? "@nslemit" : "@lemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -161,6 +191,12 @@ { int ns = (string_prefix(called_as, "NS") && Can_Nspemit(executor)); int flags = ns ? PEMIT_SPOOF : 0; + + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, ns ? "@nszemit" : "@zemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -175,6 +211,12 @@ { int ns = (string_prefix(called_as, "NS") && Can_Nspemit(executor)); int flags = PEMIT_LIST | PEMIT_PROMPT; + + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, ns ? "@nspemit" : "@pemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); @@ -225,7 +267,7 @@ const char *p; if ((nargs % 2) != 1) { - safe_str(T("#-1 FUNCTION (letq) EXPECTS AN ODD NUMBER OF ARGUMENTS"), + safe_str(T("#-1 FUNCTION (LETQ) EXPECTS AN ODD NUMBER OF ARGUMENTS"), buff, bp); return; } @@ -313,7 +355,7 @@ for (ptr = args[0]; *ptr; ptr++) { if ((qindex = qreg_indexes[(unsigned char) *ptr]) != -1) { *(global_eval_context.renv[qindex]) = '\0'; - } else if (!isspace(*ptr)) { + } else if (!isspace((int) *ptr)) { safe_str(T("#-1 REGISTER OUT OF RANGE"), buff, bp); } } @@ -635,39 +677,38 @@ soundex(char *str) { static char tbuf1[BUFFER_LEN]; - char *p, *q; + char *p; - q = remove_markup(str, NULL); memset(tbuf1, '\0', 4); p = tbuf1; /* First character is just copied */ - *p = UPCASE(*q); - q++; + *p = UPCASE(*str); + str++; /* Special case for PH->F */ - if ((UPCASE(*p) == 'P') && *q && (UPCASE(*q) == 'H')) { + if ((UPCASE(*p) == 'P') && *str && (UPCASE(*str) == 'H')) { *p = 'F'; - q++; + str++; } p++; /* Convert letters to soundex values, squash duplicates, skip accents and other non-ascii characters */ - while (*q) { - if (!isalpha((unsigned char) *q) || (unsigned char) *q > 127) { - q++; + while (*str) { + if (!isalpha((unsigned char) *str) || (unsigned char) *str > 127) { + str++; continue; } - *p = soundex_val[(unsigned char) *q++]; + *p = soundex_val[(unsigned char) *str++]; if (*p != *(p - 1)) p++; } *p = '\0'; /* Remove zeros */ - p = q = tbuf1; - while (*q) { - if (*q != '0') - *p++ = *q; - q++; + p = str = tbuf1; + while (*str) { + if (*str != '0') + *p++ = *str; + str++; } *p = '\0'; /* Pad/truncate to 4 chars */ @@ -735,12 +776,6 @@ } /* ARGSUSED */ -FUNCTION(fun_atat) -{ - return; -} - -/* ARGSUSED */ FUNCTION(fun_list) { if (!args[0] || !*args[0]) @@ -806,7 +841,7 @@ static void do_whichof(char *args[], int nargs, enum whichof_t flag, char *buff, char **bp, dbref executor, - dbref caller, dbref enactor, PE_Info *pe_info) + dbref caller, dbref enactor, PE_Info *pe_info, int isbool) { int j; char tbuf[BUFFER_LEN], *tp; @@ -834,7 +869,7 @@ process_expression(tbuf, &tp, &sp, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); *tp = '\0'; - if (parse_boolean(tbuf)) { + if ((isbool && parse_boolean(tbuf)) || (!isbool && strlen(tbuf))) { if (!first) { safe_chr(sep, buff, bp); } else @@ -852,7 +887,7 @@ FUNCTION(fun_firstof) { do_whichof(args, nargs, DO_FIRSTOF, buff, bp, executor, - caller, enactor, pe_info); + caller, enactor, pe_info, !!strcasecmp(called_as, "STRFIRSTOF")); } @@ -860,7 +895,7 @@ FUNCTION(fun_allof) { do_whichof(args, nargs, DO_ALLOF, buff, bp, executor, - caller, enactor, pe_info); + caller, enactor, pe_info, !!strcasecmp(called_as, "STRALLOF")); } /* Returns a platform-specific timestamp with platform-dependent resolution. */ @@ -940,6 +975,7 @@ start = get_tsc(); if (process_expression(tbuf, &tp, &sp, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info)) { + *tp = '\0'; break; } *tp = '\0'; Index: src/myrlimit.c =================================================================== --- src/myrlimit.c (.../183p13) (revision 469) +++ src/myrlimit.c (.../184p0) (revision 469) @@ -111,7 +111,7 @@ /* Need to init Windows Sockets to get socket data */ err = WSAStartup(wVersionRequested, &wsadata); if (err) { - printf(T("Error %i on WSAStartup\n"), err); + printf("Error %i on WSAStartup\n", err); exit(1); } iMaxSocketsAllowed = options.max_logins ? (2 * options.max_logins) : 120; Index: src/move.c =================================================================== --- src/move.c (.../183p13) (revision 469) +++ src/move.c (.../184p0) (revision 469) @@ -310,8 +310,10 @@ ok = command_check_byname(player, "HOME"); } else { /* otherwise match on exits - don't use GoodObject here! */ - ok = (match_result(player, direction, TYPE_EXIT, MAT_ENGLISH | MAT_EXIT) != - NOTHING); + ok = + (match_result + (player, direction, TYPE_EXIT, + MAT_ENGLISH | MAT_EXIT | MAT_TYPE) != NOTHING); } return ok; /* Written like this due to overeager compiler */ } @@ -387,15 +389,17 @@ if (type == MOVE_GLOBAL) exit_m = match_result(player, direction, TYPE_EXIT, - MAT_ENGLISH | MAT_EXIT | MAT_GLOBAL | MAT_CHECK_KEYS); + MAT_ENGLISH | MAT_EXIT | MAT_GLOBAL | MAT_CHECK_KEYS | + MAT_TYPE); else if (type == MOVE_ZONE) exit_m = match_result(player, direction, TYPE_EXIT, - MAT_ENGLISH | MAT_EXIT | MAT_REMOTES | MAT_CHECK_KEYS); + MAT_ENGLISH | MAT_EXIT | MAT_REMOTES | MAT_CHECK_KEYS | + MAT_TYPE); else exit_m = match_result(player, direction, TYPE_EXIT, - MAT_ENGLISH | MAT_EXIT | MAT_CHECK_KEYS); + MAT_ENGLISH | MAT_EXIT | MAT_CHECK_KEYS | MAT_TYPE); switch (exit_m) { case NOTHING: /* try to force the object */ @@ -503,7 +507,7 @@ for (i = 1; i < MAX_ARG && what[i]; i++) { if ((thing = noisy_match_result(player, what[i], TYPE_EXIT, - MAT_ENGLISH | MAT_EXIT | MAT_ABSOLUTE)) == NOTHING) + MAT_ENGLISH | MAT_EXIT | MAT_TYPE)) == NOTHING) continue; loc = Home(thing); if (!controls(player, loc)) { @@ -546,7 +550,7 @@ strcpy(objnamebuf, what); objname = objnamebuf; /* take care of possessive get (stealing) */ - box = parse_match_possessor(player, &objname); + box = parse_match_possessor(player, &objname, 0); if (box == NOTHING) { notify(player, T("I don't see that here.")); return; @@ -664,8 +668,8 @@ if ((loc = Location(player)) == NOTHING) return; switch (thing = - match_result(player, name, TYPE_THING, - MAT_POSSESSION | MAT_ABSOLUTE | MAT_ENGLISH)) { + match_result(player, name, TYPE_THING | TYPE_PLAYER, + MAT_POSSESSION | MAT_ENGLISH | MAT_TYPE)) { case NOTHING: notify(player, T("You don't have that!")); return; @@ -678,7 +682,7 @@ notify(player, T("You can't drop that.")); return; } else if (IsExit(thing)) { - notify(player, T("Sorry you can't drop exits.")); + notify(player, T("Sorry, you can't drop exits.")); return; } else if (!eval_lock(player, thing, Drop_Lock)) { notify(player, T("You can't seem to get rid of that.")); @@ -745,7 +749,7 @@ return; thing = noisy_match_result(player, what, TYPE_THING | TYPE_PLAYER, - MAT_NEAR_THINGS | MAT_ENGLISH); + MAT_NEAR_THINGS | MAT_ENGLISH | MAT_TYPE); if (!GoodObject(thing)) return; thing_loc = Location(thing); @@ -851,7 +855,10 @@ { dbref thing; dbref loc; - long match_flags = MAT_CHECK_KEYS | MAT_NEIGHBOR | MAT_ENGLISH | MAT_ABSOLUTE; + long match_flags = MAT_NEIGHBOR | MAT_ENGLISH; + + if (Hasprivs(player)) + match_flags |= MAT_ABSOLUTE; if ((thing = noisy_match_result(player, what, TYPE_THING, match_flags)) == NOTHING) return; @@ -1002,7 +1009,7 @@ /* Ok, are we allowed to follow them? */ if (!eval_lock(player, leader, Follow_Lock)) { fail_lock(player, leader, Follow_Lock, - T("You're not alllowed to follow."), Location(player)); + T("You're not allowed to follow."), Location(player)); return; } /* Ok, looks good */ Index: src/speech.c =================================================================== --- src/speech.c (.../183p13) (revision 469) +++ src/speech.c (.../184p0) (revision 469) @@ -766,9 +766,11 @@ int key; char *tbuf, *tp; char *tbuf2, *tp2; + char *namebuf, *nbp; dbref good[100]; int gcount = 0; char *msgbuf, *mb; + char *nsbuf = NULL, *tosend; char *head; char *hp = NULL; const char **start; @@ -784,6 +786,8 @@ if (!tbuf2) mush_panic("Unable to allocate memory in do_page"); + nbp = namebuf = (char *) mush_malloc(BUFFER_LEN, "page_buff"); + if (*arg1 && has_eq) { /* page to=[msg]. Always evaluate to, maybe evaluate msg */ process_expression(tbuf2, &tp2, &arg1, player, cause, cause, @@ -805,11 +809,13 @@ if (!a || !*((hp = head = safe_atr_value(a)))) { notify(player, T("You haven't paged anyone since connecting.")); mush_free(tbuf2, "page_buff"); + mush_free(namebuf, "page_buff"); return; } if (!message || !*message) { notify_format(player, T("You last paged %s."), head); mush_free(tbuf2, "page_buff"); + mush_free(namebuf, "page_buff"); if (hp) free(hp); return; @@ -887,6 +893,7 @@ notify(player, T("You're trying to page too many people at once.")); mush_free(tbuf, "page_buff"); mush_free(tbuf2, "page_buff"); + mush_free(namebuf, "page_buff"); if (hp) free(hp); return; @@ -904,6 +911,7 @@ /* Well, that was a total waste of time. */ mush_free(tbuf, "page_buff"); mush_free(tbuf2, "page_buff"); + mush_free(namebuf, "page_buff"); if (hp) free(hp); return; @@ -948,7 +956,7 @@ tp = tbuf; tp2 = tbuf2; - /* tbuf2 is used to hold a fancy formatted list of names, + /* namebuf is used to hold a fancy formatted list of names, * with commas and the word 'and' , if needed. */ /* tbuf holds a space-separated list of names for repaging */ @@ -957,23 +965,16 @@ if (i) safe_chr(' ', tbuf, &tp); safe_str_space(Name(good[i]), tbuf, &tp); - safe_itemizer(i + 1, (i == gcount - 1), ",", T("and"), " ", tbuf2, &tp2); - safe_str(Name(good[i]), tbuf2, &tp2); + safe_itemizer(i + 1, (i == gcount - 1), ",", T("and"), " ", namebuf, &nbp); + safe_str(Name(good[i]), namebuf, &nbp); } *tp = '\0'; - *tp2 = '\0'; + *nbp = '\0'; (void) atr_add(player, "LASTPAGED", tbuf, GOD, 0); /* Reset tbuf to use later */ tp = tbuf; - /* Figure out the one success message, and send it */ - if (key == 1) - notify_format(player, T("Long distance to %s: %s%s%s"), tbuf2, - Name(player), gap, message); - else - notify_format(player, T("You paged %s with '%s'"), tbuf2, message); - /* Figure out the 'name' of the player */ if ((alias = shortalias(player)) && *alias && PAGE_ALIASES) current = tprintf("%s (%s)", Name(player), alias); @@ -988,7 +989,7 @@ safe_str(T("From afar"), tbuf, &tp); if (gcount > 1) { safe_str(T(" (to "), tbuf, &tp); - safe_str(tbuf2, tbuf, &tp); + safe_str(namebuf, tbuf, &tp); safe_chr(')', tbuf, &tp); } safe_str(", ", tbuf, &tp); @@ -999,7 +1000,7 @@ safe_str(T(" pages"), tbuf, &tp); if (gcount > 1) { safe_chr(' ', tbuf, &tp); - safe_str(tbuf2, tbuf, &tp); + safe_str(namebuf, tbuf, &tp); } safe_str(": ", tbuf, &tp); } @@ -1014,22 +1015,36 @@ safe_dbref(good[i], tbuf2, &tp2); } *tp2 = '\0'; + /* Figure out the one success message, and send it */ + tosend = mush_malloc(BUFFER_LEN, "page_buff"); + if (key == 1) { + snprintf(tosend, BUFFER_LEN, T("Long distance to %s: %s%s%s"), namebuf, + Name(player), gap, message); + } else { + snprintf(tosend, BUFFER_LEN, T("You paged %s with '%s'"), namebuf, message); + } + if (!vmessageformat(player, "OUTPAGEFORMAT", player, 0, 5, message, + (key == 1) ? (*gap ? ":" : ";") : "\"", + (alias && *alias) ? alias : "", tbuf2, tosend)) { + notify(player, tosend); + } + mush_free(tosend, "page_buff"); + + /* And send the page to everyone. */ for (i = 0; i < gcount; i++) { + tosend = tbuf; if (!IsPlayer(player) && Nospoof(good[i])) { - if (msgbuf == NULL) { - msgbuf = mush_malloc(BUFFER_LEN, "page buffer"); + if (nsbuf == NULL) { + nsbuf = mush_malloc(BUFFER_LEN, "page buffer"); + snprintf(nsbuf, BUFFER_LEN, "[#%d] %s", player, tbuf); } - snprintf(msgbuf, BUFFER_LEN, "[#%d] %s", player, tbuf); - /* Swap tbuf and msgbuf */ - tp = tbuf; - tbuf = msgbuf; - msgbuf = tp; + tosend = nsbuf; } if (!vmessageformat(good[i], "PAGEFORMAT", player, 0, 5, message, (key == 1) ? (*gap ? ":" : ";") : "\"", (alias && *alias) ? alias : "", tbuf2, tbuf)) { /* Player doesn't have Pageformat, or it eval'd to 0 */ - notify(good[i], tbuf); + notify(good[i], tosend); } page_return(player, good[i], "Idle", "IDLE", NULL); @@ -1037,8 +1052,11 @@ mush_free(tbuf, "page_buff"); mush_free(tbuf2, "page_buff"); + mush_free(namebuf, "page_buff"); if (msgbuf) mush_free(msgbuf, "page_buff"); + if (nsbuf) + mush_free(nsbuf, "page_buff"); if (hp) free(hp); } Index: src/chunk.c =================================================================== --- src/chunk.c (.../183p13) (revision 469) +++ src/chunk.c (.../184p0) (revision 469) @@ -245,12 +245,18 @@ #pragma warning( disable : 4761) /* disable warning re conversion */ #endif +#ifdef WIN32 +#define PRIdS "I" +#else +#define PRIdS "t" +#endif + /* A whole bunch of debugging #defines. */ /** Basic debugging stuff - are assertions checked? */ -#undef CHUNK_DEBUG +#define CHUNK_DEBUG /** Paranoid people check for region validity after every operation * that modifies a region. */ -#undef CHUNK_PARANOID +#define CHUNK_PARANOID /** Log all moves and slides during migration. */ #undef DEBUG_CHUNK_MIGRATE /** Log creation of regions. */ @@ -459,76 +465,148 @@ #define MAX_LONG_CHUNK_LEN \ (REGION_CAPACITY - CHUNK_LONG_DATA_OFFSET) -#define LenToFullLen(len) \ - ((len) + \ - (((len) > MAX_SHORT_CHUNK_LEN) \ - ? ((len) > MAX_MEDIUM_CHUNK_LEN) \ - ? CHUNK_LONG_DATA_OFFSET \ - : CHUNK_MEDIUM_DATA_OFFSET \ - : CHUNK_SHORT_DATA_OFFSET)) +static int +LenToFullLen(int len) +{ + return (len + ((len > MAX_SHORT_CHUNK_LEN) + ? (len > MAX_MEDIUM_CHUNK_LEN) + ? CHUNK_LONG_DATA_OFFSET + : CHUNK_MEDIUM_DATA_OFFSET : CHUNK_SHORT_DATA_OFFSET)); +} -#define ChunkPointer(region, offset) \ - (((unsigned char *)(regions[(region)].in_memory)) + (offset)) -#define ChunkReferenceToPointer(ref) \ - ChunkPointer(ChunkReferenceToRegion((ref)), ChunkReferenceToOffset((ref))) +static inline unsigned char *ChunkPointer(uint16_t, uint16_t); /* - * Macros for probing and manipulating chunk headers + * Functions for probing and manipulating chunk headers */ -#define CPLenShort(cptr) \ - ((cptr)[CHUNK_SHORT_LEN_OFFSET] & CHUNK_SHORT_LEN_MASK) -#define CPLenMedium(cptr) \ - ((((cptr)[CHUNK_MEDIUM_LEN_MSB_OFFSET] & CHUNK_MEDIUM_LEN_MSB_MASK) << 8) + \ - ((cptr)[CHUNK_MEDIUM_LEN_LSB_OFFSET] & CHUNK_MEDIUM_LEN_LSB_MASK)) -#define CPLenLong(cptr) \ - ((((cptr)[CHUNK_LONG_LEN_MSB_OFFSET] & CHUNK_LONG_LEN_MSB_MASK) << 8) + \ - ((cptr)[CHUNK_LONG_LEN_LSB_OFFSET] & CHUNK_LONG_LEN_LSB_MASK)) -#define CPLen(cptr) \ - ((*(cptr) & CHUNK_TAG1_MASK) \ - ? (*(cptr) & CHUNK_TAG2_MASK) \ - ? CPLenLong((cptr)) \ - : CPLenMedium((cptr)) \ - : CPLenShort((cptr))) -#define ChunkLen(region, offset) \ - CPLen(ChunkPointer((region), (offset))) -#define CPFullLen(cptr) \ - ((*(cptr) & CHUNK_TAG1_MASK) \ - ? (*(cptr) & CHUNK_TAG2_MASK) \ - ? (CPLenLong((cptr)) + CHUNK_LONG_DATA_OFFSET) \ - : (CPLenMedium((cptr)) + CHUNK_MEDIUM_DATA_OFFSET) \ - : (CPLenShort((cptr)) + CHUNK_SHORT_DATA_OFFSET)) -#define ChunkFullLen(region, offset) \ - CPFullLen(ChunkPointer((region), (offset))) +static inline uint16_t +CPLenShort(const unsigned char *cptr) +{ + return cptr[CHUNK_SHORT_LEN_OFFSET] & CHUNK_SHORT_LEN_MASK; +} -#define ChunkIsFree(region, offset) \ - ((*ChunkPointer((region), (offset)) & CHUNK_FREE_MASK) == CHUNK_FREE) -#define ChunkIsShort(region, offset) \ - ((*ChunkPointer((region), (offset)) & CHUNK_TAG1_MASK) == CHUNK_TAG1_SHORT) -#define ChunkIsMedium(region, offset) \ - ((*ChunkPointer((region), (offset)) & (CHUNK_TAG1_MASK | CHUNK_TAG2_MASK)) \ - == (CHUNK_TAG1_MEDIUM | CHUNK_TAG2_MEDIUM)) -#define ChunkIsLong(region, offset) \ - ((*ChunkPointer((region), (offset)) & (CHUNK_TAG1_MASK | CHUNK_TAG2_MASK)) \ - == (CHUNK_TAG1_LONG | CHUNK_TAG2_LONG)) +static inline uint16_t +CPLenMedium(const unsigned char *cptr) +{ + return ((cptr[CHUNK_MEDIUM_LEN_MSB_OFFSET] & CHUNK_MEDIUM_LEN_MSB_MASK) << 8) + + (cptr[CHUNK_MEDIUM_LEN_LSB_OFFSET] & CHUNK_MEDIUM_LEN_LSB_MASK); +} -#define ChunkDerefs(region, offset) \ - (ChunkPointer((region), (offset))[CHUNK_DEREF_OFFSET]) +static inline uint16_t +CPLenLong(const unsigned char *cptr) +{ + return ((cptr[CHUNK_LONG_LEN_MSB_OFFSET] & CHUNK_LONG_LEN_MSB_MASK) << 8) + + (cptr[CHUNK_LONG_LEN_LSB_OFFSET] & CHUNK_LONG_LEN_LSB_MASK); +} -#define CPDataPtr(cptr) \ - ((*(cptr) & CHUNK_TAG1_MASK) \ - ? (*(cptr) & CHUNK_TAG2_MASK) \ - ? (cptr) + CHUNK_LONG_DATA_OFFSET \ - : (cptr) + CHUNK_MEDIUM_DATA_OFFSET \ - : (cptr) + CHUNK_SHORT_DATA_OFFSET) -#define ChunkDataPtr(region, offset) \ - (CPDataPtr(ChunkPointer(region, offset))) +static uint16_t +CPLen(const unsigned char *cptr) +{ + if (*cptr & CHUNK_TAG1_MASK) { + if (*cptr & CHUNK_TAG2_MASK) + return CPLenLong(cptr); + else + return CPLenMedium(cptr); + } else + return CPLenShort(cptr); +} -#define ChunkNextFree(region, offset) \ - ((ChunkDataPtr(region, offset)[0] << 8) + ChunkDerefs(region, offset)) +static inline uint16_t +ChunkLen(uint16_t region, uint16_t offset) +{ + return CPLen(ChunkPointer(region, offset)); +} + +static uint16_t +CPFullLen(const unsigned char *cptr) +{ + if (*cptr & CHUNK_TAG1_MASK) { + if (*cptr & CHUNK_TAG2_MASK) + return CPLenLong(cptr) + CHUNK_LONG_DATA_OFFSET; + else + return CPLenMedium(cptr) + CHUNK_MEDIUM_DATA_OFFSET; + } else + return CPLenShort(cptr) + CHUNK_SHORT_DATA_OFFSET; +} + +static inline uint16_t +ChunkFullLen(uint16_t region, uint16_t offset) +{ + return CPFullLen(ChunkPointer(region, offset)); +} + +static inline bool +ChunkIsFree(uint16_t region, uint16_t offset) +{ + return (*ChunkPointer(region, offset) & CHUNK_FREE_MASK) == CHUNK_FREE; +} + +static inline bool +ChunkIsShort(uint16_t region, uint16_t offset) +{ + return (*ChunkPointer(region, offset) & CHUNK_TAG1_MASK) == CHUNK_TAG1_SHORT; +} + +static inline bool +ChunkIsMedium(uint16_t region, uint16_t offset) +{ + return (*ChunkPointer(region, offset) & (CHUNK_TAG1_MASK | CHUNK_TAG2_MASK)) + == (CHUNK_TAG1_MEDIUM | CHUNK_TAG2_MEDIUM); +} + +static inline bool +ChunkIsLong(uint16_t region, uint16_t offset) +{ + return (*ChunkPointer(region, offset) & (CHUNK_TAG1_MASK | CHUNK_TAG2_MASK)) + == (CHUNK_TAG1_LONG | CHUNK_TAG2_LONG); +} + + +static inline uint8_t +ChunkDerefs(uint16_t region, uint16_t offset) +{ + return ChunkPointer(region, offset)[CHUNK_DEREF_OFFSET]; +} + +static void +SetChunkDerefs(uint16_t region, uint16_t offset, uint8_t derefs) +{ + ChunkPointer(region, offset)[CHUNK_DEREF_OFFSET] = derefs; +} + +static unsigned char * +CPDataPtr(unsigned char *cptr) +{ + if (*cptr & CHUNK_TAG1_MASK) { + if (*cptr & CHUNK_TAG2_MASK) + return cptr + CHUNK_LONG_DATA_OFFSET; + else + return cptr + CHUNK_MEDIUM_DATA_OFFSET; + } else + return cptr + CHUNK_SHORT_DATA_OFFSET; +} + +static inline unsigned char * +ChunkDataPtr(uint16_t region, uint16_t offset) +{ + return CPDataPtr(ChunkPointer(region, offset)); +} + +static inline uint16_t +ChunkNextFree(uint16_t region, uint16_t offset) +{ + return (ChunkDataPtr(region, offset)[0] << 8) + ChunkDerefs(region, offset); +} /* 0 for no, 1 for yes with room, 2 for exact */ -#define FitsInSpace(size, capacity) \ - (((size) == (capacity)) ? 2 : ((size) <= (capacity) - MIN_REMNANT_LEN)) +static int +FitsInSpace(int size, int capacity) +{ + if (size == capacity) + return 2; + else + return size <= capacity - MIN_REMNANT_LEN; +} /** Region info that gets paged out with its region. * This is at the start of the region; @@ -557,16 +635,6 @@ uint16_t oddballs[NUM_ODDBALLS]; /**< chunk offsets with odd derefs */ } Region; -#define RegionDerefs(region) \ - (regions[(region)].used_count \ - ? (regions[(region)].total_derefs >> \ - (curr_period - regions[(region)].period_last_touched)) / \ - regions[(region)].used_count \ - : 0) -#define RegionDerefsWithChunk(region, derefs) \ - (((regions[(region)].total_derefs >> \ - (curr_period - regions[(region)].period_last_touched)) + derefs) / \ - (regions[(region)].used_count + 1)) /* * Globals @@ -639,12 +707,42 @@ static int noisy_log = 0; #endif + /* * Forward decls */ static void find_oddballs(uint16_t region); /* + * Lookup functions + */ + +static inline unsigned char * +ChunkPointer(uint16_t region, uint16_t offset) +{ + return ((unsigned char *) (regions[region].in_memory)) + offset; +} + +static uint8_t +RegionDerefs(uint16_t region) +{ + if (regions[region].used_count) + return (regions[region].total_derefs >> + (curr_period - regions[region].period_last_touched)) / + regions[region].used_count; + else + return 0; +} + +static uint8_t +RegionDerefsWithChunk(uint16_t region, uint16_t derefs) +{ + return ((regions[region].total_derefs >> + (curr_period - regions[region].period_last_touched)) + derefs) / + (regions[region].used_count + 1); +} + +/* * Debug routines */ /** Add a message to the rolling log. */ @@ -744,7 +842,7 @@ if (ChunkIsFree(region, offset)) { fprintf(fp, "next:%04x\n", ChunkNextFree(region, offset)); } else { - fprintf(fp, "doff:%04x len:%04x ", + fprintf(fp, "doff:%04"PRIdS"x len:%04x ", ChunkDataPtr(region, offset) - (unsigned char *) rhp, ChunkLen(region, offset)); count = ChunkDerefs(region, offset); @@ -1483,7 +1581,7 @@ rp->total_derefs = 0; for (offset = FIRST_CHUNK_OFFSET_IN_REGION; offset < REGION_SIZE; offset += ChunkFullLen(region, offset)) { - ChunkDerefs(region, offset) = 0; + SetChunkDerefs(region, offset, 0); } } else { rp->total_derefs = 0; @@ -1491,7 +1589,7 @@ offset < REGION_SIZE; offset += ChunkFullLen(region, offset)) { if (ChunkIsFree(region, offset)) continue; - ChunkDerefs(region, offset) >>= shift; + SetChunkDerefs(region, offset, ChunkDerefs(region, offset) >> shift); rp->total_derefs += ChunkDerefs(region, offset); } } @@ -2208,7 +2306,7 @@ touch_cache_region(regions[region].in_memory); stat_deref_count++; if (ChunkDerefs(region, offset) < CHUNK_DEREF_MAX) { - ChunkDerefs(region, offset)++; + SetChunkDerefs(region, offset, ChunkDerefs(region, offset) + 1); regions[region].total_derefs++; if (ChunkDerefs(region, offset) == CHUNK_DEREF_MAX) stat_deref_maxxed++; @@ -2453,7 +2551,7 @@ rp->total_derefs = 0; for (offset = FIRST_CHUNK_OFFSET_IN_REGION; offset < REGION_SIZE; offset += ChunkFullLen(region, offset)) { - ChunkDerefs(region, offset) = 0; + SetChunkDerefs(region, offset, 0); } } else { rp->total_derefs = 0; @@ -2461,7 +2559,7 @@ offset < REGION_SIZE; offset += ChunkFullLen(region, offset)) { if (ChunkIsFree(region, offset)) continue; - ChunkDerefs(region, offset) >>= shift; + SetChunkDerefs(region, offset, ChunkDerefs(region, offset) >> shift); rp->total_derefs += ChunkDerefs(region, offset); } } Index: src/bsd.c =================================================================== --- src/bsd.c (.../183p13) (revision 469) +++ src/bsd.c (.../184p0) (revision 469) @@ -521,7 +521,7 @@ /* Need to include library: wsock32.lib for Windows Sockets */ err = WSAStartup(wVersionRequested, &wsadata); if (err) { - printf(T("Error %i on WSAStartup\n"), err); + printf("Error %i on WSAStartup\n", err); exit(1); } } @@ -2619,7 +2619,7 @@ user, d->addr, d->descriptor); return 0; } - player = create_player(user, password, d->addr, d->ip, NOTHING); + player = create_player(user, password, d->addr, d->ip); if (player == NOTHING) { queue_string_eol(d, T(create_fail)); do_rawlog(LT_CONN, @@ -2960,7 +2960,7 @@ break; case 3: safe_format(tbuf, &tbp, T("%s pages: %s"), Name(player), message); - notify_format(player, T("You paged %s with '%s'."), + notify_format(player, T("You paged %s with '%s'"), target != NOTHING ? Name(target) : T("a connecting player"), message); break; @@ -3307,8 +3307,9 @@ notify_noenter(player, pbuff); } - notify_format(player, "%-16s %6s %9s %5s %5s Des Host", T("Player Name"), - T("Loc #"), T("On For"), T("Idle"), T("Cmds")); + notify_format(player, "%-16s %6s %9s %5s %5s %-4s %-s", T("Player Name"), + T("Loc #"), T("On For"), T("Idle"), T("Cmds"), T("Des"), + T("Host")); for (d = descriptor_list; d; d = d->next) { if (d->connected) count++; @@ -4013,7 +4014,7 @@ return; } if ((victim = noisy_match_result(executor, args[0], NOTYPE, - MAT_EVERYTHING)) == 0) { + MAT_EVERYTHING)) == NOTHING) { safe_str(T(e_notvis), buff, bp); return; } @@ -4048,7 +4049,7 @@ return; } if ((victim = noisy_match_result(executor, args[0], NOTYPE, - MAT_EVERYTHING)) == 0) { + MAT_EVERYTHING)) == NOTHING) { safe_str(T(e_notvis), buff, bp); return; } @@ -4156,7 +4157,7 @@ dbref target = lookup_player(name); if (target == NOTHING) { target = match_result(executor, name, TYPE_PLAYER, - MAT_ABSOLUTE | MAT_PLAYER | MAT_ME); + MAT_ABSOLUTE | MAT_PLAYER | MAT_ME | MAT_TYPE); } if (!GoodObject(target) || !Connected(target)) return NULL; @@ -4338,7 +4339,7 @@ } if ((getlock(zone, Zone_Lock) == TRUE_BOOLEXP) || (IsPlayer(zone) && !(has_flag_by_name(zone, "SHARED", TYPE_PLAYER)))) { - safe_str(T("#-1 INVALID ZONE."), buff, bp); + safe_str(T("#-1 INVALID ZONE"), buff, bp); return; } @@ -4635,7 +4636,7 @@ target = lookup_player(args[0]); if (target == NOTHING) { target = match_result(executor, args[0], TYPE_PLAYER, - MAT_ABSOLUTE | MAT_PLAYER | MAT_ME); + MAT_ABSOLUTE | MAT_PLAYER | MAT_ME | MAT_TYPE); } if (target != executor && !Priv_Who(executor)) { /* This should probably be a safe_str */ @@ -4706,7 +4707,7 @@ } else { thing = noisy_match_result(player, victim, TYPE_PLAYER, - MAT_ABSOLUTE | MAT_PLAYER | MAT_PMATCH | MAT_ME); + MAT_ABSOLUTE | MAT_PMATCH | MAT_ME | MAT_TYPE); if (!GoodObject(thing)) { return; } @@ -5164,11 +5165,14 @@ flag_broadcast(0, 0, T ("GAME: Reboot w/o disconnect from game account, please wait.")); + do_rawlog(LT_WIZ, "Reboot w/o disconnect triggered by signal."); } else { flag_broadcast(0, 0, T ("GAME: Reboot w/o disconnect by %s, please wait."), Name(Owner(player))); + do_rawlog(LT_WIZ, "Reboot w/o disconnect triggered by %s(#%d).", + Name(player), player); } if (flag) { globals.paranoid_dump = 1; Index: src/SWITCHES =================================================================== --- src/SWITCHES (.../183p13) (revision 469) +++ src/SWITCHES (.../184p0) (revision 469) @@ -3,6 +3,7 @@ AFTER ALIAS ALL +ALLOCATIONS ANY ATTRIBS BAN @@ -15,6 +16,7 @@ CHOWN CHUNKS CLEAR +CLONE CMD COMMANDS CONN Index: src/funstr.c =================================================================== --- src/funstr.c (.../183p13) (revision 469) +++ src/funstr.c (.../184p0) (revision 469) @@ -240,17 +240,10 @@ /* ARGSUSED */ FUNCTION(fun_alphamax) { - char amax[BUFFER_LEN]; - char *c; int j, m = 0; - size_t len; - c = remove_markup(args[0], &len); - memcpy(amax, c, len); for (j = 1; j < nargs; j++) { - c = remove_markup(args[j], &len); - if (strcoll(amax, c) < 0) { - memcpy(amax, c, len); + if (strcoll(args[m], args[j]) < 0) { m = j; } } @@ -260,17 +253,10 @@ /* ARGSUSED */ FUNCTION(fun_alphamin) { - char amin[BUFFER_LEN]; - char *c; int j, m = 0; - size_t len; - c = remove_markup(args[0], &len); - memcpy(amin, c, len); for (j = 1; j < nargs; j++) { - c = remove_markup(args[j], &len); - if (strcoll(amin, c) > 0) { - memcpy(amin, c, len); + if (strcoll(args[m], args[j]) > 0) { m = j; } } @@ -490,26 +476,15 @@ switch (type) { case 'A': /* Case-sensitive lexicographic */ { - char left[BUFFER_LEN], right[BUFFER_LEN], *l, *r; - size_t llen, rlen; - l = remove_markup(args[0], &llen); - memcpy(left, l, llen); - r = remove_markup(args[1], &rlen); - memcpy(right, r, rlen); - safe_integer(comp_gencomp(executor, left, right, ALPHANUM_LIST), buff, - bp); + safe_integer(comp_gencomp(executor, args[0], args[1], ALPHANUM_LIST), + buff, bp); return; } case 'I': /* Case-insensitive lexicographic */ { - char left[BUFFER_LEN], right[BUFFER_LEN], *l, *r; - size_t llen, rlen; - l = remove_markup(args[0], &llen); - memcpy(left, l, llen); - r = remove_markup(args[1], &rlen); - memcpy(right, r, rlen); - safe_integer(comp_gencomp(executor, left, right, INSENS_ALPHANUM_LIST), - buff, bp); + safe_integer(comp_gencomp + (executor, args[0], args[1], INSENS_ALPHANUM_LIST), buff, + bp); return; } case 'N': /* Integers */ @@ -550,15 +525,11 @@ /* ARGSUSED */ FUNCTION(fun_pos) { - char tbuf[BUFFER_LEN]; char *pos; - size_t len; - pos = remove_markup(args[1], &len); - memcpy(tbuf, pos, len); - pos = strstr(tbuf, remove_markup(args[0], NULL)); + pos = strstr(args[1], args[0]); if (pos) - safe_integer(pos - tbuf + 1, buff, bp); + safe_integer(pos - args[1] + 1, buff, bp); else safe_str("#-1", buff, bp); } @@ -566,17 +537,14 @@ /* ARGSUSED */ FUNCTION(fun_lpos) { - char *pos; char c = ' '; - size_t n, len; - int first = 1; + int first = 1, n; if (args[1][0]) - c = remove_markup(args[1], &len)[0]; + c = args[1][0]; - pos = remove_markup(args[0], &len); - for (n = 0; n < len; n++) - if (pos[n] == c) { + for (n = 0; n < arglens[0]; n++) + if (args[0][n] == c) { if (first) first = 0; else @@ -585,7 +553,6 @@ } } - /* ARGSUSED */ FUNCTION(fun_strmatch) { @@ -1443,22 +1410,20 @@ FUNCTION(fun_ord) { - char *m; - size_t len = 0; - unsigned char what; - if (!args[0] || !args[0][0]) { + int c; + + if (!args[0] || !args[0][0] || arglens[0] != 1) { safe_str(T("#-1 FUNCTION (ORD) EXPECTS ONE CHARACTER"), buff, bp); return; } - m = remove_markup(args[0], &len); - what = (unsigned char) *m; - if (len != 2) /* len includes trailing nul */ - safe_str(T("#-1 FUNCTION (ORD) EXPECTS ONE CHARACTER"), buff, bp); - else if (isprint(what) || what == '\n') - safe_integer(what, buff, bp); - else + c = (unsigned char) args[0][0]; + + if (isprint(c)) { + safe_integer(c, buff, bp); + } else { safe_str(T("#-1 UNPRINTABLE CHARACTER"), buff, bp); + } } FUNCTION(fun_chr) @@ -1609,8 +1574,8 @@ return -1; } -/** The integer in string a will be stored in v, - * if a is not an integer then d (efault) is stored in v. +/** The integer in string a will be stored in v, + * if a is not an integer then d (efault) is stored in v. */ #define initint(a, v, d) \ do \ @@ -1794,7 +1759,7 @@ } } // Fixes align(3,123 1 1 1 1) - if (isspace(*ptr)) { + if (isspace((int) *ptr)) { lastspace = ptr; } skipspace = 0; @@ -1843,7 +1808,7 @@ spacesneeded = cols[i] - len; numspaces = 0; for (j = 0; segment[j]; j++) { - if (isspace(segment[j])) { + if (isspace((int) segment[j])) { numspaces++; } } @@ -1854,7 +1819,7 @@ // Copy the char over. safe_chr(segment[j], line, &lp); // If it's a space, expand it. - if (isspace(segment[j])) { + if (isspace((int) segment[j])) { k = (spacesneeded / numspaces); if (spacecount < (spacesneeded % numspaces)) { k++; Index: src/rob.c =================================================================== --- src/rob.c (.../183p13) (revision 469) +++ src/rob.c (.../184p0) (revision 469) @@ -61,90 +61,83 @@ notify(player, T("You do not have such power.")); return; } - victim = match_result(player, what, TYPE_PLAYER, MAT_NEAR_THINGS); + victim = noisy_match_result(player, what, TYPE_PLAYER, MAT_NEAR_THINGS); - if (player == victim) { + if (victim == NOTHING) + return; + else if (player == victim) { notify(player, T("No suicide allowed.")); return; } if (slay) do_log(LT_WIZ, player, victim, "SLAY"); - switch (victim) { - case NOTHING: - notify(player, T("I don't see that here.")); - break; - case AMBIGUOUS: - notify(player, T("I don't know what you mean!")); - break; - default: - if (Suspect(player)) - flag_broadcast("WIZARD", 0, - T("Broadcast: Suspect %s tried to kill %s(#%d)."), - Name(player), Name(victim), victim); - if (!Mobile(victim)) { - notify(player, T("Sorry, you can only kill players and objects.")); - } else if ((Haven(Location(victim)) && - !Wizard(player)) || - (controls(victim, Location(victim)) && - !controls(player, Location(victim)))) { - notify(player, T("Sorry.")); - } else if (NoKill(victim) && !Wizard(player) && (Owner(victim) != player)) { - notify(player, T("That object cannot be killed.")); - } else { - /* go for it */ - /* set cost */ - /* if this isn't called via slay */ - if (!slay) { - if (cost < KILL_MIN_COST) - cost = KILL_MIN_COST; + if (Suspect(player)) + flag_broadcast("WIZARD", 0, + T("Broadcast: Suspect %s tried to kill %s(#%d)."), + Name(player), Name(victim), victim); + if (!Mobile(victim)) { + notify(player, T("Sorry, you can only kill players and objects.")); + return; + } else if ((Haven(Location(victim)) && + !Wizard(player)) || + (controls(victim, Location(victim)) && + !controls(player, Location(victim)))) { + notify(player, T("Sorry.")); + return; + } else if (NoKill(victim) && !Wizard(player) && (Owner(victim) != player)) { + notify(player, T("That object cannot be killed.")); + return; + } + /* go for it */ + /* set cost */ + /* if this isn't called via slay */ + if (!slay) { + if (cost < KILL_MIN_COST) + cost = KILL_MIN_COST; - /* see if it works */ - if (!payfor(player, cost)) { - notify_format(player, T("You don't have enough %s."), MONIES); - break; - } - } - if (((get_random32(0, KILL_BASE_COST) < (uint32_t) cost) || slay) && - !Wizard(victim)) { - /* you killed him */ - tp = tbuf1; - safe_format(tbuf1, &tp, T("You killed %s!"), Name(victim)); - *tp = '\0'; - tp = tbuf2; - safe_format(tbuf2, &tp, T("killed %s!"), Name(victim)); - *tp = '\0'; - do_halt(victim, "", victim); - did_it(player, victim, "DEATH", tbuf1, "ODEATH", tbuf2, "ADEATH", - NOTHING); + /* see if it works */ + if (!payfor(player, cost)) { + notify_format(player, T("You don't have enough %s."), MONIES); + return; + } + } + if (((get_random32(0, KILL_BASE_COST) < (uint32_t) cost) || slay) && + !Wizard(victim)) { + /* you killed him */ + tp = tbuf1; + safe_format(tbuf1, &tp, T("You killed %s!"), Name(victim)); + *tp = '\0'; + tp = tbuf2; + safe_format(tbuf2, &tp, T("killed %s!"), Name(victim)); + *tp = '\0'; + do_halt(victim, "", victim); + did_it(player, victim, "DEATH", tbuf1, "ODEATH", tbuf2, "ADEATH", NOTHING); - /* notify victim */ - notify_format(victim, T("%s killed you!"), Name(player)); + /* notify victim */ + notify_format(victim, T("%s killed you!"), Name(player)); - /* maybe pay off the bonus */ - /* if we were not called via slay */ - if (!slay) { - int payoff = cost * KILL_BONUS / 100; - if (payoff + Pennies(Owner(victim)) > Max_Pennies(Owner(victim))) - payoff = Max_Pennies(Owner(victim)) - Pennies(Owner(victim)); - if (payoff > 0) { - notify_format(victim, T("Your insurance policy pays %d %s."), - payoff, ((payoff == 1) ? MONEY : MONIES)); - giveto(Owner(victim), payoff); - } else { - notify(victim, T("Your insurance policy has been revoked.")); - } - } - /* send him home */ - safe_tel(victim, HOME, 0); - /* if victim is object also dequeue all commands */ + /* maybe pay off the bonus */ + /* if we were not called via slay */ + if (!slay) { + int payoff = cost * KILL_BONUS / 100; + if (payoff + Pennies(Owner(victim)) > Max_Pennies(Owner(victim))) + payoff = Max_Pennies(Owner(victim)) - Pennies(Owner(victim)); + if (payoff > 0) { + notify_format(victim, T("Your insurance policy pays %d %s."), + payoff, ((payoff == 1) ? MONEY : MONIES)); + giveto(Owner(victim), payoff); } else { - /* notify player and victim only */ - notify(player, T("Your murder attempt failed.")); - notify_format(victim, T("%s tried to kill you!"), Name(player)); + notify(victim, T("Your insurance policy has been revoked.")); } - break; } + /* send him home */ + safe_tel(victim, HOME, 0); + /* if victim is object also dequeue all commands */ + } else { + /* notify player and victim only */ + notify(player, T("Your murder attempt failed.")); + notify_format(victim, T("%s tried to kill you!"), Name(player)); } } @@ -185,8 +178,8 @@ if (from != NULL && *from) { switch (vendor = - match_result(player, from, TYPE_PLAYER, - MAT_NEAR_THINGS | MAT_ENGLISH)) { + match_result(player, from, TYPE_PLAYER | TYPE_THING, + MAT_NEAR_THINGS | MAT_ENGLISH | MAT_TYPE)) { case NOTHING: notify(player, T("Buy from whom?")); return; @@ -396,6 +389,18 @@ notify(player, T("You can't give that away.")); return; } + + if (!eval_lock(player, who, From_Lock)) { + notify_format(player, T("%s doesn't want anything from you."), + Name(who)); + return; + } + + if (!eval_lock(thing, who, Receive_Lock)) { + notify_format(player, T("%s doesn't want that."), Name(who)); + return; + } + if (Mobile(thing) && (EnterOk(who) || controls(player, who))) { moveto(thing, who); Index: src/version.c =================================================================== --- src/version.c (.../183p13) (revision 469) +++ src/version.c (.../184p0) (revision 469) @@ -18,6 +18,7 @@ #include "buildinf.h" #endif #include "confmagic.h" +#include "svninfo.h" void do_version(dbref player); @@ -27,13 +28,36 @@ void do_version(dbref player) { - +#ifdef SVNREVISION + int svnrev = 0; + int scan; +#ifdef SVNDATE + char svndate[75]; +#endif /* SVNDATE */ +#endif /* SVNREVISION */ notify_format(player, T("You are connected to %s"), MUDNAME); - notify_format(player, T("Address: %s"), MUDURL); + if (MUDURL && *MUDURL) + notify_format(player, T("Address: %s"), MUDURL); notify_format(player, T("Last restarted: %s"), show_time(globals.start_time, 0)); notify_format(player, T("PennMUSH version %s patchlevel %s %s"), VERSION, PATCHLEVEL, PATCHDATE); +#ifdef SVNREVISION + scan = sscanf(SVNREVISION, "$" "Rev: %d $", &svnrev); + if (scan == 1) { +#ifdef SVNDATE + scan = sscanf(SVNDATE, "$" "Date: %s $", svndate); + if (scan == 1) + notify_format(player, T("SVN revision: %d [%s]"), svnrev, svndate); + else + notify_format(player, T("SVN revision: %d"), svnrev); +#else + notify_format(player, T("SVN revision: %d"), svnrev); +#endif /* SVNDATE */ + } +#endif /* SVNREVISION */ + + #ifdef WIN32 notify_format(player, T("Build date: %s"), __DATE__); #else @@ -41,4 +65,5 @@ notify_format(player, T("Compiler: %s"), COMPILER); notify_format(player, T("Compilation flags: %s"), CCFLAGS); #endif + } Index: src/sort.c =================================================================== --- src/sort.c (.../183p13) (revision 469) +++ src/sort.c (.../184p0) (revision 469) @@ -291,7 +291,7 @@ case '8': case '9': intval = 0; - while (*s && isdigit(*s)) { + while (*s && isdigit((int) *s)) { intval *= 10; intval += *s - '0'; s++; @@ -299,10 +299,10 @@ safe_format(buff, &bp, "%.20d", intval); if (*s == '.') { s++; - if (isdigit(*s)) { + if (isdigit((int) *s)) { intval = 0; numdigits = 0; - while (*s && isdigit(*s)) { + while (*s && isdigit((int) *s)) { intval *= 10; intval += *s - '0'; numdigits++; @@ -318,10 +318,10 @@ } break; case NUMBER_TOKEN: - if (isdigit(*(s + 1))) { + if (isdigit((int) *(s + 1))) { s++; victim = 0; - while (*s && isdigit(*s)) { + while (*s && isdigit((int) *s)) { victim *= 10; victim += *s - '0'; s++; Index: src/flags.c =================================================================== --- src/flags.c (.../183p13) (revision 469) +++ src/flags.c (.../184p0) (revision 469) @@ -146,6 +146,8 @@ {"GOING_TWICE", '\0', NOTYPE, GOING_TWICE, F_INTERNAL | F_DARK, F_INTERNAL | F_DARK}, {"KEEPALIVE", 'k', TYPE_PLAYER, 0, F_ANY, F_ANY}, + {"NO_LOG", '\0', NOTYPE, 0, F_WIZARD | F_MDARK | F_LOG, F_WIZARD | F_MDARK}, + {"OPEN_OK", '\0', TYPE_ROOM, 0, F_ANY, F_ANY}, {NULL, '\0', 0, 0, 0, 0} }; @@ -470,7 +472,6 @@ { dbref it; object_flag_type p; - COMMAND_INFO *command; int numbytes = (n->flagbits + 7) / 8; for (it = 0; it < db_top; it++) { @@ -484,26 +485,6 @@ /* Zero them out */ memset(p, 0, 1); } - /* We also need to make sure that all the command flagmasks are - * reallocated! - */ - command = (COMMAND_INFO *) ptab_firstentry(&ptab_command); - while (command) { - if (n->tab == &ptab_flag && command->flagmask) { - command->flagmask = - (object_flag_type) realloc(command->flagmask, numbytes); - /* Zero them out */ - p = command->flagmask + numbytes - 1; - memset(p, 0, 1); - } - if (n->tab == &ptab_power && command->powers) { - command->powers = (object_flag_type) realloc(command->powers, numbytes); - /* Zero them out */ - p = command->powers + numbytes - 1; - memset(p, 0, 1); - } - command = (COMMAND_INFO *) ptab_nextentry(&ptab_command); - } } @@ -870,6 +851,9 @@ add_flag("TRACK_MONEY", '\0', TYPE_PLAYER, F_ANY, F_ANY); add_flag("LOUD", '\0', NOTYPE, F_ROYAL, F_ANY); add_flag("HEAR_CONNECT", '\0', TYPE_PLAYER, F_ROYAL, F_ANY); + add_flag("NO_LOG", '\0', NOTYPE, F_WIZARD | F_MDARK | F_LOG, + F_WIZARD | F_MDARK); + add_flag("OPEN_OK", '\0', TYPE_ROOM, F_ANY, F_ANY); if ((f = match_flag("LISTEN_PARENT"))) f->type |= TYPE_PLAYER; if ((f = match_flag("TERSE"))) @@ -2656,7 +2640,47 @@ return buf; } +const char * +flag_list_to_lock_string(object_flag_type flags, object_flag_type powers) +{ + FLAGSPACE *n; + FLAG *f; + int i, first = 1; + char buff[BUFFER_LEN]; + char *bp; + + bp = buff; + if (flags) { + Flagspace_Lookup(n, "FLAG"); + for (i = 0; i < n->flagbits; i++) { + if ((f = n->flags[i]) && has_bit(flags, f->bitpos)) { + if (!first) + safe_chr('|', buff, &bp); + safe_format(buff, &bp, "FLAG^%s", f->name); + first = 0; + } + } + } + + if (powers) { + Flagspace_Lookup(n, "POWER"); + for (i = 0; i < n->flagbits; i++) { + if ((f = n->flags[i]) && has_bit(powers, f->bitpos)) { + if (!first) + safe_chr('|', buff, &bp); + safe_format(buff, &bp, "POWER^%s", f->name); + first = 0; + } + } + } + + if (first) { + return ""; + } + *bp = '\0'; + return tprintf("(%s)", buff); +} /*-------------------------------------------------------------------------- @@ -2680,34 +2704,6 @@ return buf; } -/** Show the flags and powers associated with a command. - * \param flagmask the command's flagmask. - * \param powers the command's power mask. - * \return string output of powers and flags. - */ -const char * -show_command_flags(object_flag_type flagmask, object_flag_type powers) -{ - static char fbuf[BUFFER_LEN]; - char *bp; - bp = fbuf; - if (powers) { - safe_str("Powers : ", fbuf, &bp); - safe_str(bits_to_string("POWER", powers, GOD, NOTHING), fbuf, &bp); - } - - /* do generic flags */ - if (flagmask) { - if (powers) - safe_chr('\n', fbuf, &bp); - safe_str("Flags : ", fbuf, &bp); - safe_str(bits_to_string("FLAG", flagmask, GOD, NOTHING), fbuf, &bp); - } - - *bp = '\0'; - return fbuf; -} - /** Lookup table for good_flag_name */ extern char atr_name_table[UCHAR_MAX + 1]; Index: src/funmath.c =================================================================== --- src/funmath.c (.../183p13) (revision 469) +++ src/funmath.c (.../184p0) (revision 469) @@ -929,6 +929,8 @@ { int places; double n, rounded; + char *sbp; + bool pad = 0; if (!is_number(args[0])) { safe_str(T(e_num), buff, bp); @@ -936,7 +938,7 @@ } else n = parse_number(args[0]); - if (nargs == 2) { + if (nargs >= 2) { if (!is_integer(args[1])) { safe_str(T(e_int), buff, bp); return; @@ -945,6 +947,9 @@ } else places = 0; + if (nargs == 3) + pad = parse_boolean(args[2]); + if (places < 0) places = 0; else if (places > FLOAT_PRECISION) @@ -959,7 +964,22 @@ rounded = fround(n, places); #endif + sbp = *bp; safe_number(rounded, buff, bp); + + if (pad && places > 0) { + char *decimal; + + *(*bp) = '\0'; + decimal = strchr(sbp, '.'); + if (!decimal) { + safe_chr('.', buff, bp); + safe_fill('0', places, buff, bp); + } else { + size_t padding = places - (*bp - decimal) + 1; + safe_fill('0', padding, buff, bp); + } + } } /* ARGSUSED */ @@ -2649,7 +2669,7 @@ NVAL d1, d2, r; if (nptr != 4) { - safe_str(T("#-1 FUNCTION (dist2d) EXPECTS 4 ARGUMENTS"), buff, bp); + safe_str(T("#-1 FUNCTION (DIST2D) EXPECTS 4 ARGUMENTS"), buff, bp); return; } @@ -2676,7 +2696,7 @@ NVAL d1, d2, d3, r; if (nptr != 6) { - safe_str(T("#-1 FUNCTION (dist3d) expects 6 arguments"), buff, bp); + safe_str(T("#-1 FUNCTION (DIST3D) EXPECTS 6 ARGUMENTS"), buff, bp); return; } Index: src/create.c =================================================================== --- src/create.c (.../183p13) (revision 469) +++ src/create.c (.../184p0) (revision 469) @@ -101,7 +101,7 @@ return NOTHING; } if ((loc == NOTHING) || (!IsRoom(loc))) { - notify(player, T("Sorry you can only make exits out of rooms.")); + notify(player, T("Sorry, you can only make exits out of rooms.")); return NOTHING; } if (Going(loc)) { @@ -173,15 +173,38 @@ * \endverbatim * \param player the enactor. * \param direction name of the exit forward. - * \param links 1-based array containing name of destination and optionally name of exit back. + * \param links 1-based array, possibly containing name of destination, name of exit back, + * and room to open initial exit from. */ void do_open(dbref player, const char *direction, char **links) { dbref forward; - forward = do_real_open(player, direction, links[1], NOTHING); + dbref source = NOTHING; + if (links[3]) { + source = + match_result(player, links[3], TYPE_ROOM, + MAT_HERE | MAT_ABSOLUTE | MAT_TYPE); + if (!GoodObject(source)) { + notify(player, T("Open from where?")); + return; + } + } + + forward = do_real_open(player, direction, links[1], source); if (links[2] && GoodObject(forward) && GoodObject(Location(forward))) { - do_real_open(player, links[2], "here", Location(forward)); + char sourcestr[SBUF_LEN]; /* SBUF_LEN is the size used by unparse_dbref */ + if (!GoodObject(source)) { + if (IsRoom(player)) { + source = player; + } else if (IsExit(player)) { + source = Home(player); + } else { + source = Location(player); + } + } + strcpy(sourcestr, unparse_dbref(source)); + do_real_open(player, links[2], sourcestr, Location(forward)); } } @@ -326,7 +349,8 @@ case TYPE_PLAYER: case TYPE_THING: if ((room = - noisy_match_result(player, room_name, NOTYPE, MAT_EVERYTHING)) < 0) { + noisy_match_result(player, room_name, NOTYPE, + MAT_EVERYTHING)) == NOTHING) { notify(player, T("No match.")); return; } @@ -469,22 +493,8 @@ cost = OBJECT_COST; } - if (newdbref && *newdbref) { - /* move newdbref to the start of the free list */ - if (!has_flag_by_name(player, "WIZARD", NOTYPE)) { - notify(player, T("Permission denied.")); - return NOTHING; - } - thing = parse_dbref(newdbref); - if (thing == NOTHING || !GoodObject(thing) || !IsGarbage(thing)) { - notify(player, T("That is not a valid dbref.")); - return NOTHING; - } - - if (!make_first_free(thing)) { - notify(player, T("Unable to create object with that dbref.")); - return NOTHING; - } + if (!make_first_free_wrapper(player, newdbref)) { + return NOTHING; } if (can_pay_fees(player, cost)) { @@ -591,10 +601,11 @@ * \param name the name of the object to clone. * \param newname the name to give the duplicate. * \param preserve if 1, preserve ownership and privileges on duplicate. + * \paran newdbref the (unparsed) dbref to give the object, or NULL to use the next free * \return dbref of the duplicate, or NOTHING. */ dbref -do_clone(dbref player, char *name, char *newname, int preserve) +do_clone(dbref player, char *name, char *newname, int preserve, char *newdbref) { dbref clone, thing; char dbnum[BUFFER_LEN]; @@ -620,10 +631,14 @@ return NOTHING; } if (preserve && !Wizard(player)) { - notify(player, - T("You cannot @CLONE/PRESERVE. Use normal @CLONE instead.")); + notify(player, T("You cannot @CLONE/PRESERVE. Use normal @CLONE instead.")); + return NOTHING; + } + + if (!make_first_free_wrapper(player, newdbref)) { return NOTHING; } + /* make sure owner can afford it */ switch (Typeof(thing)) { case TYPE_THING: @@ -697,7 +712,7 @@ !null_flagmask("POWER", Powers(clone))) notify(player, T - ("Warning: @CLONE/PRESERVE on an exit with WIZ, ROY, @powers, or Warnings.")); + ("Warning: @CLONE/PRESERVE on an object with WIZ, ROY, @powers, or @warnings.")); notify_format(player, T("Cloned: Exit #%d."), clone); local_data_clone(clone, thing); return clone; Index: src/extmail.c =================================================================== --- src/extmail.c (.../183p13) (revision 469) +++ src/extmail.c (.../184p0) (revision 469) @@ -422,22 +422,32 @@ case M_TAG: if (All(ms)) { if (!notified) { - notify_format(player, - T("MAIL: All messages in all folders %s."), - negate ? "untagged" : "tagged"); + if (negate) + notify(player, + T("MAIL: All messages in all folders untagged.")); + else + notify(player, T("MAIL: All messages in all folders tagged.")); notified++; } - } else - notify_format(player, - "MAIL: Msg #%d:%d %s.", (int) Folder(mp), - i[Folder(mp)], negate ? "untagged" : "tagged"); + } else { + if (negate) { + notify_format(player, T("MAIL: Msg #%d:%d untagged"), + (int) Folder(mp), i[Folder(mp)]); + } else { + notify_format(player, T("MAIL: Msg #%d:%d tagged"), + (int) Folder(mp), i[Folder(mp)]); + } + } break; case M_CLEARED: if (All(ms)) { if (!notified) { - notify_format(player, - T("MAIL: All messages in all folders %s."), - negate ? "uncleared" : "cleared"); + if (negate) { + notify(player, + T("MAIL: All messages in all folders uncleared.")); + } else { + notify(player, T("MAIL: All messages in all folders cleared.")); + } notified++; } } else { @@ -807,11 +817,7 @@ /* forwarding to a player */ target = match_result(player, current, TYPE_PLAYER, - MAT_ME | MAT_ABSOLUTE | MAT_PLAYER); - if (!GoodObject(target)) - target = lookup_player(current); - if (!GoodObject(target)) - target = short_page(current); + MAT_ME | MAT_ABSOLUTE | MAT_PMATCH | MAT_TYPE); if (!GoodObject(target) || !IsPlayer(target)) { notify_format(player, T("No such unique player: %s."), current); } else { @@ -1245,10 +1251,8 @@ return; } if (string_prefix("clear", action)) { - target = lookup_player(victim); - if (target == NOTHING) { - target = match_result(player, victim, NOTYPE, MAT_ABSOLUTE); - } + target = + match_result(player, victim, TYPE_PLAYER, MAT_PMATCH | MAT_ABSOLUTE); if (target == NOTHING) { notify_format(player, T("%s: No such player."), victim); return; @@ -1341,20 +1345,14 @@ target = AMBIGUOUS; else target = player; - } else if (*name == NUMBER_TOKEN) { - target = atoi(&name[1]); - if (!GoodObject(target) || !IsPlayer(target)) - target = NOTHING; - } else if (!strcasecmp(name, "me")) { - target = player; } else { - target = lookup_player(name); + target = + match_result(player, name, TYPE_PLAYER, + MAT_TYPE | MAT_ABSOLUTE | MAT_PMATCH | MAT_ME); + if (!GoodObject(target)) + target = NOTHING; } - /* Don't use GoodObject here! */ - if (target == NOTHING) { - target = match_result(player, name, NOTYPE, MAT_ABSOLUTE); - } if ((target == NOTHING) || ((target == AMBIGUOUS) && !Wizard(player))) { notify_format(player, T("%s: No such player."), name); return; @@ -1406,6 +1404,7 @@ ("MAIL: There are %d new msgs in the mail spool, totalling %d characters."), fu, tchars); notify_format(player, + T ("MAIL: There are %d cleared msgs in the mail spool, totalling %d characters."), fc, cchars); return; @@ -1557,7 +1556,8 @@ /* handle the case of wanting to count the number of messages */ if ((player = noisy_match_result(executor, args[0], TYPE_PLAYER, - MAT_ME | MAT_ABSOLUTE | MAT_PLAYER)) == NOTHING) { + MAT_ME | MAT_ABSOLUTE | MAT_PMATCH | MAT_TYPE)) == + NOTHING) { safe_str(T("#-1 NO SUCH PLAYER"), buff, bp); return; } else if (!controls(executor, player)) { @@ -1573,7 +1573,8 @@ case 2: if ((player = noisy_match_result(executor, args[0], TYPE_PLAYER, - MAT_ME | MAT_ABSOLUTE | MAT_PLAYER)) == NOTHING) { + MAT_ME | MAT_ABSOLUTE | MAT_PMATCH | MAT_TYPE)) == + NOTHING) { safe_str(T("#-1 NO SUCH PLAYER"), buff, bp); return; } else if (!controls(executor, player)) { @@ -1620,7 +1621,7 @@ if (nargs == 1) { player = match_result(executor, args[0], TYPE_PLAYER, - MAT_ME | MAT_ABSOLUTE | MAT_PLAYER); + MAT_ME | MAT_ABSOLUTE | MAT_PMATCH | MAT_TYPE); if (GoodObject(player)) { if (!controls(executor, player)) { safe_str(T(e_perm), buff, bp); @@ -1668,7 +1669,8 @@ /* Both a target and a message */ if ((target = noisy_match_result(player, arg1, TYPE_PLAYER, - MAT_ME | MAT_ABSOLUTE | MAT_PLAYER)) == NOTHING) { + MAT_ME | MAT_ABSOLUTE | MAT_PLAYER | MAT_TYPE)) == + NOTHING) { return NULL; } else if (!controls(player, target)) { notify(player, T("Permission denied")); @@ -1743,19 +1745,14 @@ target = AMBIGUOUS; else target = executor; - } else if (*args[0] == NUMBER_TOKEN) { - target = atoi(&args[0][1]); - if (!GoodObject(target) || !IsPlayer(target)) - target = NOTHING; - } else if (!strcasecmp(args[0], "me")) { - target = executor; } else { - target = lookup_player(args[0]); + target = + match_result(executor, args[0], TYPE_PLAYER, + MAT_TYPE | MAT_ABSOLUTE | MAT_PMATCH | MAT_ME); + if (!GoodObject(target)) + target = NOTHING; } - if (!GoodObject(target)) { - target = match_result(executor, args[0], NOTYPE, MAT_ABSOLUTE); - } if (!GoodObject(target) || !IsPlayer(target)) { notify_format(executor, T("%s: No such player."), args[0]); return; Index: src/funlist.c =================================================================== --- src/funlist.c (.../183p13) (revision 469) +++ src/funlist.c (.../184p0) (revision 469) @@ -1550,20 +1550,15 @@ char *s, *r; char sep; int wcount = 1; - char needle[BUFFER_LEN], haystack[BUFFER_LEN]; if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; - strncpy(haystack, remove_markup(args[0], NULL), BUFFER_LEN); - strncpy(needle, remove_markup(args[1], NULL), BUFFER_LEN); - - /* Walk the wordstring, until we find the word we want. */ - s = trim_space_sep(haystack, sep); + s = trim_space_sep(args[0], sep); do { r = split_token(&s, sep); - if (quick_wild(needle, r)) { + if (quick_wild(args[1], r)) { safe_integer(wcount, buff, bp); return; } @@ -2032,7 +2027,6 @@ char *s, *t; char sep; int el; - char needle[BUFFER_LEN], haystack[BUFFER_LEN]; if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; @@ -2042,15 +2036,12 @@ return; } - strncpy(haystack, remove_markup(args[0], NULL), BUFFER_LEN); - strncpy(needle, remove_markup(args[1], NULL), BUFFER_LEN); - - s = trim_space_sep(haystack, sep); + s = trim_space_sep(args[0], sep); el = 1; do { t = split_token(&s, sep); - if (!strcmp(needle, t)) { + if (!strcmp(args[1], t)) { safe_integer(el, buff, bp); return; } @@ -3192,7 +3183,7 @@ reharg.buff = buff; reharg.bp = bp; - atr_iter_get(executor, it, args[1], 0, regrep_helper, (void *) &reharg); + atr_iter_get(executor, it, args[1], 0, 0, regrep_helper, (void *) &reharg); mush_free(reharg.re, "pcre"); if (free_study) mush_free(reharg.study, "pcre.extra"); Index: src/lock.c =================================================================== --- src/lock.c (.../183p13) (revision 469) +++ src/lock.c (.../184p0) (revision 469) @@ -68,6 +68,8 @@ lock_type Leave_Lock = "Leave"; /**< Name of leave lock */ lock_type Drop_Lock = "Drop"; /**< Name of drop lock */ lock_type Give_Lock = "Give"; /**< Name of give lock */ +lock_type From_Lock = "From"; /**< Name of frop lock */ +lock_type Receive_Lock = "Receive"; /**< Name of receive lock */ lock_type Mail_Lock = "Mail"; /**< Name of mail lock */ lock_type Follow_Lock = "Follow"; /**< Name of follow lock */ lock_type Examine_Lock = "Examine"; /**< Name of examine lock */ @@ -79,6 +81,7 @@ lock_type Interact_Lock = "Interact"; /**< Name of interaction lock */ lock_type MailForward_Lock = "MailForward"; /**< Name of mailforward lock */ lock_type Take_Lock = "Take"; /**< Name of take lock */ +lock_type Open_Lock = "Open"; /**< Name of open lock */ /** Table of lock names and permissions */ lock_list lock_types[] = { @@ -96,6 +99,8 @@ {"Leave", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Drop", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Give", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, + {"From", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, + {"Receive", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Mail", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Follow", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Examine", TRUE_BOOLEXP, GOD, LF_PRIVATE | LF_OWNER, NULL}, @@ -107,6 +112,7 @@ {"Interact", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"MailForward", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Take", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, + {"Open", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {NULL, TRUE_BOOLEXP, GOD, 0, NULL} }; @@ -771,7 +777,7 @@ ModTime(thing) = mudtime; } else { notify(player, T("Permission denied.")); - free_boolexp(key); + /* Done by a failed add_lock() // free_boolexp(key); */ } } else free_boolexp(key); Index: src/destroy.c =================================================================== --- src/destroy.c (.../183p13) (revision 469) +++ src/destroy.c (.../184p0) (revision 469) @@ -10,7 +10,7 @@ * The other part is functions for checking the consistency of the * database, and repairing any inconsistencies that are found. The * major function in this group is dbck(). - * + * * * These lengthy comments are by Ralph Melton, December 1995. * @@ -24,7 +24,7 @@ * field pointing to a destroyed object. * 4. No object's zone or parent is a destroyed object. * 5. No object's owner is a destroyed object. - * + * * For the sake of efficiency, we allow indirect locks and other locks to * refer to destroyed objects; boolexp.c had better be able to cope with * these. @@ -47,7 +47,7 @@ * * Note that phases 2 and 3 do not have to happen immediately after Phase 1. * To allow some delay, we set the object GOING, and then process it on - * the check that happens every ten minutes. + * the check that happens every ten minutes. * */ @@ -72,6 +72,7 @@ #include "flags.h" #include "lock.h" #include "confmagic.h" +#include "parse.h" @@ -118,9 +119,9 @@ * * My major criteria are these (with no implied ranking, since I haven't * decided how they balance out): - * + * * 1) It's easy to destroy things you intend to destroy. - * + * * 2) It's easy to correct from destroying things that you don't intend * to destroy. This includes both typos and realizing that you didn't mean * to destroy that. This principle requires two sub-principles: @@ -159,7 +160,7 @@ * example, when rooms are destroyed, any exits leading from those * rooms are also destroyed, and when a player is destroyed, !SAFE * objects they own may also be destroyed. - * + * * To handle this, we do the following: * pre-destroying a room pre-destroys all its exits. * pre-destroying a player pre-destroys all the objects that will be purged @@ -173,28 +174,28 @@ * foo; @undestroy foo' a no-op for all foo: * undestroying a room undestroys all its exits. * undestroying a player undestroys all its GOING things. - * + * * Now, consider this scenario: * Player A owns room #1. Player B owns exit #2, whose source is room #1. * Player B owns thing #3. Player A and player B are both pre-destroyed; * none of the objects are set SAFE. Thing #3 is then undestroyed. - * + * * If you trace through the dependencies, you find that this involves * undestroying all the objects, including both players! Is that what * we want? It seems to me that it would be very surprising in practice. - * + * * To reconcile this, we introduce the following compromise. * undestroying a room undestroys all exits in the room that are not owned * by a GOING player or set SAFE.. * undestroying a player undestroys all objects he owns that are not exits * in a GOING room that he does not own. - * + * * In this way, the propagation of previous scenario would die out at exit * #2, which would stay GOING. Metaphorically, there are two 'votes' for * its destruction: the destruction of room #1, and the destruction of * player B. Undestroying player B by undestroying thing #3 removes one * of the 'votes' for exit #2's destruction, but there would still be - * the vote from room #1. + * the vote from room #1. */ @@ -880,6 +881,32 @@ giveto(Owner(thing), EXIT_COST); } +int +make_first_free_wrapper(dbref player, char *newdbref) +{ + dbref thing; + + if (!newdbref || !*newdbref) + return 1; + + if (!Wizard(player)) { + notify(player, T("Permission denied.")); + return 0; + } + thing = parse_dbref(newdbref); + if (thing == NOTHING || !GoodObject(thing) || !IsGarbage(thing)) { + notify(player, T("That is not a valid dbref.")); + return 0; + } + + if (!make_first_free(thing)) { + notify(player, T("Unable to create object with that dbref.")); + return 0; + } + + return 1; +} + /** If object is in the free list, move it to the very beginning. * \param object dbref of object to move * \return 1 if object is moved successfully, 0 otherwise @@ -941,7 +968,7 @@ return (newobj); } -/** Build the free list with a sledgehammer. +/** Build the free list with a sledgehammer. * Only do this when it's actually necessary. * Since we only do it if things are corrupted, we do not free any memory. * Presumably, this will only waste a reasonable amount of memory, since @@ -1126,7 +1153,7 @@ * an invalid dbref, change its ownership to God. */ if (!IsGarbage(thing)) - atr_iter_get(GOD, thing, "**", 0, attribute_owner_helper, NULL); + atr_iter_get(GOD, thing, "**", 0, 0, attribute_owner_helper, NULL); } } } @@ -1441,7 +1468,7 @@ do_dbck(dbref player) { if (!Wizard(player)) { - notify(player, T("Silly mortal chicks are for kids!")); + notify(player, T("Silly mortal, chicks are for kids!")); return; } notify(player, T("GAME: Performing database consistency check.")); Index: src/match.c =================================================================== --- src/match.c (.../183p13) (revision 469) +++ src/match.c (.../184p0) (revision 469) @@ -16,28 +16,29 @@ * flags = a set of bits indicating what kind of matching to do * * flags are defined in match.h, but here they are for reference: - * MAT_CHECK_KEYS - check locks when matching + * MAT_CHECK_KEYS - prefer objects whose Basic lock 'who' passes * MAT_GLOBAL - match in master room - * MAT_REMOTES - match things not nearby + * MAT_REMOTES - match ZMR exits * MAT_NEAR - match things nearby - * MAT_CONTROL - do a control check after matching + * MAT_CONTROL - only match objects 'who' controls * MAT_ME - match "me" * MAT_HERE - match "here" - * MAT_ABSOLUTE - match "#dbref" - * MAT_PLAYER - match a player's name - * MAT_NEIGHBOR - match something in the same room - * MAT_POSSESSION - match something I'm carrying - * MAT_EXIT - match an exit - * MAT_CARRIED_EXIT - match a carried exit (rare) - * MAT_CONTAINER - match a container I'm in - * MAT_REMOTE_CONTENTS - match the contents of a remote location + * MAT_ABSOLUTE - match any <#dbref> + * MAT_PMATCH - match or * + * MAT_PLAYER - match * + * MAT_NEIGHBOR - match something in 'who's location + * MAT_POSSESSION - match something in 'who's inventory + * MAT_EXIT - match an exit in 'who's location + * MAT_CARRIED_EXIT - match an exit in the room 'who' + * MAT_CONTAINER - match the name of 'who's location + * MAT_REMOTE_CONTENTS - matches the same as MAT_POSSESSION * MAT_ENGLISH - match natural english 'my 2nd flower' * MAT_TYPE - match only objects of the given type(s) * MAT_EXACT - only do full-name matching, no partial names * MAT_EVERYTHING - me,here,absolute,player,neighbor,possession,exit - * MAT_NEARBY - everything near + * MAT_NEARBY - everything,near * MAT_OBJECTS - me,absolute,player,neigbor,possession - * MAT_NEAR_THINGS - objects near + * MAT_NEAR_THINGS - objects,near * MAT_REMOTE - absolute,player,remote_contents,exit,remotes * MAT_LIMITED - absolute,player,neighbor */ @@ -334,7 +335,7 @@ int goodwho = GoodObject(who); char *name, *sname; /* name contains the object name searched for, after english matching tokens are stripped from xname */ #ifdef DEBUG_OBJECT_MATCHING - debugMatchTo = (IsPlayer(who) ? who : 1); + debugMatchTo = (goodwho && IsPlayer(who) ? who : 1); notify(debugMatchTo, "ENTERING MATCH_RESULT"); notify_format(debugMatchTo, "FLAGS: %ld, TYPE: %d", flags, (type == NOTYPE)); #endif @@ -373,7 +374,7 @@ /* dbref match */ match = abs; - if (GoodObject(match) && MATCH_TYPE) { + if (GoodObject(match) && (flags & MAT_ABSOLUTE) && MATCH_TYPE) { if (!(flags & MAT_NEAR) || Long_Fingers(who) || (nearby(who, match) || controls(who, match))) { /* valid dbref match */ @@ -527,7 +528,8 @@ *name += 3; *flags &= ~(MAT_NEIGHBOR | MAT_EXIT | MAT_CONTAINER | MAT_REMOTE_CONTENTS); } - if ((*flags & MAT_EXIT) && (!strncasecmp(*name, "toward ", 7))) { + if ((*flags & (MAT_EXIT | MAT_CARRIED_EXIT)) + && (!strncasecmp(*name, "toward ", 7))) { *name += 7; *flags &= ~(MAT_NEIGHBOR | MAT_POSSESSION | MAT_CONTAINER | MAT_REMOTE_CONTENTS); Index: src/player.c =================================================================== --- src/player.c (.../183p13) (revision 469) +++ src/player.c (.../184p0) (revision 469) @@ -53,8 +53,7 @@ dbref email_register_player (const char *name, const char *email, const char *host, const char *ip); static dbref make_player - (const char *name, const char *password, const char *host, const char *ip, - dbref try_dbref); + (const char *name, const char *password, const char *host, const char *ip); void do_password(dbref player, dbref cause, const char *old, const char *newobj); @@ -195,13 +194,12 @@ * \param password initial password of created player. * \param host host from which creation is attempted. * \param ip ip address from which creation is attempted. - * \param try_dbref NOTHING or dbref of garbage object to use. * \return dbref of created player, NOTHING if bad name, AMBIGUOUS if bad * password. */ dbref create_player(const char *name, const char *password, const char *host, - const char *ip, dbref try_dbref) + const char *ip) { if (!ok_player_name(name, NOTHING, NOTHING)) { do_log(LT_CONN, 0, 0, "Failed creation (bad name) from %s", host); @@ -217,7 +215,7 @@ return NOTHING; } /* else he doesn't already exist, create him */ - return make_player(name, password, host, ip, try_dbref); + return make_player(name, password, host, ip); } /* The HAS_SENDMAIL ifdef is kept here as a hint to metaconfig */ @@ -344,7 +342,7 @@ pclose(fp); reserve_fd(); /* Ok, all's well, make a player */ - player = make_player(name, passwd, host, ip, NOTHING); + player = make_player(name, passwd, host, ip); (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, 0); return player; } @@ -362,18 +360,13 @@ static dbref make_player(const char *name, const char *password, const char *host, - const char *ip, dbref try_dbref) + const char *ip) { dbref player; char temp[SBUF_LEN]; char *flaglist, *flagname; char flagbuff[BUFFER_LEN]; - if (try_dbref != NOTHING && GoodObject(try_dbref) && IsGarbage(try_dbref)) { - if (!make_first_free(try_dbref)) - return NOTHING; - } - player = new_object(); /* initialize everything */ Index: src/look.c =================================================================== --- src/look.c (.../183p13) (revision 469) +++ src/look.c (.../184p0) (revision 469) @@ -421,20 +421,23 @@ { if (all || (mstr && *mstr && !wildcard(mstr))) { if (parent) { - if (!atr_iter_get_parent(player, thing, mstr, mortal, look_helper, NULL) + if (!atr_iter_get_parent + (player, thing, mstr, mortal, 0, look_helper, NULL) && mstr) notify(player, T("No matching attributes.")); } else { - if (!atr_iter_get(player, thing, mstr, mortal, look_helper, NULL) && mstr) + if (!atr_iter_get(player, thing, mstr, mortal, 0, look_helper, NULL) + && mstr) notify(player, T("No matching attributes.")); } } else { if (parent) { if (!atr_iter_get_parent - (player, thing, mstr, mortal, look_helper_veiled, NULL) && mstr) + (player, thing, mstr, mortal, 0, look_helper_veiled, NULL) && mstr) notify(player, T("No matching attributes.")); } else { - if (!atr_iter_get(player, thing, mstr, mortal, look_helper_veiled, NULL) + if (!atr_iter_get + (player, thing, mstr, mortal, 0, look_helper_veiled, NULL) && mstr) notify(player, T("No matching attributes.")); } @@ -652,7 +655,9 @@ look_room(player, loc, LOOK_NORMAL); return; } - thing = match_result(loc, name, NOTYPE, MAT_POSSESSION | MAT_CARRIED_EXIT); + thing = + match_result(loc, name, NOTYPE, + MAT_POSSESSION | MAT_CARRIED_EXIT | MAT_ENGLISH); if (thing == NOTHING) { notify(player, T("I don't see that here.")); return; @@ -673,7 +678,7 @@ boxname = name; strcpy(objnamebuf, name); objname = objnamebuf; - box = parse_match_possessor(player, &objname); + box = parse_match_possessor(player, &objname, 1); if (box == NOTHING) { notify(player, T("I don't see that here.")); return; @@ -681,7 +686,34 @@ notify_format(player, T("I can't tell which %s."), boxname); return; } - thing = match_result(box, objname, NOTYPE, MAT_POSSESSION); + if (IsExit(box)) { + /* Looking through an exit at an object on the other side */ + if (!(Transparented(box) && !Cloudy(box)) + && !(Cloudy(box) && !Transparented(box))) { + notify_format(player, T("You can't see through that.")); + return; + } + box = Location(box); + if (box == HOME) + box = Home(player); /* Resolve exits linked to HOME */ + if (!GoodObject(box)) { + /* Do nothing for exits with no destination, or a variable destination */ + notify(player, T("You can't see through that.")); + return; + } + /* Including MAT_CARRIED_EXIT allows looking at remote exits, but gives slightly strange + results when the remote exit is set transparent, and possibly lets you look at the back + of the door you're looking through, which is odd */ + thing = + match_result(box, objname, NOTYPE, MAT_POSSESSION | MAT_ENGLISH); + if (!GoodObject(thing)) { + notify(player, T("I don't see that here.")); + return; + } + look_simple(player, thing); + return; + } + thing = match_result(box, objname, NOTYPE, MAT_POSSESSION | MAT_ENGLISH); if (thing == NOTHING) { notify(player, T("I don't see that here.")); return; @@ -1457,7 +1489,7 @@ dh.name = name; dh.skipdef = skipdef; /* Comment complaints if none are found */ - if (!atr_iter_get(player, thing, pattern, 0, decompile_helper, &dh)) + if (!atr_iter_get(player, thing, pattern, 0, 0, decompile_helper, &dh)) notify_format(player, T("@@ No attributes match '%s'. @@"), pattern); } @@ -1589,9 +1621,10 @@ return; } + notify_format(player, "%s@@ %s (#%d)", prefix, shortname(thing), thing); switch (Typeof(thing)) { case TYPE_THING: - notify_format(player, "%s@create %s", prefix, object); + notify_format(player, "%s@create %s", prefix, Name(thing)); break; case TYPE_ROOM: notify_format(player, "%s@dig/teleport %s", prefix, Name(thing)); Index: src/game.c =================================================================== --- src/game.c (.../183p13) (revision 469) +++ src/game.c (.../184p0) (revision 469) @@ -287,24 +287,20 @@ notify(player, T("It takes a God to make me panic.")); return; } - if (Wizard(player)) { - flag_broadcast(0, 0, T("GAME: Shutdown by %s"), Name(player)); - do_log(LT_ERR, player, NOTHING, "SHUTDOWN by %s(%s)\n", - Name(player), unparse_dbref(player)); + flag_broadcast(0, 0, T("GAME: Shutdown by %s"), Name(player)); + do_log(LT_ERR, player, NOTHING, "SHUTDOWN by %s(%s)\n", + Name(player), unparse_dbref(player)); - if (flag == SHUT_PANIC) { - mush_panic("@shutdown/panic"); - } else { - if (flag == SHUT_PARANOID) { - globals.paranoid_checkpt = db_top / 5; - if (globals.paranoid_checkpt < 1) - globals.paranoid_checkpt = 1; - globals.paranoid_dump = 1; - } - shutdown_flag = 1; - } + if (flag == SHUT_PANIC) { + mush_panic("@shutdown/panic"); } else { - notify(player, T("Your delusions of grandeur have been duly noted.")); + if (flag == SHUT_PARANOID) { + globals.paranoid_checkpt = db_top / 5; + if (globals.paranoid_checkpt < 1) + globals.paranoid_checkpt = 1; + globals.paranoid_dump = 1; + } + shutdown_flag = 1; } } @@ -436,7 +432,7 @@ do_rawlog(LT_ERR, "PANIC: Attempted to panic because of '%s' while already panicking. Run in circles, scream and shout!", message); - _exit(133); + abort(); } already_panicking = 1; @@ -455,7 +451,7 @@ if (setjmp(db_err)) { /* Dump failed. We're in deep doo-doo */ do_rawlog(LT_ERR, "CANNOT DUMP PANIC DB. OOPS."); - _exit(134); + abort(); } else { if ((f = penn_fopen(panicfile, FOPEN_WRITE)) == NULL) { do_rawlog(LT_ERR, "CANNOT OPEN PANIC FILE, YOU LOSE"); @@ -472,7 +468,7 @@ } else { do_rawlog(LT_ERR, "Skipping panic dump because database isn't loaded."); } - _exit(136); + abort(); } /** Crash gracefully. @@ -1061,6 +1057,7 @@ char *cptr; dbref errdb; dbref check_loc; + COMMAND_INFO *cmd; if (!errdblist) if (!(errdblist = mush_calloc(errdbsize, sizeof(dbref), "errdblist"))) @@ -1126,9 +1123,8 @@ log_activity(LA_CMD, player, msg); if (options.log_commands || Suspect(player)) do_log(LT_CMD, player, NOTHING, "%s", msg); - if Verbose - (player) - raw_notify(Owner(player), tprintf("#%d] %s", player, msg)); + if (Verbose(player)) + raw_notify(Owner(player), tprintf("#%d] %s", player, msg)); } strcpy(unp, command); @@ -1142,16 +1138,24 @@ if (Mobile(player)) { /* if the "player" is an exit or room, no need to do these checks */ /* try matching enter aliases */ - if (check_loc != NOTHING && + if (check_loc != NOTHING && (cmd = command_find("ENTER")) && + !(cmd->type & CMD_T_DISABLED) && (i = alias_list_check(Contents(check_loc), cptr, "EALIAS")) != -1) { - - sprintf(temp, "#%d", i); - do_enter(player, temp); + if (command_check(player, cmd, 1)) { + sprintf(temp, "#%d", i); + run_command(cmd, player, cause, tprintf("ENTER #%d", i), NULL, NULL, + tprintf("ENTER #%d", i), NULL, NULL, temp, NULL, NULL, + NULL); + } goto done; } /* if that didn't work, try matching leave aliases */ - if (!IsRoom(check_loc) && (loc_alias_check(check_loc, cptr, "LALIAS"))) { - do_leave(player); + if (!IsRoom(check_loc) && (cmd = command_find("LEAVE")) + && !(cmd->type & CMD_T_DISABLED) + && (loc_alias_check(check_loc, cptr, "LALIAS"))) { + if (command_check(player, cmd, 1)) + run_command(cmd, player, cause, "LEAVE", NULL, NULL, "LEAVE", NULL, + NULL, NULL, NULL, NULL, NULL); goto done; } } @@ -1178,11 +1182,14 @@ * so we check for exits and commands */ /* check zone master room exits */ - if (remote_exit(player, cptr)) { - if (!Mobile(player)) + if (remote_exit(player, cptr) && (cmd = command_find("GOTO")) + && !(cmd->type & CMD_T_DISABLED)) { + if (!Mobile(player) || !command_check(player, cmd, 1)) { goto done; - else { - do_move(player, cptr, MOVE_ZONE); + } else { + run_command(cmd, player, cause, tprintf("GOTO %s", cptr), NULL, + NULL, tprintf("GOTO %s", cptr), NULL, NULL, cptr, + NULL, NULL, NULL); goto done; } } else @@ -1210,11 +1217,14 @@ /* end of zone stuff */ /* check global exits only if no other commands are matched */ if ((!a) && (check_loc != MASTER_ROOM)) { - if (global_exit(player, cptr)) { - if (!Mobile(player)) + if (global_exit(player, cptr) && (cmd = command_find("GOTO")) + && !(cmd->type & CMD_T_DISABLED)) { + if (!Mobile(player) || !command_check(player, cmd, 1)) goto done; else { - do_move(player, cptr, MOVE_GLOBAL); + run_command(cmd, player, cause, tprintf("GOTO %s", cptr), NULL, + NULL, tprintf("GOTO %s", cptr), NULL, NULL, cptr, NULL, + NULL, NULL); goto done; } } else Index: src/parse.c =================================================================== --- src/parse.c (.../183p13) (revision 469) +++ src/parse.c (.../184p0) (revision 469) @@ -183,8 +183,11 @@ bool parse_boolean(char const *str) { + char clean[BUFFER_LEN]; + int i = 0; + strcpy(clean, remove_markup(str, NULL)); if (TINY_BOOLEANS) { - return (atoi(str) ? 1 : 0); + return (atoi(clean) ? 1 : 0); } else { /* Turn a string into a boolean value. * All negative dbrefs are false, all non-negative dbrefs are true. @@ -192,20 +195,20 @@ * Empty (or space only) strings are false, all other strings are true. */ /* Null strings are false */ - if (!str || !*str) + if (!clean[0]) return 0; /* Negative dbrefs are false - actually anything starting #-, * which will also cover our error messages. */ - if (*str == '#' && *(str + 1) && (*(str + 1) == '-')) + if (*clean == '#' && *(clean + 1) && (*(clean + 1) == '-')) return 0; /* Non-zero numbers are true, zero is false */ - if (is_strict_number(str)) - return parse_number(str) != 0; /* avoid rounding problems */ + if (is_strict_number(clean)) + return parse_number(clean) != 0; /* avoid rounding problems */ /* Skip blanks */ - while (*str == ' ') - str++; + while (clean[i] == ' ') + i++; /* If there's any non-blanks left, it's true */ - return *str != '\0'; /* force to 1 or 0 */ + return clean[i] != '\0'; /* force to 1 or 0 */ } } @@ -1210,6 +1213,7 @@ } break; } else { + char *onearg; char *sargs[10]; char **fargs; int sarglens[10]; @@ -1320,6 +1324,9 @@ ~(PE_COMPRESS_SPACES | PE_EVALUATE | PE_FUNCTION_CHECK); temp_tflags = PT_COMMA | PT_PAREN; nfargs = 0; + onearg = + (char *) mush_malloc(BUFFER_LEN, + "process_expression.single_function_argument"); do { char *argp; if ((fp->maxargs < 0) && ((nfargs + 1) >= -fp->maxargs)) @@ -1345,8 +1352,8 @@ } fargs[nfargs] = (char *) mush_malloc(BUFFER_LEN, "process_expression.function_argument"); - argp = fargs[nfargs]; - if (process_expression(fargs[nfargs], &argp, str, + argp = onearg; + if (process_expression(onearg, &argp, str, executor, caller, enactor, temp_eflags, temp_tflags, pe_info)) { retval = 1; @@ -1354,7 +1361,12 @@ goto free_func_args; } *argp = '\0'; - arglens[nfargs] = argp - fargs[nfargs]; + if (fp->flags & FN_STRIPANSI) { + strcpy(fargs[nfargs], remove_markup(onearg, NULL)); + } else { + strcpy(fargs[nfargs], onearg); + } + arglens[nfargs] = strlen(fargs[nfargs]); (*str)++; nfargs++; } while ((*str)[-1] == ','); @@ -1465,6 +1477,8 @@ mush_free(fargs, "process_expression.function_arglist"); if (arglens != sarglens) mush_free(arglens, "process_expression.function_arglens"); + if (onearg) + mush_free(onearg, "process_expression.single_function_argument"); } break; /* Space compression */ @@ -1481,7 +1495,7 @@ (*str)++; } break; - /* Escape charater */ + /* Escape character */ case '\\': if (!(eflags & PE_EVALUATE)) safe_chr('\\', buff, bp); Index: src/command.c =================================================================== --- src/command.c (.../183p13) (revision 469) +++ src/command.c (.../184p0) (revision 469) @@ -47,9 +47,9 @@ slab *command_slab = NULL; /**< slab for command_info structs */ static const char *command_isattr(char *command); -static int command_check(dbref player, COMMAND_INFO *cmd, int noisy); static int switch_find(COMMAND_INFO *cmd, const char *sw); static void strccat(char *buff, char **bp, const char *from); +static COMMAND_INFO *clone_command(char *original, char *clone); static int has_hook(struct hook_data *hook); extern int global_fun_invocations; /**< Counter for function invocations */ extern int global_fun_recursions; /**< Counter for function recursion */ @@ -70,6 +70,7 @@ int run_hook_override(COMMAND_INFO *cmd, dbref player, const char *commandraw); +const char *CommandLock = "CommandLock"; /** The list of standard commands. Additional commands can be added * at runtime with add_command(). @@ -77,7 +78,7 @@ COMLIST commands[] = { {"@COMMAND", - "ADD ALIAS DELETE EQSPLIT LSARGS RSARGS NOEVAL ON OFF QUIET ENABLE DISABLE RESTRICT NOPARSE", + "ADD ALIAS CLONE DELETE EQSPLIT LSARGS RSARGS NOEVAL ON OFF QUIET ENABLE DISABLE RESTRICT NOPARSE", cmd_command, CMD_T_PLAYER | CMD_T_EQSPLIT, 0, 0}, {"@@", NULL, cmd_null, CMD_T_ANY | CMD_T_NOPARSE, 0, 0}, @@ -118,7 +119,8 @@ {"@CREATE", NULL, cmd_create, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, - {"@CLONE", "PRESERVE", cmd_clone, CMD_T_ANY | CMD_T_NOGAGGED | CMD_T_EQSPLIT, + {"@CLONE", "PRESERVE", cmd_clone, + CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, {"@CLOCK", "JOIN SPEAK MOD SEE HIDE", cmd_clock, @@ -162,7 +164,8 @@ {"@FORCE", "NOEVAL", cmd_force, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, - {"@FUNCTION", "BUILTIN DELETE ENABLE DISABLE PRESERVE RESTORE RESTRICT", + {"@FUNCTION", + "ALIAS BUILTIN CLONE DELETE ENABLE DISABLE PRESERVE RESTORE RESTRICT", cmd_function, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, {"@GREP", "LIST PRINT ILIST IPRINT", cmd_grep, @@ -172,6 +175,8 @@ {"@HOOK", "LIST AFTER BEFORE IGNORE OVERRIDE", cmd_hook, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS, "WIZARD", "hook"}, + {"@INCLUDE", NULL, cmd_include, + CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, 0, 0}, {"@KICK", NULL, cmd_kick, CMD_T_ANY, "WIZARD", 0}, {"@LEMIT", "NOEVAL SILENT SPOOF", cmd_lemit, @@ -180,7 +185,8 @@ 0}, {"@LISTMOTD", NULL, cmd_listmotd, CMD_T_ANY, 0, 0}, - {"@LIST", "LOWERCASE MOTD LOCKS FLAGS FUNCTIONS POWERS COMMANDS ATTRIBS", + {"@LIST", + "LOWERCASE MOTD LOCKS FLAGS FUNCTIONS POWERS COMMANDS ATTRIBS ALLOCATIONS", cmd_list, CMD_T_ANY, 0, 0}, {"@LOCK", NULL, cmd_lock, @@ -481,15 +487,15 @@ * for local hacks - use command_add() instead. * \param name command name. * \param type types of objects that can use the command. - * \param flagmask mask of flags (one is sufficient to use the command). - * \param powers mask of powers (one is sufficient to use the command). + * \param flagstr list of flags names to restrict command + * \param powerstr list of power names to restrict command * \param sw mask of switches the command accepts. * \param func function to call when the command is executed. * \return pointer to a newly allocated COMMAND_INFO structure. */ COMMAND_INFO * make_command(const char *name, int type, - object_flag_type flagmask, object_flag_type powers, + const char *flagstr, const char *powerstr, const char *sw, command_func func) { COMMAND_INFO *cmd; @@ -499,8 +505,6 @@ cmd->restrict_message = NULL; cmd->func = func; cmd->type = type; - cmd->flagmask = flagmask; - cmd->powers = powers; switch (command_state) { case CMD_LOAD_BUILTIN: cmd->sw.names = sw; @@ -534,6 +538,46 @@ cmd->hooks.ignore.attrname = NULL; cmd->hooks.override.obj = NOTHING; cmd->hooks.override.attrname = NULL; + /* Restrict with no flags/powers, then manually parse flagstr and powerstr + separately and add to restriction, to avoid issues with flags/powers with + the same name (HALT flag and Halt power) */ + restrict_command(NOTHING, cmd, ""); + if ((flagstr && *flagstr) || (powerstr && *powerstr)) { + char buff[BUFFER_LEN]; + char *bp, *one, list[BUFFER_LEN], *p; + int first = 1; + bp = buff; + if (cmd->cmdlock != TRUE_BOOLEXP) { + safe_chr('(', buff, &bp); + safe_str(unparse_boolexp(NOTHING, cmd->cmdlock, UB_DBREF), buff, &bp); + safe_str(")&", buff, &bp); + } + if (flagstr && *flagstr) { + strcpy(list, flagstr); + p = trim_space_sep(list, ' '); + while ((one = split_token(&p, ' '))) { + if (!first) + safe_chr('|', buff, &bp); + first = 0; + safe_str("FLAG^", buff, &bp); + safe_str(one, buff, &bp); + } + } + if (powerstr && *powerstr) { + strcpy(list, powerstr); + p = trim_space_sep(list, ' '); + while ((one = split_token(&p, ' '))) { + if (!first) + safe_chr('|', buff, &bp); + first = 0; + safe_str("POWER^", buff, &bp); + safe_str(one, buff, &bp); + } + } + *bp = '\0'; + cmd->cmdlock = parse_boolexp(NOTHING, buff, CommandLock); + + } return cmd; } @@ -551,14 +595,8 @@ command_add(const char *name, int type, const char *flagstr, const char *powerstr, const char *switchstr, command_func func) { - object_flag_type flagmask = NULL, powers = NULL; - - if (flagstr) - flagmask = string_to_bits("FLAG", flagstr); - if (powerstr) - powers = string_to_bits("POWER", powerstr); ptab_insert_one(&ptab_command, name, - make_command(name, type, flagmask, powers, switchstr, func)); + make_command(name, type, flagstr, powerstr, switchstr, func)); return command_find(name); } @@ -609,16 +647,14 @@ * in the table, and if it's there, modify the parameters. * \param name name of command to modify. * \param type new types for command, or -1 to leave unchanged. - * \param flagmask new mask of flags for command, or NULL to leave unchanged. - * \param powers new mask of powers for command, or NULL to leave unchanged. + * \param key new boolexp to restrict command, or NULL to leave unchanged. * \param sw new mask of switches for command, or NULL to leave unchanged. * \param func new function to call, or NULL to leave unchanged. * \return pointer to modified command entry, or NULL. */ COMMAND_INFO * command_modify(const char *name, int type, - object_flag_type flagmask, object_flag_type powers, - switch_mask sw, command_func func) + boolexp key, switch_mask sw, command_func func) { COMMAND_INFO *cmd; cmd = command_find(name); @@ -626,10 +662,8 @@ return NULL; if (type != -1) cmd->type = type; - if (flagmask) - cmd->flagmask = flagmask; - if (powers) - cmd->powers = powers; + if (key) + cmd->cmdlock = key; if (sw) SW_COPY(cmd->sw.mask, sw); if (func) @@ -733,8 +767,7 @@ } ptab_insert(&ptab_command, cmd->name, make_command(cmd->name, cmd->type, - string_to_bits("FLAG", cmd->flagstr), - string_to_bits("POWER", cmd->powers), + cmd->flagstr, cmd->powers, cmd->switches, cmd->func)); } ptab_end_inserts(&ptab_command); @@ -1350,33 +1383,14 @@ command_parse_free_args; return NULL; } else { - char *saveregs[NUMQ]; - init_global_regs(saveregs); /* If we have a hook/ignore that returns false, we don't do the command */ - if (run_hook(player, cause, &cmd->hooks.ignore, saveregs, 1)) { - /* If we have a hook/override, we use that instead */ - if (!run_hook_override(cmd, player, commandraw)) { - /* Otherwise, we do hook/before, the command, and hook/after */ - /* But first, let's see if we had an invalid switch */ - if (*switch_err) { - notify(player, switch_err); - free_global_regs("hook.regs", saveregs); - command_parse_free_args; - return NULL; - } - run_hook(player, cause, &cmd->hooks.before, saveregs, 1); - cmd->func(cmd, player, cause, sw, string, swp, ap, ls, lsa, rs, rsa); - run_hook(player, cause, &cmd->hooks.after, saveregs, 0); - } - /* Either way, we might log */ - if (cmd->type & CMD_T_LOGARGS) - do_log(LT_CMD, player, cause, "%s", string); - else if (cmd->type & CMD_T_LOGNAME) - do_log(LT_CMD, player, cause, "%s", commandraw); + if (run_command + (cmd, player, cause, commandraw, sw, switch_err, string, swp, ap, ls, + lsa, rs, rsa)) { + retval = NULL; } else { retval = commandraw; } - free_global_regs("hook.regs", saveregs); } command_parse_free_args; @@ -1385,6 +1399,53 @@ #undef command_parse_free_args +int +run_command(COMMAND_INFO *cmd, dbref player, dbref cause, const char *commandraw, + switch_mask sw, char switch_err[BUFFER_LEN], const char *string, + char *swp, char *ap, char *ls, char *lsa[MAX_ARG], char *rs, + char *rsa[MAX_ARG]) +{ + + char *saveregs[NUMQ]; + + if (!cmd) + return 0; + + init_global_regs(saveregs); + + if (!run_hook(player, cause, &cmd->hooks.ignore, saveregs, 1)) { + free_global_regs("hook.regs", saveregs); + return 0; + } + + /* If we have a hook/override, we use that instead */ + if (!run_hook_override(cmd, player, commandraw)) { + /* Otherwise, we do hook/before, the command, and hook/after */ + /* But first, let's see if we had an invalid switch */ + if (switch_err && *switch_err) { + notify(player, switch_err); + return 1; + } + run_hook(player, cause, &cmd->hooks.before, saveregs, 1); + cmd->func(cmd, player, cause, sw, string, swp, ap, ls, lsa, rs, rsa); + run_hook(player, cause, &cmd->hooks.after, saveregs, 0); + } + /* Either way, we might log */ + if (cmd->type & CMD_T_LOGARGS) + if (cmd->func == cmd_password || cmd->func == cmd_newpassword + || cmd->func == cmd_pcreate) + do_log(LT_CMD, player, cause, "%s %s=***", cmd->name, + (cmd->func == cmd_password ? "***" : ls)); + else + do_log(LT_CMD, player, cause, "%s", commandraw); + else if (cmd->type & CMD_T_LOGNAME) + do_log(LT_CMD, player, cause, "%s", cmd->name); + + free_global_regs("hook.regs", saveregs); + return 1; + +} + /** Execute the huh_command when no command is matched. * \param player the enactor. * \param cause dbref that caused the command to be executed. @@ -1394,31 +1455,17 @@ generic_command_failure(dbref player, dbref cause, char *string) { COMMAND_INFO *cmd; - char *saveregs[NUMQ]; - if ((cmd = command_find("HUH_COMMAND"))) { - if (!(cmd->type & CMD_T_DISABLED)) { - init_global_regs(saveregs); - if (run_hook(player, cause, &cmd->hooks.ignore, saveregs, 1)) { - /* If we have a hook/override, we use that instead */ - if (!has_hook(&cmd->hooks.override) || - !one_comm_match(cmd->hooks.override.obj, player, - cmd->hooks.override.attrname, "HUH_COMMAND")) { - /* Otherwise, we do hook/before, the command, and hook/after */ - run_hook(player, cause, &cmd->hooks.before, saveregs, 1); - cmd->func(cmd, player, cause, NULL, string, NULL, NULL, string, NULL, - NULL, NULL); - run_hook(player, cause, &cmd->hooks.after, saveregs, 0); - } - /* Either way, we might log */ - if (cmd->type & CMD_T_LOGARGS) - do_log(LT_HUH, player, cause, "%s", string); - } - free_global_regs("hook.regs", saveregs); - } + if ((cmd = command_find("HUH_COMMAND")) && !(cmd->type & CMD_T_DISABLED)) { + run_command(cmd, player, cause, "HUH_COMMAND", NULL, NULL, string, NULL, + NULL, string, NULL, NULL, NULL); } } +#define add_restriction(r, j) \ + if(lockstr != tp && j) \ + safe_chr(j, lockstr, &tp); \ + safe_str(r, lockstr, &tp) /** Add a restriction to a command. * Given a command name and a restriction, apply the restriction to the @@ -1444,18 +1491,23 @@ * \retval 0 failure (unable to find command name). */ int -restrict_command(const char *name, const char *xrestriction) +restrict_command(dbref player, COMMAND_INFO *command, const char *xrestriction) { - COMMAND_INFO *command; struct command_perms_t *c; char *message, *restriction, *rsave; int clear; - FLAG *mask; - FLAG *powers; + FLAG *f; + char lockstr[BUFFER_LEN]; char *tp; + int make_boolexp = 0; + boolexp key; + object_flag_type flags = NULL, powers = NULL; - if (!name || !*name || !xrestriction || !*xrestriction || - !(command = command_find(name))) + if (!command) + return 0; + + /* Allow empty restrictions when we first load commands, as we parse off the CMD_T_* flags */ + if (GoodObject(player) && (!xrestriction || !*xrestriction)) return 0; if (command->restrict_message) { @@ -1470,6 +1522,18 @@ command->restrict_message = mush_strdup(message, "cmd_restrict_message"); } + key = parse_boolexp(player, restriction, CommandLock); + if (key != TRUE_BOOLEXP) { + /* A valid boolexp lock. Hooray. */ + command->cmdlock = key; + mush_free(rsave, "rc.string"); + return 1; + } + + flags = new_flag_bitmask("FLAG"); + powers = new_flag_bitmask("POWER"); + + /* Parse old-style restriction into a boolexp */ while (restriction && *restriction) { if ((tp = strchr(restriction, ' '))) *tp++ = '\0'; @@ -1488,77 +1552,126 @@ /* Gah. I love backwards compatiblity. */ if (!strcasecmp(restriction, "admin")) { - FLAG *roy = match_flag("ROYALTY"); - FLAG *wiz = match_flag("WIZARD"); - if (clear && command->flagmask) { - clear_flag_bitmask(command->flagmask, roy->bitpos); - clear_flag_bitmask(command->flagmask, wiz->bitpos); + make_boolexp = 1; + if (clear) { + f = match_flag("ROYALTY"); + clear_flag_bitmask(flags, f->bitpos); + f = match_flag("WIZARD"); + clear_flag_bitmask(flags, f->bitpos); } else { - if (!command->flagmask) - command->flagmask = new_flag_bitmask("FLAG"); - set_flag_bitmask(command->flagmask, roy->bitpos); - set_flag_bitmask(command->flagmask, wiz->bitpos); + f = match_flag("ROYALTY"); + set_flag_bitmask(flags, f->bitpos); + f = match_flag("WIZARD"); + set_flag_bitmask(flags, f->bitpos); } } else if ((c = ptab_find(&ptab_command_perms, restriction))) { if (clear) command->type &= ~c->type; else command->type |= c->type; - } else if ((mask = match_flag(restriction))) { - if (clear && command->flagmask) - clear_flag_bitmask(command->flagmask, mask->bitpos); + } else if ((f = match_flag(restriction))) { + make_boolexp = 1; + if (clear) + clear_flag_bitmask(flags, f->bitpos); else { - if (!command->flagmask) - command->flagmask = new_flag_bitmask("FLAG"); - set_flag_bitmask(command->flagmask, mask->bitpos); + set_flag_bitmask(flags, f->bitpos); } - } else if ((powers = match_power(restriction))) { - if (clear && command->powers) - clear_flag_bitmask(command->powers, powers->bitpos); + } else if ((f = match_power(restriction))) { + make_boolexp = 1; + if (clear) + clear_flag_bitmask(powers, f->bitpos); else { - if (!command->powers) - command->powers = new_flag_bitmask("POWER"); - set_flag_bitmask(command->powers, powers->bitpos); + set_flag_bitmask(powers, f->bitpos); } } restriction = tp; } + + if ((command-> + type & (CMD_T_GOD | CMD_T_NOGAGGED | CMD_T_NOGUEST | CMD_T_NOFIXED))) + make_boolexp = 1; + else if ((command->type & CMD_T_ANY) != CMD_T_ANY) + make_boolexp = 1; + mush_free(rsave, "rc.string"); + + /* And now format what we have into a lock string, if necessary */ + if (!make_boolexp) { + destroy_flag_bitmask(flags); + destroy_flag_bitmask(powers); + return 1; + } + + tp = lockstr; + safe_str(flag_list_to_lock_string(flags, powers), lockstr, &tp); + if ((command->type & CMD_T_ANY) != CMD_T_ANY) { + char join = '\0'; + + if (lockstr != tp) + safe_chr('&', lockstr, &tp); + safe_chr('(', lockstr, &tp); + + /* Type-locked command */ + if (command->type & CMD_T_PLAYER) { + add_restriction("TYPE^PLAYER", join); + join = '|'; + } + if (command->type & CMD_T_THING) { + add_restriction("TYPE^THING", join); + join = '|'; + } + if (command->type & CMD_T_ROOM) { + add_restriction("TYPE^ROOM", join); + join = '|'; + } + if (command->type & CMD_T_EXIT) { + add_restriction("TYPE^EXIT", join); + join = '|'; + } + if (join) + safe_chr(')', lockstr, &tp); + } + if (command->type & CMD_T_GOD) { + add_restriction(tprintf("=#%d", GOD), '&'); + } + if (command->type & CMD_T_NOGUEST) { + add_restriction("!POWER^GUEST", '&'); + } + if (command->type & CMD_T_NOGAGGED) { + add_restriction("!FLAG^GAGGED", '&'); + } + if (command->type & CMD_T_NOFIXED) { + add_restriction("!FLAG^FIXED", '&'); + } + /* CMD_T_DISABLED and CMD_T_LOG* are checked for in command->types, and not part of the boolexp */ + *tp = '\0'; + + key = parse_boolexp(player, lockstr, CommandLock); + command->cmdlock = key; + + destroy_flag_bitmask(flags); + destroy_flag_bitmask(powers); return 1; } +#undef add_restriction + /** Command stub for \@command/add-ed commands. * This does nothing more than notify the player * with "This command has not been implemented." */ COMMAND(cmd_unimplemented) { - char *saveregs[NUMQ]; if (strcmp(cmd->name, "UNIMPLEMENTED_COMMAND") != 0 && - (cmd = command_find("UNIMPLEMENTED_COMMAND"))) { - if (!(cmd->type & CMD_T_DISABLED)) { - init_global_regs(saveregs); - if (run_hook(player, cause, &cmd->hooks.ignore, saveregs, 1)) { - /* If we have a hook/override, we use that instead */ - if (!has_hook(&cmd->hooks.override) || - !one_comm_match(cmd->hooks.override.obj, player, - cmd->hooks.override.attrname, "HUH_COMMAND")) { - /* Otherwise, we do hook/before, the command, and hook/after */ - run_hook(player, cause, &cmd->hooks.before, saveregs, 1); - - cmd->func(cmd, player, cause, sw, raw, switches, args_raw, - arg_left, args_left, arg_right, args_right); - run_hook(player, cause, &cmd->hooks.after, saveregs, 0); - } - } - free_global_regs("hook.regs", saveregs); - return; - } + (cmd = command_find("UNIMPLEMENTED_COMMAND")) && + !(cmd->type & CMD_T_DISABLED)) { + run_command(cmd, player, cause, "UNIMPLEMENTED_COMMAND", sw, NULL, raw, + NULL, args_raw, arg_left, args_left, arg_right, args_right); + } else { + /* Either we were already in UNIMPLEMENTED_COMMAND, or we couldn't find it */ + notify(player, T("This command has not been implemented.")); } - - /* Either we were already in UNIMPLEMENTED_COMMAND, or we couldn't find it */ - notify(player, T("This command has not been implemented.")); } /** Adds a user-added command @@ -1575,7 +1688,7 @@ { COMMAND_INFO *command; - if (!God(player)) { + if (!Wizard(player)) { notify(player, T("Permission denied.")); return; } @@ -1597,6 +1710,85 @@ } } +void +do_command_clone(dbref player, char *original, char *clone) +{ + COMMAND_INFO *cmd; + + if (!Wizard(player)) { + notify(player, T("Permission denied.")); + return; + } + + upcasestr(original); + upcasestr(clone); + + cmd = command_find(original); + if (!cmd) { + notify(player, T("No such command.")); + return; + } else if (!ok_command_name(clone) || command_find(clone)) { + notify(player, T("Bad command name.")); + return; + } + + clone_command(original, clone); + notify(player, T("Command cloned.")); + +} + +static COMMAND_INFO * +clone_command(char *original, char *clone) +{ + + COMMAND_INFO *c1, *c2; + + upcasestr(original); + upcasestr(clone); + + c1 = command_find(original); + c2 = command_find(clone); + if (!c1 || c2) + return NULL; + + c2 = + make_command(mush_strdup(clone, "command_add"), c1->type, NULL, NULL, + c1->sw.names, c1->func); + c2->sw.mask = c1->sw.mask; + if (c1->restrict_message) + c2->restrict_message = + mush_strdup(c1->restrict_message, "cmd_restrict_message"); + c2->cmdlock = c1->cmdlock; + + if (c1->hooks.before.obj) + c2->hooks.before.obj = c1->hooks.before.obj; + if (c1->hooks.before.attrname) + c2->hooks.before.attrname = + mush_strdup(c1->hooks.before.attrname, "hook.attr"); + + if (c1->hooks.after.obj) + c2->hooks.after.obj = c1->hooks.after.obj; + if (c1->hooks.after.attrname) + c2->hooks.after.attrname = + mush_strdup(c1->hooks.after.attrname, "hook.attr"); + + if (c1->hooks.ignore.obj) + c2->hooks.ignore.obj = c1->hooks.ignore.obj; + if (c1->hooks.ignore.attrname) + c2->hooks.ignore.attrname = + mush_strdup(c1->hooks.ignore.attrname, "hook.attr"); + + if (c1->hooks.override.obj) + c2->hooks.override.obj = c1->hooks.override.obj; + if (c1->hooks.override.attrname) + c2->hooks.override.attrname = + mush_strdup(c1->hooks.override.attrname, "hook.attr"); + + ptab_insert_one(&ptab_command, clone, c2); + return command_find(clone); +} + + /** Deletes a user-added command * \verbatim * This code implements @command/delete, which deletes a @@ -1625,7 +1817,7 @@ } if (strcasecmp(command->name, name) == 0) { /* This is the command, not an alias */ - if (command->func != cmd_unimplemented) { + if (command->func != cmd_unimplemented || !strcmp(command->name, "@SQL")) { notify(player, T ("You can't delete built-in commands. @command/disable instead.")); @@ -1700,6 +1892,10 @@ } return; } + if (SW_ISSET(sw, SWITCH_CLONE)) { + do_command_clone(player, arg_left, arg_right); + return; + } if (SW_ISSET(sw, SWITCH_DELETE)) { do_command_delete(player, arg_left); @@ -1722,7 +1918,7 @@ return; } - if (!restrict_command(arg_left, arg_right)) + if (!restrict_command(player, command, arg_right)) notify(player, T("Restrict attempt failed.")); } @@ -1735,43 +1931,21 @@ notify_format(player, T("Name : %s (%s)"), command->name, (command->type & CMD_T_DISABLED) ? "Disabled" : "Enabled"); - if ((command->type & CMD_T_ANY) == CMD_T_ANY) - safe_strl("Any", 3, buff, &bp); - else { - buff[0] = '\0'; - if (command->type & CMD_T_ROOM) - strccat(buff, &bp, "Room"); - if (command->type & CMD_T_THING) - strccat(buff, &bp, "Thing"); - if (command->type & CMD_T_EXIT) - strccat(buff, &bp, "Exit"); - if (command->type & CMD_T_PLAYER) - strccat(buff, &bp, "Player"); - } - *bp = '\0'; - notify_format(player, T("Types : %s"), buff); buff[0] = '\0'; bp = buff; if (command->type & CMD_T_SWITCHES) strccat(buff, &bp, "Switches"); - if (command->type & CMD_T_NOGAGGED) - strccat(buff, &bp, "Nogagged"); - if (command->type & CMD_T_NOFIXED) - strccat(buff, &bp, "Nofixed"); - if (command->type & CMD_T_NOGUEST) - strccat(buff, &bp, "Noguest"); if (command->type & CMD_T_EQSPLIT) strccat(buff, &bp, "Eqsplit"); - if (command->type & CMD_T_GOD) - strccat(buff, &bp, "God"); if (command->type & CMD_T_LOGARGS) strccat(buff, &bp, "LogArgs"); else if (command->type & CMD_T_LOGNAME) strccat(buff, &bp, "LogName"); *bp = '\0'; - notify_format(player, T("Restrict : %s"), buff); + notify_format(player, T("Flags : %s"), buff); buff[0] = '\0'; - notify(player, show_command_flags(command->flagmask, command->powers)); + notify_format(player, T("Lock : %s"), + unparse_boolexp(player, command->cmdlock, UB_DBREF)); if (command->sw.mask) { bp = buff; for (sw_val = dyn_switch_list; sw_val->name; sw_val++) @@ -1814,7 +1988,6 @@ } } - /** Display a list of defined commands. * This function sends a player the list of commands. * \param player the enactor. @@ -1862,80 +2035,25 @@ /* Check command permissions. Return 1 if player can use command, * 0 otherwise, and maybe be noisy about it. */ -static int +int command_check(dbref player, COMMAND_INFO *cmd, int noisy) { - int ok; - const char *mess = NULL; - int check_flags, check_powers; /* If disabled, return silently */ if (cmd->type & CMD_T_DISABLED) return 0; - if ((cmd->type & CMD_T_NOGAGGED) && Gagged(player)) { - mess = T("You cannot do that while gagged."); - goto send_error; - } - if ((cmd->type & CMD_T_NOFIXED) && Fixed(player)) { - mess = T("You cannot do that while fixed."); - goto send_error; - } - if ((cmd->type & CMD_T_NOGUEST) && Guest(player)) { - mess = T("Guests cannot do that."); - goto send_error; - } - if ((cmd->type & CMD_T_GOD) && (!God(player))) { - mess = T("Only God can do that."); - goto send_error; - } - switch (Typeof(player)) { - case TYPE_ROOM: - ok = (cmd->type & CMD_T_ROOM); - break; - case TYPE_THING: - ok = (cmd->type & CMD_T_THING); - break; - case TYPE_EXIT: - ok = (cmd->type & CMD_T_EXIT); - break; - case TYPE_PLAYER: - ok = (cmd->type & CMD_T_PLAYER); - break; - default: - ok = 0; - } - if (!ok) { - mess = T("Permission denied, command is type-restricted."); - goto send_error; - } - /* A command can specify required flags or powers, and if - * any match, the player is ok to do the command. - */ - ok = 1; - check_flags = cmd->flagmask && !null_flagmask("FLAG", cmd->flagmask); - check_powers = cmd->powers && !null_flagmask("POWER", cmd->powers); - if (check_flags && check_powers) - ok = !!(has_any_flags_by_mask(player, cmd->flagmask) - || has_any_powers_by_mask(player, cmd->powers)); - else if (check_flags) - ok = !!(has_any_flags_by_mask(player, cmd->flagmask)); - else if (check_powers) - ok = !!(has_any_powers_by_mask(player, cmd->powers)); - if (!ok) { - mess = T("Permission denied."); - goto send_error; - } - return ok; - -send_error: - if (noisy) { - if (cmd->restrict_message) - notify(player, cmd->restrict_message); - else if (mess) - notify(player, mess); + if (eval_boolexp(player, cmd->cmdlock, player)) { + return 1; + } else { + if (noisy) { + if (cmd->restrict_message) + notify(player, cmd->restrict_message); + else + notify(player, T("Permission denied.")); + } + return 0; } - return 0; } /** Determine whether a player can use a command. @@ -2176,16 +2294,16 @@ } if (Wizard(player) || has_power_by_name(player, "HOOK", NOTYPE)) { if (GoodObject(cmd->hooks.before.obj)) - notify_format(player, T("@hook/before: #%d/%s"), + notify_format(player, "@hook/before: #%d/%s", cmd->hooks.before.obj, cmd->hooks.before.attrname); if (GoodObject(cmd->hooks.after.obj)) - notify_format(player, T("@hook/after: #%d/%s"), cmd->hooks.after.obj, + notify_format(player, "@hook/after: #%d/%s", cmd->hooks.after.obj, cmd->hooks.after.attrname); if (GoodObject(cmd->hooks.ignore.obj)) - notify_format(player, T("@hook/ignore: #%d/%s"), + notify_format(player, "@hook/ignore: #%d/%s", cmd->hooks.ignore.obj, cmd->hooks.ignore.attrname); if (GoodObject(cmd->hooks.override.obj)) - notify_format(player, T("@hook/override: #%d/%s"), + notify_format(player, "@hook/override: #%d/%s", cmd->hooks.override.obj, cmd->hooks.override.attrname); } } Index: src/log.c =================================================================== --- src/log.c (.../183p13) (revision 469) +++ src/log.c (.../184p0) (revision 469) @@ -278,15 +278,17 @@ do_rawlog(logtype, "RPT: %s", tbuf1); break; case LT_CMD: - strcpy(unp1, quick_unparse(player)); - if (GoodObject(object)) { - strcpy(unp2, quick_unparse(object)); - do_rawlog(logtype, "CMD: %s %s / %s: %s", - (Suspect(player) ? "SUSPECT" : ""), unp1, unp2, tbuf1); - } else { - strcpy(unp2, quick_unparse(Location(player))); - do_rawlog(logtype, "CMD: %s %s in %s: %s", - (Suspect(player) ? "SUSPECT" : ""), unp1, unp2, tbuf1); + if (!has_flag_by_name(player, "NO_LOG", NOTYPE)) { + strcpy(unp1, quick_unparse(player)); + if (GoodObject(object)) { + strcpy(unp2, quick_unparse(object)); + do_rawlog(logtype, "CMD: %s %s / %s: %s", + (Suspect(player) ? "SUSPECT" : ""), unp1, unp2, tbuf1); + } else { + strcpy(unp2, quick_unparse(Location(player))); + do_rawlog(logtype, "CMD: %s %s in %s: %s", + (Suspect(player) ? "SUSPECT" : ""), unp1, unp2, tbuf1); + } } break; case LT_WIZ: Index: src/help.c =================================================================== --- src/help.c (.../183p13) (revision 469) +++ src/help.c (.../184p0) (revision 469) @@ -13,6 +13,7 @@ #include #include #include +#include #include "conf.h" #include "externs.h" #include "command.h" Index: src/pcre.c =================================================================== --- src/pcre.c (.../183p13) (revision 469) +++ src/pcre.c (.../184p0) (revision 469) @@ -43,6 +43,7 @@ support. If you want the full thing, see http://www.pcre.org. */ /* Modified by Alan Schwartz for PennMUSH to change the use of * 'isblank' as a variable (reported to Philip Hazel for pcre 4.5) */ +/* Modified to disable warnings I don't feel like fixing */ #include #include "config.h" @@ -51,6 +52,10 @@ /* Only use if a system libpcre isn't present. */ #ifndef HAVE_PCRE +#ifndef WIN32 +#pragma GCC diagnostic warning "-Wclobbered" +#endif + #include #include #include @@ -1263,6 +1268,7 @@ + pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr); @@ -1358,6 +1364,7 @@ + pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr); @@ -1420,6 +1427,7 @@ + pcre_get_named_substring(const pcre * code, const char *subject, int *ovector, int stringcount, const char *stringname, const char **stringptr); @@ -2304,6 +2312,7 @@ + Index: src/predicat.c =================================================================== --- src/predicat.c (.../183p13) (revision 469) +++ src/predicat.c (.../184p0) (revision 469) @@ -440,7 +440,10 @@ if (!GoodObject(what)) return 0; - if (God(what) && !God(who)) + if (what == who) + return 1; + + if (God(what)) return 0; if (Wizard(who)) @@ -449,7 +452,7 @@ if (Wizard(what) || (Hasprivs(what) && !Hasprivs(who))) return 0; - if (Mistrust(who) && (who != what)) + if (Mistrust(who)) return 0; if (Owns(who, what) && (!Inheritable(what) || Inheritable(who))) @@ -923,7 +926,7 @@ * to find at least one uppercase alpha */ for (p = (unsigned char *) name; p && *p; p++) { - if (isspace(*p)) + if (isspace(*p) || !isprint(*p)) return 0; if (isupper(*p)) cnt++; @@ -1052,10 +1055,11 @@ * to the string to point at the name of the contained object. * \param player the enactor/looker. * \param str a pointer to a string to check for possessive matches. + * \param exits if true, match for exits, as well as things/players * \return matching dbref or NOTHING or AMBIGUOUS. */ dbref -parse_match_possessor(dbref player, char **str) +parse_match_possessor(dbref player, char **str, int exits) { const char *box; /* name of container */ char *obj; /* name of object */ @@ -1076,7 +1080,9 @@ /* we already have a terminating null, so we're okay to just do matches */ return match_result(player, box, NOTYPE, - MAT_NEIGHBOR | MAT_POSSESSION | MAT_ENGLISH); + MAT_NEIGHBOR | MAT_POSSESSION | MAT_ENGLISH | (exits ? + MAT_EXIT : + 0)); } @@ -1194,7 +1200,7 @@ /* our victim object can be anything */ victim = match_result(player, arg1, NOTYPE, MAT_EVERYTHING); - if (victim == NOTHING) { + if (!GoodObject(victim)) { notify(player, T("What was the victim of the verb?")); return; } @@ -1206,7 +1212,7 @@ } actor = match_result(player, argv[1], NOTYPE, MAT_EVERYTHING); - if (actor == NOTHING) { + if (!GoodObject(actor)) { notify(player, T("What do you want to do the verb?")); return; } @@ -1328,7 +1334,7 @@ guh.bp = guh.buff; guh.lookfor = lookfor; guh.sensitive = sensitive; - (void) atr_iter_get(player, thing, pattern, 0, wild ? wildgrep_util_helper + (void) atr_iter_get(player, thing, pattern, 0, 0, wild ? wildgrep_util_helper : grep_util_helper, &guh); *guh.bp = '\0'; return guh.buff; @@ -1426,7 +1432,7 @@ gh.lookfor = lookfor; gh.len = len; gh.insensitive = insensitive; - if (!atr_iter_get(player, thing, pattern, 0, grep_helper, &gh)) + if (!atr_iter_get(player, thing, pattern, 0, 0, grep_helper, &gh)) notify(player, T("No matching attributes.")); } else { tp = grep_util(player, thing, pattern, lookfor, !insensitive, 0); Index: src/switchinc.c =================================================================== --- src/switchinc.c (.../183p13) (revision 469) +++ src/switchinc.c (.../184p0) (revision 469) @@ -5,6 +5,7 @@ {"AFTER", SWITCH_AFTER}, {"ALIAS", SWITCH_ALIAS}, {"ALL", SWITCH_ALL}, + {"ALLOCATIONS", SWITCH_ALLOCATIONS}, {"ANY", SWITCH_ANY}, {"ATTRIBS", SWITCH_ATTRIBS}, {"BAN", SWITCH_BAN}, @@ -17,6 +18,7 @@ {"CHOWN", SWITCH_CHOWN}, {"CHUNKS", SWITCH_CHUNKS}, {"CLEAR", SWITCH_CLEAR}, + {"CLONE", SWITCH_CLONE}, {"CMD", SWITCH_CMD}, {"COMMANDS", SWITCH_COMMANDS}, {"CONN", SWITCH_CONN}, Index: src/set.c =================================================================== --- src/set.c (.../183p13) (revision 469) +++ src/set.c (.../184p0) (revision 469) @@ -50,6 +50,7 @@ char const *pattern, ATTR *atr, void *args); static void copy_attrib_flags(dbref player, dbref target, ATTR *atr, int flags); +extern int rhs_present; /* from command.c */ /** Rename something. * \verbatim @@ -449,7 +450,7 @@ if (Hasprivs(thing)) notify(player, T("Warning: @chzoning a privileged player.")); if (Inherit(thing)) - notify(player, T("Warning: @chzoning an TRUST player.")); + notify(player, T("Warning: @chzoning a TRUST player.")); } } if (noisy) @@ -550,7 +551,7 @@ } af.clrflags = mush_strdup(atrflag_to_string(af.clrf), "af_flag list"); af.setflags = mush_strdup(atrflag_to_string(af.setf), "af_flag list"); - if (!atr_iter_get(player, thing, atrname, 0, af_helper, &af)) + if (!atr_iter_get(player, thing, atrname, 0, 0, af_helper, &af)) notify(player, T("No attribute found to change.")); mush_free(af.clrflags, "af_flag list"); mush_free(af.setflags, "af_flag list"); @@ -917,12 +918,11 @@ return; } *q++ = '\0'; - thing = noisy_match_result(player, tbuf1, NOTYPE, MAT_EVERYTHING); + thing = + noisy_match_result(player, tbuf1, NOTYPE, MAT_EVERYTHING | MAT_CONTROL); - if ((thing == NOTHING) || !controls(player, thing)) { - notify(player, T("Permission denied.")); + if (thing == NOTHING) return; - } if (!argv[1] || !*argv[1]) { notify(player, T("Nothing to do.")); @@ -933,7 +933,7 @@ args.target = target; args.doit = doit; - if (!atr_iter_get(player, thing, q, 0, gedit_helper, &args)) + if (!atr_iter_get(player, thing, q, 0, 0, gedit_helper, &args)) notify(player, T("No matching attributes.")); } @@ -987,6 +987,53 @@ } +/** Include an attribute. + * \verbatim + * This implements @include obj/attribute + * \endverbatim + * \param player the enactor. + * \param object the object/attribute pair. + * \param argv array of arguments. (not yet used) + */ +void +do_include(dbref player, char *object, char **argv) +{ + dbref thing; + int a; + char *s; + char tbuf1[BUFFER_LEN]; + + strcpy(tbuf1, object); + for (s = tbuf1; *s && (*s != '/'); s++) ; + if (!*s) { + notify(player, T("I need to know what attribute to include.")); + return; + } + *s++ = '\0'; + + thing = noisy_match_result(player, tbuf1, NOTYPE, MAT_EVERYTHING); + + if (thing == NOTHING) + return; + + if (God(thing) && !God(player)) { + notify(player, T("You can't include God!")); + return; + } + /* include modifies the stack, but only if arguments are given */ + for (a = 0; a < 10; a++) { + if (rhs_present && argv[a + 1]) + global_eval_context.include_wenv[a] = + mush_strdup(argv[a + 1], "include_wenv"); + else + global_eval_context.include_wenv[a] = NULL; + } + if (!inplace_queue_attribute(thing, upcasestr(s), player, rhs_present)) { + notify(player, T("No such attribute.")); + } + +} + /** The use command. * It's here for lack of a better place. * \param player the enactor. @@ -1028,7 +1075,8 @@ dbref check; int i; - if ((thing = noisy_match_result(player, name, NOTYPE, MAT_NEARBY)) == NOTHING) + if ((thing = + noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING)) == NOTHING) return; if (!parent_name || !*parent_name || !strcasecmp(parent_name, "none")) @@ -1146,7 +1194,7 @@ return; } - wiped = atr_iter_get(player, thing, pattern, 0, wipe_helper, NULL); + wiped = atr_iter_get(player, thing, pattern, 0, 0, wipe_helper, NULL); switch (wiped) { case 0: notify(player, T("No attributes wiped.")); Index: src/cque.c =================================================================== --- src/cque.c (.../183p13) (revision 469) +++ src/cque.c (.../184p0) (revision 469) @@ -90,6 +90,7 @@ static void do_raw_restart(dbref victim); static int waitable_attr(dbref thing, const char *atr); static void shutdown_a_queue(BQUE **head, BQUE **tail); +static int do_entry(BQUE *entry, int include_recurses); extern sig_atomic_t cpu_time_limit_hit; /**< Have we used too much CPU? */ @@ -341,6 +342,42 @@ im_insert(queue_map, tmp->pid, tmp); } +int +inplace_queue_attribute(dbref thing, const char *atrname, dbref enactor, + int rsargs) +{ + ATTR *a; + char *start, *command; + int noparent = 0; + char *bp; + + a = queue_attribute_getatr(thing, atrname, noparent); + if (!a) + return 0; + if (!Can_Read_Attr(enactor, thing, a)) + return 0; + + global_eval_context.include_called = 1 + rsargs; + start = safe_atr_value(a); + command = start; + /* Trim off $-command or ^-command prefix */ + if (*command == '$' || *command == '^') { + do { + command = strchr(command + 1, ':'); + } while (command && command[-1] == '\\'); + if (!command) + /* Oops, had '$' or '^', but no ':' */ + command = start; + else + /* Skip the ':' */ + command++; + } + bp = global_eval_context.include_replace; + safe_str(command, global_eval_context.include_replace, &bp); + *bp = '\0'; + free(start); + return 1; +} /** Enqueue the action part of an attribute. * This function is a front-end to parse_que() that takes an attribute, @@ -576,15 +613,10 @@ int do_top(int ncom) { - int a, i; + int i; BQUE *entry; - char tbuf[BUFFER_LEN]; - int break_count; - char *r; - char const *s; for (i = 0; i < ncom; i++) { - if (!qfirst) { strcpy(global_eval_context.ccom, ""); return i; @@ -595,56 +627,130 @@ entry = qfirst; if (!(qfirst = entry->next)) qlast = NULL; - if (GoodObject(entry->player) && !IsGarbage(entry->player)) { - global_eval_context.cplr = entry->player; + do_entry(entry, 0); + free_qentry(entry); + } + return i; +} + +static int +do_entry(BQUE *entry, int include_recurses) +{ + int a; + char tbuf[BUFFER_LEN]; + int break_count; + int save_player; + int local_break_called = 0; + char *r; + char const *s; + if (GoodObject(entry->player) && !IsGarbage(entry->player)) { + save_player = global_eval_context.cplr = entry->player; + if (!global_eval_context.include_called) { giveto(global_eval_context.cplr, QUEUE_COST); add_to(entry->queued, -1); - entry->player = 0; - if (IsPlayer(global_eval_context.cplr) - || !Halted(global_eval_context.cplr)) { - for (a = 0; a < 10; a++) - global_eval_context.wenv[a] = entry->env[a]; - for (a = 0; a < NUMQ; a++) { - if (entry->rval[a]) - strcpy(global_eval_context.renv[a], entry->rval[a]); - else - global_eval_context.renv[a][0] = '\0'; - } - global_eval_context.process_command_port = 0; - s = entry->comm; - global_eval_context.break_called = 0; - break_count = 100; - *(global_eval_context.break_replace) = '\0'; + } + entry->player = 0; + if (IsPlayer(global_eval_context.cplr) + || !Halted(global_eval_context.cplr)) { + for (a = 0; a < 10; a++) + global_eval_context.wenv[a] = entry->env[a]; + for (a = 0; a < NUMQ; a++) { + if (entry->rval[a]) + strcpy(global_eval_context.renv[a], entry->rval[a]); + else + global_eval_context.renv[a][0] = '\0'; + } + global_eval_context.process_command_port = 0; + s = entry->comm; + global_eval_context.break_called = 0; + local_break_called = 0; + break_count = 100; + *(global_eval_context.break_replace) = '\0'; + if (!include_recurses) start_cpu_timer(); - while (!cpu_time_limit_hit && *s) { - r = global_eval_context.ccom; - process_expression(global_eval_context.ccom, &r, &s, - global_eval_context.cplr, entry->cause, - entry->cause, PE_NOTHING, PT_SEMI, NULL); - *r = '\0'; - if (*s == ';') - s++; - strcpy(tbuf, global_eval_context.ccom); - process_command(global_eval_context.cplr, tbuf, entry->cause, 0); - if (global_eval_context.break_called) { - global_eval_context.break_called = 0; - s = global_eval_context.break_replace; - if (!*global_eval_context.break_replace) - break; - break_count--; - if (!break_count) { - notify(global_eval_context.cplr, T("@break recursion exceeded.")); - break; + while (!cpu_time_limit_hit && *s) { + r = global_eval_context.ccom; + process_expression(global_eval_context.ccom, &r, &s, + global_eval_context.cplr, entry->cause, + entry->cause, PE_NOTHING, PT_SEMI, NULL); + *r = '\0'; + if (*s == ';') + s++; + strcpy(tbuf, global_eval_context.ccom); + process_command(global_eval_context.cplr, tbuf, entry->cause, 0); + if (global_eval_context.break_called) { + global_eval_context.break_called = 0; + local_break_called = 1; + s = global_eval_context.break_replace; + if (!*global_eval_context.break_replace) + break; + break_count--; + if (!break_count) { + notify(global_eval_context.cplr, T("@break recursion exceeded.")); + break; + } + } + if (global_eval_context.include_called) { + BQUE *tmp; + /* @include was called. Check for recursion limit */ + if (include_recurses > 20) { + notify(global_eval_context.cplr, T("@include recursion exceeded.")); + break; + } + if (!*global_eval_context.include_replace) + break; + /* Clone qentry */ + tmp = mush_malloc(sizeof *tmp, "cqueue"); + tmp->pid = entry->pid; + tmp->semattr = NULL; + tmp->player = save_player; + tmp->queued = entry->queued; + tmp->next = NULL; + tmp->left = 0; + tmp->cause = entry->cause; + for (a = 0; a < 10; a++) { + if (global_eval_context.include_called == 1) { + tmp->env[a] = + entry->env[a] ? mush_strdup(entry->env[a], "cqueue.env") : NULL; + } else { + if (global_eval_context.include_wenv[a]) { + tmp->env[a] = + mush_strdup(global_eval_context.include_wenv[a], + "cqueue.env"); + } else { + tmp->env[a] = NULL; + } + } + if (global_eval_context.include_wenv[a]) { + mush_free(global_eval_context.include_wenv[a], "include_wenv"); + global_eval_context.include_wenv[a] = NULL; } } + for (a = 0; a < NUMQ; a++) + if (!entry->rval[a]) + tmp->rval[a] = NULL; + else { + tmp->rval[a] = mush_strdup(entry->rval[a], "cqueue.rval"); + } + global_eval_context.include_called = 0; + /* Put the included actions in the clone */ + tmp->comm = + mush_strdup(global_eval_context.include_replace, "cqueue.comm"); + local_break_called = do_entry(tmp, include_recurses + 1); + for (a = 0; a < 10; a++) + global_eval_context.wenv[a] = entry->env[a]; + free_qentry(tmp); + if (local_break_called) { + /* Propagate break */ + break; + } } - reset_cpu_timer(); } + if (!include_recurses) + reset_cpu_timer(); } - free_qentry(entry); } - - return i; + return local_break_called; } /** Determine whether it's time to run a queued command. @@ -781,7 +887,7 @@ if (aname) (void) atr_clr(thing, aname, GOD); else - atr_iter_get(GOD, thing, "**", 0, drain_helper, NULL); + atr_iter_get(GOD, thing, "**", 0, 0, drain_helper, NULL); } /* If @notify and count was higher than the number of queue entries, @@ -1301,7 +1407,7 @@ victim = player; else { victim = match_result(player, what, TYPE_PLAYER, - MAT_PLAYER | MAT_ABSOLUTE | MAT_ME); + MAT_PLAYER | MAT_ABSOLUTE | MAT_ME | MAT_TYPE); } } else { victim = player; Property changes on: src ___________________________________________________________________ Added: svn:ignore + info_slave netmud flaglocal.c local.c Makefile foo cmdlocal.c funlocal.c Index: INSTALL =================================================================== --- INSTALL (.../183p13) (revision 469) +++ INSTALL (.../184p0) (revision 469) @@ -110,7 +110,7 @@ Environment variables to customize search paths: CPPFLAGS=-I/path/to/extra/headers LDFLAGS=-L/path/to/extra/libraries - CFLAGS=-Optimation and -Warning options. + CFLAGS=-Optimization and -Warning options. VAR=arg ... ./configure Index: game/restrictcnf.dst =================================================================== --- game/restrictcnf.dst (.../183p13) (revision 469) +++ game/restrictcnf.dst (.../184p0) (revision 469) @@ -2,6 +2,8 @@ # Commands to restrict # Syntax: restrict_command [" ] # restrict_function +# For commands, can be an @lock-style lock, or any combination of +# the phrases below. For functions, use any combination of the phrases. # is a space separated list that may include: # nobody Totally disable the command # nogagged Gagged players can't use it @@ -15,7 +17,7 @@ # logargs When func/cmd is used, log its name, args, and user # Any flag that must be present to use it (Command only) # Any power that must be present to use it (Command only) -# ! The opposite of a restriction (Command only). +# ! Remove a restriction (Command only). # nosidefx The side-effect version of a function won't work (Function only). # # If is given to a restrict_command, it is sent to the player Index: game/txt/hlp/pennchat.hlp =================================================================== --- game/txt/hlp/pennchat.hlp (.../183p13) (revision 469) +++ game/txt/hlp/pennchat.hlp (.../184p0) (revision 469) @@ -18,7 +18,7 @@ & + & @chat - @chat = + @chat = + This tells everyone on your . You can prepend @@ -126,6 +126,10 @@ See also: CHAT, cemit(), @chat & @channel +& @channel/list +& @channel/what +& @channel/on +& @channel/off @channel/list [] @channel/what [] @channel/on [=] @@ -152,8 +156,11 @@ See also: chat & @channel2 +& @channel/who +& @channel/hide +& @channel/title @channel/who - @channel/hide = + @channel/hide = @channel/title [=] The @channel/who command shows you who is currently on a channel, if @@ -172,9 +179,12 @@ See "help @channel3" for more. & @channel3 - @channel/mute = - @channel/gag = - @channel/recall [ = [,] ] +& @channel/mute +& @channel/gag +& @channel/recall + @channel/mute = + @channel/gag = + @channel/recall [=[, ]] Some channels broadcast messages when players connect or disconnect from the MUSH. If you don't want to hear those messages, use @@ -199,10 +209,14 @@ See "help @channel4" for more. & @channel4 - @channel/add [= ] +& @channel/add +& @channel/delete +& @channel/desc +& @channel/rename + @channel/add [=] @channel/delete - @channel/desc = - @channel/rename = + @channel/desc = + @channel/rename = @channel/add creates a new channel. On some MUSHes, any player can create a new channel, though there will be a cost associated @@ -230,11 +244,15 @@ See "help @channel5" for more. See also "help @clock". & @channel5 - @channel/priv = +& @channel/priv +& @channel/wipe +& @channel/buffer +& @channel/chown + @channel/priv = @channel/wipe - @channel/buffer = + @channel/buffer = @channel/decompile[/brief] - @channel/chown = + @channel/chown = The "priv" switch sets the channel's access privileges to those specified. The "wipe" switch clears a channel of players without deleting it. @@ -249,7 +267,8 @@ See "help @channel6" for more. & @channel6 - @channel/mogrifier = +& @channel/mogrifier + @channel/mogrifier = The Mogrifier lets you tweak every aspect of a channel's output, before it goes to individual players' @chatformats. @@ -262,7 +281,7 @@ the resultant string is sent to the player, and the message is not broadcasted. - A number of separate mogrifiers can be used. Check "help @chat mogrifying" + A number of separate mogrifiers can be used. Check 'help @chat mogrifying' for details. After all of these are called, MOGRIFY`FORMAT is called. It has the exact @@ -270,7 +289,7 @@ mogrified text (if any), so is generally intended only for reformatting the whole channel text. It is also overridden by individual @chatformats. - See "help @chat mogrifying" for examples. + See 'help @chat mogrifying' for more info and examples. & @chat mogrifying Mogrifying individual pieces of the channel chatter text: @@ -279,7 +298,7 @@ %0 - (Depends on the mogrifier.) %1 - Channel name (unmogrified). - %2 - Chat type (", :, ;, |, @) + %2 - Chat type (", :, ;, |, @). See 'help @chatformat' for descriptions. %3 - Message. %4 - Player chan title. %5 - Player name. @@ -290,50 +309,50 @@ MOGRIFY`SPEECHTEXT: %0 = "says" MOGRIFY`MESSAGE: %0 = - See "help @chat mogrifying2" for examples. + See 'help @chat mogrifying2' for examples. & @chat mogrifying2 For Talk Like a Pirate Day (Sep 19): -> @create Pirate Filter -> @chan/mogrifier public=Pirate Filter -> &MOGRIFY`BLOCK Pirate Filter=if(regmatch(%5,ninja),We don't need no ninjas!) -> &MOGRIFY`TITLE Pirate Filter=switch(poss(%#),her,Wench,Buccaneer) -> &MOGRIFY`SPEECHTEXT Pirate Filter=yo-hos -> &MOGRIFY`MESSAGE Pirate Filter=edit(%0,r,rrr) -> &MOGRIFY`CHANNAME Pirate Filter=(%1-Yarr!) + > @create Pirate Filter + > @chan/mogrifier public=Pirate Filter + > &MOGRIFY`BLOCK Pirate Filter=switch(%5,*ninja*,We don't need no ninjas!) + > &MOGRIFY`TITLE Pirate Filter=switch(poss(%#),her,Wench,Buccaneer) + > &MOGRIFY`SPEECHTEXT Pirate Filter=yo-hos + > &MOGRIFY`MESSAGE Pirate Filter=edit(%0,r,rrr) + > &MOGRIFY`CHANNAME Pirate Filter=(%1-Yarr!) Output: -> +public Hello -(Public-Yarr!) Buccaneer Walker yo-hos, "Hello" + > +public Hello + (Public-Yarr!) Buccaneer Walker yo-hos, "Hello" -> +public :thinks it's talk like a pirate day? -(Public-Yarr!) Buccaneer Walker thinks it's talk like a pirrrate day? + > +public :thinks it's talk like a pirate day? + (Public-Yarr!) Buccaneer Walker thinks it's talk like a pirrrate day? -> +public Pirates suck, Ninjas are better! -We don't need no ninjas! -(And the message is blocked, won't be sent out). + > +public Pirates suck, Ninjas are better! + We don't need no ninjas! + (And the message is blocked, won't be sent out). - See "help @chat mogrifying3" for another example. + See 'help @chat mogrifying3' for another example. & @chat mogrifying3 For keeping a channel PG and safe, and altering the channel name from to [Public], with a green "Public". -> @create PG Channel Mogrifier -> @chan/mogrifier public=PG Channel Mogrifier -> &BADWORDS PG=list of bad words -> &MOGRIFY`MESSAGE PG=regeditall(%0,\\b([edit(v(badwords),%b,|)])\\b,***) -> &MOGRIFY`CHANNAME PG=\[[ansi(g,%1)]\] -> &MOGRIFY`title PG=if(strlen(%0),\(%0\)) + > @create PG Channel Mogrifier + > @chan/mogrifier public=PG Channel Mogrifier + > &BADWORDS PG=list of bad words + > &MOGRIFY`MESSAGE PG=regeditall(%0,\\b([edit(v(badwords),%b,|)])\\b,***) + > &MOGRIFY`CHANNAME PG=\[[ansi(g,%1)]\] + > &MOGRIFY`title PG=if(strlen(%0),\(%0\)) -Output: (With a channel title of "Fast") ("Public" is green) -> +p Hello -[Public] (Fast) Walker says, "hello" -> +p what the list is going on bad bad? -[Public] (Fast) Walker says, "what the *** is going on *** ***?" + Output: (With a channel title of "Fast") ("Public" is green) + > +p Hello + [Public] (Fast) Walker says, "hello" + > +p what the list is going on bad bad? + [Public] (Fast) Walker says, "what the *** is going on *** ***?" -Combine MOGRIFY`FORMAT with speak() and you can have plenty of fun: -On-channel language systems and more! + Combine MOGRIFY`FORMAT with speak() and you can have plenty of fun: + On-channel language systems and more! & channel-list Here's the legend for reading the @channel/list output: @@ -358,11 +377,11 @@ If on, player is hiding on the channel-------------------------------/ | Size of the channel buffer in full-length lines---------------------------/ & @clock - @clock/join [= ] - @clock/speak [= ] - @clock/see [= ] - @clock/hide [= ] - @clock/mod [= ] + @clock/join [=] + @clock/speak [=] + @clock/see [=] + @clock/hide [=] + @clock/mod [=] The @clock command modifies the a lock on a chat channel if the extended chat system is in use. If no key is specified, the lock is @@ -383,46 +402,47 @@ anything. & @clock2 -You can use indirect @clocks to lock a channel to a lock of any type -(including evaluation locks) on a VISUAL object. This channel can only -be joined by an UNFINDABLE player: + You can use indirect @clocks to lock a channel to a lock of any type + (including evaluation locks) on a VISUAL object. This channel can only + be joined by an UNFINDABLE player: - >@clock/join unfindchannel=@#10 - >@lock/user:ChanJoinLock #10=isunfind/1 - >&isunfind #10=[hasflag(%#,unfindable)] - >@set #10 = VISUAL + > @clock/join unfindchannel=@#10 + > @lock/user:ChanJoinLock #10=!flag^unfindable + > @set #10=VISUAL -@clock Corresponding default user: lock for object -join ChanJoinLock -speak ChanSpeakLock -see ChanSeeLock -hide ChanHideLock -mod ChanModLock + @clock Corresponding default user: lock for object + join ChanJoinLock + speak ChanSpeakLock + see ChanSeeLock + hide ChanHideLock + mod ChanModLock -You can lock multiple channels to the same object by specfiying a -specific indirect lock instead of the default one: + You can lock multiple channels to the same object by specfiying a + specific indirect lock instead of the default one: - >@clock/join onechannel=@#10/onechanneljoin - >@clock/join anotherchannel=@#10/anotherchanneljoin - >@lock/user:onechanneljoin #10 = 1 - >@lock/user:anotherchanneljoin #10 = isunfind/1 + > @clock/join onechannel=@#10/onechanneljoin + > @clock/join anotherchannel=@#10/anotherchanneljoin + > @lock/user:onechanneljoin #10 = 1 + > @lock/user:anotherchanneljoin #10 = isunfind/1 & COWNER() cowner() Returns the dbref of the owner of a channel. & CTITLE() - ctitle(,) + ctitle(, ) Returns 's @chan/title on . You must either be able to examine the object, or it must be visibly on a channel which you are allowed to join. & CSTATUS() - cstatus(,) + cstatus(, ) Returns 's status with respect to , which may be "Off", "On", or "Gag". You must either be able to examine the object, or it must visible be on the channel; "Off" is returned for objects that you can not see on the channel. + +See also: cwho(), cflags() & CDESC() & CUSERS() & CMSGS() @@ -435,6 +455,8 @@ Return the description, number of users, number of messages, or buffer size of , respectively. This information is also displayed in @chan/list. + +See also: cbufferadd(), crecall() & CBUFFERADD() cbufferadd(, [, ]) @@ -443,14 +465,21 @@ and you must be able to perform an @nscemit. This function is only usable by objects that pass the channel's @clock/mod. + +See also: crecall(), cbuffer() & CWHO() - cwho([, ]) + cwho([, [, ]]) This function returns the dbrefs of objects which are on . can be one of "on", "off" or "all" to control whether online players, offline players, or all players are returned; it defaults to "on". (Things are always returned.) When used by mortals, hidden/dark players are shown as being offline. + + If is given, and is true, gagged objects will not be + included in the results. + +See also: cstatus() & CEMIT() cemit(, [, ]) @@ -462,27 +491,29 @@ & CFLAGS() & CLFLAGS() cflags() - cflags(,) + cflags(, ) clflags() - clflags(,) + clflags(, ) With one argument, cflags() returns a list of flags set on the given - channel, represented as a string of characters. See 'help - channel-list' for the list of flags (they appear in the "Access" - column). You must be able to see the channel to use this function. + channel, represented as a string of characters. See 'help channel-list' + for the list of flags (they appear in the "Access" column). You must be + able to see the channel to use this function. - With two arguments, cflags() returns a list of flags for that object - on that channel, currently a string consisting of zero or more of - "G" (gagging), "Q" (muted), and "H" (hidden). You must be able to - see that channel and to examine the object to use this function. If - the object is not on the channel, an error is returned. + With two arguments, cflags() returns a list of flags for that object on + that channel, currently a string consisting of zero or more of + "G" (gagging), "Q" (muted), and "H" (hidden). You must be able to see + that channel and to examine the object to use this function. If the + object is not on the channel, an error is returned. The clflags versions return a space-separated list of flag names, rather than a string of flag characters. + +See also: cstatus() & CHANNELS() channels([]) channels() - channels([,]) + channels([, ]) With no arguments, channels() returns the list of all channel names which are visible to the player. With two arguments, returns the Index: game/txt/hlp/index.hlp =================================================================== --- game/txt/hlp/index.hlp (.../183p13) (revision 469) +++ game/txt/hlp/index.hlp (.../184p0) (revision 469) @@ -127,29 +127,36 @@ -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-7 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - 1.8.3p13 : ; - @-attributes @-building @-general - @-wizard @@ @@() - @aahear @abuy @aclone - @aconnect @adeath @adescribe - @adestroy @adisconnect @adrop - @aefail @aenter @afailure - @afollow @agive @ahear - @aidescribe @aleave @alfail - @alias @allhalt @allquota - @amhear @amove @aname - @apayment @areceive @assert - @asuccess @atport @atrchown - @atrlock @attribute @aufail - @aunfollow @ause @away - @azenter @azleave @boot + 1.8.3p13 1.8.4p0 : + ; @-attributes @-building + @-general @-wizard @@ + @@() @aahear @abuy + @aclone @aconnect @adeath + @adescribe @adestroy @adisconnect + @adrop @aefail @aenter + @afailure @afollow @agive + @ahear @aidescribe @aleave + @alfail @alias @allhalt + @allquota @amhear @amove + @aname @apayment @areceive + @assert @asuccess @atport + @atrchown @atrlock @attribute + @attribute2 @aufail @aunfollow + @ause @away @azenter For more, see Entries-8 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-8 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - @break @buy @cemit - @channel @channel2 @channel3 + @azleave @boot @break + @buy @cemit @channel + @channel/add @channel/buffer @channel/chown + @channel/delete @channel/desc @channel/gag + @channel/hide @channel/list @channel/mogrifier + @channel/mute @channel/off @channel/on + @channel/priv @channel/recall @channel/rename + @channel/title @channel/what @channel/who + @channel/wipe @channel2 @channel3 @channel4 @channel5 @channel6 @charges @chat @chat mogrifying @chat mogrifying2 @chat mogrifying3 @chatformat @@ -157,6 +164,11 @@ @chownall @chzone @chzone2 @chzoneall @clock @clock2 @clone @command @command2 + +For more, see Entries-9 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-9 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @command3 @comment @config @config attribs @config chat @config cmds @config cosmetic @config cosmetic2 @config costs @@ -164,11 +176,6 @@ @config funcs @config limits @config limits2 @config limits3 @config limits4 @config log @config net @config parameters @config tiny - -For more, see Entries-9 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-9 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @conformat @cost @cpattr @create @dbck @death @debugforwardlist @decompile @decompile2 @@ -178,6 +185,11 @@ @doing @dolist @drain @drop @dump @ealias @edit @efail @elock + +For more, see Entries-10 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-10 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @emit @enable @enter @entrances @eunlock @exitformat @failure @filter @filter2 @@ -185,38 +197,41 @@ @flag2 @follow @force @force2 @forwardlist @function @function2 @function3 @function4 - -For more, see Entries-10 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-10 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @gedit @give @grep2 @grep @halt @haven @hide @hook @hook2 @idescformat @idescribe @idle - @infilter @inprefix @invformat - @kick @lalias @leave - @lemit @lfail @link - @list @listen @listen2 - @listmotd @lock @lock10 - @lock2 @lock3 @lock4 - @lock5 @lock6 @lock7 - @lock8 @lock9 @log - @logwipe @lset @mail - @mailfilter @mailforwardlist @malias - @malias2 @malias3 @malias4 - @malias5 @message @motd + @include @infilter @inprefix + @invformat @kick @lalias + @leave @lemit @lfail + @link @list @listen + @listen2 @listmotd @lock For more, see Entries-11 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-11 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + @lock-attribute @lock-bit @lock-carry + @lock-channel @lock-complex @lock-eval2 + @lock-evaluation @lock-evaluation2 @lock-flag + @lock-host @lock-indirect @lock-list + @lock-objid @lock-owner @lock-power + @lock-simple @lock-type @log + @logwipe @lset @mail + @mailfilter @mailforwardlist @malias + @malias2 @malias3 @malias4 + @malias5 @message @motd @move @mvattr @name @nameaccent @nameformat @newpassword @notify @nscemit @nsemit @nslemit @nsoemit @nspemit @nsprompt @nsremit @nszemit @nuke @obuy @odeath + +For more, see Entries-12 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-12 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @odescribe @odrop @oefail @oemit @oenter @ofailure @ofollow @ogive @oidescribe @@ -224,19 +239,20 @@ @oname @opayment @open @oreceive @osuccess @otport @oufail @ounfollow @ouse - @oxenter @oxleave @oxmove - @oxtport @ozenter @ozleave - @pageformat @parent @password - -For more, see Entries-12 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-12 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + @outpageformat @outpageformat2 @oxenter + @oxleave @oxmove @oxtport + @ozenter @ozleave @pageformat + @pageformat2 @parent @password @payment @pcreate @pemit @pemit2 @poll @poor @power @power2 @power3 @prefix @pricelist @prompt @ps @purge @quota + +For more, see Entries-13 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-13 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @readcache @receive @recycle @rejectmotd @remit @restart @runout @rwall @scan @@ -248,16 +264,16 @@ @stats @success @sweep @switch @switch2 @teleport @tport @trigger @trigger2 - -For more, see Entries-13 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-13 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @tz @ufail @ulock @undestroy @unfollow @unlink @unlock @unrecycle @uptime @uptime2 @use @uunlock @verb @verb2 @verb3 + +For more, see Entries-14 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-14 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @verb4 @version @vrml_url @wait @wait2 @wait3 @wall @warnings @warnings2 @@ -265,105 +281,105 @@ @wipe @wizmotd @wizwall @zemit @zenter @zleave \ ] ^ - ` `2 `3 - `4 abode abs() - accent() accent2 accent3 - accent4 accname() acos() - -For more, see Entries-14 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-14 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - action lists action2 add() - after() ahelp alias() - align() align2 align3 - allof() alphamax() alphamin() - ancestors and() andflags() - andlpowers() anews angles - anonymous attributes anonymous2 anonymous3 - anonymous4 ansi ansi() - aposs() art() asin() - atan() atan2() atrlock() - attr trees attr trees2 attr trees3 - attr trees4 attrcnt() attrib trees - attrib trees2 attrib trees3 attrib trees4 - attrib-ownership attrib_set() attribute flags - attribute flags2 attribute flags3 attribute functions - attribute list attribute trees attribute trees2 + ^-listens ` `2 + `3 `4 abode + abs() accent() accent2 + accent3 accent4 accname() + acos() action lists action2 + add() after() ahelp + alias() align() align2 + align3 align4 allof() + alphamax() alphamin() ancestors For more, see Entries-15 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-15 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - attribute trees3 attribute trees4 attributes - attributes list attributes2 attributes3 - attributes4 attrpcnt() audible - audible2 band() baseconv() - beep() before() being killed - benchmark() bitwise functions bnand() - bnot() boolean functions boolean values - boolean2 boolean3 bor() - bound() brackets() brief - builder buy bxor() - caller cand() capstr() - case() caseall() cat() - cbuffer() cbufferadd() cd - cdesc() ceil() cemit() - center() cflags() ch - chan_usefirstmatch changes channel functions + and() andflags() andlpowers() + anews angles anonymous attributes + anonymous2 anonymous3 anonymous4 + ansi ansi() aposs() + art() asin() atan() + atan2() atrlock() attr trees + attr trees2 attr trees3 attr trees4 + attrcnt() attrib trees attrib trees2 + attrib trees3 attrib trees4 attrib-ownership + attrib_set() attribute flags attribute flags2 + attribute flags3 attribute functions attribute list + attribute trees attribute trees2 attribute trees3 + attribute trees4 attributes attributes list + attributes2 attributes3 attributes4 + attrpcnt() audible band() + baseconv() beep() before() For more, see Entries-16 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-16 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - channel-list channels() charges2 - chat checkpass() children() - chown_ok chr() clflags() - clients clock() clone() - cloudy cmds() cmsgs() - code color commands - communication functions comp() comsys - con() cond() condall() - config() conn() connected - connection functions contact control - controls() convsecs() convtime() - convutcsecs() copyright copyrite - cor() cos() costs - cowner() create() crecall() - credits csecs() cstatus() - ctime() ctitle() ctu() + being killed benchmark() bitwise functions + bnand() bnot() boolean functions + boolean values boolean2 boolean3 + bor() bound() brackets() + brief builder buy + bxor() caller cand() + capstr() case() caseall() + cat() cbuffer() cbufferadd() + cd cdesc() ceil() + cemit() center() cflags() + ch chan_usefirstmatch changes + channel functions channel-list channels() + charges2 chat checkpass() + children() chown_ok chr() + clflags() clients clock() + clone() cloudy cmds() For more, see Entries-17 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-17 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - cusers() cv cwho() - dark dark2 database + cmsgs() code color + commands communication functions comp() + comsys con() cond() + condall() config() conn() + connected connection functions contact + control controls() convsecs() + convtime() convutcsecs() copyright + copyrite cor() cos() + costs cowner() create() + crecall() credits csecs() + cstatus() ctime() ctitle() + ctu() cusers() cv + cwho() dark database dbref # dbref functions dbref number dbref2 dbrefs debug debug2 debugforwardlist dec() + +For more, see Entries-18 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-18 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- decode64() decompose() decrypt() default() delete() desert destroy_ok die() dig() digest() dismiss dist2d() dist3d() div() doing doing() download drop - drop-tos dynhelp() e() - edefault() edit() element() - elements() elist() elock() - emit() empty enactor - encode64() encrypt() endtag() + drop-tos droptos dynhelp() + e() edefault() edit() + element() elements() elist() + elock() emit() empty + enactor encode64() encrypt() + endtag() enter enter_ok + entrances() eq() escape() + etimefmt() etimefmt2 etimefmt3 + eval() evaluation order evaluation2 + events examine executor -For more, see Entries-18 +For more, see Entries-19 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-18 +& Entries-19 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - enter enter_ok entrances() - eq() escape() etimefmt() - etimefmt2 etimefmt3 eval() - evaluation order evaluation2 events - examine executor exit() - exits exits2 exp() + exit() exits exp() extract() failure fdiv() filter() filterbool() findable() first() firstof() fixed @@ -373,100 +389,101 @@ floordiv() fmod() fn() fold() fold2 folderstats() follow followers() following() - foreach() foreach2 fraction() + foreach() foreach2 forwardlist + fraction() fullalias() fullname() + function list functions functions() + functions2 gagged gender + get get() get_eval() + getpids() give global commands -For more, see Entries-19 +For more, see Entries-20 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-19 +& Entries-20 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - fullalias() fullname() function list - functions functions() functions2 - gagged gender get - get() get_eval() getpids() - give global commands globals - go going goto - grab() graball() grep() - grepi() gt() gte() - halt hasattr() hasattrp() - hasattrpval() hasattrval() hasflag() - haspower() hastype() haven - hear_connect heavy height() + globals go going + going_twice goto grab() + graball() grep() grepi() + gt() gte() halt + hasattr() hasattrp() hasattrpval() + hasattrval() hasflag() haspower() + hastype() haven hear_connect + heavy height() help here hidden() home home() homes host() hostname() html html functions html() i18n idle - -For more, see Entries-20 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-20 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- idle() idlesecs() if() ifelse() ilev() iname() inc() index index() info information functions inherit - inherit2 insert() interiors - interiors2 internationalization inum() - inventory ipaddr() isdaylight() - isdbref() isint() isnum() - isobjid() isword() itemize() - items() iter() iter2 - itext() judge jump_ok - jury_ok keepalive kill - lalign() lambda last - last & lastlogout last() lastip - lastlogout lastsite lattr() - lattrp() lcon() lcstr() For more, see Entries-21 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-21 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - ldelete() leave left() - lemit() letq() lexits() - lflags() license light - link() link_ok linking - list functions list() listen_parent - listening listening2 listening3 - lists lit() ljust() - llockflags() llocks() lmath() - ln() lnum() loc() - locale localize() locate() - locate2 locate3 lock list - lock types lock types2 lock() - lockflags() locking locklist - lockowner() locks locks() - locktypes locktypes2 log() - logout look look2 + insert() interiors interiors2 + internationalization inum() inventory + ipaddr() isdaylight() isdbref() + isint() isnum() isobjid() + isword() itemize() items() + iter() iter2 itext() + judge jump_ok jury_ok + keepalive kill lalign() + lambda last last & lastlogout + last() lastip lastlogout + lastsite lattr() lattrp() + lcon() lcstr() ldelete() + leave left() lemit() + letq() lexits() lflags() + license light link() + link_ok linking list functions For more, see Entries-22 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-22 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - looping loud lparent() - lpids() lplayers() lports() - lpos() lsearch() lsearch2 - lsearchr() lset() lstats() - lt() lte() lthings() - lvcon() lvexits() lvplayers() - lvthings() lwho() lwhoid() - macros macros2 mail - mail functions mail() mail-admin - mail-folders mail-forward mail-other - mail-reading mail-sending maildstats() - mailfilter mailfrom() mailfstats() - mailsend() mailstats() mailstatus() - mailsubject() mailtime() malias() - map() mapsql() mapsql2 - master room match() matchall() + list() listen_parent listening + listening2 listening3 lists + lit() ljust() llockflags() + llocks() lmath() ln() + lnum() loc() locale + localize() locate() locate2 + locate3 lock keys lock list + lock types lock types2 lock() + lockflags() locking lockkeys + locklist lockowner() locks + locks() locktypes locktypes2 + log() logout look + look2 looping loud + lparent() lpids() lplayers() + lports() lpos() lsearch() + lsearch2 lsearchr() lset() For more, see Entries-23 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-23 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + lstats() lt() lte() + lthings() lvcon() lvexits() + lvplayers() lvthings() lwho() + lwhoid() macros macros2 + mail mail functions mail() + mail-admin mail-folders mail-forward + mail-other mail-reading mail-sending + maildstats() mailfilter mailfrom() + mailfstats() mailsend() mailstats() + mailstatus() mailsubject() mailtime() + malias() map() mapsql() + master room match() matchall() matching math functions max() me mean() median() member() merge() message() mid() min() mistrust + +For more, see Entries-24 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-24 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- mix() mix2 mod() modulo() modulus() money money() monitor move @@ -479,35 +496,36 @@ nattrp() ncand() nchildren() ncon() ncond() ncondall() ncor() nearby() neq() - -For more, see Entries-24 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-24 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- newbie newbie2 newbie3 news nexits() next() nextdbref() nlsearch() nmwho() - no_command no_leave no_tel - no_warn noaccents noleave - non-standard attributes noname nor() - nospace nospoof not() - nowarn nplayers() nsearch() - nsemit() nslemit() nsoemit() - nspemit() nsprompt() nsremit() - nszemit() nthings() null() - num() numversion() nvcon() - nvexits() nvplayers() nvthings() - nwho() obj() object parents - objeval() objid() objmem() - oemit() on-vacation opaque + no_command no_leave no_log For more, see Entries-25 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-25 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - open() or() ord() + no_tel no_warn noaccents + noleave non-standard attributes noname + nor() nospace nospoof + not() nowarn nplayers() + nsearch() nsemit() nslemit() + nsoemit() nspemit() nsprompt() + nsremit() nszemit() nthings() + null() num() numversion() + nvcon() nvexits() nvplayers() + nvthings() nwho() obj() + object parents objects objeval() + objid() objmem() oemit() + on-vacation opaque open() + open_ok or() ord() ordinal() orflags() orlflags() orlpowers() orphan outputprefix + +For more, see Entries-26 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-26 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- outputsuffix owner() page page2 paranoid parent parent() parents parents2 @@ -515,20 +533,20 @@ parse() patchlevels pcreate() pemit() pfun() pfun2 pfun3 pi() pickrand() - pidinfo() player player() - playermem() pmatch() poll() + pidinfo() player() playermem() + players pmatch() poll() ports() pos() pose pose2 poss() power() powers list powers list2 powers() powers2 prompt() prompt_newlines - -For more, see Entries-26 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-26 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- pueblo pueblo features pueblo() puppet puppets puppets2 queue quiet quit + +For more, see Entries-27 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-27 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- quota() r() r-function rand() randword() read recv() regedit() regeditall() @@ -538,126 +556,129 @@ regexp syntax4 regexp syntax5 regexp syntax6 regexp syntax7 regexp syntax8 regexps regexps2 registers registers2 - regmatch() regmatchi() regrab() - regraball() regraballi() regrabi() - regrep() regrepi() - regular expression functions remainder() - -For more, see Entries-27 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -& Entries-27 --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - remit() remove() repeat() - replace() rest() restarts() - restarttime() restrict restrict2 - restrict3 reswitch() reswitchall() - reswitchalli() reswitchi() reverse() - revwords() right() rjust() - rloc() rnum() room - room() root() round() - royalty rquota rules - runout2 s() s-function - safe say scan() - score scramble() screenheight - screenwidth search() search2 - secs() secure() semaphores - semaphores2 semaphores3 semaphores4 - semaphores5 semaphores6 semipose + reglattr() reglattrp() regmatch() + regmatchi() regnattr() regnattrp() + regrab() regraball() regraballi() + regrabi() regrep() regrepi() + regular expression functions regxattr() + regxattrp() remainder() remit() + remove() repeat() replace() For more, see Entries-28 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-28 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - sent() session set() - setdiff() setinter() setq() - setq2 setq3 setr() - setting-attributes setunion() sex - sha0() shared shared players - shared players2 shl() shr() - shuffle() sign() sin() - slay socket commands softcode - sort() sortby() sorting - sortkey() soundex() soundex2 - soundlike() soundslike() space() - speak() speak2 speak3 - speak4 speak5 speak6 - speak7 speakpenn() spellnum() - splice() spoofing sql functions - sql() sqlescape() sqrt() + rest() restarts() restarttime() + restrict restrict2 restrict3 + reswitch() reswitchall() reswitchalli() + reswitchi() reverse() revwords() + right() rjust() rloc() + rnum() room() rooms + root() round() royalty + rquota rules runout2 + s() s-function safe + say scan() score + scramble() screenheight screenwidth + search() search2 secs() + secure() semaphores semaphores2 + semaphores3 semaphores4 semaphores5 + semaphores6 semipose sent() + session set() setdiff() For more, see Entries-29 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-29 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + setinter() setq() setq2 + setq3 setr() setting-attributes + setunion() sex sha0() + shared shared players shared players2 + shl() shr() shuffle() + sign() sin() slay + socket commands softcode sort() + sortby() sorting sortkey() + soundex() soundex2 soundlike() + soundslike() space() speak() + speak2 speak3 speak4 + speak5 speak6 speak7 + speakpenn() spellnum() splice() + spoofing sql examples sql functions + sql() sqlescape() sqrt() squish() ssl() stack - starttime() stats() stddev() - step() sticky strcat() - string functions strings stringsecs() - strinsert() stripaccents() stripansi() - strlen() strmatch() strreplace() - sub() subj() substitutions - substitutions2 substitutions3 substitutions4 - success suspect switch wildcards - switch() switch2 switchall() - switches t() table() - tag() tagwrap() take - tan() teach tel() - tel_ok terminfo() terse - testlock() textentries() textfile() - think time functions time() For more, see Entries-30 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-30 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - timefmt() timefmt2 timestring() - topics topics2 tr() - track_money translation transparent - transparent2 trim() trimpenn() - trimtiny() trunc() trust - trust2 type() types of objects - types2 u() u2 - u3 ucstr() udefault() - ufun() ufun2 ufun3 - ulambda() uldefault() ulocal() - ulocal2 unfindable unfollow - uninspected unique() unregistered - unsetq() use user-defined commands - user-defined2 utctime() utility functions - v() v-function vadd() - val() valid() vcross() + starttime() stats() stddev() + step() sticky strallof() + strcat() strfirstof() string functions + strings stringsecs() strinsert() + stripaccents() stripansi() strlen() + strmatch() strreplace() sub() + subj() substitutions substitutions2 + substitutions3 substitutions4 success + suspect switch wildcards switch() + switch2 switchall() switches + t() table() tag() + tagwrap() take tan() + teach tel() tel_ok + terminfo() terse testlock() + textentries() textfile() things + think time functions time() For more, see Entries-31 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-31 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - vdim() vdot() vector functions - verbose verbs version() - visible() visual vmag() - vmax() vmin() vmul() - vrml vsub() vunit() - warnings warnings list warnings list2 - where() whisper whisper2 - who who2 width() - wildcards wildgrep() wildgrepi() - wipe() with wizard - wordpos() words() wrap() - xattr() xattrp() xcon() - xexits() xget xmwho() - xmwhoid() xor() xplayers() - xthings() xvcon() xvexits() - xvplayers() xvthings() xwho() + timefmt() timefmt2 timestring() + topics topics2 tr() + track_money translation transparent + trim() trimpenn() trimtiny() + trunc() trust type() + types types of objects u() + u2 u3 ucstr() + udefault() ufun() ufun2 + ufun3 ulambda() uldefault() + ulocal() ulocal2 unfindable + unfollow uninspected unique() + unregistered unsetq() use + user-defined commands user-defined2 utctime() + utility functions v() v-function + vadd() val() valid() + vcross() vdim() vdot() For more, see Entries-32 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- & Entries-32 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - xwhoid() z_tel zemit() - zfun() zmo zmp - zmr zmt zmwho() - zone zone master objects zone master rooms - zone masters zone objects zone() - zones zones2 zwho() + vector functions verbose verbs + verbs2 version() visible() + visual vmag() vmax() + vmin() vmul() vrml + vsub() vunit() warnings + warnings list warnings list2 where() + whisper whisper2 who + who2 width() wildcards + wildgrep() wildgrepi() wipe() + with wizard wordpos() + words() wrap() xattr() + xattrp() xcon() xexits() + xget xmwho() xmwhoid() + xor() xplayers() xthings() + xvcon() xvexits() xvplayers() + xvthings() xwho() xwhoid() + +For more, see Entries-33 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +& Entries-33 +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + z_tel zemit() zfun() + zmo zmp zmr + zmt zmwho() zone + zone master objects zone master rooms zone masters + zone objects zone() zones + zones2 zwho() & &Entries -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Index: game/txt/hlp/pennfunc.hlp =================================================================== --- game/txt/hlp/pennfunc.hlp (.../183p13) (revision 469) +++ game/txt/hlp/pennfunc.hlp (.../184p0) (revision 469) @@ -64,9 +64,10 @@ aposs() attrib_set() default() edefault() eval() get() grep() grepi() hasattr() hasattrp() hasattrval() lattr() nattr() obj() pfun() - poss() regrep() regrepi() subj() udefault() - ufun() uldefault() ulocal() v() wildgrep() - wildgrepi() xattr() xget() zfun() + poss() reglattr() regrep() regrepi() regxattr() + subj() udefault() ufun() uldefault() ulocal() + v() wildgrep() wildgrepi() xattr() xget() + zfun() See also: ATTRIBUTES, NON-STANDARD ATTRIBUTES & Bitwise functions @@ -182,10 +183,10 @@ These functions take a regular expression (regexp, or re) and match it against assorted things. - regedit() regeditall() regeditalli() regediti() regmatch() - regmatchi() regrab() regraball() regraballi() regrabi() - regrep() regrepi() reswitch() reswitchall() reswitchalli() - reswitchi() + regedit() regeditall() regeditalli() regediti() reglattr() + reglattrp() regmatch() regmatchi() regrab() regraball() + regraballi() regrabi() regrep() regrepi() reswitch() + reswitchall() reswitchalli() reswitchi() regxattr() regxattrp() See also: string functions, regexp & SQL functions @@ -410,11 +411,12 @@ Ansi: Place ansi characters (as defined in 'help ansi()') within ()s to define a column's ansi markup. - Continued in 'help align3' + See 'help align3' for examples. +See also: center(), ljust(), rjust(), table() & ALIGN3 Examples: - > &line me=align(<5 10 20,\([left(xget(%0,sex),1)]\),name(%0),name(loc(%0))) + > &line me=align(<5 10 20,([left(get(%0/sex),1)]),name(%0),name(loc(%0))) > th iter(lwho(),u(line,##),%b,%r) (M) Walker Tree (F) Jane Doe Nowhere @@ -431,8 +433,25 @@ + Luke + +----------------------------------------+ - Continued in 'help align4' -See also: center(), ljust(), rjust(), table() + See 'help align4' for another example. +& ALIGN4 + + > &dropcap me=%b_______%r|__%b%b%b__|%r%b%b%b|%b|%r%b%b%b|_| + > &story me=%r'was the night before Christmas, when all through the house%r + Not a creature was stirring, not even a mouse.%r + The stockings were hung by the chimney with care,%r + In hopes that St Nicholas soon would be there. + > th align(9'(ch) 68, u(dropcap), u(story) + + _______ + |__ __| 'was the night before Christmas, when all through the house + | | Not a creature was stirring, not even a mouse. + |_| The stockings were hung by the chimney with care, + In hopes that St Nicholas soon would be there. + + The dropcap 'T' will be in ANSI cyan-highlight, and merges with the 'story' + column. + & ALLOF() allof([, ... , ], ) @@ -452,7 +471,7 @@ > say allof(#-1,#101,#2970,,#-3,0,#319,null(This Doesn't Count),|) You say, "#101|#2970|#319" -See also: firstof(), BOOLEAN VALUES +See also: firstof(), BOOLEAN VALUES, strallof(), filter() & ALPHAMAX() alphamax([, ... , ]) @@ -462,7 +481,7 @@ This is equivilent to last(sort( ... ,a)). -See also: alphamin() +See also: alphamin(), max() & ALPHAMIN() alphamin([, ... , ]) @@ -472,7 +491,7 @@ This is equivilent to first(sort( ... ,a)). -See also: alphamax() +See also: alphamax(), min() & AND() & CAND() and(, [, ... , ]) @@ -791,12 +810,17 @@ > say chr(65) You say, "A" & CLONE() - clone() + clone([, [, ]]) - This function clones , and returns the dbref number of the - clone. + This function clones , as per @clone, and returns the dbref number + of the clone, or #-1 if the object could not be cloned. - This is a side-effect function and may not be enabled on some MUSHes. + The clone will have the same name as the original object unless you give + a for it. Normally, the clone will be created with the first + available dbref, but wizards may give the of a garbage object to + use instead. + +See also: @clone, create(), dig(), open() & CMDS() cmds() @@ -1460,7 +1484,7 @@ > say filter(test/is_odd, 1 2 3 4 5 6) You say, "1 3 5" -See also: anonymous attributes +See also: anonymous attributes, firstof(), allof() & FINDABLE() findable(, ) @@ -1474,7 +1498,7 @@ Returns the first element of a list. -See also: before(), rest(), last() +See also: before(), rest(), last(), firstof(), strfirstof() & FIRSTOF() firstof([, ... , ], ) @@ -1500,7 +1524,7 @@ > say firstof(get(%#/royal cheese),#-1 This Has No Meaning,0,) You say, "" -See also: allof(), BOOLEAN VALUES +See also: allof(), BOOLEAN VALUES, strfirstof(), filter() & FLAGS() flags() flags([/]) @@ -2169,18 +2193,26 @@ See also: first(), rest(), before(), after() & LATTR() & LATTRP() +& REGLATTR() +& REGLATTRP() lattr([/][, ]) lattrp([/][, ]) + reglattr([/][, ]) + reglattrp([/][, ]) - Returns a list of all the attributes on which you can see, and - which match the wildcard . If no is - given, it defaults to "*". Note that this does not include branches in + lattr() returns a list of all the attributes on which you can see, + and which match the wildcard . If no + is given, it defaults to "*". Note that this does not include branches in attribute trees; you must use the "**" wildcard to include those. The resulting list will be separated by , or a space if no separator is given. + + reglattr() returns attributes whose names match the regexp . The + match is not case-sensitive (as attribute names are always upper-case), + and the "`" branch separator has no special meaning in the pattern. - lattrp() also includes attributes inherited from parents. + lattrp() and reglattrp() also include attributes inherited from parents. When returning large numbers of attributes, the results may be truncated due to buffer limits. In these cases, you can use nattr() and xattr() to @@ -2191,18 +2223,27 @@ & NATTRP() & ATTRCNT() & ATTRPCNT() +& REGNATTR() +& REGNATTRP() nattr([/]) nattrp([/]) + regnattr([/]) + regnattrp([/]) nattr() returns the number of attributes on that you can see - which match the given . It is considerably faster - than words(lattr()) and doesn't suffer from buffer length constraints. - It's designed primarily for statistical purposes. + which match the given . It is considerably faster than + words(lattr()) and doesn't suffer from buffer length constraints. It's + designed primarily for statistical purposes. defaults + to "*", which does not include branches in attribute trees; use "**" if + you need to count attribute trees. + + regnattr() matches attribute names against the regular expression . - nattrp() also counts matching attributes on the parent. attrcnt() and - attrpcnt() are aliases. + nattrp() and regnattrp() also count matching attributes on the parent. + + attrcnt() and attrpcnt() are aliases for nattr() and nattrp() respectively. -See also: lattr(), hasattr() +See also: lattr(), hasattr(), xattr(), wildcards & LCON() lcon() @@ -2393,9 +2434,10 @@ loc() For things and players, loc() returns the dbref of the object which - contains . For exits, it returns the destination (the source is - an exits home()). For rooms, it returns the drop-to, if one is set, or - #-1 otherwise. + contains . For rooms, it returns the drop-to, if one is set, or + #-1 otherwise. For exits, it returns the destination (the source is + an exits home()). This will be #-1 for unlinked exits, #-2 for variable + exits, and #-3 for exits @linked to "home". You must be able to examine , or be near it, for this function to work. @@ -2403,7 +2445,7 @@ You can also get the location of the enactor using the %L substitution, whether you are near to/can examine it or not. -See also: locate(), rloc(), home(), where(), rnum(), room() +See also: locate(), rloc(), home(), where(), rnum(), room(), @link & LOCALIZE() localize() @@ -2455,7 +2497,7 @@ & LOCATE2 You can control where to look with: - a - Absolute match (check to see if is a dbref) + a - Absolute match (match against any dbref) c - Exits in the room e - Exits in 's location h - If is "here", return 's location @@ -2510,7 +2552,7 @@ llocks([]) locks() - llocks(), aliased locks(), list locks set on , including + llocks() and locks() both list @locks set on , including user-defined locks (prefixed with USER:) If no object is given, llocks() returns all the predefined lock @@ -2823,7 +2865,7 @@ This function returns the largest number in its list of arguments. It can take any number of arguments. -See also: min(), lmath(), bound() +See also: min(), lmath(), bound(), alphamax() & MEAN() mean([, ... , ]) @@ -2893,7 +2935,7 @@ This function returns the smallest number in its list of arguments. It can take any number of arguments. -See also: max(), lmath(), bound() +See also: max(), lmath(), bound(), alphamin() & MIX() mix([/], , [, ... , , ]) @@ -3134,7 +3176,7 @@ > say namegraball(#0 #1 #2,room) You say, "#0 #2" -See also: namelist(), locate(0 +See also: namelist(), locate() & NAND() & NCAND() nand([, ... , ]) @@ -3793,10 +3835,18 @@ See also: sqrt(), power() & ROUND() - round(, ) + round(, [, ]) Rounds to decimal places. must be between - 0 and config(float_precision). + 0 and config(float_precision). If the optional argument is + true, the result will be padded with 0s if it would otherwise have + fewer than digits after the decimal point. + + Examples: + > think round(3.14159, 2) + 3.14 + > think round(3.5, 3, 1) + 3.500 See also: ceil(), floor(), bound(), trunc() & FN() @@ -4223,8 +4273,8 @@ & SPEAK() & SPEAKPENN() speak(, [, - [, [/] - [, [/][, [, ]]]]]) + [, [/] + [, [/][, [, ]]]]]) This function is used to format speech-like constructs, and is capable of transforming text within a speech string; it is useful @@ -4232,7 +4282,8 @@ If begins with &, the rest of the string is treated as the speaker's name, so you can use it for NPCs or tacking - on titles (such as with @chatformat). + on titles (such as with @chatformat). Otherwise, the name of the object + is used. When only and are given, this function formats as if it were speech from , as follows. @@ -4437,26 +4488,9 @@ If evaluates to a true boolean, then the first call will be with row number 0 and %1-%9 will be set to the field names. - See 'help mapsql2' for examples. + See 'help sql examples' for examples. See also: anonymous attributes, sqlescape(), sql(), @sql -& MAPSQL2 - - > @@ Field, Type, Null?, Key?, Default, Extra - > &each_row me=align(<15 <15 <5 <5 <10 <14,%1,%2,%3,%4,%5,%6) - > &tabledesc me=mapsql(each_row,describe %0,%r,1) - > think u(tabledesc,quotes) - Field Type Null Key Default Extra - quoteid int(11) PRI auto_increment - quote text - - > &each_bb me=(%0) - %1 (%2) - > &query me=SELECT name, count(*) FROM bbs GROUP BY name ORDER BY name - > think mapsql(each_bb, v(query), %r) - (1) - Announcements (5) - (2) - Advertisements (20) - ... etc - & SQL() sql([, [, [, ]]]) @@ -4471,18 +4505,46 @@ is evaluated, so it's useful to either read it from another attribute with u() or use lit() to protect commas. If you will be interpolating user-provided values into the query, be careful to escape - them with sqlescape(), like this: - - > &SEL_GETID obj = SELECT id FROM mytable WHERE name = '[sqlescape(%0)]' - > &DOIT obj = $do *: ... [setq(0,sql(u(SEL_GETID,%0),~,|))] ... + them with sqlescape(). - A query that doesn't return any rows, such as a UPDATE or SELECT that - has no matches will return a null string. + A query that doesn't return any rows, such as an UPDATE or SELECT that + has no matches will return a null string. - If is specified, there is a side-effect: the number of affected + If is specified, and alters the database (such as an + UPDATE or INSERT query), there is a side-effect: the number of affected rows is stored into the specified q-register. + + See 'help sql examples' for examples. See also: sqlescape(), mapsql(), @sql, setq(), r() +& SQL Examples + + Example of using sqlescape() to prevent injection attacks: + > &SEL_GETID obj=SELECT id FROM mytable WHERE name = '[sqlescape(%0)]' + > &DOIT obj=$do *: think setq(0,sql(u(SEL_GETID,%0),~,|)); @@ More cmds + + Using mapsql() to format results: + > @@ Field, Type, Null?, Key?, Default, Extra + > &each_row me=align(<15 <15 <5 <5 <10 <14,%1,%2,%3,%4,%5,%6) + > &tabledesc me=mapsql(each_row,describe `[sqlescape(%0)]`,%r,1) + > think u(tabledesc,quotes) + Field Type Null Key Default Extra + quoteid int(11) PRI auto_increment + quote text + + > &each_bb me=(%0) - %1 (%2) + > &query me=SELECT name, count(*) FROM bbs GROUP BY name ORDER BY name + > think mapsql(each_bb, v(query), %r) + (1) - Announcements (5) + (2) - Advertisements (20) + + Using sql() to update fields: + > &update me=UPDATE `foo` SET `time` = '[sqlescape(%0)]' WHERE + `loc` = '[sqlescape(%1)]' + > &foo me=$foo *: think sql(u(update, %0, %L),,0)%q0 rows updated. + > foo bar + 5 rows updated. + & SQLESCAPE() sqlescape() @@ -4528,9 +4590,8 @@ & STARTTIME() starttime() - Returns a string containing the time the MUSH first started up (not - including @shutdown/reboots). The time is in the same format that the - time() function returns. + Returns the time the MUSH first was last restarted (not including + @shutdown/reboots), in the same format as time(). Example: > say starttime() @@ -4540,8 +4601,9 @@ & RESTARTTIME() restarttime() - Returns a string which is the time the MUSH last rebooted. The time is in - the same format as the time() function returns. + Returns the time the MUSH was last restarted, including @shutdown/reboots, + in the same format as time(). If @shutdown/reboot hasn't been used since + the MUSH was started, this is the same value as starttime(). See also: convtime(), starttime(), restarts() & RESTARTS() @@ -4581,11 +4643,34 @@ Returns the sample standard deviation of its arguments. See also: mean(), median() +& STRFIRSTOF() +& STRALLOF() + strfirstof([, ... , ], ) + strallof([, ... , ], ) + + strfirstof() returns the first which evaluates to a non-empty + string (a string at least 1 character long). If all s evaluate empty, + is returned instead. + + strallof() returns all s which evaluate to non-empty strings, with + each expression separated by . + + Examples: + > say strfirstof(, ,@@(Nothing),foo,default) + You say, "foo" + + > say strfirstof(get(%#/fullname), u(%#/ansiname), %n) + You say, "Mike" + + > say strallof(, ,foo,@@(Nothing),%b,bar|baz,#-1,|) + You say, "foo| |bar|baz|#-1" + +See also: allof(), firstof(), first(), strlen(), cat() & STRINSERT() strinsert(, , ) This function returns , with added before the - character in . Note that the first character in a string is + character in . Note that the first character in is numbered 0, not 1. Examples: @@ -4617,7 +4702,7 @@ > say strlen(foobar) You say, "6" -See also: words() +See also: words(), strfirstof() & STRMATCH() strmatch(, [, ]) @@ -4646,8 +4731,8 @@ & STRREPLACE() strreplace(, , , ) - Returns string with the characters starting at - replaced by . As with other string functions, the first + Returns with the characters starting at + replaced by . As with most other string functions, the first character is at position 0. Example: @@ -4721,12 +4806,16 @@ Examples: > say switch(test, *a*, foo, *b*, bar, *t*, neat, baz) You say, "neat" + > say switchall(ack, *a*, foo, *b*, bar, *c*, neat, baz) You say, "fooneat" + > say switch(moof, *a*, foo, *b*, bar, *t*, neat, baz) You say, "baz" + > say switch(moof, *a*, foo, *b*, bar, *t*, neat, #$) You say, "moof" + > say case(moof, *f, foo, moof, bar, baz) You say, "bar" & SWITCH WILDCARDS @@ -4762,9 +4851,9 @@ definitions of true and false vary depending on the value of the 'tiny_booleans' @config option. See 'help boolean values' for details. -See also: not, if(), cond() +See also: not(), if(), cond(), @break, or(), and() & TABLE() - table(, [, [, [[, ]]]]) + table([, [, [, [, ]]]]) This function returns the elements of in a tabular format. All other parameters are optional. @@ -4797,8 +4886,8 @@ & TEL() tel(, [, [, ]]) - This function will teleport to , exactly as - @teleport =. is an optional boolean that, if + This function will teleport to , exactly as + @teleport =. is an optional boolean that, if true, makes the function act like @teleport/silent. is an optional boolean that, if true, makes the function act like @teleport/inside. @@ -4825,9 +4914,9 @@ other players is restricted to see_all objects. See also: pueblo(), width(), height(), ssl() & TESTLOCK() - testlock(, ) + testlock(, ) - testlock() returns 1 if the would pass the lock defined in + testlock() returns 1 if the would pass the lock defined in as run by the caller, and 0 if it would fail. testlock() evaluates the lock from the caller's perspective. @@ -5038,11 +5127,11 @@ Examples: > say trim(%b%bfoo bar baz%b%b%beek%b%b) - You say, "foo bar baz eek" + You say, "foo bar baz eek" > say trim(***BLAM***,*) - You say, "BLAM" + You say, "BLAM" > say trim(-----> WOW <---,-,r) - You say, "-----> WOW <" + You say, "-----> WOW <" See also: squish(), edit() & TRUNC() @@ -5054,7 +5143,9 @@ does not start with a number, 0 is returned. Example: - say trunc(101Dalmations) + > say trunc(3.141593) + You say, "3" + > say trunc(101Dalmations) You say, "101" val() is an alias for trunc(). @@ -5064,7 +5155,7 @@ type() This function returns the type of an object - one of PLAYER, THING, EXIT, - ROOM or GARBAGE. + ROOM or GARBAGE - or #-1 if the object can't be found. Example: > @create Test @@ -5185,7 +5276,7 @@ may be configured in the MUSH. See also: anonymous attributes, udefault(), get(), ATTRIBUTES, ulocal(), - pfun(), attribute flags + pfun(), attribute flags, @include & UCSTR() ucstr() @@ -5286,7 +5377,6 @@ but is usually slightly more efficient. See also: SUBSTITUTIONS, get(), r(), ATTRIBUTES - & VADD() vadd(, [, ]) @@ -5508,8 +5598,8 @@ Returns the number of the word within where the th character falls. Characters and words are numbered starting with 1, and s between words are treated as belonging to the word that - follows them. If is not within the string, #-1 is returned. - defaults to a space. + follows them. If the list is less than characters long, #-1 is + returned. defaults to a space. Example: > say wordpos(foo bar baz, 5) @@ -5544,12 +5634,16 @@ Examples: > @desc here=wrap(Wrapped paragraph, 72) > @desc here=wrap([space(4)]Indented paragraph, 72) - > @desc here=iter(wrap(Hanging indent, 72, 76, |), - switch(#@, >1, space(4))]##, |, %r) + > @desc here=iter(wrap(Hanging indent, 72, 76, %r), + switch(#@, >1, space(4))%i0, %r, %r) & XATTR() & XATTRP() +& REGXATTR() +& REGXATTRP() xattr([/], , [, ]) xattrp([/], , [, ]) + regxattr([/], , [, ]) + regxattrp([/], , [, ]) xattr() fetches or fewer attribute names from starting at position . It is useful when the number of attributes on an @@ -5559,11 +5653,14 @@ It is equivalent to extract(lattr([/]), , , ) - xattrp() will include attributes from parents. Do note that parent - attributes are listed _after_ child attributes, not sorted + is a wilddcard pattern which defaults to "*". + regxattr() matches attributes against the regular expression . + + xattrp() and regxattrp() will include attributes from parents. Do note that + parent attributes are listed _after_ child attributes, not sorted alphabetically. -See also: nattr(), lattr() +See also: nattr(), lattr(), wildcards & XOR() xor(, [, ... , ]) Index: game/txt/hlp/pennv183.hlp =================================================================== --- game/txt/hlp/pennv183.hlp (.../183p13) (revision 469) +++ game/txt/hlp/pennv183.hlp (.../184p0) (revision 469) @@ -1,16 +1,4 @@ & 1.8.3p13 -& changes -This is a list of changes in this patchlevel which are probably of -interest to players. More information about new commands and functions -can probably be gotten via 'help '. 'help credits' -lists the [initials] of developers and porters that are used in the list -of changes. - -Information about changes in prior releases can be found under -help topics named for each release (e.g. 'help 1.7.2p30'). -A list of the patchlevels associated with each release can -be read in 'help patchlevels'. - Version 1.8.3 patchlevel 13 Feb 13, 2010 Minor Changes: Index: game/txt/hlp/pennv184.hlp =================================================================== --- game/txt/hlp/pennv184.hlp (.../183p13) (revision 0) +++ game/txt/hlp/pennv184.hlp (.../184p0) (revision 469) @@ -0,0 +1,102 @@ +& 1.8.4p0 +& changes +This is a list of changes in this patchlevel which are probably of +interest to players. More information about new commands and functions +can probably be gotten via 'help '. 'help credits' +lists the [initials] of developers and porters that are used in the list +of changes. + +Information about changes in prior releases can be found under +help topics named for each release (e.g. 'help 1.7.2p30'). +A list of the patchlevels associated with each release can +be read in 'help patchlevels'. + +Version 1.8.4 patchlevel 0 May 09, 2010 + +Major Changes: + * Commands can now be restricted with an @lock-style lock in restrict.cnf + and @command/restrict, allowing more complex restrictions. [MG] + +Minor Changes: + * @shutdown/reboot logs who was responsible. Suggested by Kitai. [SW] + * Rewrite of help @lock to improve clarity, by Sketch. + * New NO_LOG flag to disable command logging on a per-object basis. + Based on code by Teal. [SW] + * mindb+maxdb classes for lsearch/@search no longer reset to default + values when > db_top or < 0 is given: Instead treated as an integer + comparison. [GM] + * @open can now open exits in remove locations, as well as your current + location. Suggested by Bane. [MG] + * New OPEN_OK flag allows anyone to open exits in a room, and @lock/open + to restrict who can. Based on patch by ranmir@M*U*S*H. [MG] + * Master Room exits and ZMR exits now run the "goto" command, and @ealias + and @lalias run the "enter"/"leave" commands, so @hooks get run, command + restrictions checked, etc. [MG] + * New @lock/from and @lock/receive locks, to control who can give to an + object, and what objects can be given to them, respectively. From a + suggestion by Nammyung@M*U*S*H, based on locks on ElendorMUSH. [MG] + * Changed the restrictions for valid @function names to match what was + reported by valid(). [MG] + +Commands: + * New @include / command, which inserts into the current + action list. Patch by Javelin. + * @scan can now take multiple switches at the same time. [MG] + * @version now reports the SVN revision of the current version, when + available. Suggested by Paige. [MG] + * @clone can take a garbage dbref for the new object, the same as @create. + Suggested by Dan. [MG] + * 'look' now supports more english-matching (look this foo's 1st bar). [MG] + * You can now look at objects on the other side of transparent exits, with + "look [toward] 's ". Suggested by Trinsec. [MG] + * All wizards can now use @command/add. Suggested by qa'toq. [MG] + * function_alias in alias.cnf now creates a proper alias, not a clone, of + functions. @function/alias added, which does the same in-game. [MG] + * New @command/clone and @function/clone commands, which create copies of + a command/function which initially work the same as, but are independant + of, the originals. Based on suggestion by Bane. [MG] + * Added a comment line to the beginning of @decompile's output showing + the object name and dbref. [MG] + +Functions: + * Added strfirstof() and strallof(), which return the first arg/all args + which are non-empty strings. [MG] + * Added reglattr[p](), regxattr[p]() and regnattr[p](), regexp variants of + lattr[p](), xattr[p]() and nattr[p](). Suggested by Trinsec. [MG] + * The *emit() functions, and cbufferadd(), are now disabled when + function_side_effects are off. Suggested by Cheetah. [MG] + * round() now takes an optional third argument to 0-pad the results if + needed. Suggested by Trinsec. [SW] + * Many functions (particularly ones which take only numbers, dbrefs or + attribute names as arguments) now ignore ANSI in their arguments, rather + than throwing an error. [MG] + * nattr()'s now defaults to *, not **, the same as + lattr() and other attribute functions. [MG] + * clone() can now take a and , as per @clone. [MG] + * cwho() now takes an optional 3rd argument to omit gagged objects. + Suggested by Trinsec. [MG] + +Attributes: + * @outpageformat lets you alter how you view pages that you send. + +Fixes: + * isprint() bug in ord() fixed. [GM] + * Possible crashbug in @destroy fixed. Reported by Dan. [MG] + * Minor bug in benchmark() fixed. [MG] + * channels() was incorrectly sorted for channel names containing + ansi. Reported by Trelane. [MG] + * Help fixes by Teal and others. [MG] + * Minor updates to some README files. [MG] + * Some typos and translation errors fixed by Stoko. + * namelist() now ignores null items. Reported by Minion. [MG] + * The matching code would always perform absolute (dbref) matches, even + when it wasn't told to. [MG] + * Improvements to the match flags used by many pieces of code, hopefully + fixing a number of minor bugs. [MG] + * Paranoid dumps no longer treat ANSI tags as invalid characters in attrs. + Reported by Trelane. [MG] + * The /silent switch for @lemit didn't work. [MG] + * @decompile/db showed '@create ' for THINGs, not '@create ', + and @decomp/name could break. Reported by Paige. [MG] + * Crash bug in locks fixed. Reported by Tanaku. [SW] + Index: game/txt/hlp/penntop.hlp =================================================================== --- game/txt/hlp/penntop.hlp (.../183p13) (revision 469) +++ game/txt/hlp/penntop.hlp (.../184p0) (revision 469) @@ -420,23 +420,25 @@ change the object's characteristics such as flags and attributes. It may also mean that you have the ability to destroy it. - Here are the conditions under which object O controls victim V: - 1. If V is God, O must be God - 2. If V is Wizard, O must be Wizard or God - 3. If O is a Wizard, O controls V - 4. If V is Royalty, O must be Royalty, Wizard or God - 5. If O is MISTRUST, O must be V to control V - 6. If V and O are owned by the same player: - 6a. If V is not TRUST, O controls V - 6b. If V is TRUST, O must be TRUST or the player must be TRUST - 7. If V is on a zone, and isn't a player and isn't TRUST, - O controls V if O passes the zone-lock of the zone. - 8. If V is owned by a SHARED player, and V isn't a player and isn't set - TRUST, O controls V if O passes the zone-lock of the SHARED player. - - Step 7 is skipped if config(zone_control_zmp_only) is on. There's - also one special case: anyone can @link an unlinked exit (at which - point the exit is @chowned to the linker). + These checks are performed, from top to bottom, to see if object O + controls object V: + 1. If O and V are the same object, O controls V + 2. If V is God, O does not control V + 3. If O is a Wizard, O controls V + 4. If V is a Wizard, O does not control V + 5. If V is Royalty and O is not, O does not control V + 6. If V is MISTRUST, O does not control V + 7. If O and V are owned by the same player, and either: + a. V is not set TRUST, or + b. O is set TRUST + then O controls V + 8. If V is a player, or set TRUST, O does not control V + 9. If the zone_control_zmp_only @config option is set to 'No', V is on a + Zone, and O passes the Zone's @lock/zone, O controls V + 10. If V is owned by a SHARED player, and O passes the owner's @lock/zone, + O controls V + 11. If V has an @lock/control, and O passes the lock, O controls V + 12. O does not control V See also: controls(), TRUST, MISTRUST, ZONES, SHARED PLAYERS & COSTS @@ -524,16 +526,17 @@ See also: MYOPIC, OPAQUE, MUSHCODE & DROP-TOS +& DROPTOS When you use the @link command on a room, it sets another room or object as the DROP-TO location. By default, any non-STICKY object that someone drops in the room will automatically be transported to the drop-to location, rather than staying in the room. Any STICKY - object droped in the room will go to its home. + object dropped in the room will go to its home. - If the room is set STICKY, objects dropped in the room will stay - there until the last player leaves/disconnects, at which point they - will be transported as described above. + If the room is set STICKY, objects dropped in the room will stay there + until the last player leaves, at which point they will be transported + as described above. If the room has a @lock/dropto set on it, only objects that pass the lock will be transported (either immediately or when the last player @@ -544,7 +547,7 @@ See also: @link, STICKY, LINK_OK, @lock & %# -& %N +& %n & %~ & %: & ENACTOR @@ -646,49 +649,6 @@ was thus the executor. See also: ENACTOR, CALLER, SUBSTITUTION -& EXITS - An exit is a one-way link that takes you from its source room to its - destination room. To open an exit from a room, you must control that - room. To open an exit to a room, you must either control the room - or it must be set LINK_OK. If an exit is set DARK is will not show - up in the list of obvious exits in a room. - - If an exit is set TRANSPARENT, someone who looks at the exit will - also see the description and contents of the destination room. If an - exit is set CLOUDY, someone who looks at the exit will also see the - contents of the room beyond, but not its description. If an exits is - set -both- CLOUDY and TRANSPARENT, the description but not the - contents will be seen. - - If you have code on an exit (In an @asuccess or the like), note that - [loc(exit)] is the exit's destination, and [home(exit)] is the - exit's starting point. If an exit @emit's something, it will be - heard in the source room. - -(continued in exits2) -& EXITS2 - You can create an exit that sends those who go through it to their - homes by typing '@link =home'. - - Starting with PennMUSH version 1.50p10, exits can have more than one - destination. To make an exit with a variable destination, open the - exit (using @open), then type '@link =variable'. Finally, add - an attribute named 'DESTINATION' to the exit (&destination ), - which will be evaluated for the dbref # of the destination room when - the exit is used. - - For example: - @open South ;s;south - @link s=variable - &destination s=[switch(rand(3),0,#100,1,#101,2,#102)] - - This exit would take you to either room #100, #101, or #102 - depending on the random number. - - Anyone can create variable exits, but the destinations must be to - places that the exit can normally @link to. - -See also: @link, @open, link_ok, CLOUDY, TRANSPARENT, @firstexit & FAILURE FAILURE @@ -833,6 +793,7 @@ (continued in help listening2) & ^ +& ^-LISTENS & LISTENING2 If you need an object to "listen" for more than one pattern, you can also use ^-patterns. These work similar to user-defined commands, @@ -1114,8 +1075,8 @@ (continued in help powers2) & POWERS2 & POWERS LIST2 - no_pay Doesn't need money for anything - no_quota Has an unlimited quota + no_pay * Doesn't need money for anything + no_quota * Has an unlimited quota open_anywhere Can @open a link from any room. pemit_all Can @pemit to HAVEN/ulocked players. player_create Can use @pcreate command. @@ -1129,8 +1090,11 @@ sql_ok Can perform SQL queries tport_anything Can @teleport anything. tport_anywhere Can @teleport to anywhere. - unkillable Can not be killed + unkillable * Cannot be killed can_nspemit Can use @nspemit and nspemit() + + * When these powers are set on a player, all the objects they own which + are not set MISTRUST are also considered to have the power. See also: help @power, and especially @power/list & PUPPETS @@ -1343,11 +1307,11 @@ (sens|respons)e and \1ibility - matches "sense and sensibility" and "response and responsibility", but - not "sense and responsibility". + matches "sense and sensibility" and "response and responsibility", but + not "sense and responsibility". - You can give names to subpatterns and refer to them that way instead of using - numbers. + You can give names to subpatterns and refer to them that way instead of + using numbers. (?Psubexpr) (Note: Literal <>'s) is a named capture, and (?P=NAME) refers back to it. The above pattern might be written: @@ -1754,41 +1718,62 @@ file for that command. (If you are looking for information on @switch, see 'help @switch'.) & TYPES OF OBJECTS +& TYPES +& OBJECTS - Everything on a MUSH is an object in the MUSH database. There are - four types of objects: players, rooms, exits, things. You can see - the type of an object when you 'examine' it, or with the 'type()' - function. + Everything on a MUSH is an object in the MUSH database. There are four + types of objects: players, things (once called 'objects'), rooms and exits. + You can see the type of an object when you 'examine' it, or with the + type() function. + + For more information on any of the types, see 'help '. - Unique Characteristics - PLAYERS - Can own other objects and can be connected to. Can receive @mail. - Can move around, speak/pose/emit, enter MUSH commands, enter - global $-commands. You can have $-commands on a player, but not - ^-patterns. Players can be carried, can carry other objects, and - can follow. - ROOMS - Fixed container objects, linked together by exits. Cannot move. - Rooms can enter MUSH commands and execute global $-commands. You - can have $-commands and ^-patterns on a room. - -(continued in help TYPES2) -& TYPES2 - EXITS - Objects that link rooms and things together. Cannot move, but can - be @teleport-ed to a new location. Exits can enter MUSH commands - and execute global $-commands. You can NOT have $-commands or - ^-patterns on exits. Exits can lead TO things (if the - link_to_object @config option is true), but they can only lead - FROM rooms. +See also: type(), hastype() +& PLAYERS - THINGS - Can move around, speak/pose/emit, enter MUSH commands, enter - global $-commands. Can send @mail as themselves. You can have - $-commands and ^-patterns on things. Things can carry, be carried, - and can follow. + Players can be created at the login screen (or with @pcreate) and connected + to. They can also receive @mail, and have a number of attributes set on + them by the MUSH automatically, including LAST, LASTSITE, etc. They can + have multiple @aliases, and are checked for $-commands and ^-listens. + + @linking a player sets their home. -See also: EXITS, USER-DEFINED COMMANDS, LISTENING, GLOBALS +See also: TYPES OF OBJECTS, type(), hastype(), @pcreate +& ROOMS + + Rooms are outermost-containers: they cannot be moved. They are created + with @dig. Rooms can contain exits. They are checked for $-commands and + ^-listens. Rooms do not have aliases. + + @linking a room creates a drop-to. Rooms have no location; loc() on a room + returns its drop-to (as does home()). + +See also: TYPES OF OBJECTS, type(), hastype(), @dig, DROP-TOS +& THINGS + + Things are created with @create. They can move around the MUSH, be entered + and carried. They are checked for $-commands and ^-listens. Things do not + have aliases. + + @linking a thing sets its home. + +See also: TYPES OF OBJECTS, type(), hastype(), @create +& EXITS + + Exits are created with @open. They link rooms together, and can be used by + players and things to move from one room to another with the GOTO command. + Exits cannot move (though they can be @teleported to another room). They + can have multiple aliases as part of their @name. They are NOT checked for + $-commands or ^-listens. + + You can change the destination of an exit with the @link command. home() + returns the source room of an exit, and loc() returns its destination. + + Setting an exit CLOUDY and/or TRANSPARENT causes its destination's + description and/or contents to be shown after the exit's description when + looked at. + +See also: TYPES OF OBJECTS, type(), hastype(), @open, @link & $-COMMANDS & MACROS & USER-DEFINED COMMANDS @@ -1842,11 +1827,47 @@ See also: STACK, SUBSTITUTIONS, @lock & VERBS - For most verbs there are three forms: Verb (what the Enactor sees), - Overb (what others in the area see) and Averb (the action to be - taken when the event happens). Example: @Drop, @Odrop and @Adrop + Verb attributes are ones which are shown (or triggered) when you use a + particular command, or perform a certain action. There are normally three: + the 'verb' attribute (shown to the enactor), the 'overb' attribute (shown + to others in the enactor's location), and the 'averb' attribute (an action + list which is triggered). One example is @use, @ouse, and @ause, which are + shown/triggered when the 'use' command is run on an object. - You can create your own verbs with the @verb command. See help @verb. + Some verbs which involve movement have a fourth attribute, 'oxverb', shown + in the enactor's old location (for example, @oxmove), while some verbs have + less (for example, @oname/@aname are shown when an object's name changes, + but there is no @name attribute). + + You can create your own verbs for softcoded commands/actions with the + @verb command. + + Continued in 'help verbs2'. +& VERBS2 +& NONAME +& NOSPACE + + Normally, the enactor's name and a space are prepended to the 'overb' and + 'oxverb' attributes automatically. The NOSPACE attribute flag prevents a + space being placed between the name and attribute value, and the NONAME + attribute flag stops the name being added at all. + + Example: + > @ouse Foo=has used Foo! + > use Foo + Sketch has used Foo! + + > @ouse Foo=;'s used Foo! + > @set Foo/ouse=nospace + > use Foo + Sketch's used Foo! + + > @ouse Foo=Foo has been used by %n! + > @set Foo/ouse=noname + > use Foo + Foo has been used by Sketch! + +See also: @verb, attribute flags & WARNINGS If the building warning system has been enabled in the source code, @@ -2031,19 +2052,24 @@ @function. In the config file, the syntax is: - restrict_command command-name restriction [" ] - restrict_function function-name restriction + restrict_command [" ] + restrict_function From the game: - @command/restrict command-name=restriction [" ] - @function/restrict function-name=restriction + @command/restrict = [" ] + @function/restrict = For commands, if is given, that message is sent to the player who runs it instead of a generic, unhelpful error message. -(Continued in restrict2) + Continued in 'help restrict2'. & RESTRICT2 - can be one of the following: + + For commands, should be an @lock-style boolexp (though, + for backwards compatability, the restrictions below can be used, and will + be converted into an @lock automatically). For functions, + should be any combination of the phrases below. + god Command or function is usable only by God. wizard Usable only by wizards. admin Usable only by Wiz/Roy. @@ -2052,27 +2078,43 @@ noguest Usable only by non-guest @powered objects. nobody Nothing can use it. Same as the /disable switch to @command or @function. + logname When used, log cmd/fun name, and who is using it + logargs When used, log cmd/fun name and args, and who is using it + + Functions only: noparse Function arguments are not evaluated. Only applies to @functions. localize %q-registers are saved/restored when evaluating, as if the @function were wrapped in localize(). userfn Function can only be called from within an @function. - Commands can also use the 'noplayer' restriction, which stops player - objects from using the command, as well as any generic or any - . + Commands only: + noplayer Cannot be used by players. + Commands can also give any flag, power or type, to restrict to + objects with one of those flags or powers, or of one of those types. -(Continued in restrict3) + Continued in 'help restrict3'. & RESTRICT3 - In cases where there are a function and command that do the same - thing (Like pemit() and @pemit), the command's restrictions are also - checked when the function is called, so restricting @pemit also - restricts pemit(). However, a function's restrictions are not checked - when a command is called, to allow disabling side-effect functions. + In cases where there are a function and command that do the same + thing (like pemit() and @pemit), the command's restrictions are also + checked when the function is called, so to use pemit() you must also be + able to use @pemit. However, a function's restrictions are not checked + when a command is called, to allow disabling side-effect functions. - Some functions (Like name()) have non-side-effect and side-effect - versions depending on how many arguments they're called with. The - side-effect version can be disabled while keeping the safe - non-side-effect form with the 'nosidefx' restriction. This can also - be used to disable pure side-effect functions. + Some functions (like name()) have non-side-effect and side-effect + versions depending on how many arguments they're called with. The + side-effect version can be disabled while keeping the safe + non-side-effect form with the 'nosidefx' restriction. This can also + be used to disable pure side-effect functions. + + Examples: + Only allow admin to use ansi(): + > @function/restrict ansi=admin + + Don't let anyone set SUSPECT or GAGGED use @emit, and log the name of + anyone who uses it. + > @command/restrict @emit=logname + > @command/restrict @emit=!flag^suspect&!flag^gagged + +See also: @command, @function, @lock Index: game/txt/hlp/penncmd.hlp =================================================================== --- game/txt/hlp/penncmd.hlp (.../183p13) (revision 469) +++ game/txt/hlp/penncmd.hlp (.../184p0) (revision 469) @@ -151,20 +151,25 @@ > @death me=You have just slain Cyclonus! > @odeath me=falls to the ground and vanishes. -See also: kill, BEING KILLED, ACTION LISTS +See also: kill, BEING KILLED, ACTION LISTS, VERBS & @adescribe +& @odescribe + @odescribe [=] @adescribe [=] - - Sets the adescribe attribute on , which is triggered whenever - someone looks at it. A common use of this command is: - - @adescribe me=think %n just looked at you. - - which will inform you whenever someone looks at you. While it is possible to - set a message to be broadcasted to everyone in the area when someone looks - at you, this is strongly discouraged, as many people find it annoying. - -See also: @describe, @aidescribe, look, ACTION LISTS + + These attributes contain the message shown to others in the enactor's + location when he looks at , and the actions to be taken by + when someone looks at it. (See 'help @describe' for the attribute shown + to the enactor when he looks at .) When the enactor is inside + , the @oidescribe and @aidescribe attributes will be used instead, + if set. Please note that using these attributes to show long messages is + often found annoying. + + Examples: + > @odescribe Walker=glances at Walker and sniggers. + > @adescribe me=think %n just looked at you. + +See also: look, @describe, @idescribe, ACTION LISTS & @adestroy @adestroy [=] @@ -204,8 +209,8 @@ in. The @adrop attribute is triggered when is dropped. When is an exit, @drop is shown to objects going through , - and @odrop is shown to objects in the exit's destination. @adrop is triggered - when someone passes through the exit. + and @odrop is shown to objects in the exit's destination. @adrop is + triggered when someone passes through the exit. Example: > @drop Box=You put the box down gently. @@ -213,7 +218,7 @@ > @odrop South=arrives from the North. -See also: drop, empty, ACTION LISTS, @success +See also: drop, empty, ACTION LISTS, VERBS, @success & @aefail & @oefail & @efail @@ -224,8 +229,8 @@ These attributes contain the message shown to someone who fails to enter , the message shown to others when someone fails to enter , and the actions to be taken when someone fails to enter it, respectively. - -See also: enter, @enter, FAILURE, ACTION LISTS + +See also: enter, @enter, FAILURE, ACTION LISTS, VERBS & @aufail & @oufail & @ufail @@ -238,7 +243,8 @@ Note that these attributes are @ufail, NOT @ufailure, for TinyMUSH compatibility. - + +See also: use, @use, FAILURE, ACTION LISTS, VERBS & @afailure & @ofailure & @failure @@ -255,7 +261,7 @@ "look" inside the room, though failure to pass the lock does not prevent the object from looking. -See also: get, move, EXITS, @lock, ACTION LISTS +See also: get, move, @lock, ACTION LISTS, VERBS, @succ & @follow & @ofollow & @afollow @@ -269,7 +275,7 @@ of the person following is automatically prepended to the @ofollow message. -See also: follow, unfollow, @unfollow, followers(), ACTION LISTS +See also: follow, unfollow, @unfollow, followers(), ACTION LISTS, VERBS & @unfollow & @ounfollow & @aunfollow @@ -283,34 +289,35 @@ of the person stopping following is automatically prepended to the @ounfollow message. -See also: follow, unfollow, @follow, followers(), ACTION LISTS +See also: follow, unfollow, @follow, followers(), ACTION LISTS, VERBS & @ahear -& @aahear & @amhear +& @aahear @ahear [=] - @aahear [=] @amhear [=] + @aahear [=] Sets the actions to be taken after the object's @listen is matched. @ahear will only be triggered by sound made by other objects, and - @amhear is only triggered by sound made by itself. @amhear + @amhear is only triggered by sound made by itself. @aahear will be triggered by all matching sound, regardless of the source. See also: @listen, LISTENING, ACTION LISTS & @leave & @oleave +& @oxleave & @aleave @leave [=] @oleave [=] + @oxleave [=] @aleave [=] These attributes contain the message shown to anyone leaving , - the message shown to others inside when someone leaves it, - and the actions to be taken by when someone leaves it, respectively. - The name of the object leaving is automatically added to the beginning of - the @oleave message. + the message shown to others inside when someone leaves it, the + message shown to others in 's location when someone leaves it, and + the actions to be taken by when someone leaves it, respectively. -See also: leave, @oxleave, @lfail, ACTION LISTS, +See also: leave, @oxleave, @lfail, ACTION LISTS, VERBS & @lfail & @olfail & @alfail @@ -326,30 +333,26 @@ Such a failure usually occurs because is set NO_LEAVE, or because the person trying to leave does not pass 's @lock/leave. -See also: leave, @leave, NO_LEAVE, locktypes, ACTION LISTS +See also: leave, @leave, NO_LEAVE, locktypes, ACTION LISTS, VERBS & @alias - @alias [=[;[; ... ; ]]] + @alias [=[;[;...;]]] + @alias [=] - @alias is a special attribute that lists a player's aliases; players - can be paged by their aliases, matched with *, and all other game - functions which look up player names will also accept an alias. The - attribute is visible to all players. - - Players can have more than one alias, separated by semicolons. It's - recommended that you include your normal @name in your alias; because you - can @name yourself to one of your aliases, it ensures that, if you change - your name, others can still refer to you by your normal/original name. + For players, the ALIAS attribute has special meaning: it contains a list + of aliases (separated by semicolons) which can be used instead of his name + to refer to the player. - The maximum number of aliases a player may have is controlled by the - 'max_aliases' @config option. + The number aliases allowed is controlled by the 'max_aliases' @config + option. The same rules which apply to player names also apply to aliases, + and you cannot use another player's name as your alias (though you can + include your own name in your aliases, and can change your name to one of + your aliases). If the page_aliases @config option is on, the first alias in the list is shown along with the player's name when they page others. - The same rules that apply to player names apply to aliases. - - @alias only has an effect on players, though you can set them on other - types as well. (An exit's aliases are part of its name; see 'help @name'.) + For other types of object, @alias has no special meaning. (Exit aliases + are part of the exit's name - see 'help @name' for details.) See also: @name, alias(), fullalias() & @allquota @@ -364,22 +367,25 @@ See also: @quota, @squota & @move & @omove +& @oxmove & @amove @move [=] @omove [=] + @oxmove [=] @amove [=] - These attributes contain the message shown to immediately after it - moves, the message shown to others in the room moves into, and - the actions to be taken when moves, respectively. 's name - is added automatically to the beginning of the @omove message. Please note - that long @omoves are frequently found annoying. + These attributes contain the message shown to immediately after + it moves, the message shown to others in the room moves into, the + message shown to objects in the location leaves, and the actions + to be taken when moves, respectively. Please note that long + @omoves are frequently found annoying. Example: > @move me=You moved! You are now in the room: [name(here)]. > @omove me=stalks into the room wearing a malevolent expression. + > @oxmove me=stalks away, glaring. -See also: goto, @oxmove, ACTION LISTS +See also: goto, @oxmove, ACTION LISTS, VERBS & @aenter & @enter & @oenter @@ -400,7 +406,7 @@ > @oxenter Sofa=sits down on the sofa. It looks comfy. > @aenter Sofa=@pemit/silent owner(me)=%n sat down on [name(me)]! -See also: enter, @ealias, leave, ACTION LISTS +See also: enter, @ealias, leave, ACTION LISTS, VERBS & @apayment & @payment & @opayment @@ -418,7 +424,7 @@ > @opayment Collecting Tin=makes a donation to charity. > @apayment Collecting Tin=&%# me=%0 at [time()] -See also: give, @cost, buy, MONEY, ACTION LISTS +See also: give, @cost, buy, MONEY, ACTION LISTS, VERBS & @atport & @tport & @otport @@ -441,7 +447,7 @@ > @otport me=appears in a puff of smoke. > @oxtport me=disappears in a puff of smoke. -See also: @teleport, ACTION LISTS +See also: @teleport, ACTION LISTS, VERBS & @atrchown @atrchown /= @@ -491,12 +497,9 @@ > @success Box=You pick up the box. > @osuccess Box=picks up the box. -See also: get, goto, @lock, SUCCESS, FAILURE, @odrop, ACTION LISTS +See also: get, goto, @lock, SUCCESS, FAILURE, @odrop, ACTION LISTS, VERBS & @attribute @attribute - @attribute/access[/retroactive] = - @attribute/delete - @attribute/rename = The @attribute command displays and modifies the MUSH's standard attributes (see "@list/attribs" for a list of them). @@ -506,20 +509,29 @@ *** they are run at each startup. The first form of the command displays the full name of the attribute - , along with the its attribute flags, and the dbref of the player - who added it to the attribute table. + , along with the its attribute flags, and the dbref of the object + which added it to the attribute table. + + Continued in 'help @attribute2'. +& @attribute2 + @attribute/access[/retroactive] = + @attribute/delete + @attribute/rename = @attribute/access adds as a new standard attribute, with the default attribute flags . If is already a standard attribute, this command modifies its default attribute flags. Use "none" - for if you don't want any default attribute flags. If the - /retroactive switch is given, all existing copies of the attribute will be - @atrchown'd to the player running the command, and will have its flags - changed to . + for if you don't want any default attribute flags. + + If the /retroactive switch is given with /access, all existing copies of + the attribute will be @atrchown'd to the player running the command, and + will have its flags changed to . @attribute/delete removes a standard attribute from the table. @attribute/rename renames a standard attribute. + Only Wizards can modify the attribute table. + See also: ATTRIBUTEs, STANDARD ATTRIBUTES, attribute flags, @set, @atrchown & @ause & @use @@ -542,7 +554,7 @@ > @ause Jack-In-The-Box=@wait 3=POSE pops up with a bang! > use Jack-In-The-Box -See also: use, @charges, @runout, ACTION LISTS +See also: use, @charges, @runout, ACTION LISTS, VERBS & @away @away [=] @@ -574,8 +586,8 @@ Only admin and those with the "boot" power can @boot other players. See also: QUIT, LOGOUT -& @BREAK -& @ASSERT +& @break +& @assert @break [=] @assert [=] @@ -585,7 +597,8 @@ don't like @switch. If is given, it is executed instead of the rest of the commands in the current action list. - @assert does the inverse: it stops execution if evaluates to false. + @assert does the inverse: it stops execution if evaluates to + false. Examples: > @va obj=$testme *: @pemit %#=You try a test ; @@ -672,7 +685,7 @@ > @chown here=me (for a room) > @chown box=Soundwave (for a thing) -See also: CHOWN_OK, Zone Masters, @chownall +See also: CHOWN_OK, Zone Masters, @chownall, owner() & @chownall @chownall[/preserve] [=] @@ -704,16 +717,18 @@ Continued in 'help @chzone2'. & @chzone2 - To see the Zone of an object, you can use either 'brief' or 'examine' to examine it. The Zone is listed on the same line as the Owner of the object. - Players can @chzone objects they own if they own the zone master or + Players can @chzone objects they own if they own the zone object or if they pass its @lock/chzone. Wizards can @chzone objects to any - zone master as long as the object has a zone-lock. + zone. + + If does not have a Zone @lock when something is @chzoned to it, the + lock is automatically set to = (see 'help @lock' for more info). - Whenever an object besides a player is @chzoned to a zone master, the + Whenever an object besides a player is @chzoned to a zone object, the WIZARD, ROYALTY, and TRUST flags will be reset, as will all @power's (for security purposes). For similar reasons, it is strongly recommended that you do not @chzone admin- or wizard-owned objects to any zone @@ -721,16 +736,16 @@ See also: ZONES, @chzoneall, zone() & @chzoneall - @chzoneall = + @chzoneall = - Changes the zone of all objects owned by to . + Changes the zone of all objects owned by to . If is "none", the zone is reset to NOTHING. Only wizards may use this command. See also: @chzone, ZONES & @clone - @clone [=] - @clone/preserve [=] + @clone [=[, ]] + @clone/preserve [=[, ]] This command creates a copy of . The clone will have the same name as the original unless a is given for it. You can only clone @@ -749,6 +764,9 @@ Normally, the Wizard and Royalty flags, @powers and @warnings are stripped from the cloned object, but Wizards may use the /preserve flag to prevent this. + + The clone will normally be created with the first available dbref, but + Wizards may specify the of a garbage object to use that instead. To clone a room and all its exits, use code like: > @teleport setq(0,%L)[clone(here)] @@ -759,6 +777,7 @@ @command @command/ @command/alias = + @command/clone = @command/restrict = @command can be used for adding new built-in commands, altering the way @@ -769,7 +788,9 @@ about how a command is parsed. The /alias switch creates an alias for , allowing players to type - to run . + to run . The /clone switch creates a separate copy of + , which works the same initially but can be restricted, @hooked, + etc, separately. @command/restrict can be used to restrict who can use . See 'help restrict' for more information. @@ -787,7 +808,7 @@ @command/add is a powerful tool that lets you create new commands which are matched before normal $-commands, and which can be set not to parse their arguments, but (via @hook) can still execute softcode like an - $-command. Only God can @command/add or @command/delete. + $-command. Only Wizards can @command/add, and only God can @command/delete. You can use these additional switches, along with @command/add, to control how the new command parses its arguments: @@ -807,6 +828,7 @@ are never case-sensitive. See 'help @command3' for examples. +See also: @hook, RESTRICT, EVALUATION ORDER & @command3 Examples: > @create Dining Machine @@ -826,8 +848,6 @@ Walker drinks aet. > drink/noeval reverse(tea) Walker drinks reverse(tea). - -See also: @hook, RESTRICT, EVALUATION ORDER & @comment @comment [=] @@ -872,6 +892,32 @@ See also: look, @exitformat, @nameformat, @descformat, @invformat, @idescformat +& @include + @include /[=,,...] + + @include inserts the contents of the attribute provided into the + action list in-place, without adding a new queue entry. It is + useful to avoid having to copy the same code into multiple commands. + The attribute to be included must be visible to the enactor. + + Example: + &CHECKS me=@assert [orflags(%#,Wr)]; @break [gt(words(lwho()),%0)] + &CMD1 me=$cmd *: @include me/CHECKS; @pemit %#=You passed. + &CMD2 me=$othercmd *: @include me/CHECKS; @@ Do something else... + + When including attribute contents, @include ignores any ^...: or $...: + at the start, so the CHECKS attribute above could also be written + like this, to allow for "unit testing": + + &CHECKS me=$testchk *: @assert [orflags(%#,Wr)]; + @break [gt(words(lwho()),%0)] + + The including environment (%0-%9) is available to the included actions. + If arguments are provided to @include, they are substituted for the + environment's %0, %1, etc. while the included action list is running. + The environment is then restored after the @include. + +See also: @trigger, ufun(), @break & @invformat @invformat [=] @@ -960,14 +1006,16 @@ See also: look, @exitformat, @conformat, @descformat, @nameaccent, @invformat, @idescformat & @cost - @cost [=] + @cost [=] The COST attribute contains the number of pennies that must be given to - to trigger its @pay/@opay/@apay attributes. If less than this + to trigger its @pay/@opay/@apay attributes. If less than this amount is given, the money will be refused, and if more is given, the difference is refunded. This attribute is evaluated, with the amount being given passed as %0. + It is only checked for THING-type objects; pennies can always be given + to other types of object. Example: > @cost Exit Machine=10 @@ -1012,19 +1060,19 @@ & @create @create [=[,]] - Creates a thing with the specified name. Creating a thing costs - a certain amount of MUSH money, which usually defaults to 10 pennies (see - '@config object_cost'). You can specify a higher cost if you wish, but not - a lower one. This cost is refunded if you @destroy the thing. + This command creates a new thing called . Creating an object costs + a certain number of pennies (see '@config object_cost'); you can specify + a higher cost if you wish. This cost is refunded to you when the object + is destroyed. - Some MUSHes choose to limit the number of objects you can create by setting - a quota. + Some MUSHes choose to limit the number of objects you can create by + setting a quota. Wizards can also specify the of a garbage object to use when creating the object. Otherwise, the object is given the next available dbref. -See also: give, @quota, MONEY +See also: give, @quota, MONEY, @clone, create(), @dig, @open, @pcreate & @dbck @dbck @@ -1051,13 +1099,13 @@ @decompile[/] [=] @decompile[/] /[=] - This command produces a list of the commands that you would have to - enter in order to recreate . Useful for either copying objects - from one MUSH to another, or for making logs of important objects to - protect against an accidental @nuke or a crash. + @decompile outputs a list of the commands that you would have to enter + in order to recreate . Useful for either copying objects from + one MUSH to another, or for making logs of important objects to protect + against an accidental @nuke or a crash. - If a is given, all output lines will be prefixed with . - This is useful for creating client-side scripts for editting code. + All output lines are prefixed with , if one is given. This is + useful for creating client-side scripts for editing code. You can either @decompile an entire object, or just certain parts of it. To @decompile just a few attributes, for example, you could type: @@ -1128,10 +1176,10 @@ The description can be formatted using the @descformat attribute. This is particularly useful for @parents and ancestors. - When inside a thing or player, you will see it's @idescribe instead, if + When inside a thing or player, you will see its @idescribe instead, if one is set. - @describe can be abbreviated as @desc + @describe can be abbreviated as @desc. See also: look, @adescribe, @idescribe, @descformat & @destroy @@ -1149,8 +1197,8 @@ for destruction as well. If is a player, and the @config option destroy_possessions is on, everything he owns is marked for destruction as well. (If really_safe is also on, his SAFE objects will not be destroyed.) - If the adestroy @config option is on, the ADESTROY attribute will be triggered - when the object is first @destroy'd. + If the adestroy @config option is on, the ADESTROY attribute will be + triggered when the object is first @destroy'd. The MUSH checks for GOING objects every ten minutes or so (see '@config purge_interval'); each one is set with the GOING_TWICE flag, and will be @@ -1160,7 +1208,7 @@ When an object is destroyed, any commands, @waits and semaphores it has queued are drained, and the object's owner has the quota for the object, - and the cost of creating it initially, refunded. + and the initial cost of creating it, refunded. Continued in 'help @destroy2'. & @destroy2 @@ -1191,31 +1239,31 @@ /teleport switch is given, you will be teleported to the room after it's created, as per the @teleport command. - If is given, the MUSH will automatically open an exit named from your - current location to the new room named , if you have permission. - You can also specify , to create an exit from the new room back - to your current location. Opening exists also costs pennies; see '@config - exit_cost'. The exit names may contain multiple aliases, separated with - semicolons. + If is given, the MUSH will automatically open an exit from your + current location to the new room named , if you have permission. + You can also specify , to create an exit from the new room back + to your current location. Opening exists also costs pennies; see + '@config exit_cost'. The exit names may contain multiple aliases, separated + with semicolons, as per 'help @name'. See 'help @dig2' for examples. & @dig2 Examples: - >@dig Kitchen + > @dig Kitchen This command will create a new room named 'Kitchen'. You will be informed - what the dbref# of this room is. + what the dbref of this room is. - > @dig Kitchen=Kitchen ;n;north;kitchen;k + > @dig Kitchen=Kitchen ;n;north;kitchen;k This will create the room as above, and also open an exit leading to it named "Kitchen " with the aliases n, north, kitchen and k. It will NOT create an exit coming back from the Kitchen room. - > @dig Kitchen=Kitchen ;n;north;kitchen;k, Out ;s;south;out;o + > @dig Kitchen=Kitchen ;n;north;kitchen;k, Out ;s;south;out;o This will do just the same as the above, except it will also create an exit named "Out " with the aliases s, south, out and o coming back from the kitchen to whatever room you are currently in. -See also: @open, @link, EXITS, @create, DBREF +See also: @open, @link, EXITS, @create, DBREF, dig() & @doing @doing @doing/header @@ -1235,7 +1283,7 @@ in which case it is a -separated list. If the string "##" appears anywhere in , it will be replaced - with the current element of . The string "##" is replaced with the + with the current element of . The string "#@" is replaced with the position of the current element in the list. If the /notify switch is given, the command "@notify me" is queued after @@ -1262,7 +1310,7 @@ If the /all switch is given, then all queue entries associated with the selected semaphore(s) are discarded, and the semaphore attribute(s) are cleared. Otherwise, only the indicated of queue entries are - discarded. If no is given, then the /all switch is assumed. + discarded. If no is given, then the /all switch is assumed. You may not specify both the /any switch and a specific attribute. Similarly, you may not specify both the /all switch and a number. @@ -1289,7 +1337,7 @@ configured to do forking dumps (see "@config forking_dump"). These switches should ONLY be used if a normal @dump is not being done - correctly. They should generally only be done by wizards with access to + correctly. They should generally only be done by wizards with access to the account on which the MUSH is running, since others will not have access to the checkpoint log file. @@ -1407,7 +1455,7 @@ Zone entry is assumed to occur before room entry, so these are triggered before the room's @[oa]enter. -See also: @zleave, ZONES, @zemit, zwho() +See also: @zleave, ZONES, @zemit, zwho(), VERBS & @zleave & @ozleave & @azleave @@ -1431,7 +1479,7 @@ Zone leaving is assumed to occur after room leaving, so these are triggered after the room's @[oa]leave. -See also: @zenter, ZONES, @zemit, zwho() +See also: @zenter, ZONES, @zemit, zwho(), VERBS & @entrances @entrances[/] [][=[, ]] @@ -1500,7 +1548,8 @@ See 'help @filter2' for an example. -See also: AUDIBLE, @infilter, attribute flags, LISTENING, @forwardlist +See also: AUDIBLE, @infilter, attribute flags, LISTENING, @forwardlist, + @prefix & @filter2 Example: @@ -1533,7 +1582,8 @@ results more complexly. See also: @search, lsearch(), @entrances -& @FORWARDLIST +& @forwardlist +& forwardlist @forwardlist [=] If is set AUDIBLE, any sound it hears which passes its @filter @@ -1547,12 +1597,14 @@ control you, use @lock/forward me=$me) See also: @filter, @prefix, AUDIBLE, PUPPET, @debugforwardlist, @lock -& @DEBUGFORWARDLIST -& DEBUGFORWARDLIST +& @debugforwardlist +& debugforwardlist @debugforwardlist [=] - When is set DEBUG, the debug output is forwarded to all the dbrefs - in its @debugforwardlist attribute. + When has an @debugforwardlist attribute set, any debug output it + produces (either because it has the DEBUG flag set, or because an attribute + with the DEBUG attribute flag is evaluated) is forwarded to all the dbrefs + listed in the debugforwardlist. The @debugforwardlist must be a space-seperated list of dbrefs. In order to forward to an object, you must either control it, have the pemit_all power, @@ -1572,10 +1624,9 @@ Continued in 'help @force2'. & @force2 - Normally, the action list is parsed for function evaluation and - substitutions twice - once when @force is run, once when runs the - action list. If the /noeval switch is given, is not evaluated - until it is run by . + Normally, the action list is evaluated twice - once when @force is run, and + again when runs the action list. If the /noeval switch is given, + is not evaluated until it is run by . Examples: > @create Lackey @@ -1588,7 +1639,7 @@ > #103 page Cyclonus=Whee Lackey pages: Whee -See also: PUPPET, DBREF +See also: PUPPET, DBREF, objeval() & @flag @flag @flag/list [] @@ -1619,7 +1670,9 @@ flag table. It requires the exact flag name or alias to be used. Be very very careful with this. -See also: help flags. See help @flag2 for information on @flag/add + See 'help @flag2' for information on @flag/add. + +See also: FLAGS, @set, @power, flag permissions & @flag2 @flag/add is used to add a new flag with the given name. Arguments other than the flag name are optional: @@ -1655,7 +1708,7 @@ can see the flag on an , and are given along with the in @flag/add. By default, anyone can see the flag: - dark must be Only God (#1) to see the flag on objects. + dark must be Only God (#1) to see the flag on objects mdark must be WIZARD or ROYALTY odark must own the (or be WIZARD or ROYALTY) @@ -1666,11 +1719,13 @@ & @function @function [] - @function[/preserve] =,[,, - [,]] - or @function =/ + @function[/preserve] =, [, , + [, ]] + @function =/ @function/ @function/restrict[/builtin] = + @function/alias = + @function/clone = When used without any arguments, this command lists all global user-defined functions. For wizards and others with the Functions @@ -1681,14 +1736,20 @@ how that function is parsed, and how many arguments it takes. can be one of: - /disable, to disable a built in function. + /disable, to disable a built-in function. /enable, to re-enable it. /delete, to remove a user-defined function. /restrict, to change the restriction flags on an existing function. + + @function/alias creates an alias for the built-in function + so that it can also be called as . @function/clone creates a new + copy of named , which works the same initially but + can be restricted separately. You cannot alias or clone @functions. Otherwise, this command defines a global function with the name , which evaluates to on . -(continued in help @function2) + + Continued in 'help @function2'. & @function2 can be anything that the player using the @function command controls (if safer_ufun is enabled) or can examine (if not). @@ -1713,115 +1774,118 @@ Example: > &WORD_CONCAT #10=%0 %1 - > say "[ufun(#10/word_concat,foo,bar)] + > say u(#10/word_concat, foo, bar) You say, "foo bar" - > @function word_concat = #10, word_concat - > say "[word_concat(foo,bar)] + > @function word_concat=#10, word_concat + > say word_concat(foo,bar) You say, "foo bar" -(continued in help @function3) + Continued in 'help @function3'. & @function3 Global user-defined functions are not automatically loaded when the game is restarted. In order to avoid objects which attempt to use functions that have not been loaded, a @startup containing @function commands should be set on a wizard object with as low a dbref number - as possible; object #1 (generally God) is suggested for this use. + as possible; God (#1) is suggested for this use. For example, if you have one object that stores all your global functions, you could set the following command (the object is #100 in the example): - @startup #1=@dol lattr(#100)=@function ##=#100,## + @startup #1=@dolist lattr(#100)=@function ##=#100,## And then store each function as an attribute of the same name on object #100. -(continued in help @function4) + + Continued in 'help @function4'. & @function4 - Normally, built in functions cannot be overriden by @functions. - However, if a built-in function is deleted with @function/delete, you - can then make a @function with the same name. "Deleted" built-ins can - still be called through the FN() function, and can have restrictions - applied with @function/restrict/builtin. @function/restore will - delete the @function and turn the built in version back on. + Normally, built in functions cannot be overriden by @functions. However, + if a built-in function is deleted with @function/delete, you can then + make a @function with the same name. "Deleted" built-ins can still be + called through the FN() function, and can have restrictions applied with + @function/restrict/builtin. @function/restore will delete the @function + and turn the built in version back on. - Using @function on an already-added @function will delete the old one - and install a new function with none of the settings of the old one - kept. + Using @function on an already-added @function will delete the old one and + install a new function with none of the settings of the old one kept. - For example: - @function/delete ansi - &ansi_fun #1234=%1 - @function ansi=#1234, ansi_fun, 2, -2, noguest + Example: + > @function/delete ansi + > &ansi_fun #1234=%1 + > @function ansi=#1234, ansi_fun, 2, -2, noguest - will create a new version of ansi() that doesn't do any colorization, - and that needs two arguments, like the built-in version. It will be - restricted to non-guest players. + This creates a new version of ansi() that doesn't do any colorization, + and that needs two arguments, like the built-in version. It will be + restricted to non-guest players. See also: RESTRICT, FUNCTIONS, @startup, fn() & @grep @grep[/] [/]= - This command searches attributes in an object for . It takes - four switches: + This command searches attributes in an object for . You must be + able to examine . @grep takes four switches: @grep/list Lists the names of the attributes on the object containing . + This is the default. @grep/ilist Same as above, but is case-insensitive when trying to match . @grep/print - Prints out all the attributes, highlighting the pattern itself in - boldface, if you're ANSI. + Prints out all the attributes, ansi-highlighting the pattern itself. @grep/iprint Same as above, case-insensitive. - When used without a switch, @grep defaults to @grep/list. -(continued in help @grep2) + Continued in 'help @grep2'. & @grep2 - You must be able to see attributes on (i.e. you must control - the object, it must be VISUAL, or you must be a Wizard or Royalty). - - is an optional wildcard pattern specifying attributes to - match (much like @edit). If is not provided, all attributes - are assumed (just as if you had provided "*"). + is an optional wildcard pattern specifying attributes to check. If + is not provided, it defaults to "*". Note that this does not + include attribute trees; use "**" to check branch attributes as well. is not treated as a wildcard pattern, so you can grep for patterns containing '*', '?', etc. Also, is NOT PARSED, so '[v(0)]' and the like can be searched for. + +See also: grep(), wildgrep(), regrep(), WILDCARDS & @halt & @allhalt - @halt [=] + @halt [=] @halt/pid @halt/all @allhalt - The @halt command removes all queued actions for . If is specified, that new command is placed in the queue for - the object instead. If no new command is specified, the object is - set HALT. + The @halt command removes all queued actions for . If given, + is placed in the queue for the object instead. If no action + list is specified, the object is set HALT. - If is a player, it clears the queue for the player and and - all of his objects. You can use "@halt me" to clear your own queue - without setting yourself HALT. + If is a player, it clears the queue for the player and all of + his objects. You can use "@halt me" to clear your own queue without + setting yourself HALT. - Only wizards and objects with the halt @power can @halt other - player's objects. Note that halting an object does NOT affect any - objects waiting on it as a semaphore. + Only wizards and objects with the halt @power can @halt other player's + objects. Note that halting an object does NOT affect any objects waiting + on it as a semaphore. - @halt/pid will cancel a single queue entry with the given pid (The + @halt/pid will cancel a single queue entry with the given pid (the number in parenthesis before it in @ps). You must control the object that queued the command or have the halt power to do this. - @halt/all is a synonym for @allhalt and is a wizard-only command + @halt/all is a synonym for @allhalt, and is a wizard-only command which halts all objects in the game in an effort to free up the queue. + +See also: @wait, @ps, SEMAPHORES, @drain, @notify & @haven - @haven = + @haven [=] - This message is sent to a player whose pages you are refusing, either - through use of the HAVEN flag or through the use of a page lock, if - it evaluates to something non-null. + When someone attempts to page and is unable to, either because + is set HAVEN or because of his page lock, they will be shown + , if it evaluates to something non-null. -See also: HAVEN, page, @lock, @away + Example: + > @set me=HAVEN + > @haven me=I'm AFK and can't answer pages. Please @mail instead. + +See also: HAVEN, page, @lock, @away, @idle & @hide @hide[/] @hide[/] [] @@ -1843,32 +1907,30 @@ & @idescribe & @oidescribe & @aidescribe - @idescribe [=] - @oidescribe [=] - @aidescribe [=] + @idescribe [=] + @oidescribe [=] + @aidescribe [=] @idescribe command sets the internal description for an object, which is - shown to anyone who enters or looks while inside the object. Meaningless - for rooms and exits. May be abbreviated to @idesc. - - @oidescribe sets the message seen by others when someone looks at the - idesc, and @aidescribe sets the action the object will take (just as - with @desc, @odesc, @adesc). + shown to anyone who enters or looks while inside the object. It's only + used for players and things; rooms and exits always use @describe. + + The @oidescribe attribute is shown to others inside when someone + looks at the @idescribe, and the @aidescribe is triggered when someone + lookst at the @idescribe. - If there is no IDESCRIBE set for an object, those who enter or look - inside it will see its @desc, and no o-message or action will be - available. If you want to use @aidescribe without @idescribe, set - @idescribe to a blank string. + If there is no IDESCRIBE set for an object, those who enter or look inside + it will see its @describe. In this case, others in the object will see + nothing, and the @aidescribe will not be triggered. If you want to use + @aidescribe without @idescribe, set @idescribe to a blank string, or to + u(describe) to show the description. - If [=] or [=] omitted, the attribute will be - reset. - -See also: enter, @enter, ENTER_OK, @describe, look, @idescformat +See also: enter, @enter, ENTER_OK, @describe, look, @idescformat, VERBS & @hook @hook/ [=, ] @hook/list [] - @hook tells the command parser to evaluate given attributes at certain points + @hook makes the command parser evaluate given attributes at certain points in command evaluation. The possible points, indicated by the proper switch: @hook/ignore: The attribute is evaluated before the built-in command is run. @@ -1894,7 +1956,7 @@ Leaving out the object and attribute clears an existing hook. Wizards can see existing hooks with @command or @hook/list. - See HELP @HOOK2 for an example. + See 'help @hook2' for examples. & @hook2 An example of @hook: @@ -1907,49 +1969,56 @@ Room Zero You are in Room Zero. It's very dark here. You're done looking. + + > &cmd.say #3=$say *: @remit %L=[if(hasflag(%#,OOC),%b)]%n says, "%0" + > @hook/override say=#3, cmd.say + > @set me=OOC + > "test + Robert says, "test" & @idle - @idle = + @idle [=] This message is sent in return to every page which successfully reaches you if it evaluates non-null. It is useful if you are idle for long periods of time and wish to inform people where you are, or if you are in a meeting and cannot quickly return pages. - Clever example: - - @idle me=[switch(gt(idlesecs(me),120),1,I'm idle. Use @mail,)] + Example: + > @idle me=switch(idlesecs(me),>120,I'm idle. Use @mail) Players paging me will only see the "I'm idle" message if I've been idle for over 2 minutes (120 seconds). + +See also: @away, @haven & @infilter - @infilter = , , , ... + @infilter [=[, [, ..., ]]] @infilter is meant to be used on objects that have an @listen of "*" (ie, objects that listen to everything, which is commonly used for - things like chairs so that someone inside the object can hear - everything said/done outside it). @infilter filters out any messages - that match one of the patterns and prevents those inside the object - from hearing them. It does not stop the @ahear of the listening object - from being triggered by things that match the @listen. + things like chairs so that someone inside the object can hear everything + said/done outside it). @infilter filters out any messages that match one + of the patterns and prevents those inside the object from hearing them. + It does not stop the @ahear of the listening object from being triggered + by things that match the @listen. For an explanation of infilter patterns, see the help for "@filter". -See also: @filter, @listen, AUDIBLE, LISTENING +See also: @filter, @listen, @inprefix, AUDIBLE, LISTENING & @inprefix - @inprefix = + @inprefix [=] - @inprefix is intended for use with objects with a @listen of "*". - It prepends the string to any message propagated to the - contents of from the outside. If there is no @inprefix, - no string is prepended to the output. + When an object has an @listen, any string it hears which is propagated to + its contents will be prefixed with . Useful for vehicles, etc, + which have an @listen of "*". Example: - - [ First, @create Vehicle and Test (objects #103 and #104) and drop them ] - > @inprefix Vehicle = From outside, - Vehicle - Set. + > @create Vehicle + Created: Object #103. + > @create Test + Created: Object #104. + > @inprefix Vehicle=From outside, + > @listen Vehicle=* > enter Vehicle - Vehicle(#103) > @force #104=:bounces. From outside, Test bounces. @@ -1983,22 +2052,18 @@ The @list command lists useful MUSH information. Switches include: - /motd : Alias for @listmotd, shows current messages of the day. - /functions : Lists all built-in functions and @functions - /commands : Lists all built-in commands - /attribs : Lists all standard attributes - /locks : Lists the built-in lock types - /flags : Alias for @flag/list, shows all flags - /powers : Alias for @powers/list, shows all powers + motd : Alias for @listmotd, shows current messages of the day. + functions : Lists all built-in functions and @functions. + commands : Lists all built-in commands. + attribs : Lists all standard attributes. + locks : Lists the built-in lock types. + flags : Alias for @flag/list, shows all flags. + powers : Alias for @powers/list, shows all powers. + allocations : Information about memory allocations. Admin-only. By default, information is shown in upper-case. Add the /lowercase switch to show output in lowercase instead. - These admin-only commands require the use of '@list ' and don't work - as '@list/': - - allocations : Information about memory allocations. - See also: list(), @config, config(), functions(), @stats, @command, @function, @flag, @power, @attribute, @listmotd, @motd, locktypes & @listmotd @@ -2048,38 +2113,38 @@ ahear/amhear/aahear attribute will be triggered. In addition, anything inside the object will hear it as well. -For example: - @listen Chair = * + For example: + > @listen Chair=* Since the wildcard (*) matches anything, anyone inside the object will hear anything said outside it. - @listen Butler = * has arrived. - @ahear Butler = :walks over to the new arrival and takes %p coat. - > Cyclonus has arrived. - > Butler walks over to the new arrival and takes his coat. + > @listen Butler=* has arrived. + > @ahear Butler=:walks over to the new arrival and takes %p coat. In this case, the listen pattern is met whenever someone 'arrives' in the room, and then the object does whatever is inside its @ahear attribute. + Cyclonus has arrived. + Butler walks over to the new arrival and takes his coat. -(continued in help @listen2) + Continued in 'help @listen2'. & @listen2 An object "hears" anything that another player standing in the same room would hear. For example, if you type in a command, the object does NOT hear it. If the command has a result that people in the room hear, the object will hear it. -For example: - @listen Recorder = @emit * - @ahear Recorder = :records {%0} - @emit Whee! + For example: + > @listen Recorder=@emit * + > @ahear Recorder=:records %0 + > @emit Whee! > Whee! In this example, the Recorder's listen-pattern is NOT matched, because it doesn't hear the '@emit Whee!', it only hears the 'Whee!' part, which doesn't match. - @listen Recorder = Cyclonus says, "*" - "Whee! - > Cyclonus says, "Whee!" - > Recorder records: Whee! + > @listen Recorder=Cyclonus says, "*" + > say Whee! + Cyclonus says, "Whee!" + Recorder records: Whee! See also: LISTENING, @ahear, @amhear, @aahear & LOCKING @@ -2102,16 +2167,25 @@ locktypes may also have such success/failure messages: see "help failure" for info. - You can specify and as either the name of an object - in the immediate area, a DBREF number, "me", or "here". + Just like attributes, locks can be inherited from parents. By default, + locks are set no_inherit, but this flag can be cleared using @lset. More + details and a list of flags can be found in HELP @LSET. -(continued in help @lock2) -& @lock2 + A listing of lock types, such as pagelocks, look at "help locktypes". + For the available key types, such as how to check an attribute on an + object trying to pass a lock, see "help lockkeys". + +See also: @lock-simple, locktypes, lockkeys, @clock, failure, success. + elock(), lock(), @lset, @clock, testlock(), locks(), lockflags(), + lockowner(), clock(), llocks() +& @lock-simple +& @lock-objid +SIMPLE LOCKS You can lock an object in several different ways. The simplest lock is one that always succeeds (#true) or always fails (#false), or that matches one other object by prefixing it with a '=', signifying - a DBRef # match.: + a dbref match: @lock My Toy = #false This lock will always fail. @@ -2126,55 +2200,41 @@ You can lock an object -against- another object as well, using the '!' symbol before any other key: - @lock Shared Toy = !Vector Sigma + @lock Shared Toy = !=Vector Sigma This locks the object "Shared Toy" to everyone -except- Vector Sigma. Everyone except Vector will be able to pick up the object. -(continued in help @lock3) -& @lock3 - You can lock an object to something that has to be carried: - @lock Door = +Secret Door Key - This locks the exit "Door" to someone carrying the object - "Secret Door Key". Anyone carrying that object will be able to - go through the exit. + The above locks take the form @lock = =, but you can + also test for an object id, instead of a dbref, with: + @lock =objid^ + +& @lock-owner +& @lock-carry +OWNER LOCK - You can lock an object to -either- an object or to someone carrying - the object with: - @lock Disneyworld Entrance = Child - This locks the exit "Disneyworld Entrance" to either the object - "Child" -or- to someone carrying the object "Child". (OK, so - it's a weird example.) - - You can lock an object to a specific player by using a *: - @lock Note == *Jazz - Only the player "Jazz" will be able to pick up the Note object. - -(continued in help @lock4) -& @lock4 An "owner" lock allows you to lock something to anything owned by the same player: @lock Box = $My Toy - This locks "Box" to anything owned by the owner of "My Toy" - (since players own themselves, that includes the owner as well). + This locks "Box" to anything owned by the owner of "My Toy" + (since players own themselves, that includes the owner as well). - An "indirect" lock allows you to lock something to the same thing as - another object (very useful in setting channel locks; see help - @clock): - @lock Second Puppet = @First Puppet - This locks the object "Second Puppet" to whatever the object - "First Puppet" is locked to. Normally, the lock type that is - checked is the same as the lock on the first. You can specify a - different lock type with @object/LOCKNAME. For example: @lock - Second Puppet = @First Puppet/Use Second Puppet's basic lock now - checks First Puppet's use lock. +CARRY LOCK + You can lock an object to something that has to be carried: + @lock Door = +Secret Door Key + This locks the exit "Door" to someone carrying the object "Secret Door + Key". Anyone carrying that object will be able to go through the exit. - There are also some more complex locks called attribute and - evaluation locks. In addition, you can make complex locks (combining - several types or reversing them). + You can lock an object to -either- an object or to someone carrying the + object with: + @lock Disneyworld Entrance = Child + This locks the exit "Disneyworld Entrance" to either the object + "Child" -or- to someone carrying the object "Child". (OK, so it's + a weird example.) + + This is the same as @lock Entrance=+Child|=Child. -(continued in help @lock5) -& @lock5 +& @lock-attribute ATTRIBUTE LOCKS You can lock an object to an attribute on the person trying to pass the lock (as long as the object can "see" that attribute): @@ -2193,8 +2253,7 @@ starting with a letter "less than" the letter "g". This assumes that ICNAME is visual or the object with the lock can see it. -(continued in help @lock6) -& @lock6 +& @lock-complex COMPLEX LOCKS You can combine or reverse locks very easily using the following BOOLEAN symbols and parentheses () to group them: @@ -2202,19 +2261,17 @@ | - "or" For example: - @lock My Toy = =me | !*Chromia | +Toy Box Key - This locks "My Toy" to me, -against- the player Chromia, or to - anyone carrying the object "Toy Box Key". - @lock My Toy = *Marissa & +Toy Box Key + @lock My Toy = =*Marissa & +Toy Box Key This locks "My Toy" to the player Marissa, who needs to be carrying the object "Toy Box Key". - @lock My Toy= *Chromia | ( *Marissa & +Toy Box Key ) - This locks it to Chromia, OR to Marissa if she is carrying the - Key. + @lock My Toy= =*Chromia | ( =*Marissa & +Toy Box Key ) + This locks it to Chromia, OR to Marissa if she is carrying the Key. + @lock My Toy = =me | (!=*Chromia & +Toy Box Key) + This locks "My Toy" to me, or to anyone -except- the player Chromia + who is carrying the object "Toy Box Key". -(continued in help @lock7) -& @lock7 -EVALUATION LOCKS +& @lock-evaluation +EVALUATION LOCK An evaluation lock is set using this format: @lock =/ @@ -2231,26 +2288,33 @@ and doesn't have permission to do that, the person will automatically fail to pass the lock. -(continued in help @lock8) -& @lock8 + Continued in 'help @lock-eval2'. +& @lock-eval2 +& @lock-evaluation2 - Example: - @lock Stage = ispuppet/1 - &ispuppet Stage = hasflag(%#, PUPPET) - This locks the object "Stage" to puppets only. + Example: + @lock Thursday Cafe = whichday/Thu + &whichday Thursday Cafe = first(time()) + This locks the object "Thursday Cafe" (probably an exit) unless today + is Thursday. - Whenever someone tries to pick up the object, the attribute - "ispuppet" will be checked, substituting in the person's DBREF - number for %#. - - [hasflag(, PUPPET)] will come out to 1 if the object with - has the "PUPPET" flag. Otherwise, it will come out to be - 0. Since the value in the @lock is 1, only objects with the - PUPPET flag will be able to pass this lock. + Whenever someone tries to pass through the exit, the attribute + "whichday" will be evaluated, extracting the first word returned from + time() (the day of the week). The result is compared with the value in + the lock ("Thu"), and the lock will only be passable when the strings + match--Only on Thursdays. -(continued in help @lock9) -& @lock9 - You can also test for set flags, powers, or object types in a lock + If you have an evaluation lock that just does [hasflag(%#,FLAGNAME)], + you should probably use a bit lock instead. + +See also: @lock-bit +& @lock-bit +& @lock-flag +& @lock-type +& @lock-power +& @lock-channel +BIT LOCKS + You can test for set flags, powers, or object types in a lock directly, without using an evaluation lock, with these formats: @lock =flag^ @@ -2261,19 +2325,15 @@ ), hastype(%#, ), or haspower(%#, ) succeeding if the flag is set. - You can test for channel membership with: - - @lock =channel^ - For example, @lock/use Admin Commands=flag^wizard|flag^royalty -(continued in help @lock10) -& @lock10 - You can test for an object id, instead of a dbref, with: + You can also test for channel membership with: - @lock =objid^ + @lock =channel^ +& @lock-list +LIST LOCK You can test to see if the enactor is a member of a space-separated list of dbrefs or objids on an attribute on the object, with: @@ -2284,12 +2344,67 @@ &deny commands = #200 #1020 @lock/use commands = !dbreflist^deny & dbreflist^allow -See also: locktypes, @clock, elock(), lock(), objid() +& @lock-indirect +INDIRECT LOCKS + An "indirect" lock allows you to lock something to the same thing as + another object (very useful in setting channel locks; see help + @clock): + @lock Second Puppet = @First Puppet + This locks the object "Second Puppet" to whatever the object + "First Puppet" is locked to. Normally, the lock type that is + checked is the same as the lock on the first. You can specify a + different lock type with @object/LOCKNAME. For example: + @lock Second Puppet = @First Puppet/Use + Second Puppet's basic lock now checks First Puppet's use lock. + +& @lock-host +HOST LOCKS + + You can check to make sure an object is owned by a player connected from + a specific host or IP address using the following: + + @lock =ip^ + @lock =hostname^ + + and can contain wildcards. must be able + to see the LASTIP attribute (for ip locks) or LASTSITE attribute (for + hostname locks) on the enactor's owner. + + For example: + @lock =ip^127.0.0.1 + This locks to players (and the objects of players) currently + connected from the computer the MUSH is running on. + +See also: ipaddr(), hostname(), LASTSITE +& lockkeys +& lock keys + + There are many key types, and it is also possible to form more complex + locks by using boolean symbols and grouping. See HELP @LOCK-COMPLEX + for examples. + + The types of keys are outlined below. Detailed help for each is available + by typing "help @lock-", replacing with the word on the left. + + Simple - Always true, always false, or locking to an object. + Objid - Check if the object trying to pass the lock matches an objid. + Owner - Lock to objects owned by the owner of an object. + Carry - Lock to someone carrying an object such as a key. + Indirect - Use the result of a lock on another object. + Attribute - Check an attribute on the object trying to pass the lock. + Evaluation - Evaluate an attribute on the object the lock is on. + Bit - Check for a flag, type, power, or channel membership. + List - Check if the object trying to pass the lock is part of a list. + Host - Check for players connecting from a particular host/ip. + + Complex - Combine other lock keys using groups and boolean operators. + +See also: @lock, locktypes, @clock, objid() & locktypes & locklist & lock types & lock list - Your MUSH will almost certainly support these standard lock types: + These are the standard lock types supported by PennMUSH: @lock/basic Who can pick up the player/object, or go through the exit. @@ -2301,11 +2416,12 @@ @lock/parent Who can @parent something to this object/room @lock/link Who can @link something to this object/room or who can @link this unlinked exit. + @link/open Who can @open an exit from this room @lock/mail Who can @mail the player @lock/user: User-defined. No built-in function of this lock, but users can test it with elock() - See 'help locktypes2' for more + Continued in 'help locktypes2'. & lock types2 & locktypes2 More standard lock types: @@ -2316,11 +2432,13 @@ @lock/leave Who can leave this object (or room, via exits/@tel) @lock/drop Who can drop this object or in this room @lock/give Who can give this object + @lock/from Who can give things to this object + @lock/receive What things can be given to this object @lock/follow Who can follow this object @lock/examine Who can examine this object if it's VISUAL @lock/chzone Who can @chzone to this object if it's a ZMO @lock/forward Who can @forwardlist a message to this object - @lock/control Who can control this object (only if set) + @lock/control Who can control this object (only if set; non-player) @lock/dropto Who can trigger this container's drop-to. @lock/destroy Who can destroy this object if it's DESTROY_OK @lock/interact Who can send sound (say/pose/emit/etc) to this object @@ -2341,6 +2459,7 @@ wizard (w) This lock can only be set by wizards. locked (+) This lock can only be set by the owner of the lock. +See also: @lock, lockflags(), llockflags(), lset() & @log @log[/] @@ -2380,7 +2499,7 @@ See also: message(), @chatformat, @pageformat & @motd - @motd[/] []. + @motd[/] [] The default for this command (and with the /connect) switch, is a wizard only command that will set a temporary message that @@ -2429,33 +2548,33 @@ > @oname me=has regenerated from %0! > @aname me=think >> Renamed from %0 to %1 at [time()] by %n(%#). -See also: @name, name() +See also: @name, name(), VERBS & @newpassword - @newpassword = + @newpassword = - This wizard-only command changes 's password. If - is logged in, s/he will be informed that the password was changed. + This wizard-only command changes 's password. If is + connected, she will be informed that the password was changed and who by, + but not what it was changed to. -See also: @password +See also: @password, checkpass() & @notify @notify[/any][/all] [/][=] - This command notifies a semaphore, allowing commands queued for - that semaphore to be executed. + This command notifies a semaphore, allowing commands queued for that + semaphore to be executed. - If the /any switch is given, then all semaphores associated with - are @notified. Otherwise, only the specified semaphore - attribute (or SEMAPHORE if no attribute is specified) is @notified. + If the /any switch is given, then all semaphores associated with + are @notified. Otherwise, only the specified semaphore (or + SEMAPHORE if no attribute is specified) is @notified. - If the /all switch is given, then all queue entries associated - with the selected semaphore(s) are executed. Otherwise, only the - first of queue entries are run. If no is given, - then only one queue entry is run. + If the /all switch is given, then all queue entries associated with the + selected semaphore(s) are executed. Otherwise, only the first of + queue entries are run. If no is given, then only one queue entry + is run. - If the /all switch was not used, and there were not enough queue - entries waiting to satisfy the requested (or 1, if no - number was given), then subsequent @waits will not block until - the requested have been run. + If the /all switch was not used, and there were not enough queue entries + waiting to satisfy the requested , then the semaphore becomes + negative, and subsequent @waits will not block until it reaches 0 again. You may not specify both the /any switch and a specific attribute. Similarly, you may not specify both the /all switch and a number. @@ -2485,109 +2604,93 @@ See also: @emit, @lemit, @pemit, @prompt, @remit, @oemit, @zemit, nsemit(), nslemit(), nspemit(), nsprompt(), nsremit(), nsoemit(), nszemit(), PROMPT_NEWLINES -& @odescribe - @odescribe [=] - - This sets the message that will be shown to others whenever anyone - looks at . The name of the person looking will be added to - the beginning of the message. Please note that @odescs are often found - annoying. - - If the = part is omitted, the message will be reset. - -See also: look, @describe, @idescribe & @oemit - @oemit[/] [/] [...] = + @oemit[/] [/] [... ]= This command shows to everyone in the location of - EXCEPT . The object can be specified by name if in your current - location, or by DBREF number. A list of objects can be given, in - which case the message is shown in all locations to all except those - objects. + EXCEPT . A list of objects can be given, in which case the message + is shown in the locations of each, to everyone but those objects. - If a room is specified (usually via dbref), this command shows - to everyone in except for (which may be - a list, as above). In this case, object(s) are matched with reference to - . Therefore, if you want to send a message to everything but an - object called "spy" in #100, you can simply use "@oemit #100/spy=Test"; - you don't need to know the dbref of "spy". - - The /noeval switch prevents the MUSH from evaluating the message. + If is specified (usually as a dbref), this command shows + to everyone in except for the given s. In this case, each + is matched relative to . + + The /noeval switch prevents the MUSH from evaluating . The /spoof switch causes nospoof notifications to show the enactor's dbref instead of the executor's dbref, and requires control over the enactor or the Can_nspemit power. + + Examples: + Show a message in the locations of players Bob and Fred, to everyone + except those two players: + > @oemit *Bob *Fred=Bob throws a paper aeroplane at Fred. + + Show a message in #50 to everyone except the object 'Spy'. + > @oemit #50/Spy=Sssh! -See also: @emit, @pemit, NOSPOOF and SPOOFING. -& @oxmove - @oxmove [= ] - - Sets the message shown to others in the source room whenever - moves elsewhere. 's name is automatically inserted at the - beginning of this message. Note that long @oxmoves are annoying. - - Example: - @oxmove me=stalks away, glaring. - - If the = is omitted, the message is cleared. - -See also: go, @move, @omove, @amove +See also: @emit, @pemit, @nsoemit, oemit(), nsoemit(), NOSPOOF, SPOOFING & @open - @open - @open ;= - @open ;=,; - - This command opens an exit in the room you are standing in with the - specified name. You can then use the @link command to set the exit's - destination, or you can set it automatically by using the DBREF of a - destination, which can be a room or thing. (Note that you CANNOT open - exits from things.) If you also include the second exit name, an exit - from the destination room will be opened back to the room you are in. - - NOTE: you can have as many exit aliases as you like by adding more, - separated by semicolons. An exit alias allows you to type that instead of - the full exit name to go through the exit. Only the exit name appears in - the list of Obvious Exits in a room. - - Ex: @open Up;u;climb = #255, Down;dow;do;d;fall - -See also: EXITS, @link, @dig -& @oxleave - @oxleave [= ] + @open [=[, [, ]]] - This message is shown to everyone in the room that a person enters - when doing a 'leave' command. This will be shown in addition to the - enter messages of the room, not instead of. + This command opens an exit, named , in your current location, + or in if one is given. Exits can only be opened from rooms. + If a is given, the exit will be linked (as per @link) to + that object. If you don't have permission to link to , the + exit will be created but unlinked. + + If is given, the MUSH will attempt to open an exit back + from and link it to 's source. + + Both and can include any number of aliases + for the exits, separated by semicolons. See 'help @name' for details. - If the = part is omitted, the message will be reset. + To open an exit in a room, you must control the room, have the + Open_Anywhere @power, or the room must be set OPEN_OK and you must pass + its @lock/open. -See also: leave, @leave, @oleave, @aleave + Example: + > @open Up ;up;u;climb=#255, Down ;down;d;fall + +See also: EXITS, @link, @dig, open() & @parent - @parent = + @parent [=] - This command sets the parent of to . may be - an object of any type; can be anything but a player. The - player must control . must be controlled by the - player or LINK_OK. - If is "none" or blank, the object is unparented. - -See also: PARENTS, parent(), lparent() + This command sets the parent of to . If no is + given, or is "none", 's parent is cleared. You must + control , and must either control or it must be set + LINK_OK and you must pass its @lock/parent. + +See also: PARENTS, parent(), lparent(), ANCESTORS & @password @password = This changes your password. Please note that passwords ARE case-sensitive. + +See also: @newpassword, checkpass() & @pageformat - @pageformat [=] +& @outpageformat + @outpageformat [=] + @pageformat [=] - Sets the message that is seen when receives a page. is - evaluated. + @pageformat changes the message seen by when it receives a page. + @outpageformat sets the message seen by when it sends a page. - %0 will be set to the page message. + %0 will be set to the page message (not including :, ; or "). %1 will be set to ':' ';' or '"' for pose, semipose and normal page, - respectively, + respectively. %2 will be set to the alias of the pager, if any. %3 will be a space-separated list of recipient dbrefs. %4 will be set to the default message. + See 'help @pageformat2' for examples. + +See also: page, speak(), @chatformat, @message +& @pageformat2 +& @outpageformat2 + For simple page timestamps: + > @pageformat me=\[[time()]\] %4 + > @outpageformat me=\[[time()]\] %4 + To obtain 'page_aliases' behavior: > @pageformat me=[setq(0,%n[if(%2,%b(%2))],1,switch(%3,%!,,itemize(iter(%3, name(##),%b,|),|)))][switch(%1,",%q0 pages[if(%q1,%b%q1)]: %0,:,From @@ -2597,65 +2700,64 @@ > @pageformat me=[setq(1,switch(%3,%!,,itemize(iter(%3,name(##),%b,|),|)))] [switch(%1,",%n pages[if(%q1,%b%q1)]: %0,:,From afar [if(%q1,%b(to %q1))]\, %n %0,From afar[if(%q1,%b(to %q1))]\, %n%0)] - -See also: page, speak() & @receive & @oreceive & @areceive - @receive [=] - @oreceive [=] - @areceive [=] + @receive [=] + @oreceive [=] + @areceive [=] - @receive sets the message that is shown to the recipient who - acquires an object by 'get'ing it or having it 'give'n to them. - @oreceive is a message shown to others in the recipient's location, - and @areceive is an action run by the recipient. If not set, - the recipient gets a default message ("Jane gave you A Headache"). + These attributes contain the message shown when he receives an + object (via 'get' or 'give'), the message shown to others in 's + location when he receives an object, and the actions to be taken by + when he receives an object, respectively. - %0 will be set to the dbref of the object received. - %1 will be set to the dbref of the giver if a 'give' was performed. + In all cases, %0 is the dbref of the object received. If the object was + 'give'n, %1 will be the dbref of the giver. -See also: give +See also: give, get, @give, @success, ACTION LISTS, VERBS & @give & @ogive & @agive - @give [=] - @ogive [=] - @agive [=] - - @give sets the message that is shown to the giver when giving an object - to someone else. @ogive is a message shown to others in the giver's - location, and @agive is an action run by the giver. If not set, - the giver gets a default message. - - %0 will be set to the dbref of the object given. - %1 will be set to the dbref of the recipient. + @give [=] + @ogive [=] + @agive [=] + + These attributes contain the message shown to when he gives an + object, the message shown to others in 's location when he gives an + object, and the actions to be taken by when he gives an object, + respectively. + + In all cases, %0 is the dbref of the object being given, and %1 is the + dbref of the recipient. -See also: give +See also: give, @receive, ACTION LISTS, VERBS & @pcreate - @pcreate = [, ] + @pcreate =[, ] - This wizard-only command creates a player with the given name and - password. + This wizard-only command creates a player with the given name and password. + If specified, is the dbref of a garbage object to be used for the + new player. + +See also: pcreate() & @prompt - @prompt[/] = + @prompt[/] = - A variation of @pemit/list that adds a telnet GOAHEAD control code - to the end of messages sent to players. Players with clients - that handle GOAHEAD may get the message as a prompt in their - client's input area. + A variation of @pemit/list that adds a telnet GOAHEAD control code to the + end of messages sent to players. Players with clients that handle GOAHEAD + may get the message as a prompt in their client's input area. @prompt supports the following @pemit switches: /silent, /noisy, /spoof, /noeval See also: @pemit, @nsprompt, prompt(), nsprompt(), PROMPT_NEWLINES & PROMPT_NEWLINES - PROMPT_NEWLINES <1|0> + PROMPT_NEWLINES [1|0] This socket-level command is used to indicate whether a newline should - be sent after the telnet GOAHEAD code issued by @prompt/prompt() - to telnet-capable clients. By default, in order to maximize - portability, newlines are sent. + be sent after the telnet GOAHEAD code issued by @prompt/prompt() to + telnet-capable clients. By default, in order to maximize portability, + newlines are sent. Some clients, like TinyFugue, are smart enough to interpret GOAHEAD and treat prompts specially by putting them into their input window. These @@ -2666,39 +2768,39 @@ See also: @prompt, prompt(), terminfo() & @pemit - @pemit[/] = + @pemit[/] = + @pemit/list[/] = + @pemit/port[/silent] = - The basic form of this command sends to directly. - It is very similar in its effects to @emit except only one object - will see the message. You may @pemit to objects in the same room, - objects you are carrying, and to objects that are carrying you, - or @pemit remotely, using # or *. + The basic form of this command sends to directly. It is + very similar in its effects to @emit except only one object will see the + message. - The /list switch to this command allows you to @pemit a message to - a list: @pemit/list [ ] = - There can be any number of objects in the list. You will not get back a - "confirmation" message for the /list form of this command. + @pemit/list sends the message to multiple objects. You will not get a + confirmation message when using this switch. + + @pemit/port can only be used by Wizards/Royalty, and sends to a + single connection. It can be used to send messages to connections which + are still at the login screen. -(continued in help @pemit2) + See "help @pemit2" for more. & @pemit2 The @pemit command can take the following additional switches: /contents -- equivalent to @remit. /silent -- does not tell the @pemit'ing object a confirmation message. /noisy -- tells the @pemit'ing object a confirmation message. - /noeval -- the message will not be evaluated for substitutions + /noeval -- will not be evaluated for substitutions /spoof -- the enactor's dbref will be used for nospoof notifications instead of the executor's dbref. Requires control over enactor or Can_nspemit power. - /port -- is taken to be a port number, instead of a dbref, - and the message is only sent to that port. Wiz/roy only. - Note that page-lock and the HAVEN flag will block @pemits as well, - except from Wizards or those with the pemit_all power. + You cannot @pemit to objects set HAVEN, or objects whose @lock/page you do + not pass, unless you are set WIZARD or have the pemit_all @power. - See also @emit, @oemit, @remit, NOSPOOF, and SPOOFING. +See also: @emit, @nspemit, @oemit, @remit, NOSPOOF, SPOOFING, page & @poll @poll - @poll + @poll @poll/clear This command manipulate the message at the top of WHO/DOING. By itself, @@ -2707,11 +2809,12 @@ See also: @doing, WHO, DOING & @poor - @poor . - This is a god only command. It sets every player's money supply to - value. + @poor + + This command sets the pennies of every player on the MUSH to . It + can only be used by God. -See also: MONEY +See also: MONEY, give & @power @power/list [] @power @@ -2729,14 +2832,14 @@ God can add, delete, and otherwise manipulate power definitions. See help @power2 for these commands. & @power2 - @power/add =[], [], [], [] - @power/delete - @power/alias = - @power/letter [=] - @power/restrict =[], [] - @power/type = - @power/enable - @power/disable + @power/add =[], [], [], [] + @power/delete + @power/alias = + @power/letter [=] + @power/restrict =[], [] + @power/type = + @power/enable + @power/disable These commands manipulate power definitions. Only God may use them. /disable disables a power, making it invisible and unusable @@ -2849,7 +2952,7 @@ See also: @motd, @list, @listmotd & @remit - @remit[/switches] = . + @remit[/switches] = Sends the message to all contents of , which can be a room, thing, or player. The message is also sent to the itself. @@ -2869,7 +2972,8 @@ See also: @emit, @pemit, @oemit, SPOOFING, NOSPOOF, CONTROL. & @restart - @restart or @restart/all + @restart + @restart/all This command halts (as described in @halt), and then triggers the STARTUP attribute on the object, if set. If is a player, @@ -2878,7 +2982,6 @@ all objects (see @allhalt) and restarts them, and can only be used by a wizard. - See also: @halt, @startup & @rwall @rwall[/emit] @@ -2892,7 +2995,7 @@ & @scan @scan[/] - @scan gives you a list of all objects containing $commands (user-defined + @scan gives you a list of all objects containing $-commands (user-defined commands) which could match . If given no switches, it checks you, your possessions, your location, objects in your location, the zone/zone master room of your location, your zone, and objects in the @@ -2901,11 +3004,17 @@ matched, and what attributes they are in. It does NOT scan objects that you do not control and are not set VISUAL. - This command can take four switches: + This command any combination of these four switches: /room -- just matches on your location and objects in it. /self -- just matches on you and anything you're carrying. /zone -- just matches on zones of your location and yourself. /globals -- just matches on objects in the master room. + + If no switch is given, all locations are checked. must be + entered exactly as you would type it (so, to match the $-command + $foo *: you must type '@scan foo ', not just '@scan foo'). + +See also: $-commands, EVALUATION ORDER & @search @search [] [=[,...]][,,] @@ -3012,11 +3121,11 @@ actions are executed. This is equivalent to "@switch/first". Example: - &FOO thing = $foo *:@select %0=*a*,:acks,*b*,:bars,*c*,:cheeps,:glurps - foo abc - > thing acks - foo xxx - > thing glurps + > &FOO thing = $foo *:@select %0=*a*,:acks,*b*,:bars,*c*,:cheeps,:glurps + > foo abc + thing acks + > foo xxx + thing glurps The string "#$" in 's will be expanded to the evaluated result of before it is acted on. @@ -3053,21 +3162,21 @@ The fourth form sets (or unsets) an attribute flag on the specified attribute. See 'help attribute flags'. & @sex - @sex = + @sex = You can use this command to set yourself or any of your objects to be male, female, neuter, or plural. The SEX attribute is used for pronoun substitution by the MUSH, and anything not recognizable will be treated as neuter. - @sex me = Male - @sex me = Female - @sex me = Woman - @sex me = They - @sex me = Plural - @sex me = No thank you (silly, but possible) + @sex me=Male + @sex me=Female + @sex me=Woman + @sex me=They + @sex me=Plural + @sex me=No thank you (silly, but possible) -See also: GENDER, SUBSTITUTION +See also: GENDER, subj(), poss(), aposs(), obj() & @shutdown @shutdown[/panic][/reboot][/paranoid] @@ -3166,7 +3275,8 @@ queries and quick checks. If you pass arbitrary data to @sql, be sure you call sqlescape() on it (see the example in help sql()). - Example: @sql SHOW TABLES + Example: + > @sql SHOW TABLES See also: sql(), sqlescape(), mapsql() & @squota @@ -3178,7 +3288,7 @@ specified, this shows current quota, and reminds you to set one. Using + or - you can add to the limit, or subtract it. & @startup - @startup = + @startup [=] Sets the list of actions on that will happen whenever the MUSH is restarted. This lets you start up objects that need to be running @@ -3241,26 +3351,28 @@ @switch/regexp will cause the expressions to be matched as case-insensitive regular expressions. -(continued in help @switch2) + See 'help @switch2' for examples. +See also: switch wildcards, @select, switch(), @break & @switch2 -Examples: - &SWITCH_EX thing = $foo *:@switch %0=*a*,:acks,*b*,:bars,:glurps - foo abc - > thing acks - > thing bars - foo xxx - > thing glurps + Examples: + > &SWITCH_EX thing=$foo *: @switch %0=*a*, :acks, *b*, :bars, :glurps + > foo abc + thing acks + thing bars + > foo xxx + thing glurps - &SWITCH_EX thing = $foo *:@switch/first %0=*a*,:acks,*b*,:bars,:glurps - foo abc - > thing acks + > &SWITCH_EX thing=$foo *: @switch/first %0=*a*, :acks, + *b*, :bars, :glurps + > foo abc + thing acks - &SWITCH_EX thing = $test:@switch hasflag(%#,PUPPET)=1,"Puppet!,"Not Puppet! - test - > thing says, "Not Puppet!" -See also: switch wildcards, @select, switch() + > &SWITCH_EX thing=$test: @switch hasflag(%#,PUPPET)=1, say Puppet!, + say Not Puppet! + > test + thing says, "Not Puppet!" & @teleport - @teleport[/silent][/inside] [=] . + @teleport[/silent][/inside] [=] Teleports to . must be a thing; if you do not supply a thing, the object is assumed to be yourself. The @@ -3296,16 +3408,16 @@ as %0 - %9. Examples: - &GREET me=POSE waves hi. - @tr me/GREET - > Cyclonus waves hi. + > &GREET me=POSE waves hi. + > @trigger me/GREET + Cyclonus waves hi. - &GREET me=POSE waves to %0! ; say Hi there, %1. - @trig me/GREET = Gears, Arcee - > Cyclonus waves to Gears. - > You say, "Hi there, Arcee." + > &GREET me=POSE waves to %0! ; say Hi there, %1. + > @trigger me/GREET=Gears, Arcee + Cyclonus waves to Gears. + You say, "Hi there, Arcee." -(continued in help @trigger2) + Continued in 'help @trigger2'. & @trigger2 @trigger is very useful for splitting up large commands and for making them neater, but it does cause a time delay in execution, because the @@ -3314,8 +3426,9 @@ @trigger. However, in most cases, the time saved by cramming everything into one attribute is outweighed by the time spent debugging. +See also: @include, ufun() & @ulock - @ulock = + @ulock [=] This is an abbreviation of @lock/use. @@ -3326,7 +3439,7 @@ "@ulock toy=!*Bob". If I want only Bob to be able to use it, I would "@ulock toy=*Bob". -See also: @lock, locktypes +See also: @lock, @uunlock, locktypes & @uptime @uptime[/mortal] @@ -3337,7 +3450,7 @@ Wizards can use the /mortal switch to avoid seeing the extra process statistics. - Continued in HELP @UPTIME2 + Continued in 'help @uptime2'. & @UPTIME2 While the exact statistics displayed depends on the operating system of the game's server, typical things might include the process ID, @@ -3373,12 +3486,16 @@ & @uunlock @uunlock - Un-use-locks the object. See also: @lock, @ulock + Un-use-locks the object. + +See also: @lock, @ulock & @version @version Tells the player the name of the MUSH, which version of the code is currently running on the system, when it was compiled, and when the last restart was. + +See also: version(), numversion() & @verb @verb =,,,,,, @@ -3396,8 +3513,7 @@ By supplying up to ten , you may pass those values on the stack (i.e. %0, %1, %2, etc. up through %9). - See "help @verb2" for more. - + Continued in 'help @verb2'. & @verb2 In order to use this command, at least one of the following criterion must apply: @@ -3408,54 +3524,53 @@ which did the @verb must be either privileged or control or must be VISUAL. - See "help @verb3" for examples. - + See 'help @verb3' for examples. & @verb3 Examples: - &VERB_EXAMPLE Test Object=$test:@verb me=%#,TEST,You just tested.,OTEST, + > &VERB_EXAMPLE Test Object=$test:@verb me=%#,TEST,You just tested.,OTEST, just tested the example.,ATEST,%N - test - > You just tested. - > [others see] Cyclonus just tested the example. + > test + You just tested. + [others see] Cyclonus just tested the example. - &TEST Test Object=You have just tested this object! - &ATEST Test Object=@emit %0 has failed! - &OTEST Test Object=tests test object. - test - > You have just tested this object! - > [others see] Cyclonus tests test object. - > Cyclonus has failed! + > &TEST Test Object=You have just tested this object! + > &ATEST Test Object=@emit %0 has failed! + > &OTEST Test Object=tests test object. + > test + You have just tested this object! + [others see] Cyclonus tests test object. + Cyclonus has failed! - Another example follows in "help @verb4" + See 'help @verb4' for another example. & @verb4 In order to make this into a global command that anyone can use, we need to put it on a WIZARD object in the Master Room. - &DO_TEST Global=$test *:@select locate(%#,%0)=#-1, + > &DO_TEST Global=$test *:@select locate(%#,%0)=#-1, {@pemit %#=I don't see that here.}, {@verb locate(%#,%0,n)=%#, TEST,You test [capstr(%0)]., OTEST,tests [capstr(%0)]., ATEST} - &TEST Example=You test this fun example. - &ATEST Example=POSE has been tested! - test example - > You test this fun example. - > [others see] You test Example. - > Example has been tested! + > &TEST Example=You test this fun example. + > &ATEST Example=POSE has been tested! + > test example + You test this fun example. + [others see] You test Example. + Example has been tested! -See also: USER-DEFINED COMMANDS, STACK, @trigger, @select +See also: USER-DEFINED COMMANDS, STACK, VERBS, @trigger & @wait @wait[/until]