The WARPEDcore

The WARPEDcore Trispis Wed, 2006-09-13 04:53

This community web book is the new official home of the WARPEDcore project. Here, within this collaborative book, you will find ...

0 - The Manifest

0 - The Manifest Trispis Thu, 2006-09-14 04:05

This section of this book was originally derived from The WARPEDcore Manifesto and will henceforth be referred to as the Manifest. This is now a living document, intended to be tweaked, modified, updated, etc... basically, the intent is that this project take on a life of its own (I planted the seed. I hope it grows.)

As this project progresses, this section can be referenced as a guide when resolving conflicts between design theory and design application (some things work great in theory, but when it boils down to applying them they just... don't work as intended).

Welcome to The WARPEDcore

0.0 - Intro: What is it?

0.0 - Intro: What is it? Trispis Thu, 2006-09-14 19:09

INTRODUCTION

The world changes. And as the world changes, some things stay the same. A number of changes in the MU-niverse in recent years have resulted in a great deal of this document becoming technically obsolete. But this document was never intended as a technical manual. It's a starting philosophy... an illustration of a far off land as seen from a local mountaintop. With that in mind, I have made notes within this document (in bold italics like this message) as well as a few comments below specific pages. I have, for the most part, left the 'theory' in place... even in those places where it's become technically inaccurate.

This document should now be considered a combination of "history" and "planning"... a sort of snapshot image of where this project came from and where it intended to be going (and should sort of still be intending to go).

For years there have been some rumblings about making a decent set of 'core components' for a 'slightly more than minimal db' for PennMUSH. I'm fairly certain there have been similar rumblings among other MUD server flavors. Some evidence of that can be seen in the recent emergence of the Sandbox Globals Project (kudos to Audumla and her team for their diligence in bringing that to fruition). Nonetheless, there is still a 'core' lacking in even this development.

This page attempts to explain what is meant by the concept of a MUD 'core' within the context of this web book, and outlines the goals of the WARPEDcore project.

  1. HISTORY

    This history of this project is, for the most part, restricted to M*U*S*H (the Social MUSH run by Javelin, former maintainer of the PennMUSH source) and several players there who expressed their interest. Twice in the history of M*U*S*H, there have been very intense discussions and bboard interactions on various aspects of this whole 'core' notion. What should it contain? How should it be designed? Who should be responsible for it? Etc. Although both of these more intense discussions eventually degraded into a thousand different opinions, a great deal of overall insight was shared. And from that experience (I, Trispis@M*U*S*H, attempted to actually coordinate the second of those interactions -- sorta like trying to harness a thunderstorm in a paper sack.), I learned that most of the people involved just wanted "something". Their differences of opinion were not nearly as significant as their common desires.

  2. GOALS

    And just what were those 'common desires'? Well, mostly it boiled down to some sort of standardization -- some natural and/or intuitive means of standardizing certain components of MUSH (to reduce inter-MUSH disparities, to reduce the 're-learning' requirements when changing from one game to another, or any number of other syntactic versions of the same thought).

    With that in mind, I studied the various individual requests and assertions, and I discovered something. In order to provide *any* form of standardization at an inter-MUSH level, there needed to be a 'core'... far deeper than simply a 'common set of globals' (+finger, +who, etc.). There needed to be a central, interactive, accessible, maintenance feature. Something that even disassociated softcode packages (Myrrdin's Bulletin Board, Places/Mutter, Keran's Weather, softcoded dynamic space systems, etc.) can 'hook' themselves to.

    So, that's where I decided I needed to apply myself -- to the creation of a MUSH 'core'. And I began to outline some conceptual approaches to this. And, in so doing, I found myself inevitably returning to the concept of a 'db kernel' with a 'registry' -- a system of tracking and maintaining installed softcode packages (such as those mentioned in the previous paragraph).

    A 'db kernel with a registry', yeah... and some maintenance utilities, yeah.

    THAT's what a MUSH "core" is... It's something that is central to *any* and *all* installed packages. Even if a softcoded package isn't designed around the concept of a 'core', the core itself can still provide useful services around and/or for that package.

0.1 - Overview: Where are we going with this?

0.1 - Overview: Where are we going with this? Trispis Thu, 2006-09-14 20:03

OVERVIEW

What is the 'core'? In theory, it's a THING which records and, via a simple function, reports the dbrefs of all the various packages installed on a MUSH. But, in practice, it's a little more than that. Once it builds some momentum,... once all of the 'feep' has had a chance to ripen, it has the potential to become a full-fledged MUSH maintenance utility. Therefore, in order to retain perspective on what actually constitutes the "core", great care must be taken in the development process to ensure that only "core items" get packaged with the core.

  1. DEVELOPMENT

    This brings us to the development process. This core will be developed as a bunch of very small components, focused around the central 'registry object'. That is, in an effort to retain focus on what has been determined to be the 'core' (the 'one object linking all other objects'), all of the installation scripts for various additional features (maintenace tools, whatever) will be maintained and developed individually and separately.

    It is conceivable -- even highly likely -- that there will emerge some interdependencies between these separate packages. This is only natural (one package being a frill for another package, and so on and so forth). This further emphasizes the need to keep the 'core' isolated and protected from 'feep'.

    Yet, by maintaining packages individually in this way, there is also a great deal of freedom afforded to the user... freedom to decide which features and how many of them they want and/or need. And due to the 'script' quality of softcode installation, creating a larger package out of the smaller components becomes a relatively trivial task.

  2. STANDARDIZATION

    There will, of course, need to be a few 'ground rules', in order to provide inter-operable standardization. These will be kept, as much as possible, to a bare minimum. And will further be divided into two groups:

    • "conventional procedures" recommended (but not mandated) for general community support (i.e., these are things that everyone, so far, basically does however they want... but which would simplify the world a lot if everyone did them consistently similar).
    • "mandatory procedures" for being considered 'WARPEDcore compliant' (very few of these, but at least two emerged from the first 2 lines of code I wrote for the 0.00alpha version), and to prevent conflicts with the above conventions.

0.2 - Design: And just how are we expected to do this?

0.2 - Design: And just how are we expected to do this? Trispis Thu, 2006-09-14 20:46

DESIGN PHILOSOPHY

The WARPEDcore is designed around two primary features of MUSH coding. The object and the attribute.

  1. Objects:

    The WARPEDcore Project concerns itself with five (5) primary object groups.

    PLANNED OBJECTS
    Group                   # objects
    Global Command Objects  6-9
    @function Objects       3
    The WARPEDcore          1
    Parents                 10-13
    Utilities               ?
    Total                   20-26 (plus utilities)
    
    1. Global Command objects -- objects located in the Master Room which contain $commands. The WARPEDcore assumes the potential for the existence of nine (9) different combinations of powers and users. Although it is understood that not all of the following will exist on any given MUSH, it is conceivable that they could. Furthermore, it is assumed -- through discussion with seasoned veteran game gods, coders, and developers -- that separation of commands in a manner along the lines of this structure is, indeed, a recommendable approach. In summary, Global Command objects (THINGs inside the Master ROOM object) tend to have:
      1. three primary user groups
        • all players, including mortals (MORT)
        • admins, defined as royalty and above (ROY)
        • wizards only (WIZ)
      2. three primary power requirements
        • no extra powers (MORT)
        • limited powers which are included in the ROYALTY flag (ROY)
        • extra powers only available from the WIZARD flag (WIZ)

      Each user group tends to need $command objects with powers equal to or greater than their own power level. There is some debate as to whether or not admins and wizards need $command objects for power levels less than they possess. Nonetheless, the WARPEDcore assumes it is a possibility and accounts for it as such.

      NOTE: The WARPEDcore does not recommend, nor does it account for, optional objects having specific @powers (e.g., see_all, tport_anywhere, tport_anything). The inside track from one MUSH developer asserts that privilege checking is more robust and reliable when checking for a flag, than when checking for a @power. Therefore, the WARPEDcore restricts its design assumptions to only the above three power categories: mortal (no additional powers/privs), royalty flag, and wizard flag.

      Using the above categories of users and powers, the following nine THINGs can be derived:

      The "users" below are assumed to be upwardly inclusive (i.e., mortals == mortals, royalty, and wizards; royalty == royalty and wizards; wizards == wizards only).

      • mortal powered commands for mortal users
      • royalty powered commands for mortal users
      • wizard powered commands for mortal users
      • mortal powered commands for royalty users (debatable, but possible)
      • royalty powered commands for royalty users
      • wizard powered commands for royalty users
      • mortal powered commands for wizard users (debatable, but possible)
      • royalty powered commands for wizard users (debatable, but possible)
      • wizard powered commands for wizard users
    2. @function THINGs -- THINGs containing attributes which are applied globally via the @function command. Similar to $command THINGs, the WARPEDcore assumes the need for a variety of power levels for various @functions (The WARPEDcore project is being developed on PennMUSH. Therefore, unlike $command THINGs, the WARPEDcore does not assume delineation of user groups for @function THINGs, because PennMUSH has a built-in @function/restrict command expressly for this purpose.). And, again, these power groups are:
      • no extra powers (MORT)
      • limited powers included in the ROYALTY flag (ROY)
      • extra powers only available from the WIZARD flag (WIZ)
    3. The WARPEDcore: A Registry -- At its most basic, primary level, this term references a single object serving two primary purposes:
      • a registry for, or database of, all of the other object types. (Details about this THING are contained in the remainder of this document.)
      • a set of core @functions shared and/or utilized by all other object types covered in the WARPEDcore design.
    4. Parents
      • In the Master Room, for example, the fewer attributes that need checked for $commands, the better. One way to accomplish this is to set all non-$command attributes no_command. But a simpler method is to simply use @parent, and put all of the non-$command attributes on the parent... and store the parent in the contents of the $command THING.
      • As @functions propagate, this same method can be used to separate the primary attribute (the one actually called by the @function-ed name) from any/all of its supplementary support attributes (written on the parent, which is stored in the contents of the @function THING itself).
      • When considered from an organizational perspective, each of the above 13 THINGs (9 possible $command THINGs, 3 @function THINGs, and the WARPEDcore) could, in a minimalist configuration, all use a single parent, since parenting operates with the privileges of the child THING. Alternatively, each of the above THINGs could have a parent of its own on which support attributes of various types are kept, plus a common 'grand'-parent for shared utility functions. This, too, has been deemed reasonable as 'good design structure'. And, as such, the WARPEDcore will anticipate this type of design and will have accomodations for dealing with it.
    5. Utilities -- this object category refers to WARPEDcore utilities only. That is, objects which are included under the umbrella of 'Official WARPEDcore Distribution' objects, but which are not members of the categories listed above (an example: a global testing and debugging zone and/or widget set).

    In summary, as far as objects are concerned, the WARPEDcore Project focuses on the fact that a MUSH requires a certain number of objects to build a game's global infrastructure (not including: add-in packages like Myrddin's BBoard, or custom-built packages like chargen). In common practice, as a game grows in size, more and more objects become part of the infrastructure. How many THINGs are in your game's Master ROOM? How many THINGs does your game use for @functions? How quickly can you locate the code for any given feature on your game? The WARPEDcore attempts to provide a paradigm for an infrastructure which uses a fixed number of objects in a versatile and well-organized manner.

  2. Attributes

    The WARPEDcore assumes, and is designed to accomodate and account for, several specific types of attributes. Each type has been assigned a four-digit identifier for use in other aspects of the WARPEDcore (explained later in this document).

    Type        4dig        For...
    COMMAND     CMND        attributes containing $commands
    LISTEN      LSTN        attributes containing ^listen patterns
    UFUN        UFUN        attributes called via u(), filter(), etc.
    TRIGGER     TRIG        non-$command and non-^listen attribs 
                            which should be triggered with @trigger.
    DATA        DATA        attribs which contain data elements or 
                            data structures
    LIST        LIST        attribs which contain delimited lists
    LOCK        LOCK        attributes used in indirect locks
    ZONE        ZONE        zone-specific or zone-related attributes
    HELP        HELP        attributes containing help files
    NOTE        NOTE        attributes containing notes, comments, etc.
    TEMP        TEMP        temporary storage (users should be able 
                            to expect to freely delete these without 
                            disrupting functionality)
    

    **** DBREF - One person who reviewed this document suggested that there be a four-digit prefix for indicating storage of a #dbref pointer, such as DBRF. After lengthy consideration, it has been decided that "DBREF" is not actually an attribute category. Rather, when storing a #dbref in an attribute, that attribute is more correctly categorized as a DATA attribute (or, in the case of a list of #dbrefs, a LIST attribute). Furthermore, in any instance other than a PREFIX, it would likely not be used in the four-digit form (e.g., DATA.SUPPORT_FUNCS.DBREF). Thus, there is no reason (at least not within the design of WARPEDcore guidelines) to truncate DBREF any shorter than the five characters which have become standard and common (DBREF == DataBase REFerence number, aka #dbref). -- If, however, you disagree with this and wish to have a separate category and four-digit identifier for #dbrefs, there is sufficient flexibility in the documentation options to allow this in a WARPEDcore compliant manner (see the documentation options in later sections)

    NOTE: It is possible for a single attribute to belong to more than one of the above types (e.g., 'help' files for a specfic 'zone'). Which type is primary to the attribute is, of course, a subjective assessment. This issue is further addressed later in this document.

0.3 - Attributes: Give me where to stand...

0.3 - Attributes: Give me where to stand... Trispis Fri, 2006-09-15 03:28

The introduction of attribute trees creates a new behavioral model for exploration and exploitation.

An implication worth noting is the emphatic new conceptual distinction between a single attribute

&example me=this is an example

and the single attribute which also serves as the root segment of an attribute tree

&example me=these are my examples
&example`a me=these are my 'a' examples
&example`a`1 me=this is example 'a1'
&example`a`2 me=this is example 'a2'
&example`b me=these are my 'b' examples
&example`b`1 me=this is example 'b1'
&example`b`2 me=this is example 'b2'

This is a new conceptual imperative: Any single attribute can, at any time, conceivably be (become, be treated as, and/or behave as) a portion of an attribute tree.

This imperative's potential lends itself somewhat naturally to subroutine management such as that illustrated by the ~reboot module in which @startup behaves both as a single attribute (containing code which is triggered at startup)

@startup #1=<this code is automatically triggered and it retrieves code from attribs in the startup` tree without directly triggering those attribs>

and as the root of a tree of other attributes (each containing code to be placed in the queue by the code in the @startup attribute).

&startup`0000 #1=<this is the first piece of code retrieved for execution by me/startup>

(Changes to ~reboot pending.)

Other implications resulting from this imperative can be found, coincidentally, within god's startup actions: specifically those actions involving the @attrib command and its family.

Give me where to stand and I will move the earth.

A remark attributed to Archimedes by Pappus of Alexandria (in his "Collection") and commonly called "Archimedes Lever", this simple assertion of relativity long predates that of Einstein's mathematical equations. Furthermore, Archimedes assertion better illustrates the reality of human experience.

In a very 'human experience' way, Archimedes Lever describes this new imperative of attribute trees with tremendous precision.

An examination of a minimalist example can illuminate this for us quite nicely, so let us look at a tree based on single-character name segments. To explore this concept, we'll use our special attribute, the tilde (~), as the root of the tree, then expand it with other common single characters (0-9, a-z, possibly others) as branches and leaves.

Let us first work with 0-9 as leaves, directly attached to the root.

~
~`0
~`1
~`2

etc...

This imperative carries one set of implications if the root attribute needs different attribute flags than the numbered leaf attributes, and another set of implications if the root attribute is flag-indifferent (e.g., it's empty - the default, since it's automatically generated whether you intend to use it or not).

Once again, our startup` tree, if applied to a player ancestor, illustrates this well -- you want the basic processing code (the startup attribute) to be available to all players, yet you also want the remainder of ancestor's startup' leaves to not be inherited (i.e., only apply directly to ancestor) -- you can do this by setting the branch (startup`) no_inherit.

If the tree is expanded to more levels (e.g., the addition of a-z as leaves on the 0-9 branches), the aforementioned implications remain present. However, as the number of levels increase (at least the first few branches beyond the first branch) these same implications can become organizational organizational variables. For example, ...

~
~`0
~`0`a
~`0`b
...
~`1
~`1`a
~`1`b
...

It's important to remember, at this time, that restrictions are inherited but privs are not, and that restrictions are only inherited by the leaves of the branch to which they're applied.

Adding to this, entire trees can be completely veiled from a default examine by simply veiling their root attribute.

So, one of potentially countless applications of our 'where to stand' philosophy is that at any single branch point (where to stand) we have the ability to control (restrict) all of its leaves (move the world)... all the while leaving the branch point itself (which may be an in-use leaf of a lower branch) and all subsequent branches (leaves of the current branch which are also branch points for subsequent branches and/or leaves) and their leaves unaffected.

And this is as good a time as any to complicate the overall situation even further (at least initially) by re-introducing the attribute naming concepts from the original version of this section. (Until I add a more updated and relevant version of these concepts, you can review the 'Old' subpage of this page.)

Old - A rose by any other name..

Old - A rose by any other name.. Trispis Sun, 2007-03-11 12:00

NAMING CONVENTIONS

One of the key components of 'standardizing' relates to attribute naming conventions. For example: If you wanted to find all attributes on a given object which contain $commands, you would either:

  • Use grep() to find all attributes whose contents begin with the $ character.
  • or...

  • Name all of your attributes in such a way that their contents are identifiable by that name, and use lattr() to find all attributes identifiable as containing $commands via some component of their attribute name.

If this example is extended to include other attribute types (HELP, UFUN, etc.), it becomes obvious that the latter method (standardized naming) is the preferable approach. And, as you will see in further reading of this document, it becomes THE key component in management of globals. In fact, standardized attribute naming is the crux of the entire WARPEDcore project. By utilizing a functional and intuitive standardized naming convention, it becomes possible to easily manage and coordinate a large number of objects, including those not written expressly under these documented conventions.

The WARPEDcore will use the following naming conventions. And, although these are recommended for all softcoders (simply to provide easy readability in the event someone else might have to sort through your code someday), it is understood that pre-existing style and/or habit may be difficult to circumvent. Therefore, in addition to these recommended conventions, the WARPEDcore also provides a means of documenting pre-existing code and pre-existing attribute naming conventions.

  1. Recommended Procedures -
    1. Name Components: Except in special circumstances which dictate otherwise, attribute names should consist of a set of component item segments joined by a non-alphanumeric delimiting character. In this section, you will find the WARPEDcore recommended procedures.
      NOTE: As stated earlier in this document, the PREFIXes listed below also serve as Official WARPEDcore attribute type identifiers. See also: the 'Adaptation' section below, for details on documenting pre-existing code.
      1. PREFIX: This is the first component of an attribute name and it will identify the attribute's "type" classification ($command, ^listen, user-defined function, @trigger, data, etc.). This component shall be one of the following types. In the list below (repeated here for convenience when using the multi-part document), you will find both the full name (for those who like to spell things out), as well as a corresponding four-digit prefix (for those who like things to line up neatly), for each type. See the section on documentation, further along in this book, for more information on how to document the use of these.
        Type        4dig        For...
        COMMAND     CMND        attributes containing $commands
        LISTEN      LSTN        attributes containing ^listen patterns
        UFUN        UFUN        attributes called via u(), filter(), etc
        TRIGGER     TRIG        non-$command and non-^listen attribs 
                                which should be triggered with @trigger.
        DATA        DATA        attribs which contain data elements or 
                                data structures
        LIST        LIST        attribs which contain delimited lists
        LOCK        LOCK        attributes used in indirect locks
        ZONE        ZONE        zone-specific or zone-related attributes
        HELP        HELP        attributes containing help files
        NOTE        NOTE        attributes containing notes, comments, etc.
        TEMP        TEMP        temporary storage (users should be able to 
                                expect to freely delete these without 
                                disrupting functionality)
        

        NOTE: It is conceivable that an attribute might belong to more than one of the above types. In such situations, it is recommended that the broader category (per the object's purpose) be considered the PREFIX for that attribute (e.g., LOCK`ZONE -- as an object may have numerous locks, but only one zone). Nevertheless, it remains a subjective decision. Think about it in terms of where you want attributes grouped when listed in a default, lexicographical sort.

      2. PRIMARY: This is the second component of an attribute name. If related to a $command or ^listen pattern -- either directly, or indirectly via a support attribute -- it should reflect the originating syntax (CMND`WHO, UFUN`WHO). In situations where no 'input origination' is applicable -- such as automated or timed processes, or general utility functions -- it should reflect the general purpose of the process (UFUN`ALPHASORT).
      3. SECONDARY: This optional component can be used to identify the purpose of individual subprocesses (e.g. UFUN`FINGER``ERROR, TRIG`UPDATE`LOOP, etc.).
      4. TERTIARY: Again, optional. And again, for identifying subprocesses (at this point, numerals might seem likely candidates, such as: TRIG`UPDATE`LOOP`3).
      5. SUFFIX: Finally, an optional suffix may be used to indicate other relevant details (DATA`UPDATE`LOOP`3`VARIABLES, CMND`SET-FACTION`REGEXP, etc.)
    2. Name Delimiters:

      All attribute name components should be separated by the back-tick (`) character.
      Syntax Summary:
      <PREFIX>`<PRIMARY>[`<SECONDARY>][`<TERTIARY>][`<SUFFIX>]

    3. Registers, Globs, and Wildcards -
      1. When using the most basic form of globbing registers ($foo *), it is recommended that the X character be used to indicate the asterisk or 'globbed wildcard' (*) (aka the presence of a single %-register) when two commands or processes have the same basic beginning syntax and one of them has a single glob (e.g., $foo, and $foo *), or when the attribute only accepts one such input (e.g., CMND`FINGER_X, UFUN`FOO_X). (This convention is derived from general mathematics and/or algebra in which x has become the 'default first variable'. And because it is the character which most closely resembles the asterisk, which cannot be used in attribute names. Thus, it seems intuitive not only for basic learning, but also for simplifying a standard. See below for more enhanced conventions.)
      2. In situations where multiple globs or registers are present, this above representation can be expanded to use R0, R1, etc. for %0 (%-register 0), %1 (%-register 1), etc. (respectively). (This is derived from the r() function,... for those wondering why it's not P# for 'Percent'.)
      3. Regular expression -based $commands (where %0 == the entire input) can be potentially troublesome for this type of attribute naming process. Nonetheless, regexp command structure can be indicated by having R0 be the last listed register (derived from the fact that R0 isn't technically complete until all other registers have been completed), or by appending a suffix identifier. For example: CMND`FOO_R1_R2_R0 or CMND`FOO_R1_R2.REGEXP
      4. Furthermore, if it is necessary to distinguish between * and ? -based registers, the above conventions can be further expanded to include: X0, X1, X2, etc. for *-based registers and Q0, Q1, Q2, etc. for ?-based registers (Q for Question mark).
      5. Lastly, note that these variable representations are intended primarily to express what the attribute accepts as input. It is far too difficult and complex to attempt to address and document all possible output combinations -- especially considering the fact that a ufun containing a switch() could easily have options for calling more than a dozen different other ufun's and sending different stuff to each. If you wish to reflect both input and output, your attribute name should reflect that you are doing so (.e.g., UFUN`FOO`IN_R0-R1-R2`OUT_BAR-R0X1_BAZ-R1X2 -- NOTE: Attempting to indicate this much information immediatly crosses the border into excessiveness and is not recommended. Yet, as it is conceivable that an extremely large project might actually need this for clarity, it has been included in this document.)
    4. Other
      1. The underscore (_) should be used for indicating the presence of a literal 'space' (e.g. CMND`FINGER_X) in the syntax of the command.
      2. The hyphen (-) and should be used to indicate other special characters (slash, colon, comma, etc.)
      3. The dot(.) should be used when adding a supplimental name segment for which a new tree branch is either not required or not desired (e.g., &CMND`FINGER_X.NOTE).
  2. Mandatory Procedures - (Mandatory Procedures have been removed, due to new (since the time of the original version of this document) features of Pennmush which make a 'registry thing' unnecessary.)
  3. Adaptation Options

    This section acknowledges the enormous burden of rewriting existing code to comply with the above recommended conventions. Additionally, it also acknowledges the difficulty in changing existing behaviors (old habits are hard to break). Therefore, in order to simplifying the conversion of pre-existing code (and, thus, pre-existing attribute names), personal preference, and/or habitual behavior to WARPEDcore managable structures, the following Adaptation Options have been established (NOTE: Even I, the author of this document, do not *always* use the same standards from one project to another. Ever since I started coding, I've experimented with different ways to benefit from structured attribute naming conventions. Thus, my own coded systems aren't even compatible with each other. Yet, it is out of this experimentation and in direct response to that universal disparity, that I present these conventions... and these Adaptation Options. I may or may not eventually rewrite my existing code using the conventions recommended above, but I will certainly use the Adaptation Options listed herein to make them WARPEDcore managable). The hope here is that rewrites can be reduced to a bare minimum, by simply providing a WARPEDcore compliant documentation of existing attribute naming conventions.

    The following documentation conventions are recommended for adapting existing code or existing coding styles (ref: attribute names) to WARPEDcore managable structures. These conventions are divided into two sections. The first section covers the conventions for identifying general attribute types. The second section covers some special 'personal attributes' which are recommended for all objects which are intended to be registered with the WARPEDcore.

    1. Documentation Attributes (Likely to be rewritten)

      Based on the above list of recommended PREFIX components to denote attribute types, the following documentation conventions are recommended for adapting pre-existing code to WARPEDcore managable structures. In summary, you should provide a ~. attribute for each attribute type relevant to your code (i.e., if you don't have any LIST-type attributes, there is no need to document them). And each attribute should indicate your code's conventions for that attribute type, using the following procedures (derived partially from regular expression syntax).

      1. if you document your code using these conventions, your object should contain an attribute named ~ (a single tilde). The presence of this attribute will indicate you also have other WARPEDcore documentation attribs per the remaining items in this section. And, you may add optional comments in this attribute per the following two guidelines...
        • If your attribute naming conventions comply with the recommendations above, this attrubute's contents should contain at least a tilde (~) as its first character. And, if you use the recommended 4-digit type identifiers, it should be immediately followed by a number 4. Examples:
          • &~ object=~ This package is believed to be WARPEDcore compliant and uses full words for attribute types and other attribute name components.
          • &~ object=~4 This package is believed to be WARPEDcore compliant and uses the 4-digit identifiers for attribute types and other attribute name components.
        • If your attribute naming conventions deviate from those recommended above, ensure that the first character of this attribute's contents IS NOT a tilde (e.g., &~ object=This is an adapted version of some old code I did ages ago. Some of it isn't fully compliant to the WARPEDcore style.)
      2. documentation attributes should begin with ~. (tilde dot) and be followed immediately by one of the aforementioned attribute type identifiers (aka, the recommended PREFIX components).
      3. the attributes should contain the character string YOU used for the respective attrib-type.
      4. if your string is used as a PREFIX and/or is not followed immediately by a dot (.), denote this by adding a comma (,) and a caret (^).
      5. if your string is used as a SUFFIX and/or is not immediately preceeded by a dot (.), denote this by adding a comma (,) and a dollar sign ($).
      6. if you use an inner string (something neither a prefix nor a suffix, yet a consistent character string -- e.g. FINGER.COMMAND.2), denote this by itself (i.e., no comma or other symbol following it, but still denote it).
      7. if you do not consistently use any specific character string, do not denote it at all (don't add the attribute at all).

      Some examples:

      • &~.COMMAND =DO_,^ -- This would indicate that attributes on this object which contain $commands (attributes of type "COMMAND") have a PREFIX element (denoted by the ^) of DO_
      • &~.COMMAND =_CMD,$ -- In this case, COMMAND-type attribs have a SUFFIX component (denoted by the $) of _CMD
      • &~.COMMAND =COMMAND -- In this case, CMND-type attribs (always) contain the string COMMAND in their name, but it is not consistently a prefix or suffix (possibly either, or, or neither).
      • Objects which do not have a consistent procedure for COMMAND-type attribute names, should not have a ~.COMMAND attribute.

      Other examples:

      • &~.TRIGGER =.TRIG,$ -- Just to illustrate a few more... This would indicate that attributes on this object which are of the TRIG-type have a SUFFIX component ($) of .TRIG. NOTE: Even though the four-digit identifier is the same as that recommended (TRIG) and the delimiter used is the same as that recommended (.), it is a SUFFIX, rather than a PREFIX (recommended). Therefore, this documentation is recommended.
      • &~.HELP =HELP_,^ -- This would indicate that attributes on this object containing help files have a PREFIX component (^) of HELP_. NOTE: Even though the four-digit identifier is the recommended one (HELP) and it is a PREFIX (recommended), it uses the underscore (_) as its post-prefix delimiter rather than the recommended dot (.). Therefore, this documentation is recommended.
    2. Personal Attributes (Likely to be rewritten)

      The following is a list of special 'personal attributes' which are recommended to be included - at least as many as are applicable - in all softcode packages, regardless of whether or not you use any of the other aforementioned conventions

      NOTE: Use the single tilde attribute to denote the presence of these special attribs. Do not, however, confuse the presence of these 'personal attributes' with 'being WARPEDcore compliant'. That is, if all you have done is add these attributes for personal reference or credit, then the single tilde attribute's contents' first character should NOT be a tilde. The attributes listed below are for package identification only and bear no relevance whatsoever to overall WARPEDcore compliance.

      • ~.AUTHOR -- to contain the name or preferred identity (or plural, if more than one) of the current author(s) or maintainers(s).
      • ~.AUTHOR.EMAIL -- to contain the email address of the package's author or maintainer
      • ~.AUTHOR.URL -- to list the author's URL (aka webpage), if s/he has one.
      • ~.LICENSE -- to identify the name (e.g., GPL, LGPL, Modified NPL, whatever) or general type (Creative, Public Domain, whatever) of the license applicable to the code.
      • ~.LICENSE.URL -- to list the URL where this code's license can be found (e.g., It's not feasible to attach complete copies of the GNU General Public License to a softcode package. Especially considering the enormous numbers of packages on the net which are increasingly using this license. Thus, a URL pointer is appropriate.)
      • ~.URL -- to list the URL where this code can be acquired (http, ftp, etc. should be specified).

      Since much of this is still in early development, some of these procedures may be subject to modification. And the list of 'special attributes' is certainly likely to grow in time.

NOTE: This page is out of date and will soon be updated to include the new (since the time this document was originally released) 'attribute trees' feature of PennMUSH as part of these design concepts. (Thanks, Talek!)

Although I see many option and combinations, these are my notes to illustrate the direction I see going with this...

Wise Man Say: Flowering Shrub uses Attribute Tree features to organize code for examination.

Sample Template:

<grandpackage>`<package>`<attr_type>.<syntax>

In this template,

<grandpackage> would be the equivalent of any one of: The Sandbox Globals Project, all of Myrddin's stuff bundled together, The mythical MUDcore supposedly written by Amberyl, etc., &c. Ideally, this would be an abbreviated version thereof (e.g., SGP for The Sandbox Globals Project). The WARPEDcore Project will use the single tilde (~) for this.

<package> would be the equivalent of a category of commands. In order to see this properly, one must envision the product as it could be at some point just just beyond what one would think of as 'complete'. Let's take, for example, a +finger command. No matter how much stuff you pack into and/or around this, in the end, it's just a single command. However, history shows that there are a number of 'social information' commands related to this (i.e., +who, +where, etc.), each of which could be quite robust in its own right yet each also just a single command. As single commands, they'd not be individual members of this category; but, as a group of 'social information' commands, together they become a <package>, such as 'socials' For example:

&SGP`SOCIALS`CMND.FINGER_X

Although I may not have presented this perfectly in this initial draft of my thoughts, the point here is that when you start writing attribute names, think bigger than the immediate feature -- place the immediate feature (whether it be a command such as +finger, or a unique ufun to sort-by-avg-idle-over-last-2-hours) into the context of a larger picture and include your 'maximum package name' appropriately as part of your attribute naming process. This sets your code up in a way such that it can be 'grafted' (copy/paste-migrated) onto yet a larger package than what you might have planned (<greatgrandpackage>?). For example, assuming licensing permits, SGP could be adapted to this design such that very little modification would be needed to make it 'attachable' to the WARPEDcore as a compatible module, yet still retaining it's separateness in development maintainership. E.g.,

~`SGP`SOCIALS`CMND.FINGER_X

And, please... if you see a better way of doing this, by all means, do it... but PLEASE... POST SOMETHING HERE! Share your insight!

reserved attributes

reserved attributes Trispis Mon, 2004-03-08 12:45

I have been intermittently refining my installer for the warpedcore cron (for details, ref: most recent innovations conference presentation).

Two issues have sort of emerged (in my mind) from this refinement process.

1) purifying the cron concept (i.e., making sure that the installer only does things necessary for the cron itself, independent of any warpedcore ideas I may also have),

and as a direct result of that,

2) ways to extend the cron into the itbg discussed vision.

There's also a third issue that tends to arise every time I do an installer, and it is this issue thing I want to discuss (now having teased you with my cron, which is really irrelevant to this).

Every time I try to create an intelligent (self-monitoring, featureful, whatever) installer, there's one thing I keep concluding as 'necessary' -- an attribute on the player... a place to store and/or update installation status data.

And every time I think of this, I encounter the same problem...

What if the player happens to be using (regardless of how remote the possibility is, it nonetheless exists) the attribute name I'm using in my installer?

So, I've written a version which tries to determine a 'safe' attribute name from a limited selection of options (e.g., A B or C), as a solution for this. Specifically, to temporarily store 'their attribute contents' somewhere else while I use my static attribute name for my installation purposes (and at the end of the installer, I move their contents back).

What I'm wondering is ... is there any way to get a pulse on the MU* community to determine if "<an attribute reserved in some way for installers>" is a desirable and/or feasibly implementable fixed feature.'

At present, I am only thinking of a single reserved attrib; but, for the sake of general inquiry, it's probably appropriate to consider a larger scale implementation (a set of standardized reserved attribs for technical use/needs).

I discussed this with Javelin on M*U*S*H, and he proposed some ideas. I've included his input below.

* From afar, Javelin [...] can think of at least one algorithm for generating an attrib that's not on the current player for sure. Or, [if] this is for admin use, you could do an attrib tree rooted at [<string>`].

* From afar, Javelin would be inclined to suggest the attrib tree approach a la "registry". Attrib settable only from port descriptor is kind of a nasty hack.

* Javelin pages: Well, you could promote a conventional attribute hierarchy called "EXTSYSTEM" or something, and have people who write external systems claim a subhierarchy with their name (TRISPIS) or system name (WARPEDCORE), and then use an attribute named EXTSYSTEM`WARPEDCORE`OBJS or whatever. If God does @attrib/access on EXTSYSTEM to make it wizard-only or whatever, mortals won't be able to muck with any of the attributes beneath that label.

* Javelin pages: You still have a problem on sites where someone's using EXTSYSTEM`WARPEDCORE already, but that seems more than highly unlikely.

* From afar, Javelin was going to write an object integrity checker using a similar principle, actually. Each object's attrib would get hashed with SHA() and then the hash stored under SHA`, so you could quickly see if any attribs had changed since you last generated the hashes.

* From afar, Javelin *could* see a point in a hardcode function like tmpname(obj) that would return a valid unused attribute name for obj.

* Javelin pages: But it wouldn't return the same name every time, necessarily.

* From afar, Javelin (also knows how to softcode such a function)

* Javelin pages: Do you just need an attrib name known not to exist, or does the same name have to persist over time? (Answer: for my purposes it only needs to persist for the duration of the install, but I can certainly envision more extended duration needs).

* Javelin pages: Well, you can secure ~ as a special on a per-game basis, obviously, by warning Gods to use @attrib to do so. That's a bit specific to put in the distribution, though

* Javelin pages: [...] The @attrib command would be something like: @attrib/access/retroactive ~=wizard

* Javelin pages: The certain safe attrib algorithm is pretty simple. Sort the existing attribs by length, and iterate through them from shortest to longest. Make your new attrib name by taking the n'th character of the n'th shortest attribute and incrementing it (A->B, B->C,... Z->A, similar for symbols). If there is no n'th character of the n'th shortest attrib, assume it's an A. When finished, check to see if the attrib is on the object. If so, add an A to the end and check again (if it's still on the object, you lose, but that's highly pathological, as it means people are using extremely long attrib names to screw with you.)

* Javelin pages: The concept of that algorithm is you're creating an attrib that's known to be different from the first attrib, known to be different from the second, known to be different from the third, etc.

* SYNC: Mon Mar 08 10:05:00 2004

attribute trees are presently part of the development branch and about to be merged into the stable branch (see Jav's latest post about this), so now might be a very good time to be investigating these options in that frame of reference.

Ciao

0.4 - @FUNCTIONS: No, no! Not TH@!

0.4 - @FUNCTIONS: No, no! Not TH@! Trispis Fri, 2006-09-15 04:02

@FUNCTIONS

The WARPEDcore creates and utilizes two libraries of custom @functions, generally categorized as core functions (~functions) and module functions (.functions).

  1. ~functions
    1. The Tilde (~): Functions which have been incorporated into the WARPEDcore either as a primary distribution function or as one of the various primary module add-ons will have the tilde (~) as their first character. This is the only unique and/or mandatory feature of these functions. (i.e., on the WARPEDcore, their attributes will be named in the format: FN_~<name>)
    2. The List: Below is a list of all known functions currently included in the WARPEDcore and/or it's primary modules.
      • ~([version|indate|update]) - This is the primary WARPEDcore function. If no argument is given, simply returns the WARPEDcore #dbref. If one of the optional arguments is input, it returns information about the WARPEDcore accordingly. Any other input results in a #-1 error.
      • ~db(<module>[, <element>]) - This function returns the primary (aka first, aka main) #dbref of any registered <module>. If the optional <element> (single integer only) is provided it can be used to return other subsequent registered #dbrefs for <module>.
      • ~ldb(<module>) - This returns all #dbrefs registered for <module>.
  2. .functions
    1. The Dot (.): Functions which are added by modules other than the primary WARPEDcore should use the dot (.) as their first character. This is the only unique and/or recommended feature of these functions. Ideally, these @functions will be installed on one of the 3 @function THINGs described in the DESIGN section (above). (i.e., on the various @function objects, their attributes will be named in the format: FN_.<name>)
    2. Examples: Below are some fictitious examples for how one might use this aspect of the WARPEDcore.
      • .weather(<season|short|long>) - this is an example of how one might implement a custom function for accessing some known features of "Keran's Weather".
      • .bb(<hdr|bdy>,<groupname|groupnum>,<messagetitle|messagenum>) - this is an example of how one might implement a custom function for accessing messages from "Myrddin's Bulletin Board".
  3. +functions
    1. The Plus (+): Functions which are added by the game maintainers and which are unique to the particular game on which they are installed, should use the plus (+) as their first character. This is the only unique and/or recommended feature of these functions. Ideally, these @functions will be installed on one of the 3 @function THINGs described in the DESIGN section (above) using attribute names such as: FN_+<name>.
    2. Examples:
      • +space2tilde(<string>) - it seems every MUSH has a @function similar to this, to convert "something like this" into "something~like~this"
      • +tilde2space(<string>) - and, of course, the reverse, to convert "this~string" into "this string"

0.5 - The Registry: The beginning of the end

0.5 - The Registry: The beginning of the end Trispis Fri, 2006-09-15 04:21

The REGISTRY

See the comments below this page.

As indicated in several places throughout this document, the WARPEDcore is intended to serve as a registry for any and/or all of your global objects ($command globals in the Master Room, as well as global @function objects). This section covers the procedures and standards for registering such objects, and lists any reserved module names (intended solely for standardization purposes).

  1. Attribute Names

    As indicated in the section on attribute naming conventions, the WARPEDcore is intended to record the #dbrefs of your globals and other key objects of your game. This is accomplished by storing said #dbrefs in attributes on the WARPEDcore itself, using a special attribute naming convention. When registering an object, the following guidelines must be observed.

    1. The attribute name must begin with DB_, followed by the registered module name
    2. The module name, if it isn't completely obvious, should be representative of the object being registered.
    3. Any characters allowed in an attribute name are allowed in a module name. However, it is recommended that the dot (.), the tilde (~), and the underscore (_) not be used as the first character, and that the underscore (_) be used in place of a literal space.
    4. Examples:

    • DB_BBOARD
    • DB_MYRDDINS_BBOARD
    • DB_PLACES-MUTTER
  • Attribute Contents

    The registry attributes (those beginning with DB_) only contain #dbrefs. Furthermore, the #dbrefs stored in these attributes should be efficiently kept to a minimum. When registering a module, only register the lowest 'child' #dbrefs of any parented systems. Furthermore, do not register objects which are spontaneously created by other registered #dbrefs. Some examples...

    • DB_MYRDDINS_BBOARD would contain only the #dbref for the main $command object. The "bbpocket" object would not be registered, since that object is the parent of the main command object (and thus, implicitly included already). Likewise, none of the #dbrefs for the individual bboard group objects should be listed either, as they are subject to spontaneous creation and destruction by the main object.
    • DB_ACTIVITY The +activity global on M*U*S*H (although not yet a publicly released package, it is hoped that it someday will be -- nevertheless, it is still a register-able module) has a $command object parented to a functions object, a timed processes object, and 8 databases (one for each day of the week, and one for the week as a whole). This module would register the $command object first, followed by the triggered processes object. The 8 database #dbrefs could optionally be registered, but the fact that they are located in the contents of the triggered processes object might be sufficient in itself -- this is a subjective call, based on coder preference. It would not, however, list the functions object, because it is a parent to one of the other objects. In all, this attribute could conceivably contain two (2) or ten (10) #dbrefs.
  • Reserved Module Names

    The following module names (in the form of attribute names) have been reserved in an effort to promote standardization growth.

    • DB_MORT_CMND_FOR_MORT
    • DB_ROY_CMND_FOR_MORT
    • DB_WIZ_CMND_FOR_MORT
    • DB_MORT_CMND_FOR_ROY
    • DB_ROY_CMND_FOR_ROY
    • DB_WIZ_CMND_FOR_ROY
    • DB_MORT_CMND_FOR_WIZ
    • DB_ROY_CMND_FOR_WIZ
    • DB_WIZ_CMND_FOR_WIZ
    • DB_MORT_FUNC
    • DB_ROY_FUNC
    • DB_WIZ_FUNC

    These reserved names will allow installation packages to locate the appropriate objects for writing their attributes, rather than creating a new object.

  • 0.6 - The Cron: Is it that time already?

    0.6 - The Cron: Is it that time already? Trispis Fri, 2006-09-15 14:43

    This page replaces the section of the Manifesto called "UTILITIES". Somewhere on this site is a post I made about the cron; and, since I have code written for the core and the cron, I've decided to relegate the remaining previously-documented piece (the Debug Zone) to a potential contributor module.

    You can read my whole ITBG Presentation for a philosophical history of this module. I've included the currently pertinant points here. The URL's referenced below can be retrieved from www.archive.org, if you really need to see them.

    We need an optimized cron. Something which provides maximum potential to both the core, and the game in general. Yet which also must be inter-connected with a registry (a MU* portions maintenance and accounting widget).

    Are there cron systems available? Of course. Myrddin has a nice one. Raevnos wrote a pretty nifty one for M*U*S*H a couple years ago which even uses an internal registry. So why not use one of these? Especially Raev's... which superficially appears almost to have been written specifically for the warpedcore design (described above) ??? why not? Raev's a good guy,... surely he'd be open to some sort of contribution negotiation...

    But wait...

    Javelin implemented a cron of a wholly different type on M*U*S*H. A chat channel broadcast based cron. Objects can connect to this channel and listen for the various and sundry broadcasts. Jav's also has a very intrigunig side-effect -- systems using the cron all happen to be conveniently connected to a specific chat channel -- or, phrased a bit more organically: objects using the cron have created a sort of registry of their own via the cwho() function.

    Raev's has an added benefit of having objects registered in various 'intervals', but Jav's is a simpler implementation which doesn't need any maintenance after a purge.

    Jav's can also be easily extended to do broadcasts as frequently as once a minute, (Jav's currently is only once an hour) without any noticable increase in overhead or workload (even more frequently, if you're careful).

    A channel based system could be expanded to have multiple channels for the various frequencies (hourly, 2hourly, whatever). Plus, channels for other broadcasts (core system messages, if such a need arises, perhaps?). But is channel proliferation desireable? probably not.

    But, a channel based system does allow for a significantly larger amount of information to be broadcast each 'tick'.

    Jav's version does multiple emits for hours which fit multiple categories. For example...

      <-Clock-> HOURLY: Wed Oct 22 20:00:04 2003 
      <-Clock-> HOUR20: Wed Oct 22 20:00:04 2003 
      <-Clock-> FOURHOURLY: Wed Oct 22 20:00:06 2003
    

    like that. This isn't bad on an hourly basis. But if broadcasts were every minute, the ticks on the hour would be hugely spammy... especially if a wider variety of less frequent intervals were included (5min, 10min, etc.)

    So, I played around with the channel concept and came up with some modifications and enhancements.

    First, I dabbled with a bit-based system which uses 1's and 0's to indicate whether or not a given broadcast tick was a member of the various intervals (daily, 12hourly, 8hourly, 6hourly, 4hourly 3hourly, 2hourly, hourly, 30m, 20m, 15m, 10m, 5m).

    http://www.elsemu.net/~nemo/cron_bits.txt

    The objections to this mainly pertained to the fact that a bit-based system (strings of 1's and 0's) isn't conducive to human implementation.

    So, I dabbled with another version using an alphanumeric (more 'human readable') implementation, using the same intervals.

    http://www.elsemu.net/~nemo/cron_alphanum.txt

    They each have their advantages.

    The alphanumeric would be easier to document/explain in a help file, and easier for most folks to get adjusted to using.

    But the one with bits allows you to do a few things the other doesn't, such as listen for 5m intervals that AREN'T also 15m intervals (*0?1).

    So, I combined them and added a snippet of code which tells you the number of the weekday (3rd Monday in October, for example)...

    http://www.elsemu.net/~nemo/cron_both.txt

    The only questions I haven't investigated too deeply so far are:

    • Which timestring to include (local or utc)?
    • Is it desirable or necessary to broadcast both local time and utc time?
    • Do 8 (or whatever) hour crons happen at 00:00:00: local time or UTC time if I'm in tz -5?

    Nonetheless, this particular cron design appears to fulfill the core's needs quite nicely... flexibly... thoroughly... efficiently.

    0.7 - Contributions: It's your turn now

    0.7 - Contributions: It's your turn now Trispis Fri, 2006-09-15 14:57

    CONTRIBUTED CODE

    In an effort to keep the 'core' and its primary modules from becoming excessively large and/or complex as an overall package, the "substance" of this project will (hopefully) manifest in the form of 'contributed code' or 'contributed modules'. These contributions will mainly take the form of .function()s (see the section on @functions above) and should be installed on one of the three @functions THINGs, depending on the privs required. Some proposed suggestions for what I envision contributions to look like have already been briefly illustrated above, but I feel this deserves a little more attention and am dedicating this section to further enhancing this aspect of the WARPEDcore.

    Some examples of what I anticipate seeing are as follows...

    • A function library
      • .verb() - It seems feasible, and possibly even logical, to write rudamentary and/or highly customized forms of these functions to use globally, in place of workhorse @parent THINGs. Some MUSHes encourage sharing of such code, others don't care and often have multiple clones of basically the same code. So, it might be beneficial to be able to do something like...
        @osucc =.verb(osucc,indoor,outdoor)

        ... which would return an OSUCC message appropriate for an indoor exit which leads to an outdoor room. (other variations might be written for dealing with second story windows -- where it's not likely that you 'walk through the window to main street')

      • .time() - Similar to time(), this custom function would return IC time, rather than RL server time, and could easily be incorporated into descriptions (much like the proposed .weather() example earlier in this document).
        NOTE: The Cron, as it is written, should be easily adaptable to pretty much any time compression algorithm you choose for your game (if it's not already, the hope is that we'll get a contrib patch of some sort to make it so).
    • Tools and Utilities
      • @config controls - config() is neat, but some commands for utilizing it (instead of 'think config(foo)', maybe some +config toys).
      • Debug Zone - A Zone Master Room for debugging global behaviors.

    The whole idea here being that of creating some basic, optional utilities and features.

    0.8 - Legal-eze: The devil in the detail...

    0.8 - Legal-eze: The devil in the detail... Trispis Fri, 2006-09-15 15:09

    Any code, other than Official WARPEDcore Code (see below), referenced or listed in this document is licensed by its respective author. The author of this document claims no affiliation with such code other than that of 'fair use reference' based on general knowledge of its existence (i.e., licensing for SGP, Keran's Weather, Myrddin's Bulletin Board, etc. is deferred to their respective authors and/or maintainers).

    Talk trash about me if you must, but... while I'm alive, please show me respect for having done the initial work to make this available to the public by retaining my asserted claim thereto, therewith, and/or therein.

    The WARPEDcore Community Enforced, Documentation and Inspired Application of Softcode License.

    WCEDIASL? Okay. that's just... excessive. Back to The WARPEDcore Softcode and Documentation License (WSDL).

    We're talking about credit for the inspired application of pieces of a larger work (namely, features of the softcoding platforms of the MUD family). It's like talking about patenting something you made out of tinker toys. It's TINKER TOYS, for crying out loud! But still... that is a pretty darned cool thing you made out of them.

    Due to the nature of its programming environment, Softcode requires that (except in the 'proverbial vaccuum') its produced 'programs' be published (or, more precisely, made visible to someone other than the author). As such, it falls in the realm of text (as opposed to virtual machinery or other newfangled concepts of the digital age, which include binary executables and such). As text, the only area of relevant applicable law is copyright law. And, because of the "near-public-domain" mandated state of this particular programming environment, there is little room to make any meaningful 'enforcible' claim (meaning - proving measurable damage in a court of law, without being charged oneself for making a mockery of a Judge's court).

    We have to assume that people (potentially even crooked, malicious, or spitefully mean-spirited people that you don't like) are gonna use your code. I mean.. that's the point, right? You're wanting to let SOMEONE use it... and because of that, there's potential for others (to whom you may not have explicitly, in person, mano a mano, granted such permission) to procure use of it as well.

    And, knowing that, you'd like to somehow ensure that you're properly credited for your effort... and to further ensure that this credit is carried along with your product, wherever it ends up going.

    At first this might seem like a pointlessly overwhelming challenge for such a relatively inconsequential programming environment. But there is a silver lining. The MU-niverse is rather small. At a generous estimate, I'd start with a population of say 1,000,000 people: less than 10,000 active/serious softcoders (who would care a nit about a license), less than 1,000 active game gods with more than a year experience, and less than 100 currently active people with more than 10 years experience. In a MU-niverse so small and tightly-interconnected (everyone knows someone on some other game, etc. - heh, the seven degrees of separation from Javelin?), there is much more room for placing emphasis on respect for the person, rather than respect for the position. That is, we don't have to respect every game god of every game regardless how small as though they were the president of an independent 500 year old nationstate just because s/he had a spare $25/mo to lease a server somewhere - instead, respect is something hard-earned (in the sense that it can be earned through positive contribution and/or effort) and time-honored (time-honored in two senses: 1. that it is inheritable/transferrable in 'long-standing games', and 2. it is based on, and honors, longevity/experience in the MU-niverse itself).

    Thus, the MU-niverse is both 'infinite in potential' yet simultaneously small enough that it naturally retains a community feel... and, thus, some of the innate features and qualities of the community social environment. Of specific relevance to this topic (copyright/license), is the fact that, if you are discovered to be using someone else's product in a manner which disrespects that person, you are subject to (and likely to actually suffer from) social consequences (peer pressure is very powerful in the MU-niverse). And it is upon these features of the MU-niverse that the WARPEDcore will build its license. The WARPEDcore will assume that the MU-niverse protects its members as an innate survival feature. Specifically, with reference to the crediting and/or licensing of softcode, it will be assumed that very little effort needs be placed into asserting one's rights - they are, for the most part, assumed (assumed to at least follow the spirit of larger, related U-niverses, such as - in relation to this topic - real life copyright laws and licenses). That is, to say... if you create some original work, put your name on it, and put it 'out there for others to use', there is a strong enough force in the MU-niverse to enforce certain 'implied rights' (e.g., if Fubar B. Wibblemeep strips my name off of my product and starts distributing it, verbatim, as though it were his own, the MU-niverse would catch him... probably quite quickly... and not for violation of any documented 'law' in any country - but more for a violation of community trust-spirit).

    Borrowing from Moses' famous document,

    To users: Thou shalt not covet, nor steal, thy neighbor's softcode. (Use it, distribute it, build upon it and/or otherwise change it to suit thy needs. Just don't claim it as wholly thine own... lest "the court of public opinion" shalt surely catch thee and punish thee.)

    To producers: Thou shalt contribute thy softcode freely, and in full confidence that thou shalt receive retained credit for thy contributions.

    And from this, we arrive at the ~`legal attribute. A single attribute in which to assert, assign, delineate, specify, and/or document authorship/maintainership credit and terms of use. For WARPEDcore, it is deemed appropriate to include the following:

    * a URL pointing to further information (and optionally, name of a person or group).

    Examples

    &~`legal foo=Joe Softcoder http://my.softcode.mush

    &~`legal foo=The WARPEDcore Project. See: http://community.pennmush.org

    &~`legal foo=Trispis @ M*U*S*H, License: WSDL http://community.pennmush.org.

    As the author of this document, I have full faith in the MU-niverse that no more than this is required (in fact, I explicitly don't think a link to the specific page of this specific book is necessary) and, further, that removal of such documenation in the spirit of fraud would violate a community value so powerfully self-preserving that it is capable of being its own deterrent. (I can't force you not to remove the above attribute. It's like the 'do not remove under penalty of law' tags on your livingroom throw pillows - you removed them. so what. no one cares. just don't go bragging that you made the pillows by hand from antique material you inherited from your great grandmother; and if you inherit a situation where such documentation was removed prior to your inheritance, don't claim your grandmother made the pillows. The MU-niverse will simply laugh at you and possibly make a public example of you... possibly for a very long time, too, at least until you "get it".) I'll leave the details of this philosophy to the MU-niverse itself to maintain.

    There's a nifty 'audio tagline' used by Ten Thirteen Productions (The X-Files, Millenium). It is simply the voice of a young boy proudly asserting, "I made this." (ref. TV Acres)

    That's the perfect expression of what we, both as individuals and as a community-oriented MU-niverse, want to protect. I believe this.

    And now, here's our 'legal-eze' to which the WARPEDcore "~`legal" pointer attribute will be pointing... Based on the BSD and MIT templates, I leave in place the WARPEDcore Softcode and Documentation License as it was originally written, the only modification being adaptation to this web-book format.

    The WARPEDcore Manifesto (the document on which this book is based), this collaborative web-book, and all softcode (including softcode installation scripts) referenced in this document as being "Official" WARPEDcore Modules (i.e., ~reboot, ~cron, and other softcode scripts designated as portions of the WARPEDcore Project), unless otherwise specified in their individual documentation, are released and maintained under the terms of the following License, DISCLAIMER, and Copyright.

    0.8.0 - License

    0.8.0 - License Trispis Fri, 2006-09-22 04:05

    The WARPEDcore Softcode and Documentation License (WSDL)

    Redistribution and use of WARPEDcore materials (the original manifesto, this collaborative web-book, scripts, modules, etc.) in text or digital forms, with or without modification, are permitted provided that the following conditions are met:

    • Redistributions in text (paper and ink) form must retain the copyright notice, this list of conditions and the DISCLAIMER.
    • Redistributions in digital form (http, ftp, etc.) must either retain the copyright notice, this list of conditions and the DISCLAIMER within the distributed copies, or include a URL or hyperlink to their internet-location.
    • Neither the name of this project (WARPEDcore) nor the names of its authors and/or contributors may be used to endorse or promote products derived from the herein covered material without specific prior written permission.

    0.8.1 - DISCLAIMER

    0.8.1 - DISCLAIMER Trispis Fri, 2006-09-22 04:07

    THIS MATERIAL IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    0.8.2 - Copyright

    0.8.2 - Copyright Trispis Fri, 2006-09-22 04:16

    This community web-book is copyrighted to it's current author and/or maintainer, presently Chuc McGuire (aka Trispis @ community.pennmush.org).

    In the event of a transfer of this copyright to some potential subsequent maintainer, the remainder of this page will include a complete, reverse-cronological copyright history.

    Copyright 2007, Chuc McGuire
    Copyright 2002-2006, Chuc McGuire

    0.8.3 - Development and Testbed Licensing

    0.8.3 - Development and Testbed Licensing Trispis Sat, 2007-07-07 07:39

    A few recent events to which I have been subjected, or which I have witnessed objectively, have reminded me of an event from my gradeschool days. I'm going to relate this story with fictional names (to protect the innocent, as well as the guilty).

    Trudy's Candy Bar

    Trudy was seven years old when she entered second grade. And, for the first time in her education, she finally got to have her own private storage bin (basically a plastic tub about the size of two breadboxes), in which to store her books and personal belongings.

    One day, Trudy's mother put a chocolate candy bar in with Trudy's lunch as a special treat. Trudy was so excited that, the moment she arrived at school, she showed it to her teacher and all of her classmates. Oh, what a wonderful chocolate treat she was going to have for dessert at lunch time. She placed her lunch into her personal storage bin, just like every morning, exchanging it for the writing pad, pencils, etc. which had been stored there overnight, and proceeded with her daily lesson as normal.

    When lunchtime finally arrived, much to Trudy's dismay (as well as her teacher and the rest of her classmates), there was no candy bar in her lunchpail. The teacher, almost enraged, but trying to maintain composure, stood and addressed the entire classroom as they ate lunch, "we all know Trudy brought a chocolate candy bar with her lunch today. everyone saw it. now it is gone. if you know who has taken it, please come and tell me."

    At that very moment, Johnny emerged from the bathroom, his hands and face smeared with chocolate, and he proclaimed loud enough for all to hear, "Don't ask me who took it. I was in the bathroom the whole time!"

    This alternative license addendum is specifically intended for installations under development, and/or testbed installations.

    Often (more often than not?), softcoders do not have games of their own on which to develop their widgets and what-nots in the privacy of a protected environment. This license is intended to protect a softcoder's rights in those situations where necessity and/or opportunity place their project's development on a game or server over which they do not have control.

    NOTE: Although this is the primary intent of this license, it is not the exclusive range of its potential applicability.

    NOTE: It is possible, even highly likely, that the author of the package governed by this license may have a public (i.e., non-development) version of the same system released under a completely different license. This is another specific intent of this alternative license - to protect the private development process of an otherwise publicly released package (i.e., Joe Coder doesn't want his latest and greatest features becoming public until he's darned well ready - this license is intended to protect his development time-table ... his right to guide and control the development process of his own coded systems).

    NOTE: In an ideal world, this license would be unnecessary. But, as Jethro Tull so clearly stated it "He who made kittens put snakes in the grass" -- i.e., it's definitely NOT an ideal world. So, the world being as it is, this license will be developed as the "Gentleman's Agreement" which should exist without being written, but which apparently also needs to be documented for reference.

    0.9 - Credits: Who's who

    0.9 - Credits: Who's who Trispis Fri, 2006-09-15 15:15

    CREDITS

    Credit and thanks for contribution in the form of discussion, critique, philosophical commentary, recommended additions and changes, motivational kudos, and/or any other form of constructive input toward the creation of the original Manifesto and Code pieces is extended to the following people:

    • Matt @ M*U*S*H -- Without Matt's enthuseastic encouragement, I never would have even started this project. Thanks, mate.
    • Javelin @ M*U*S*H -- As usual, Javelin has been supportive with encouragement and insightfully constructive input. Thanks.
    • Others Players at M*U*S*H -- As mentioned in the introduction and early portions of this document, much credit and many thanks are extended to any and/or all of M*U*S*H's citizenry who have contributed ideas, suggestions, and/or encouragement to the creation of projects such as this one, and this one in particular.

    Credit for specific individual contributions should be documented within the contributions themselves.

    Credit for bug reports and patches will be maintained in this book in some way.

    0.9.0 - Addendum

    0.9.0 - Addendum Trispis Sun, 2006-09-24 07:09

    This page lists specific additional credit pertaining to rewrites of and/or modifications to the content of this web-book.

    • 2006/09/24 - Legal-eze: scoob, Mike, Javelin, Walker, and Sketch @ M*U*S*H all contributed thoughts and/or opinions which were considered in the initial rework of this section.
    • 2006/09/15 - Attributes: Javelin reminded me that this section can now (after my 2 year hiatus) be updated to utilize attribute trees (thanks, again, to Talek and the other PennMUSH developers for their work on this)

    0.9.1 - illustrations and comments

    0.9.1 - illustrations and comments Trispis Wed, 2006-10-04 19:42


    joan stark - jgs
    www.ascii-art.com
                        .'\   /`.
                      .'.-.`-'.-.`.
                 ..._:   .-. .-.   :_...
               .'    '-.(o ) (o ).-'    `.
              :  _    _ _`~(_)~`_ _    _  :
             :  /:   ' .-=_   _=-. `   ;\  :
             :   :|-.._  '     `  _..-|:   :
              :   `:| |`:-:-.-:-:'| |:'   :
               `.   `.| | | | | | |.'   .'
                 `.   `-:_| | |_:-'   .'
              jgs  `-._   ````    _.-'
                       ``-------''

    ... she went on. "Would you tell me, please, which way I ought to go from here?"
    "That depends a good deal on where you want to get to," said the Cat.
    -- Lewis Carroll

    0.9.2 - History

    0.9.2 - History sad hack Mon, 2009-11-16 04:47

    The history of this project, prior to being hosted on this website (community.pennmush.org), can be found here --> ~

    1 - The Code

    1 - The Code Trispis Fri, 2006-09-15 16:56

    This section of this book contains the code, available for viewing, editing, contributing, tweaking, etc.

    That is to say, the code will be developed within this collaborative book paradigm. The 'official installation packages' will be released on ftp.pennmush.org for public download (no need to copy/paste bits and pieces out of this book - whole package compilations will be available for that purpose).

    Each module will have a subsection to itself, with optional subsections thereunder (e.g., a module with 5 objects might have an intro page with 5 sub-pages, one for each object).

    At least that's the initial plan. We'll see how things go, after we get some code online and some participation started.

    1.0 - Official Release

    1.0 - Official Release Trispis Fri, 2006-09-15 17:06

    This section will include all pieces of contributed code which have been selected for inclusion in the official release of the WARPEDcore.

    This section's activity should, for the most part, be limited to either...

    1. a new contribution migrating into the official release from the unofficial contribution section.
    2. or...

    3. a patch or bug-fix is needed for an existing official release module

    At least that's the plan. We'll see how it goes...

    1.0.0 ~reboot

    1.0.0 ~reboot Trispis Mon, 2006-09-25 04:45


    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ WARPED      ~~~~~~~~~~~~~~~~                                           ~
    @@        ~~~~~~~~~        ~~~~~~~~~              WARPEDcore             ~~
    @@     ~~~~~~                    ~~~~~~             ~reboot            ~~~
    @@   ~~~~          Adoption          ~~~~         200609250b         ~~~~
    @@  ~~~              Date              ~~~~~~                    ~~~~~~
    @@ ~~             2006.09.25              ~~~~~~~~~        ~~~~~~~~~
    @@ ~                                           ~~~~~~~~~~~~~~~~        core
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ========================================================================

    @@
    @@ LEGAL
    @@
    @@ This material is released under the terms of the
    @@ WARPEDcore Softcode and Documentation License (WSDL).
    @@ For details, see: http://community.pennmush.org
    @@
    @@ USE AT YOUR OWN RISK.
    @@
    @@ Copyright 2006, The WARPEDcore Project
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ README
    @@
    @@ PLEASE READ THIS SECTION. It is IMPORTANT!
    @@
    @@
    @@ This is a very powerful and delicate piece of code. PLEASE read ALL
    @@ of the comments VERY CAREFULLY. Most of this code must be manually
    @@ installed (edit a line appropriately, copy/paste).
    @@
    @@ DO NOT, I repeat, DO NOT attempt to quote this file into your game!
    @@
    @@
    @@ USE AT YOUR OWN RISK.
    @@
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ BEGIN REQUIREMENTS
    @@
    @@ * PennMUSH version 1.7.7p21 or newer.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ The Theory
    @@
    @@ Unless you've tweaked a great deal, your #1/startup contains one of the
    @@ following:
    @@
    @@ a) a very long string of @<command>;@<command>;@<command>[;etc]'s.
    @@
    @@ b) at least one @dolist.
    @@
    @@ c) a combination of the above.
    @@
    @@ If startup sequencing is highly important, you probably have "c"
    @@ (above), in which you have the most crucial items done as direct
    @@ commands, followed by a dolist or two for the rest.
    @@
    @@ Depending on how much tweaking you've done, you may or may not have a
    @@ well-organized and easily managed process.
    @@
    @@ That's what this package attempts to provide - a well-organized and
    @@ easily managed god/startup - while also retaining as much startup
    @@ precidence as possible.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ The 'cut' line.
    @@
    @@ The text above this point contains no code, and should be removed
    @@ if you intend to /quote this file in some way. The recommended procedure
    @@ is to read and follow the instructions and to copy, line by line, the
    @@ needed pieces as you go; however, I did attempt to write this so that it
    @@ could be /quoted if done so with care and responsibility. And, even if
    @@ you do /quote it, you will inevitably have some manual adjustments to
    @@ make when it's done.
    @@
    @@ ========================================================================
    @@ . . C . . u . . t . . H . . e . . r . . e . .
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ authorship, credit, and copyright information.
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    &~.legal #1=WARPEDcore~reboot, see: http://community.pennmush.org
    &~.version #1=200609250b
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ data attributes
    @@
    @@ ------------------------------------------------------------------------
    @@
    @@ configs
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ god configs
    @@
    @@
    @@
    &~`ORDER #1=0:First 1:Attribute 2:Function 3:Command 4:Hook 5-8:Unused 9:Last
    @@
    &~`ORDER.NOTE #1=Neither this attribute nor its contents is used by the @startup and/or ~`<reboot> code in any way. It's simply a way to store your design plan for reference (e.g., "okay, it's been 3 years since I had to make any changes to this -- now, which numeric group was I using for @commands again?"). It contains a suggested default arrangement. If you don't need it (and plan to dump everything into ~`0???), ignore it.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ local configs
    @@
    @@
    &~`RENUM`INTERVAL #1=10
    @@
    &~`RENUM`INTERVAL.NOTE #1=This is the renumbering interval used for the auto-renumbering.
    @@
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ the code.
    @@
    @@ ------------------------------------------------------------------------
    @@
    @@ functions
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ the renumbering function
    @@
    @@
    &~`RENUM`UFUN #1=iter(lnum(0,9), setq(0,itext(0))[iter(setr(1, filter(me/~`NNNN`FILTER, lattr(me/~`%q0???))), set(me, itext(0).TEMP:[v(itext(0))])[attrib_set(me/[itext(0)])])][iter(%q1, set(me, %q0[rjust(mul(inum(0), v(~`RENUM`INTERVAL)), 3, 0)]:[v(itext(0).TEMP)])[attrib_set(me/[itext(0)].TEMP)])])
    @@
    &~`RENUM`UFUN.NOTE #1=this function divides the possible 10,000 attribs into groups of 1000, by managing the first number as a separate iteration process, renumbering each group of 1000 (possible) attribs as a separate sub-process. This allows you, if you so choose, to manage groups of processes separately. For example, putting all "really super important" startup commands in STARTUP`0??? attributes, all remaining @attribute commands in STARTUP`1??? attributes, all remaining @command commands in STARTUP`2??? attributes, etc. (or, if don't have very many and don't need such subdivisions, you can put them all into the 0??? category and be done with it - you just won't be utilizing this subdividing feature). It must be operated manually (Logged into god, think u(me/~`RENUM`UFUN))
    @@
    &~`NNNN`FILTER #1=isnum(rest(%0,`))
    @@
    &~`NNNN`FILTER.NOTE #1=This is the filter to ensure that only ~`#### attributes are processed, just in case someone adds a ~`NOTE or whatever without thinking. It is used by ~`RENUM`UFUN and @startup.
    @@
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ globals
    @@
    @@ ------------------------------------------------------------------------
    @@
    @@ @attribs
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ These are @attribs needed by the WARPEDcore
    @@
    @@ &~`0010 #1=@attribute/access/retroactive ~=safe veiled visual no_clone
    @@
    @@ This prepares the ~ attribute (and subsequent tree features) for use
    @@ with the WARPEDcore.
    @@
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ Help
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ No such animal.
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ activation
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ the @startup attribute
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ simplest conversion is...
    @@
    @@ first, make a backup copy of your existing #1/startup.
    @@
    @cpattr #1/STARTUP=#1/STARTUP.BACKUP
    @@
    @@ confirm the operation..
    @@
    ex #1/STARTUP
    ex #1/STARTUP.BACKUP
    @@
    @@ next, copy your existing glob of goo from #1/startup to this system's
    @@ "Last" numeric group, in the last entry (this assumes a 'failsafe'
    @@ position for all your pre-existing code)...
    @@
    @cpattr #1/STARTUP=#1/~`9999
    @@
    @@ then, at your leisure, proceed to gradually migrate things from their
    @@ current location (#1/~`9999) into their appropriate new separate
    @@ attributes.
    @@
    @@ give #1 an appropriate new @startup.
    @@
    @startup #1=@dolist/delimit | [iter(sort(filter(me/~`NNNN`FILTER, lattr(me/~`????)), a), v(itext(0)), %b, |)]=##
    @@
    &STARTUP`NOTE #1=This makes something like "@dolist/delimit | @<command>|@<command>|@<command>[&c]=##"; and it does so in a manner which prevents non-god insertion of malicious commands. YMMV.
    @@
    @@ When you finish migrating everything from ~`9999 into appropriate
    @@ individual attribute placements (deleting each piece from this
    @@ attribute as you do so, eventually deleting this attribute as well),
    @@ you can delete #1/STARTUP.BACKUP (the failsafe backup I made you create
    @@ earlier in the script).
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ The end result should be a game which, during a game restart, processes
    @@ "all startup commands" in the earliest possible queue cycle that such a
    @@ single action can occur. God is granted five (5) initial queue cycles
    @@ during startup, in which it is allowed the unique privilege of freely
    @@ cramming stuff into the queue at will, before anyone else's @startup is
    @@ processed. This code attempts to use a single @dolist to get as much
    @@ 'stuff' into the queue as early as possible.
    @@
    @@ ALSO NOTE: This code is not restricted only to #1/startup. It can be
    @@ used in anything's @startup, or in @aconnect, or any other place you
    @@ need to process several commands in sequence.
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ========================================================================

    Credits

    Credits Trispis Thu, 2007-01-11 08:54
    • 2007/01/11 - Concept originated with Trispis @ M*U*S*H.
    • 2007/01/11 - Design and implementation issues were tweaked and resolved with some help from Javelin and Mike @ M*U*S*H.

    1.0.1 ~cron

    1.0.1 ~cron Trispis Thu, 2007-01-11 08:26

    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ WARPED      ~~~~~~~~~~~~~~~~                                           ~
    @@        ~~~~~~~~~        ~~~~~~~~~              WARPEDcore             ~~
    @@     ~~~~~~                    ~~~~~~              ~cron             ~~~
    @@   ~~~~          Adoption          ~~~~         200601110b         ~~~~
    @@  ~~~              Date              ~~~~~~                    ~~~~~~
    @@ ~~             2007.01.11              ~~~~~~~~~        ~~~~~~~~~
    @@ ~                                           ~~~~~~~~~~~~~~~~        core
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ========================================================================

    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ LEGAL
    @@
    @@ This material is released under the terms of the
    @@ WARPEDcore Softcode and Documentation License (WSDL).
    @@ For details, see: http://community.pennmush.org
    @@
    @@ USE AT YOUR OWN RISK.
    @@
    @@ Copyright 2007, The WARPEDcore Project
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ SYSTEM REQUIREMENTS
    @@
    @@ * PennMUSH version 1.7.4p21 or newer.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ The 'cut' line.
    @@
    @@ It is safe to remove everything above the following line, before quoting
    @@ this script into your MUSH.
    @@
    @@ ========================================================================
    @@ . . . . C . . . u . . . t . . . . . . H . . . e . . . r . . . e . . . .
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ create ~cron
    @@
    @create ~cron
    @set ~cron=NO_COMMAND
    @describe ~cron=WARPEDcore~cron
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ legal reference and version
    @@
    &~`legal ~cron=http://community.pennmush.org
    @@
    &~`version ~cron=200701110b
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ data
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ variables: configurable.
    @@
    @@ documentation is provided.
    @@
    &CONF`INTERVAL ~cron=300
    &NOTE`CONF`INTERVAL ~cron=This value represents the frequency of emits in a number of SECONDS. Note, setting this to anything other than an appropriate multiple of sixty (60) will have very screwy results. Recommended values are the following: 60 300 600 900 1200 1800 3600 (1m 5m 10m 15m 20m 30m and 60m, respectively). Default: 300 (5m)
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ the code.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ the loop.
    @@
    @@ fix this so that the emit is caculated before the final wait length.
    @@
    @STARTUP ~cron=@wait/until [cemit(~, if(gt(sub(secs(),convtime(starttime())),10),Re-)Started., 1)][setr(s, mul(setr(i, v(CONF`INTERVAL)), inc(div(secs(), %qi))))]=@tr me/TRIG`CRON`LOOP=%qs
    @@
    &NOTE`STARTUP ~cron=triggers TRIG.CRON.LOOP to start the cron
    @@
    @@
    &TRIG`CRON`LOOP ~cron=@wait/until [cemit(~, ufun(UFUN`CEMIT,%0), 1)][setr(s, mul(setr(i, v(CONF`INTERVAL)), inc(div(secs(), %qi))))]=@tr me/TRIG`CRON`LOOP=%qs
    @@
    &NOTE`TRIG`CRON`LOOP ~cron=this cemits cron message and reinitiates loop.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ the functions
    @@
    &UFUN`CEMIT ~cron=[u(UFUN`TZ)][@@(UFUN`TZ sets and returns %qz - the timezone offset based on system configuration)]~%0~[u(UFUN`ETIMESTRING, %0)][@@(UFUN`ETIMESTRING sets and returns %qt - the enhanced time string value for %0)][if(hasattrval(me/UFUN`IC),~[u(UFUN`IC, %0)])][@@(does whatever you write UFUN`IC to do)]
    @@
    &NOTE`UFUN`CEMIT ~cron=this calculates, arranges, and returns the message for the cron cemit, using the subsequent UFUN.* attribs. %0 is the secs() value of the current emit sent to all subsequent functions.
    @@
    @@
    &UFUN`TZ ~cron=[setr(z, div(sub(secs(), convtime(utctime())), 3600))]
    @@
    &NOTE`UFUN`TZ ~cron=determines sets %qz to the timezone offset in hours, based on your system's configuration.
    @@
    @@
    &UFUN`ETIMESTRING ~cron=[setq(t, convsecs(%0))][inc(div(dec(elements(%qt, 3)), 7))][@@(<-- this calculates N for 'Nth <Weekday> of the month')][if(not(strmatch(elements(%qt, 2), elements(convsecs(add(%0, lmath(mul,60 60 24 7))), 2))), .0)][@@(<-- this appends '.0' to the previously calculated 'N' if and only if this is also the 'last <Weekday> of the month')] %qt
    @@
    &NOTE`UFUN`ETIMESTRING ~cron=sets %qt to the timestring value for %0 and emits %qt preceded by the <N[.0]> enhancement.
    @@
    @@
    &UFUN`IC ~cron=
    @@
    &NOTE`UFUN`IC ~cron=write this for your IC cron data. it is sent %qs - the UTSECS value of current emit .
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ create the cron broadcast channel and configure its locks on the ~cron.
    @@
    @chan/add ~=object player quiet
    @@
    @dolist join speak see hide mod=@clock/## ~=@[num(~cron)]
    @dolist Join Speak See Hide Mod=@lock/user:Chan##Lock ~cron=LOCK`CHAN`[ucstr(##)]/1
    @@
    @@
    &LOCK`CHAN`JOIN ~cron=cor(orflags(owner(%#), Wr), not(t(member(iter(cwho(~), owner(%i0)), owner(%#)))), u(LOCK`CHAN`JOIN.CUSTOM))
    @@
    &NOTE`LOCK`CHAN`JOIN ~cron=join-locks the channel to wizards and royalty, mortal players who don't already have an object on channel, and whatever you write in LOCK`CHAN`JOIN.CUSTOM
    @@
    &LOCK`CHAN`JOIN.CUSTOM ~cron=0
    @@
    &NOTE`LOCK`CHAN`JOIN.CUSTOM ~cron=write your own truth value test here.
    @@
    @@
    &LOCK`CHAN`SPEAK ~cron=strmatch(%#, num(me))
    @@
    @@
    &LOCK`CHAN`SEE ~cron=1
    @@
    @@
    &LOCK`CHAN`HIDE ~cron=strmatch(%#, num(me))
    @@
    @@
    &LOCK`CHAN`MOD ~cron=0
    @@
    @@
    @chan/on ~=~cron
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ Help
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ Help files
    @@
    &HELP`CRON ~cron=%r<~> <TZ>~<SECS>~<ETIMESTRING>~<IC>%r%r [ljust(<~>,12)] this is the channel name.%r [ljust(<TZ>,10)] TimeZone offset in hours>%r [ljust(<SECS>,12)] secs() of the current emit%r [ljust(<ETIMESTRING>,12)] includes <#wkday> and <time()> of current emit%r [ljust(<IC>,10)] includes whatever is custom written by the game gods%r%rexample...%r%r<~> -6 1067209500~4.0 Sun Oct 26 17:05:00 2003~<IC stuff>%r%rSee also the +help on: ic_time%r
    @@
    &HELP`IC_TIME ~cron=%rthe <IC> section of the ~cron includes whatever softcoded "IC time" data your local wizards have configured for this portion.%r%r[get(me/note`ufun`cron`ic)]
    @@
    @@
    @@ The following regexp listen patterns were contributed by Mike @ M*U*S*H
    @@ for some common listen intervals. Although it's not necessary to use
    @@ regexp listen patterns, it can be very useful especially if you wanted
    @@ to combine a few of the effects (e.g., opening a secret exit only
    @@ on the third Wednesday of the month at precisely midnight).
    @@
    @@ In each one,
    @@ %1 is <TZ~SECS>
    @@ %2 is the <N>th Weekday of the month
    @@ %3 is the Weekday itself,
    @@ %4 the month,
    @@ %5 the Day of the Month,
    @@ %6 the HH,
    @@ %7 the MM,
    @@ %8 the SS,
    @@ %9 the YYYY
    @@ (%0 is the entire com message)
    @@ if all the individual %<1-9> registers aren't needed, you can of course
    @@ write shorter code.
    @@
    @@ These are untested, but I think they should work, with the caveat that
    @@ if you ever broadcast at intervals of less than one minute,
    @@ things will get nasty.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ &1M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(..):(..) (....)$:blah
    @@ &2M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(.[02468]):(..) (....)$:blah
    @@ &5M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(.[05]):(..) (....)$:blah
    @@ &10M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(.0):(..) (....)$:blah
    @@ &15M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(00|15|30|45):(..) (....)$:blah
    @@ &20M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):([024]0):(..) (....)$:blah
    @@ &30M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):([03]0):(..) (....)$:blah
    @@ &1H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(00):(..) (....)$:blah
    @@ &2H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (.[02468]):(00):(..) (....)$:blah
    @@ &3H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|03|06|09|12|15|18|21):(00):(..) (....)$:blah
    @@ &4H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|04|08|12|16|20):(00):(..) (....)$:blah
    @@ &6H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|06|12|18):(00):(..) (....)$:blah
    @@ &8H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|08|16):(00):(..) (....)$:blah
    @@ &12H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|12):(00):(..) (....)$:blah
    @@ &24H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00):(00):(..) (....)$:blah
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ activate
    @@
    @restart ~cron
    @@
    @@ The End.

    Credits

    Credits Trispis Thu, 2007-01-11 09:01
    • 2007/01/11 - This code is based on a chat-based broadcast-cron on M*U*S*H. I'm assuming that was written by Javelin, but have seen no documentation either way. This is a clean-room version of that style system - It is all original code written by Trispis @ M*U*S*H who has never seen the code which operates the system installed by Javelin on M*U*S*H. The development origin this specific package is documented in a MUDtoberfest/ITBG presentation available from the mush.pennmush.org website
    • 2007/01/11 - Efficiency tweaks and other suggestions contributed by Mike @ M*U*S*H

    1.0.2 ~() the warpedcore function

    1.0.2 ~() the warpedcore function sad hack Sun, 2009-11-01 11:05


    @@
    @@ ========================================================================
    @@ the warpedcore function `()
    @@
    @@ FIRST BETA RELEASE 2009.11.07.b
    @@ Beta versioning: YYYY.MM.DD.b
    @@ This is, technically, still very much "alpha" in many ways;
    @@ but... I'm calling it "beta" now, anyway.
    @@
    @@ ========================================================================
    @@


    @@ System Requirements (notes for porting):
    @@
    @@ * the tilde (~) must be valid in all attribute names, including the
    @@ single character attribute name "~"
    @@ * additionally, the tilde (~) must also be valid as the name of this
    @@ @function.
    @@
    @@ * pennmush-compatible attribute tree-ing (not mandatory, but uses the
    @@ backtick (`) as an attribute name segment separator).
    @@
    @@ * many_attribs @power or equivalent for large content packs.
    @@
    @@ * side-effects enabled, and a pennmush-compatible parent() function.
    @@
    @@ * pennmush-compatible #lambda.
    @@
    @@ ========================================================================
    @@ DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER
    @@
    @@ If you do not have either:
    @@
    @@ a. absolute familiarity with the content you are installing to this
    @@ system, or...
    @@
    @@ b. absolute trust in the source of the content you are installing to
    @@ this system
    @@
    @@ then, DO NOT USE IT.
    @@
    @@ This system evaluates package content.
    @@
    @@ You have been warned.
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ AUTHORSHIP
    @@
    @@ Unless otherwise explicitly stated, Trispis is the author of this
    @@ content management system, heretofore referred to as "~()" or
    @@ "the warpedcore function".
    @@
    @@ To contact the author, send email to: <nemosolid><@><gmail><.><com>
    @@ All content package objects are authored by their respective authors;
    @@ for information regarding content packages, see the respective package
    @@ object.
    @@
    @@ ------------------------------------------------------------------------
    @@ WARPEDcore Softcode and Documentation License
    @@
    @@ Copyright (c) 2009, Chuc McGuire
    @@ All rights reserved.
    @@
    @@ Redistribution and use of WARPEDcore materials (the manifesto, scripts,
    @@ modules, etc.) in text or digital forms, with or without modification,
    @@ are permitted provided that the following conditions are met:
    @@
    @@ * Redistributions in text (paper and ink) form must retain the above
    @@ copyright notice, this list of conditions and the following disclaimer.
    @@ * Redistributions in digital form (http, ftp, etc.) must either retain
    @@ the above copyright notice, this list of conditions and the following
    @@ disclaimer within the distributed copies, or include a URL or hyperlink
    @@ to them.
    @@ * Neither the name of this project (un~fu) nor the names of its
    @@ authors and/or contributors may be used to endorse or promote products
    @@ derived from the herein covered material without specific prior written
    @@ permission.
    @@
    @@
    @@ THIS MATERIAL IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    @@ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    @@ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
    @@ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    @@ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    @@ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    @@ MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@
    @@ This system evaluates package content!
    @@
    @@ You have been warned, AGAIN!
    @@
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ ~()
    @@
    @@ NOTE: If you are not a Wizard and are hacking in your own script for
    @@ personal/private use, you'll have to do a lot of editing to this script.
    @@ This script, as written, is intended to create a global @function and,
    @@ therefore, requires the necessary power to do so (presumably, a wizard
    @@ at minimum, for installation, with an accompanying modification to god's
    @@ @startup).
    @@
    @@
    @switch isdbref(~())/[hasflag(%#,wizard)]=0/1, {@function [pemit(%#,Installation started.)][setq(0, create(warpedcore, 10))][pemit(%#, Add the following to god's @startup:%r@function ~=%q0\, ~`FUNCTION\, 0\, 10)][set(%q0,quiet)][set(%q0, ~:)][set(%q0, ~`DBREF:)][set(%q0, ~`DBREF`~:%q0)][set(%q0, ~`FUNCTION:%q0)][@@(debugged by Paige@M*U*S*H)]~=%q0, ~`FUNCTION, 0, 10}, 1/1, {@pemit %#=Update started.}, {@pemit %#=RTFM when the errors stop.}
    @@
    @@ Add the following to god's @startup:
    @@ @function ~=<#dbref of ~>/~`FUNCTION, 0, 10
    @@
    @wait 0=th Ready?
    @@
    @wait 0=th On three.
    @@
    th ...
    @@
    @@ ========================================================================
    @@
    @DESCRIBE ~()=%rthe warpedcore function%r%rSee: ~(~,help,~)
    @set ~()/DESCRIBE=no_command visual prefixmatch public nearby
    @@
    &~ ~()=[@@(Null)]
    @set ~()/~=veiled
    @@
    &~`AUTHOR ~()=Unless otherwise explicitly stated, Trispis is the author of this content management system, heretofore referred to as "~" or "the warpedcore function".%r To contact the author, send email to: [lit(nemosolid)][lit(@)][lit(gmail)][lit(.)][lit(com)]%r
    @@
    &~`LICENSE ~()=WARPED~core Softcode and Documentation License. http://community.pennmush.org/book/warpedcore/0-manifest-7
    @@
    &~`VERSION ~()=2009.11.07.b
    @@
    &~`FUNCTION ~()=ifelse(words(%0), ifelse(words(%1), [null(iter(lnum(0, 4), setq(%i0, v(%i0))))][u(~`U`PATH)], u(~`FUNCTION`PACK, %0)), v(~`DBREF`~))[@@(%q0=packname, %q1=attrpattrn, %q2=width, %q3=UFUN:usercontent, %q4=UFUN:ansi)]
    &~`FUNCTION`PACK ~()=ifelse(isdbref(setr(d, v(~`PACK`%0))), %qd, u(~U`PACK`ERROR,%0))
    @@
    &~`PACK ~()=[@@(Packages of Content. Each ~`PACK`<package> attrib should contain a single #dbref; nothing more, nothing less.)]
    @@
    &~`U ~()=[setq(0, first(%0), 1, rest(%0), 2, width(%#))][u(~`U`[switch(words(%0), 0, INFO, 1, PACK, PATH)], %q0, %q1)]
    &~`U`DATA ~()=center(ifelse(hasattrpval(me, %qa), ulocal(%qa,%qa,%q2), last(%qa, `)), setr(2,ifelse(isnum(%q2), %q2, dec(width(%#)))))%r%r[u(~`U`DATA`ELEMENTS)]
    &~`U`DATA`ELEMENTS ~()=iter(setr(e, u(CONTENT`DATA`[elements(%qa, 3, `)]))|[setdiff(map(#lambda/last(\%0, `), lattrp(me/%qa`*)), %qe)][setq(r, words(%qe), x, lmath(max, map(#lambda/strlen(\%0), %qe) [dec(div(%q2, 4))]))], iter(%i0, if(hasattrpval(me, %qa`%i0), switch(inum(1)[inum(0)],2*,%r,1%qr,%r)[align(>%qx [sub(%q2, inc(%qx))], map(#lambda/capstr(\%0), edit(lcstr(%i0), _, %b)), ulocal(%qa`%i0, %qa`%i0,%q2))]%r),%b,),|,)
    &~`U`TEXT ~()=ulocal(%qa, %qa, %q2)%r[u(~`U`TEXT`MENU, lattrp(me/%qa`??*))]
    &~`U`TEXT`MENU ~()=if(words(%0), %r[table(setr(m, map(#lambda/last(\%0, `), %0)), inc(lmath(max, map(#lambda/strlen(\%0), %qm))), ifelse(isnum(%q2),%q2,width(%#)))])
    &~`U`UFUN ~()=ulocal(%qa, %qa, %q2, %q3, %q4)
    &~`U`ELSE ~()=Not sure what to do with %0 %1.
    &~`U`FILE ~()=u(~`U`FILE`[switch(words(setr(a, lattrp(me/CONTENT`**`[edit(%q1, %b, **)]))), 0, ERROR0, >1, ERROR2,DISPLAY)])
    &~`U`FILE`BODY ~()=u(~`U`[elements(%qa,2,`)])
    &~`U`FILE`DISPLAY ~()=ucstr(%q0)/%qa%r[u(~`U`FILE`HEAD)][u(~`U`FILE`BODY)][u(~`U`FILE`FOOT, %1)]
    &~`U`FILE`ERROR0 ~()=#-1 No match for %q0 %q1.
    &~`U`FILE`ERROR2 ~()=#-2 Too many matches. Choose one:%r[iter(%qa,edit(rest(rest(%i0,`),`),`,%b),%b,%r)]
    &~`U`FILE`FOOT ~()=if(hasattrp(me,FOOT),%r[u(FOOT,%1)])
    &~`U`FILE`HEAD ~()=if(hasattrp(me,HEAD),ulocal(HEAD,%1)%r)
    &~`U`PACK ~()=u(~`U`PACK`[ifelse(setr(e, isdbref(setr(d, v(~`PACK`%0)))), DISPLAY, ERROR)], %0, %qd)
    &~`U`PACK`DISPLAY ~()=ucstr(%0)%r[u(%1/describe)]%r[if(words(setr(z, lattr(%1/CONTENT`TEXT`??*) [lattr(%1/CONTENT`DATA`??*)] [lattr(%1/CONTENT`UFUN`??*)])), u(~`U`TEXT`MENU, %qz))]
    &~`U`PACK`ERROR ~()=#-0 No such package as: %0
    @@
    @@ all of the above code is moot, without this last attribute.
    @@ Thanks to Talek for attribute trees.
    @@ Thanks to the Penndevs generically for following all of the leads
    @@ which led to the inclusion of the many_attribs @power.
    @@ Remember: functions are executed with the power of the #dbref
    @@ which calls them. So, this object needs no power.
    @@
    &~`U`PATH ~()=ifelse(isdbref(setr(d, v(~`PACK`%q0))), setq(p, parent(me))[null(parent(me,%qd))][u(~`U`FILE)][null(parent(me, ifelse(isdbref(%qp), %qp,)))], u(PACK`ERROR, %q0))
    @@
    @@ The Beginning.
    @@
    @@ Changes planned for two-variable syntax. 12/24/09.

    ~help

    ~help sad hack Sun, 2009-11-01 20:37


    @@ ========================================================================
    @@ the warpedcore function ~help files
    @@
    @@ FIRST BETA RELEASE 2009.12.21.b
    @@ Beta versioning: YYYY.MM.DD.b
    @@ This is, technically, still very much "alpha" in many ways;
    @@ but... I'm calling it "beta" now, anyway.
    @@
    @@ ========================================================================
    @@


    @@ DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER
    @@
    @@ If you do not have either:
    @@
    @@ a. absolute familiarity with the content you are installing to this
    @@ system, or...
    @@
    @@ b. absolute trust in the source of the content you are installing to
    @@ this system
    @@
    @@ then, DO NOT USE IT.
    @@
    @@ This system evaluates package content.
    @@
    @@ You have been warned.
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ AUTHORSHIP
    @@
    @@ Unless otherwise explicitly stated, Trispis is the author of this
    @@ content management system, heretofore referred to as "~()" or
    @@ "the warpedcore function".
    @@
    @@ To contact the author, send email to: <nemosolid><@><gmail><.><com>
    @@ All content package objects are authored by their respective authors;
    @@ for information regarding content packages, see the respective package
    @@ object.
    @@
    @@ ------------------------------------------------------------------------
    @@ WARPEDcore Softcode and Documentation License
    @@
    @@ Copyright (c) 2009, Chuc McGuire
    @@ All rights reserved.
    @@
    @@ Redistribution and use of WARPEDcore materials (the manifesto, scripts,
    @@ modules, etc.) in text or digital forms, with or without modification,
    @@ are permitted provided that the following conditions are met:
    @@
    @@ * Redistributions in text (paper and ink) form must retain the above
    @@ copyright notice, this list of conditions and the following disclaimer.
    @@ * Redistributions in digital form (http, ftp, etc.) must either retain
    @@ the above copyright notice, this list of conditions and the following
    @@ disclaimer within the distributed copies, or include a URL or hyperlink
    @@ to them.
    @@ * Neither the name of this project (un~fu) nor the names of its
    @@ authors and/or contributors may be used to endorse or promote products
    @@ derived from the herein covered material without specific prior written
    @@ permission.
    @@
    @@
    @@ THIS MATERIAL IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    @@ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    @@ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
    @@ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    @@ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    @@ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    @@ MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@
    @@ This system evaluates package content!
    @@
    @@ You have been warned, AGAIN!
    @@
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@
    @switch isdbref(~())=0, th RTFM after the errors., @set ~()=~`PACK`help:[create(~help,10)]
    @link ~(help) = ~()
    @set ~(help) = NO_COMMAND
    @@
    @DESCRIBE ~(help)=The ~help package.
    @set ~(help)/DESCRIBE=no_command visual prefixmatch public nearby
    @@
    @~ ~(help)=
    @set ~(help)/~=veiled root
    @@
    &~`AUTHOR ~(help)=Unless otherwise explicitly stated, Trispis is the author of this content management system, heretofore referred to as "~()" or "the warpedcore function".%r To contact the author, send email to: [lit(nemosolid)][lit(@)][lit(gmail)][lit(.)][lit(com)]%r
    &~`AUTHOR2 ~(help)=Individual content packages, such as this one, are authored by their respective authors. See the individual content package for authorship.
    &~`AUTHOR3 ~(help)=The distribution version of this package (~help) only contains the help file(s) for the warpedcore function, written by Trispis; however, it is intended to allow the addition of an unlimited quantity of other help files, most of which are quite likely written by other people.
    &~`LICENSE ~(help)=WARPED~core Softcode and Documentation License. http://community.pennmush.org/book/warpedcore/0-manifest-7
    @@
    &CONTENT ~(help)=
    @set ~(help)/CONTENT=root
    &CONTENT`TEXT ~(help)=
    @set ~(help)/CONTENT`TEXT=root
    &CONTENT`TEXT`HELP ~(help)=
    @set ~(help)/CONTENT`TEXT`HELP=root
    @@
    &CONTENT`TEXT`HELP`~ ~(help)=~\()%r%rThe function:%r%r[iter(~\(\)|#dbref of ~ object%r~\(<pack>\)|#dbref of <pack>%r~\(<pack>\, <\[path] file\[\, parms]>\)|process <file> from <pack> with optional path and parameters,align(36 [sub(width(%#),37)], first(%i0, |), rest(%i0, |)), %r, %r)%r%r~\(\) examples:%r%r th ~\(help\, ~\)%r th ~\(display\, scroll1\, setr\(f\, width\(\%#\)\)\, ~\(help\, ~2\, sub\(\%qf\, 9\)\)\, y\)%r th ~\(display\, scroll1\, setr\(f\, width\(\%#\)\)\, rest\(~\(help\, ~2\, sub\(\%qf\,9\)\)\, \%r\)\, y\)%r%rSee also: ~2
    @@
    &CONTENT`TEXT`HELP`~2 ~(help)=~2%r~\() syntax conventions:%r%rThere is one premise on which the input syntax of the ~() function is based. Specifically, at present, most things returned by the ~() function are intended, in some way, to be displayed; whether it be a display of textual material (rules, help files, descriptions, etc.), data structures (properties/stats of players, mobs, weapons, equipment, etc.), packaging frills (borders, layouts, etc.), or otherwise.%r%rSince ~() can self-reference (i.e., it can call itself again to package up some other result it returns), <width> is considered a crucial, primary parameter for all packages. And, since not all ~() packs will embrace any sort of user input (unrelated to any internal, stored, information), user input is considered secondary to <width>, with all other inputs following thereafter. Thus, for consistency and uniformity among content packs, the preferred organization of input parameters (i.e., if you want to contribute a package feature) is as follows:%r%r~(<pack>, <attr>\[, <width>\[, <user input>\]\[, <other, parms>\]\])
    @@
    @@ The Beginning.

    1.1 - Contributions and Development

    1.1 - Contributions and Development Trispis Fri, 2006-09-15 17:12

    This section is where user contributions will be run through the paces as they are considered for inclusion in the official release versions. Each and every line of code in the WARPEDcore will start its life here. This section is where MOST of the activity of this entire book SHOULD take place.

    At the most basic explanation (as I am presently understanding this book format), the procedure should work something like this...

    • To contribute a module for consideration, use the 'create content' option on your account to create a 'book page' parented to THIS page (The WARPEDcore/The Code/Unofficial Contributions). It will go through the moderation process to be added as a page in the book. Then, it will be publicly evaluated and/or otherwise abused in discussion and tweaking via 'edits' and 'replies' (see below). And, eventually, will be considered for inclusion in the official release (at which time, it would be appropriately moved thereto).
    • To submit a patch or tweak, use the 'edit' tab (just below the title of this page) and include a comment in the 'log' window at the bottom, explaining what you did. It, too, will go through the moderation process before being approved for inclusion (it might also be a good idea to start out with a discussion thread, see below)
    • To make a suggestion or request (i.e., you know something is needed, but are uncertain if you'd be able to code it right, or whatever) or to otherwise discuss or comment upon existing code submissions, use the 'reply' option.

    NOTE: Just because a contribution isn't immediately considered for inclusion in the official release does not necessarily mean it's been rejected therefrom. I suspect many contributions will go through a very long period of 'not quite ready'-ness, for whatever reason (maybe the core isn't really ready to deal with the larger implications of adding some specific module - whatever). Point being: don't be discouraged if your really cool idea version 42.b5 just hangs out here for a while in the 'debug, comment, and abuse' phase.

    1.1.0 ~reboot

    1.1.0 ~reboot Trispis Fri, 2006-09-15 19:55


    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ WARPED      ~~~~~~~~~~~~~~~~                                           ~
    @@        ~~~~~~~~~        ~~~~~~~~~              WARPEDcore             ~~
    @@     ~~~~~~                    ~~~~~~             ~reboot            ~~~
    @@   ~~~~          Adoption          ~~~~         200609250b         ~~~~
    @@  ~~~              Date              ~~~~~~                    ~~~~~~
    @@ ~~             2006.09.25              ~~~~~~~~~        ~~~~~~~~~
    @@ ~                                           ~~~~~~~~~~~~~~~~        core
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ========================================================================

    1.1.1 ~cron

    1.1.1 ~cron Trispis Sat, 2006-09-16 03:48


    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ WARPEDcore~cron Version 20070107a1
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ LEGAL
    @@
    @@ This material is released under the terms of the
    @@ WARPEDcore Softcode and Documentation License (WSDL).
    @@ For details, see: http://community.pennmush.org
    @@
    @@ USE AT YOUR OWN RISK.
    @@
    @@ Copyright 2007, The WARPEDcore Project
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ SYSTEM REQUIREMENTS
    @@
    @@ * PennMUSH version 1.7.4p21 or newer.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ The 'cut' line.
    @@
    @@ It is safe to remove everything above the following line, before quoting
    @@ this script into your MUSH.
    @@
    @@ ========================================================================
    @@ . . . . C . . . u . . . t . . . . . . H . . . e . . . r . . . e . . . .
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ create ~cron
    @@
    @create ~cron
    @set ~cron=NO_COMMAND
    @describe ~cron=WARPEDcore~cron
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ legal reference and version
    @@
    &~`legal ~cron=http://community.pennmush.org
    @@
    &~`version ~cron=20070107a1
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ data
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ variables: configurable.
    @@
    @@ documentation is provided.
    @@
    &CONF`INTERVAL ~cron=300
    &NOTE`CONF`INTERVAL ~cron=This value represents the frequency of emits in a number of SECONDS. Note, setting this to anything other than an appropriate multiple of sixty (60) will have very screwy results. Recommended values are the following: 60 300 600 900 1200 1800 3600 (1m 5m 10m 15m 20m 30m and 60m, respectively). Default: 300 (5m)
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ the code.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ the loop.
    @@
    @@ fix this so that the emit is caculated before the final wait length.
    @@
    @STARTUP ~cron=@wait/until [cemit(~, if(gt(sub(secs(),convtime(starttime())),10),Re-)Started., 1)][setr(s, mul(setr(i, v(CONF`INTERVAL)), inc(div(secs(), %qi))))]=@tr me/TRIG`CRON`LOOP=%qs
    @@
    &NOTE`STARTUP ~cron=triggers TRIG.CRON.LOOP to start the cron
    @@
    @@
    &TRIG`CRON`LOOP ~cron=@wait/until [cemit(~, ufun(UFUN`CEMIT,%0), 1)][setr(s, mul(setr(i, v(CONF`INTERVAL)), inc(div(secs(), %qi))))]=@tr me/TRIG`CRON`LOOP=%qs
    @@
    &NOTE`TRIG`CRON`LOOP ~cron=this cemits cron message and reinitiates loop.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ the functions
    @@
    &UFUN`CEMIT ~cron=[u(UFUN`TZ)][@@(UFUN`TZ sets and returns %qz - the timezone offset based on system configuration)]~%0~[u(UFUN`ETIMESTRING, %0)][@@(UFUN`ETIMESTRING sets and returns %qt - the enhanced time string value for %0)][if(hasattrval(me/UFUN`IC),~[u(UFUN`IC, %0)])][@@(does whatever you write UFUN`IC to do)]
    @@
    &NOTE`UFUN`CEMIT ~cron=this calculates, arranges, and returns the message for the cron cemit, using the subsequent UFUN.* attribs. %0 is the secs() value of the current emit sent to all subsequent functions.
    @@
    @@
    &UFUN`TZ ~cron=[setr(z, div(sub(secs(), convtime(utctime())), 3600))]
    @@
    &NOTE`UFUN`TZ ~cron=determines sets %qz to the timezone offset in hours, based on your system's configuration.
    @@
    @@
    &UFUN`ETIMESTRING ~cron=[setq(t, convsecs(%0))][inc(div(dec(elements(%qt, 3)), 7))][@@(<-- this calculates N for 'Nth <Weekday> of the month')][if(not(strmatch(elements(%qt, 2), elements(convsecs(add(%0, lmath(mul,60 60 24 7))), 2))), .0)][@@(<-- this appends '.0' to the previously calculated 'N' if and only if this is also the 'last <Weekday> of the month')] %qt
    @@
    &NOTE`UFUN`ETIMESTRING ~cron=sets %qt to the timestring value for %0 and emits %qt preceded by the <N[.0]> enhancement.
    @@
    @@
    &UFUN`IC ~cron=
    @@
    &NOTE`UFUN`IC ~cron=write this for your IC cron data. it is sent %qs - the UTSECS value of current emit .
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ create the cron broadcast channel and configure its locks on the ~cron.
    @@
    @chan/add ~=object player quiet
    @@
    @dolist join speak see hide mod=@clock/## ~=@[num(~cron)]
    @dolist Join Speak See Hide Mod=@lock/user:Chan##Lock ~cron=LOCK`CHAN`[ucstr(##)]/1
    @@
    @@
    &LOCK`CHAN`JOIN ~cron=cor(orflags(owner(%#), Wr), not(t(member(iter(cwho(~), owner(%i0)), owner(%#)))), u(LOCK`CHAN`JOIN.CUSTOM))
    @@
    &NOTE`LOCK`CHAN`JOIN ~cron=join-locks the channel to wizards and royalty, mortal players who don't already have an object on channel, and whatever you write in LOCK`CHAN`JOIN.CUSTOM
    @@
    &LOCK`CHAN`JOIN.CUSTOM ~cron=0
    @@
    &NOTE`LOCK`CHAN`JOIN.CUSTOM ~cron=write your own truth value test here.
    @@
    @@
    &LOCK`CHAN`SPEAK ~cron=strmatch(%#, num(me))
    @@
    @@
    &LOCK`CHAN`SEE ~cron=1
    @@
    @@
    &LOCK`CHAN`HIDE ~cron=strmatch(%#, num(me))
    @@
    @@
    &LOCK`CHAN`MOD ~cron=0
    @@
    @@
    @chan/on ~=~cron
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ Help
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ Help files
    @@
    &HELP`CRON ~cron=%r<~> <TZ>~<SECS>~<ETIMESTRING>~<IC>%r%r [ljust(<~>,12)] this is the channel name.%r [ljust(<TZ>,10)] TimeZone offset in hours>%r [ljust(<SECS>,12)] secs() of the current emit%r [ljust(<ETIMESTRING>,12)] includes <#wkday> and <time()> of current emit%r [ljust(<IC>,10)] includes whatever is custom written by the game gods%r%rexample...%r%r<~> -6 1067209500~4.0 Sun Oct 26 17:05:00 2003~<IC stuff>%r%rSee also the +help on: ic_time%r
    @@
    &HELP`IC_TIME ~cron=%rthe <IC> section of the ~cron includes whatever softcoded "IC time" data your local wizards have configured for this portion.%r%r[get(me/note`ufun`cron`ic)]
    @@
    @@
    @@ The following regexp listen patterns were contributed by Mike @ M*U*S*H
    @@ for some common listen intervals. Although it's not necessary to use
    @@ regexp listen patterns, it can be very useful especially if you wanted
    @@ to combine a few of the effects (e.g., opening a secret exit only
    @@ on the third Wednesday of the month at precisely midnight).
    @@
    @@ In each one,
    @@ %1 is <TZ~SECS>
    @@ %2 is the <N>th Weekday of the month
    @@ %3 is the Weekday itself,
    @@ %4 the month,
    @@ %5 the Day of the Month,
    @@ %6 the HH,
    @@ %7 the MM,
    @@ %8 the SS,
    @@ %9 the YYYY
    @@ (%0 is the entire com message)
    @@ if all the individual %<1-9> registers aren't needed, you can of course
    @@ write shorter code.
    @@
    @@ These are untested, but I think they should work, with the caveat that
    @@ if you ever broadcast at intervals of less than one minute,
    @@ things will get nasty.
    @@
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ &1M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(..):(..) (....)$:blah
    @@ &2M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(.[02468]):(..) (....)$:blah
    @@ &5M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(.[05]):(..) (....)$:blah
    @@ &10M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(.0):(..) (....)$:blah
    @@ &15M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(00|15|30|45):(..) (....)$:blah
    @@ &20M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):([024]0):(..) (....)$:blah
    @@ &30M foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):([03]0):(..) (....)$:blah
    @@ &1H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (..):(00):(..) (....)$:blah
    @@ &2H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (.[02468]):(00):(..) (....)$:blah
    @@ &3H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|03|06|09|12|15|18|21):(00):(..) (....)$:blah
    @@ &4H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|04|08|12|16|20):(00):(..) (....)$:blah
    @@ &6H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|06|12|18):(00):(..) (....)$:blah
    @@ &8H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|08|16):(00):(..) (....)$:blah
    @@ &12H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00|12):(00):(..) (....)$:blah
    @@ &24H foo=^^<~> (.+)~(.|.\.0) (...) (...) (..) (00):(00):(..) (....)$:blah
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ activate
    @@
    @restart ~cron
    @@
    @@ The End.

    1.1.2 ~config

    1.1.2 ~config Trispis Thu, 2007-01-11 08:46

    Below is a list of 'to do' items.

    1. Get and maintain plain vanilla default master list (i.e., set up a new PennMUSH "out of the box" and separate the code for setting up defaults in &DATA`<category>`<item>`DEFAULT attributes).

    KNOWN BUG: the do-options code, as written, generates a category called 'parameters'.
    Mike pages: If you just stick setdiff(<foo>,@config parameters,|) in (where <foo> is the textentries(help,@config %0*,|) I believe) that should fix that bit.

    KNOWN BUG: the 'tiny' category doesn't get a description set.

    KNOWN ISSUE: Haven't yet finished the /diff switch for two reasons:
    1. time
    2. have only tested this on M*U*S*H (haven't ever done a plain vanilla, per the 'to do' above).

    Here's the code to generate all of the data (not yet separated per 'vanilla' above).


    @@
    &CMND.DO-OPTIONS [v(~)]=$do-options:@pemit %#=Doing options.[null(u(list-options))]
    @@
    &list-options [v(~)]=localize(setq(0,,1,,2,,3,0,4,0,5,0)[null(iter(sort(textentries(help, @config %0*,|),,|), if(isint(right(%i0, 1)), setq(5, 0), if(%q3, u(save-option, %q2, %q0))[switch(inum(0), 1, , u(save-category, %q0, %q1))][setq(3, 0, 2, , 0, rest(%i0), 5, 1)])[setq(4, 1)][iter(textfile(help, %i0), switch(setr(9, squish(%i0)), , if(%q3,u(save-option, %q2, %q0)[setq(3, 0, 2, )]), *=*:*, switch(1, %q3, u(save-option, %q2, %q0))[setq(2, %q9, 3, 1)], switch(1, %q4, if(%q5, setq(1, %q9))[setq(4,0)], %q3, setq(2, %q2 %q9))), %r, %b)], |, %b))])
    @@
    &save-option [v(~)]=set(me, DATA`%1`[first(%0, =)]`DEFAULT:[config(first(%0, =))])[set(me, DATA`%1`[first(%0, =)]`TYPE:[before(after(%0, <), >)])][set(me, DATA`%1`[first(%0, =)]:[squish(after(%0, :))])]
    @@
    &save-category [v(~)]=set(me,DATA`%0:%1)
    @@
    &credit-options [v(~)]=code for generating all of the attributes and contents originally written by Mike @ M*U*S*H with attribute name adaptations by Trispis @ c.p.o.
    @@

    And here's the display code, as it presently exists


    @@
    &cmnd`config [v(~)]=$~config:@pemit %#=u(UFUN`DISP)
    @@
    &cmnd`config.diff [v(~)]=$~config/diff:@pemit %#=u(UFUN`DISP`DIFF)
    @@
    &cmnd`config.list_x [v(~)]=$~config/list *:@pemit %#=ifelse(setr(e, u(UFUN`ERRCK`CATY, %0)), %qe, u(UFUN`DISP`HEADER)[u(UFUN`DISP`CATY, %0)][u(UFUN`DISP`FOOTER)])
    @@
    &cmnd`config.show_x [v(~)]=$~config/show *:@pemit %#=ifelse(setr(e, u(UFUN`ERRCK`ITEM, %0)), %qe, u(UFUN`DISP`HEADER)[u(UFUN`DISP`ITEM,%0)][u(UFUN`DISP`FOOTER)])
    @@
    &ufun`disp [v(~)]=[u(UFUN`DISP`HEADER)][u(UFUN`DISP`SYNTAX)][iter(setr(l, lattr(me/DATA`))[setq(w, lmath(max, iter(%ql, strlen(last(%i0, `)))))], [align(%qw [sub(width(%#), sub(%qw, 2))], setr(c, lcstr(last(%i0, `))), v(%i0))], %b, %r)][u(UFUN`DISP`FOOTER)]
    @@
    &ufun`disp`diff [v(~)]=null(iter(config(), switch(v(lattr(me/DATA`*`%i0`DEFAULT)), config(%i0), setq(d, %qd %i0), #-*, setq(e, %qe %i0), setq(o, %qo %i0))))%rDiffering values: %qd%r%rErrors: %qe%r%rOther differences: %qo%r
    @@
    &ufun`disp`caty [v(~)]=Config Category: %0%rDescription: [v(DATA`%0)]%r[setq(n, lmath(max, iter(setr(l, iter(lattr(me/DATA`%0`), lcstr(last(%i0,`)))), inc(strlen(%i0)))))][table(%ql, %qn, width(%#))]
    @@
    &ufun`disp`item [v(~)]=ljust(Config Item: %0, setr(w, div(width(%#), 2)))Config Type: [v(%qi`type)]%r%rDescription: [v(%qi)]%r%r[ljust(Default Setting: [v(%qi`DEFAULT)], %qw)]Current Setting: [config(%0)]
    @@
    &ufun`errck`caty [v(~)]=ifelse(or(not(dec(words(%0))), hasattr(me, DATA`%0)), ,Unknown category: %0)
    @@
    &ufun`errck`item [v(~)]=ifelse(or(words(setr(i, lattr(me/DATA`*`%0))), not(dec(words(%0)))), , Unknown config item: %0)
    @@
    &ufun`disp`header [v(~)]=-[center(- WARPEDcore~config -, sub(width(%#), 6), =)]-%r
    @@
    &ufun`disp`footer [v(~)]=%r-[setr(f, repeat(=, div(sub(width(%#), 3), 2)))]-%qf-
    @@
    &~`legal [v(~)]=WARPED~core Softcode and Documentation License - http://community.pennmush.org
    @@

    In The Beginning, God connected

    In The Beginning, God connected sad hack Mon, 2009-02-02 11:52

    First Post Deleted
    ~myth 1.0

    In The Beginning,...

    @@ ========================================================================
    NOT A SCRIPT                      How~To                       NOT A SCRIPT
    @@ ------------------------------------------------------------------------
    NOT A SCRIPT                      How~To                       NOT A SCRIPT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    NOT A SCRIPT                      How~To                       NOT A SCRIPT
    @@ ------------------------------------------------------------------------
    
    This is the pre-alpha how~to pseudocode blueprint for the use of this
    fully operational battlestati... 
    
    ... er,... heh,... ahem,... I mean,...
    
    ... for the use of this nominally complete warpedcore script set.
    
    @@ ------------------------------------------------------------------------
    
    • Create godfiles.
      • Create godfile0 - new game, starting from minimal db
        • @dolist
        • <god0 files>
        • =
        • cat <file> >> godfile0.txt
        • ;tweak
        • ;maintain
        • ;contribute
      • Create godfile1 - self-maintenance, for running game
        (e.g., keep itb branch updated here)
        • @dolist
        • <god1 files>
        • =
        • cat <file> >> godfile1.txt
        • ;tweak
        • ;maintain
        • ;contribute
    • Create wizfiles
      • Create wizfile0 - new wiz
        • @dolist
        • <wiz0 files>
        • =
        • cat <file> >> wizfile0.txt
        • ;tweak
        • ;maintain
        • ;contribute
      • Create wizfile1 - self-maintenance
        • @dolist
        • <wiz1 files>
        • =
        • cat <file> >> wizfile1.txt
        • ;tweak
        • ;maintain
        • ;contribute
    • Create other files - e.g., character creation &/| maintenance, globals package installation &/| maintenance, world areas, etc.; as much as you want to be able to recreate.
        • @dolist
        • <other files>
        • =
        • cat <file> >> <otherfile>.txt
        • ;tweak
        • ;maintain
        • ;contribute
    @@ ------------------------------------------------------------------------
    NOT A SCRIPT                                                   NOT A SCRIPT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    NOT A SCRIPT                                                   NOT A SCRIPT
    @@ ------------------------------------------------------------------------
    NOT A SCRIPT                                                   NOT A SCRIPT
    @@ ========================================================================
    

    0 c_self.txt

    0 c_self.txt sad hack Tue, 2009-02-03 09:11
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@                        USE AT YOUR OWN RISK
    @@                        USE AT YOUR OWN RISK
    @@                        USE AT YOUR OWN RISK
    @@ ------------------------------------------------------------------------
    @@ Uncomment the following line if you need it.
    @@ LOGOUT
    @@
    c One
    @@ connect One
    @@
    @@ c Kris Kringle
    @@ connect Kris Kringle
    @@ ------------------------------------------------------------------------
    @@ SELF                           Self Setup                           SELF
    @@ ------------------------------------------------------------------------
    @newpassword [num(me)]=Xyzzy
    @@
    @name me=Zeus
    @alias me=One
    @describe me=In The Beginningfoo, . . .
    @@
    @@ @name me=Trispis
    @@ @alias me=T
    @@ @describe me=A sad hack.
    @@
    @@ @name me=Kris
    @@ @alias me=Santa;Nick;Kringle
    @@ @describe me=Carrying a fat sack.
    @@ ------------------------------------------------------------------------
    @@ SELF                                                                SELF
    @@ ------------------------------------------------------------------------
    

    c_one.txt

    c_one.txt sad hack Wed, 2009-06-17 17:48


    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ USE AT YOUR OWN RISK
    @@ USE AT YOUR OWN RISK
    @@ USE AT YOUR OWN RISK
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ PLEASE NOTE: This is a task-specific adaptation of c_self.txt. This
    @@ script is intended for one, and only one, highly specific task:
    @@
    @@ *** God's FIRST connection to a PennMUSH's very first bootup from the
    @@ default "minimaldb" which comes with the distribution. ***
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ connect
    @@
    c One
    th I think; therefore, I, ~, teh singularity, am.
    @@
    @@ ------------------------------------------------------------------------
    @@ The following line ensures that #1 can queue lots of commands (e.g.,
    @@ lots of @dolists in @startup).
    @@
    give me=1000
    @@
    @@ ------------------------------------------------------------------------
    @@ Uncomment the following line, if you want to ensure that God has enough
    @@ money to queue any number of commands up to the maximum possible.
    @@
    @@ give me=[sub(config(max_pennies),inc(money(me)))]
    @@
    @@ ------------------------------------------------------------------------
    @@ SELF Self Setup SELF
    @@ ------------------------------------------------------------------------
    @newpassword #1=Xyzzyeus
    @@
    @name me=Zeus
    @alias me=One
    @describe me=In The Beginningfoo, . . .
    @@
    @@ ------------------------------------------------------------------------
    @@ SELF SELF
    @@ ------------------------------------------------------------------------
    @@ Recommended next steps, alphabetically: selflock, itb/startup, home

    1 ITB (~reboot adaptation)

    1 ITB (~reboot adaptation) sad hack Tue, 2009-02-03 09:18


    @@ ========================================================================
    @@ ~, the singularity
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ STARTUP STARTUP
    @@
    @@ To add this feature (the ITB module) to an existing game as a stand-
    @@ alone script, either fill in the attribs in full prior to running the
    @@ script or comment out this &startup attribute during the install, build
    @@ the ~`ITB tree appropriately online, then copy/paste the &startup attrib
    @@ manually whenever you're ready for it.
    @@
    &startup me=@tr[@@(I, ~, aka teh singularity, have now begun queue cycle 1: triggering queue cycles 2-5, each of which is capable of sending a couple hundred or more commands queue without pre-emption by any other PLAYER's @startup. Do ya understand me or do ya simply trust me?)] me/~`ITB = ~`ITB[@@(End queue cycle 1.)]
    @@
    @attrib/access ~=veiled
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~ branch
    @@
    &~ me=[@@(NOTE: This is a branch attribute which should be capable of evaluating null.)]
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB branch
    @@
    &~`ITB me=@dolist/delimit | [@@(Queue cycle 2: Sends to queue, beginning at queue cycle 6, either: a sequenced list of commands from 0TH branch during full boot, or a single @@ during @shutdown/reboot.)][switch(reboots(), 0, [u(setr(2,~`ITB`0TH),%q2)], @@)]=##;@dolist/delimit | [@@(Queue cycle 3: Sends a sequenced list from 1ST and 2ND branches into queue immediately after what was sent by queue cycle 2.)][iter(1ST 2ND, [u(setr(3, ~`ITB`[itext(0)]), %q3)], %b, |)]=##;@dolist/delimit | [@@(Queue cycle 4: Sends a sequenced list from CONF, ATTR, FUNC, COMM, and HOOK branches into queue immediately after what was sent by queue cycle 3.)][iter(CONF ATTR FUNC COMM HOOK, [u(setr(4, ~`ITB`[itext(0)]), %q4)], %b, |)]=##;@dolist/delimit | [@@(Queue cycle 5: Sends a sequenced list from NXT and END branches into queue immediately after what was sent by queue cycle 4.)][iter(NXT END, [u(setr(5, ~`ITB`[itext(0)]), %q5)], %b, |)]=##
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    &~`ITB`UTIL me=[iter(%0, v(itext(0)), %b, |)]
    &~`ITB`SEC0 me=[@@(Level 0x0: No connections allowed at all, other than god and wizards.|0x1: No mortal logins allowed during god's @startup, but can connect to existing characters afterward.|0x2: No mortal logins allowed during god's @startup, but can connect to existing characters and guests afterward. ala registration_only.|L0x3: No mortal logins allowed during god's @startup; afterward, game opens to all comers - connect, guest, and create.|Level 1x1: Connections to existing PLAYERS allowed, only.|1x2: Same as 1x1, but add guests after @startup.|1x3: Ditto, but add both guests and creates after @startup.|Level 2x2: PLAYERs and guests allowed, only.|2x3: Ditto, but add creates after @startup.|Level 3x3: All comers.)][@@(Syntax summary: 0x0|0x1|0x2|0x3|1x1|1x2|1x3|2x2|2x3|3x3)]1x2
    @@ SEC0 summary is: the first number indicates who can connect immediately (during god's @startup), the second number indicates who can connect afterward.
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`0TH branch
    @@
    @@ Things to be done first, but only during full restart
    @@
    &~`ITB`0TH me=[@@(Queue cycles 6 -through- 6 + #attribs in 0TH branch -1: Only processed during full boot.)][u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`0TH`0 me=@@ First command to be processed. Perfectly acceptible to be a simple comment command like this. Nonetheless, one command should exist on this branch for clean delimiter support.
    &~`ITB`0TH`1 me=@config/set logins=[switch(left(u(~`ITB`SEC0),1),<1,No,Yes)]
    &~`ITB`0TH`2 me=@config/set guests=[switch(left(u(~`ITB`SEC0),1),<2,No,Yes)]
    &~`ITB`0TH`3 me=@config/set player_creation=[switch(left(u(~`ITB`SEC0),1),<3,No,Yes)]
    @@ &~`ITB`0TH`4 me=@dolist [mwho()]=@boot[@@(, mercilessly, the connection jackhammer with #dbref:)] ##
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`1ST branch
    @@ Things to be done first, prior to all other startup processing
    @@
    &~`ITB`1ST me=[@@(&c)][u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`1ST`0 me=@@ Placeholder to support delimiter.
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`2ND branch
    @@ Things to be done after the "first" things, but prior to general
    @@ category processing.
    @@
    &~`ITB`2ND me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`2ND`0 me=@@ Placeholder to support delimiter.
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`CONF branch
    @@
    &~`ITB`CONF me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`CONF`PLAYER_START me=@config/set player_start=#0
    &~`ITB`CONF`MASTER_ROOM me=@config/set master_room=#2
    &~`ITB`CONF`BASE_ROOM me=@config/set base_room=#0
    &~`ITB`CONF`DEFAULT_HOME me=@config/set default_home=#0
    @@
    @@ &~`ITB`CONF`EXITS_CONNECT_ROOMS me=@config/set exits_connect_rooms=No
    @@ &~`ITB`CONF`ZONE_CONTROL_ZMP_ONLY me=@config/set zone_control_zmp_only=No
    @@ &~`ITB`CONF`ANCESTOR_PLAYER me=-1[@@(Do script)]
    @@ &~`ITB`CONF`ANCESTOR_ROOM me=-1[@@(Do script)]
    @@ &~`ITB`CONF`ANCESTOR_EXIT me=-1[@@(Do script)]
    @@ &~`ITB`CONF`ANCESTOR_THING me=-1[@@(Do script)]
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`ATTR branch
    @@
    &~`ITB`ATTR me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`ATTR`~ me=@attrib/access ~=veiled
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`FUNC branch
    @@
    &~`ITB`FUNC me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`FUNC`0 me=@@ placeholder for delimiter support
    @@
    @@ &~`ITB`FUNC`~ me=@function ~=obj,attr[,args]
    @@ &~`ITB`FUNC`~.switch me=@function/switch foo
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`CMND branch
    @@
    &~`ITB`CMND me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`CMND`0 me=@@ placeholder for delimiter support
    @@
    @@ &~`ITB`CMND`foo me=
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`HOOK branch
    @@
    &~`ITB`HOOK me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`HOOK`0 me=@@ placeholder for delimiter support
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`NXT branch
    @@ Things to be done after general category processing, but prior to
    @@ finishing the startup sequence.
    @@
    &~`ITB`NXT me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`NXT`5 me=@switch [and(lt(setr(l,left(setr(s,u(~`ITB`SEC0)),1)),1),gt(right(%qs,1),%ql))]=0,@@,@config/set logins=Yes
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`END branch
    @@ These are the final things for god to process at startup.
    @@
    &~`ITB`END me=[u(~`ITB`UTIL, lattr(me/%0`*))]
    @@
    &~`ITB`END`0 me=@switch [and(lt(setr(l,left(setr(s,u(~`ITB`SEC0)),1)),2),gt(right(%qs,1),%ql))]=0,@@,@config/set guests=Yes
    &~`ITB`END`9 me=@switch [and(lt(setr(l,left(setr(s,u(~`ITB`SEC0)),1)),3),gt(right(%qs,1),%ql))]=0,@@,@config/set player_creation=Yes
    @@
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    1.1 ITB basic

    1.1 ITB basic sad hack Tue, 2009-02-03 09:31


    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ STARTUP STARTUP
    @@
    &startup me=@tr me/~`ITB
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~ branch
    @@
    &~ me=[@@(NOTE: This attribute is a branch.)][@@(NOTE: This specific attribute should be capable of evaluating null; as such, this commenting style is in use.)]
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB branch
    @@
    &~`ITB me=@dolist [lattr(me/~`ITB`*)]=@tr me/##=##
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ~`ITB`branches
    @@ This completes the theory.
    @@
    &~`ITB`Z me=@dolist [lattr(me/%0`*)]=@tr me/##
    @@
    &~`ITB`Z`ZZ me=@@ Reserved.
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    2 Ancestors

    2 Ancestors sad hack Tue, 2009-02-03 09:36


    @@ ~MakeAllAncestors
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_PLAYER
    @@
    @set me=~`ITB`CONF`ANCESTOR_PLAYER:@config/set ANCESTOR_PLAYER=[pcreate(ANCESTOR_PLAYER, left(scramble(ANCESTORPLAYERPASSWORD), rand(8, 12)))]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_PLAYER
    @@
    @@ ANCESTOR_PLAYER
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/basic Who can pick up the player/object, or go through
    @@ the exit.
    @@
    @lock/basic #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING EXIT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/enter Who can enter the player/object (aka @elock)
    @@
    @lock/enter #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/use Who can use the object (aka @ulock)
    @@
    @lock/use #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/page Who can page/@pemit the player
    @@
    @lock/page #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @@ @lock/link #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/mail Who can @mail the player
    @@
    @lock/mail #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @lock/listen #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @lock/command #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/leave Who can leave this object (or room, via exits/@tel)
    @@
    @@ @lock/leave #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/drop Who can drop this object or in this room
    @@
    @@ @lock/drop #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/give Who can give this object
    @@
    @@ @lock/give #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/follow Who can follow this object
    @@
    @@ @lock/follow #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/forward Who can @forwardlist a message to this object
    @@
    @lock/forward #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/dropto Who can trigger this container's drop-to.
    @@
    @@ @lock/dropto #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_PLAYER)]==#1
    @@
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/interact Who can send sound (say/pose/emit/etc) to this object
    @@
    @lock/interact #[config(ANCESTOR_PLAYER)]=$#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/take Who can get things contained in this object
    @@
    @lock/take #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_ROOM
    @@
    @set me=~`ITB`CONF`ANCESTOR_ROOM:@config/set ANCESTOR_ROOM=[dig(ANCESTOR_ROOM)]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_ROOM
    @@
    @set #[config(ANCESTOR_ROOM)]=FLOATING
    @@
    @teleport me=#[config(ANCESTOR_ROOM)]
    @@
    @tel #[config(ANCESTOR_PLAYER)]=#[config(ANCESTOR_ROOM)]
    @@
    @link #[config(ANCESTOR_PLAYER)]=#[config(ANCESTOR_ROOM)]
    @@
    @chown #[config(ANCESTOR_ROOM)]=#[config(ANCESTOR_PLAYER)]
    @@
    @set #[config(ANCESTOR_ROOM)]=!HALT
    @@
    @@ ANCESTOR_ROOM
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ @lock/teleport Who can teleport to the room
    @@
    @lock/teleport #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ ROOM
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @lock/link #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/speech Who can speak/pose/emit in this room
    @@
    @@ @lock/speech #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ ROOM
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @@ @lock/listen #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @lock/command #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/drop Who can drop this object or in this room
    @@
    @lock/drop #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/dropto Who can trigger this container's drop-to.
    @@
    @lock/dropto #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_ROOM)]==#1
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/take Who can get things contained in this object
    @@
    @lock/take #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_EXIT
    @@
    @set me=~`ITB`CONF`ANCESTOR_EXIT:@config/set ANCESTOR_EXIT=[open(ANCESTOR_EXIT,#[config(ANCESTOR_ROOM)])]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_EXIT
    @@
    @chown #[config(ANCESTOR_EXIT)]=#[config(ANCESTOR_PLAYER)]
    @@
    @set #[config(ANCESTOR_EXIT)]=!HALT
    @@
    home
    @@
    @@ ANCESTOR_EXIT
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/basic Who can pick up the player/object, or go through
    @@ the exit.
    @@
    @lock/basic #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING EXIT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/use Who can use the object (aka @ulock)
    @@
    @@ @lock/use #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @lock/link #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @@ @lock/listen #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @@ @lock/command #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_EXIT)]==#1
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_THING
    @@
    @set me=~`ITB`CONF`ANCESTOR_THING:@config/set ANCESTOR_THING=[create(ANCESTOR_THING,10)]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_THING
    @@
    @chown #[config(ANCESTOR_THING)]=#[config(ANCESTOR_PLAYER)]
    @@
    @set #[config(ANCESTOR_THING)]=!HALT
    @@
    @link #[config(ANCESTOR_THING)]=#[config(ANCESTOR_PLAYER)]
    @@
    @tel #[config(ANCESTOR_THING)]=#[config(ANCESTOR_PLAYER)]
    @@
    @@ ANCESTOR_THING
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/basic Who can pick up the player/object, or go through
    @@ the exit.
    @@
    @lock/basic #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING EXIT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/enter Who can enter the player/object (aka @elock)
    @@
    @lock/enter #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/use Who can use the object (aka @ulock)
    @@
    @lock/use #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @lock/link #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/mail Who can @mail the player
    @@
    @lock/mail #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING?
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @@ @lock/listen #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @@ @lock/command #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/leave Who can leave this object (or room, via exits/@tel)
    @@
    @@ @lock/leave #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/drop Who can drop this object or in this room
    @@
    @lock/drop #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/give Who can give this object
    @@
    @lock/give #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/follow Who can follow this object
    @@
    @@ @lock/follow #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/forward Who can @forwardlist a message to this object
    @@
    @@ @lock/forward #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING?
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/dropto Who can trigger this container's drop-to.
    @@
    @lock/dropto #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_THING)]==#1
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/interact Who can send sound (say/pose/emit/etc) to this object
    @@
    @lock/interact #[config(ANCESTOR_THING)]=$#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/take Who can get things contained in this object
    @@
    @lock/take #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ @shutdown/reboot

    2.0.1 PLAYER

    2.0.1 PLAYER sad hack Tue, 2009-02-03 09:51


    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_PLAYER
    @@
    @set me=~`ITB`CONF`ANCESTOR_PLAYER:@config/set ANCESTOR_PLAYER=[pcreate(ANCESTOR_PLAYER, left(scramble(ANCESTORPLAYERPASSWORD), rand(8, 12)))]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_PLAYER
    @@
    @@ ANCESTOR_PLAYER
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/basic Who can pick up the player/object, or go through
    @@ the exit.
    @@
    @lock/basic #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING EXIT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/enter Who can enter the player/object (aka @elock)
    @@
    @lock/enter #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/use Who can use the object (aka @ulock)
    @@
    @lock/use #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/page Who can page/@pemit the player
    @@
    @lock/page #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @@ @lock/link #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/mail Who can @mail the player
    @@
    @lock/mail #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @lock/listen #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @lock/command #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/leave Who can leave this object (or room, via exits/@tel)
    @@
    @@ @lock/leave #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/drop Who can drop this object or in this room
    @@
    @@ @lock/drop #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/give Who can give this object
    @@
    @@ @lock/give #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/follow Who can follow this object
    @@
    @@ @lock/follow #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/forward Who can @forwardlist a message to this object
    @@
    @lock/forward #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/dropto Who can trigger this container's drop-to.
    @@
    @@ @lock/dropto #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_PLAYER)]==#1
    @@
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/interact Who can send sound (say/pose/emit/etc) to this object
    @@
    @lock/interact #[config(ANCESTOR_PLAYER)]=$#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/take Who can get things contained in this object
    @@
    @lock/take #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    2.0.2 ROOM

    2.0.2 ROOM sad hack Tue, 2009-02-03 09:52


    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_ROOM
    @@
    @set me=~`ITB`CONF`ANCESTOR_ROOM:@config/set ANCESTOR_ROOM=[dig(ANCESTOR_ROOM)]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_ROOM
    @@
    @set #[config(ANCESTOR_ROOM)]=FLOATING
    @@
    @teleport me=#[config(ANCESTOR_ROOM)]
    @@
    @tel #[config(ANCESTOR_PLAYER)]=#[config(ANCESTOR_ROOM)]
    @@
    @link #[config(ANCESTOR_PLAYER)]=#[config(ANCESTOR_ROOM)]
    @@
    @chown #[config(ANCESTOR_ROOM)]=#[config(ANCESTOR_PLAYER)]
    @@
    @set #[config(ANCESTOR_ROOM)]=!HALT
    @@
    @@ ANCESTOR_ROOM
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ @lock/teleport Who can teleport to the room
    @@
    @lock/teleport #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ ROOM
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @lock/link #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/speech Who can speak/pose/emit in this room
    @@
    @@ @lock/speech #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ ROOM
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @@ @lock/listen #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @lock/command #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/drop Who can drop this object or in this room
    @@
    @lock/drop #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/dropto Who can trigger this container's drop-to.
    @@
    @lock/dropto #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_ROOM)]==#1
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/take Who can get things contained in this object
    @@
    @lock/take #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    2.0.3 EXIT

    2.0.3 EXIT sad hack Tue, 2009-02-03 09:55


    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_EXIT
    @@
    @set me=~`ITB`CONF`ANCESTOR_EXIT:@config/set ANCESTOR_EXIT=[open(ANCESTOR_EXIT,#[config(ANCESTOR_ROOM)])]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_EXIT
    @@
    @chown #[config(ANCESTOR_EXIT)]=#[config(ANCESTOR_PLAYER)]
    @@
    @set #[config(ANCESTOR_EXIT)]=!HALT
    @@
    home
    @@
    @@ ANCESTOR_EXIT
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/basic Who can pick up the player/object, or go through
    @@ the exit.
    @@
    @lock/basic #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING EXIT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/use Who can use the object (aka @ulock)
    @@
    @@ @lock/use #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @lock/link #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @@ @lock/listen #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @@ @lock/command #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_EXIT)]==#1
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    2.0.4 THING

    2.0.4 THING sad hack Tue, 2009-02-03 09:56


    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ANCESTOR_THING
    @@
    @set me=~`ITB`CONF`ANCESTOR_THING:@config/set ANCESTOR_THING=[create(ANCESTOR_THING,10)]
    @@
    @tr me/~`ITB`CONF`ANCESTOR_THING
    @@
    @chown #[config(ANCESTOR_THING)]=#[config(ANCESTOR_PLAYER)]
    @@
    @set #[config(ANCESTOR_THING)]=!HALT
    @@
    @link #[config(ANCESTOR_THING)]=#[config(ANCESTOR_PLAYER)]
    @@
    @tel #[config(ANCESTOR_THING)]=#[config(ANCESTOR_PLAYER)]
    @@
    @@ ANCESTOR_THING
    @@ ------------------------------------------------------------------------
    @@ LOCKS LOCKS
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/basic Who can pick up the player/object, or go through
    @@ the exit.
    @@
    @lock/basic #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING EXIT
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/enter Who can enter the player/object (aka @elock)
    @@
    @lock/enter #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/use Who can use the object (aka @ulock)
    @@
    @lock/use #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/zone Who can control objects on this zone
    @@
    @@ @lock/zone #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/parent Who can @parent something to this object/room
    @@
    @@ @lock/parent #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/link Who can @link something to this object/room
    @@ or who can @link this unlinked exit.
    @@
    @lock/link #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/mail Who can @mail the player
    @@
    @lock/mail #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING?
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/user: User-defined. No built-in function of this lock,
    @@ but users can test it with elock()
    @@
    @@ @lock/user:
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/listen Who can trigger my @ahear/^-pattern actions
    @@
    @@ @lock/listen #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/command Who can trigger my $-pattern commands
    @@
    @@ @lock/command #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/leave Who can leave this object (or room, via exits/@tel)
    @@
    @@ @lock/leave #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/drop Who can drop this object or in this room
    @@
    @lock/drop #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/give Who can give this object
    @@
    @lock/give #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/follow Who can follow this object
    @@
    @@ @lock/follow #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/examine Who can examine this object if it's VISUAL
    @@
    @@ @lock/examine #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/chzone Who can @chzone to this object if it's a ZMO
    @@
    @@ @lock/chzone #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ SPECIAL
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/forward Who can @forwardlist a message to this object
    @@
    @@ @lock/forward #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING?
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/control Who can control this object (only if set)
    @@
    @@ @lock/control #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/dropto Who can trigger this container's drop-to.
    @@
    @lock/dropto #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/destroy Who can destroy this object if it's DESTROY_OK
    @@
    @lock/destroy #[config(ANCESTOR_THING)]==#1
    @@ PLAYER ROOM EXIT THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/interact Who can send sound (say/pose/emit/etc) to this object
    @@
    @lock/interact #[config(ANCESTOR_THING)]=$#[config(ANCESTOR_PLAYER)]
    @@ PLAYER THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ @lock/take Who can get things contained in this object
    @@
    @lock/take #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@ PLAYER ROOM THING
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    2.1 Locks and Keys

    2.1 Locks and Keys sad hack Tue, 2009-02-03 09:40


    @@ ========================================================================
    @@ LOCKTYPES LOCKTYPES
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    &~`LOCKTYPES`ALL me=destroy examine control link command listen parent basic page mail forward enter use give follow interact drop leave dropto take teleport speech zone chzone user
    &~`LOCKTYPES`PLAYER me=destroy examine control link command listen parent basic page mail forward enter use give follow interact drop leave dropto take
    &~`LOCKTYPES`ROOM me=destroy examine control link commmand listen parent basic leave dropto take teleport speech
    &~`LOCKTYPES`EXIT me=destroy examine control link command listen parent basic
    &~`LOCKTYPES`THING me=destroy examine control link command listen parent basic enter use give follow interact drop leave dropto take
    @@
    @dolist PLAYER ROOM EXIT THING=@cpattr me/~`LOCKTYPES`##=#[config(ANCESTOR_##)]/~`LOCKTYPES
    @dolist ALL ROOM EXIT THING=@cpattr me/~`LOCKTYPES`##=#[config(ANCESTOR_PLAYER)]/~`LOCKTYPES`##
    @@
    &~`KEY #[config(ANCESTOR_PLAYER)]=@dolist [v(~`LOCKTYPES)]=@lock/## me=[v(~`KEY`##)]
    @dolist [v(~`LOCKTYPES`PLAYER)]=&~`KEY`## #[config(ANCESTOR_PLAYER)]=
    @dolist [v(~`LOCKTYPES`PLAYER)]=@lock/## #[config(ANCESTOR_PLAYER)]==#[config(ANCESTOR_PLAYER)]
    @@
    &~`KEY #[config(ANCESTOR_ROOM)]=@dolist [v(~`LOCKTYPES)]=@lock/## me=[v(~`KEY`##)]
    @dolist [v(~`LOCKTYPES`ROOM)]=&~`KEY`## #[config(ANCESTOR_ROOM)]=
    @dolist [v(~`LOCKTYPES`ROOM)]=@lock/## #[config(ANCESTOR_ROOM)]==#[config(ANCESTOR_PLAYER)]
    @@
    &~`KEY #[config(ANCESTOR_EXIT)]=@dolist [v(~`LOCKTYPES)]=@lock/## me=[v(~`KEY`##)]
    @dolist [v(~`LOCKTYPES`EXIT)]=&~`KEY`## #[config(ANCESTOR_EXIT)]=
    @dolist [v(~`LOCKTYPES`EXIT)]=@lock/## #[config(ANCESTOR_EXIT)]==#[config(ANCESTOR_PLAYER)]
    @@
    &~`KEY #[config(ANCESTOR_THING)]=@dolist [v(~`LOCKTYPES)]=@lock/## me=[v(~`KEY`##)]
    @dolist [v(~`LOCKTYPES`THING)]=&~`KEY`## #[config(ANCESTOR_THING)]=
    @dolist [v(~`LOCKTYPES`THING)]=@lock/## #[config(ANCESTOR_THING)]==#[config(ANCESTOR_PLAYER)]
    @@
    @@ @shutdown/reboot
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    2.1.1 Keys (Custom)

    2.1.1 Keys (Custom) sad hack Tue, 2009-02-03 09:42

    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ KEYS
    @@ ------------------------------------------------------------------------
    &~`target me=me
    &~`targetkey me==me
    @@
    @dolist [v(~`LOCKTYPES`[type(v(~`TARGET))])]=@set [v(~`target)]=~`KEY`##:[v(~`targetkey)]
    @@
    &~`target me
    &~`targetkey me
    @@ ------------------------------------------------------------------------
    &~`KEY`DESTROY [v(~`TARGET)]==#1
    &~`KEY`EXAMINE [v(~`TARGET)]=
    &~`KEY`CONTROL [v(~`TARGET)]==me
    &~`KEY`LINK [v(~`TARGET)]==me
    &~`KEY`COMMAND [v(~`TARGET)]==me
    &~`KEY`LISTEN [v(~`TARGET)]==me
    &~`KEY`PARENT [v(~`TARGET)]==me
    &~`KEY`BASIC [v(~`TARGET)]==me
    &~`KEY`PAGE [v(~`TARGET)]=
    &~`KEY`MAIL [v(~`TARGET)]=
    &~`KEY`FORWARD [v(~`TARGET)]==me
    &~`KEY`ENTER [v(~`TARGET)]==me
    &~`KEY`USE [v(~`TARGET)]==me
    &~`KEY`GIVE [v(~`TARGET)]==me
    &~`KEY`FOLLOW [v(~`TARGET)]=
    &~`KEY`INTERACT [v(~`TARGET)]=
    &~`KEY`DROP [v(~`TARGET)]=
    &~`KEY`LEAVE [v(~`TARGET)]=
    &~`KEY`DROPTO [v(~`TARGET)]==me
    &~`KEY`TAKE [v(~`TARGET)]==me
    &~`KEY`TELEPORT [v(~`TARGET)]==me
    &~`KEY`SPEECH [v(~`TARGET)]=
    &~`KEY`ZONE [v(~`TARGET)]==me
    &~`KEY`CHZONE [v(~`TARGET)]==me
    &~`KEY`USER [v(~`TARGET)]==me
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------

    3 Home

    3 Home sad hack Tue, 2009-02-03 09:47

    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ HOME Go Home HOME
    @@ ------------------------------------------------------------------------
    @@
    @dig/teleport Olympus
    @set here=FLOATING
    @link me=here
    @lock here==me
    @describe here=Where the gods live.
    @@
    @@ ------------------------------------------------------------------------
    @@ HOME HOME
    @@ ------------------------------------------------------------------------

    4 U R Here

    4 U R Here sad hack Mon, 2009-06-01 13:54


    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ This script creates a "new character connection room" for all newly
    @@ created characters. This is where you appear if you use the 'create'
    @@ command at the connection screen. It is equipped with a single exit,
    @@ which can be locked, leading to room #0 (base room).
    @@ blah blah blah...
    @@
    @@
    @dig/teleport You Are Here
    @@
    @@
    @describe here=%rWelcome to: [mudname()]%r%r[center(U R, 15)]%r[center(ansi(gh, *),15)]%r[center(Here! ,15)]%r%rPleez:%r%r%tset yer @sex, &email, and &kungfoo attribs;%r%treed nuze ayupi; and, type 'i agrue'.%r%renjoy the gams.%r%relves have left the building... ...to you.%r%r%t10Q VeriMUSH%r
    @@
    @@
    @open i agree;i might be a grue=#0
    @@
    @@ Configure here=new character connection room.
    @@ Attach "newbie tour" and/or "char[acter ]gen[eration]" here.
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ ========================================================================

    5 Bob, teh @builder

    5 Bob, teh @builder sad hack Mon, 2009-06-01 14:02


    @@ ------------------------------------------------------------------------
    @@ BUILDER Create Builder BUILDER
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@
    @@ For Midnight.
    @@ Can I kick it?
    @@ Yes, you can!
    @@
    @dig/teleport Where To Stand
    @@
    @pcreate Bob=builder
    @describe *Bob=A builder.
    @power *Bob=builder
    @@
    @chown here=*Bob
    @describe here=Bob teh @bilderz crib.
    @set here=FLOATING !HALT
    @@
    @tel *Bob=here
    @link *Bob=here
    @@
    @@ ------------------------------------------------------------------------
    @@ BUILDER BUILDER
    @@ ------------------------------------------------------------------------

    PIGLet

    PIGLet Trispis Mon, 2007-06-18 22:18

    PIGLet pieces.

    It will be interesting to watch the differences between these two file types.

    ~let()

    ~let() Trispis Mon, 2007-06-18 22:20


    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ========================================================================
    @@ DISCLAIMER: Use at your own risk.
    @@ This script is intended for the Pennmush server.
    @@ Guaranteed to break if used in Rhost or MUX.
    @@ See license at: http://community.pennmush.org/node/343
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ Announcement
    @@
    th ~> Script started.
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ UPDATE: To update an existing installation, set the following line to
    @@ your let() function's #dbref. Otherwise, let it set a blank attribute to
    @@ begin a fresh installation (i.e., leave it alone).
    @@
    &~ me=
    @@
    @@ Setting the above line is all you need to do. Make sure you did it
    @@ and that you did it the way you wanted. No further changes needed.
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ Update/Creation Announcement and Implementation...
    @@
    th ~> [ifelse(isdbref(v(~)), Updating, Installing[attrib_set(me/~, create(~let function))][attrib_set(v(~)/DATA, v(~))])]: [name(v(~))]...
    @@
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ Library
    @@
    th ~> [ifelse(dec(words(lparent(v(~)))), Checking, Creating [name(parent(v(~), setr(0, create(Font Library 1))))][attrib_set(%q0/describe, name(%q0))])]
    @@
    @@
    @@ ------------------------------------------------------------------------
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ Preparation
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@ Credits.
    @@
    &CRED`COPYRIGHT [v(~)]=© Copyright 2007, Chuc McGuire
    &CRED`LICENSE [v(~)]=WARPEDcore Softcode and Documentation License, http://community.pennmush.org/node/343
    @@
    @set [v(~)]=DATA`ANSIORDS:[iter(h H u U i I x X r R g G y Y b B m M c C w W, ord(%i0))]
    @@
    @@ Tweak ~let() with no args so that it lists installed fonts after the #dbref.
    @@
    @@ ~let()
    @@ ~let(<font[:<ansi>]>, <string>)
    @@
    &UFUN`~LET [v(~)]=localize(ifelse(nor(words(%0), words(%1)), %! [iter(lattrp(me/FONT`), after(%i0, `))], switch(1, t(words(setr(e, u(UFUN`ERCK`FONT, setr(f, first(%0, :)))))), %qe, t(words(setr(e, u(UFUN`ERCK`STRING, setr(s, %1))))), %qe, setq(a, u(UFUN`ESET`ANSI, rest(%0, :)))[u(UFUN`DISP, %qf, %qa, %qs)])))
    @@
    &UFUN`DISP [v(~)]=map(UFUN`DISP2, lnum(1, words(v(FONT`%qf`032), |)), %b, %r)
    &UFUN`DISP2 [v(~)]=setq(0, %0)[foreach(UFUN`DISP3, %qs)]
    &UFUN`DISP3 [v(~)]=map(UFUN`DISP4, elements(v(FONT`%qf`[rjust(ord(%0), 3, 0)]), %q0, |), %b, )
    &UFUN`DISP4 [v(~)]=ansi(%qa[first(%0, \, )], chr(rest(%0, \, )))
    @@
    @@
    @@ &~letlen()
    @@
    &UFUN`~LETLEN [v(~)]=localize(switch(1, t(words(setr(e, u(UFUN`ERCK`FONT, setr(f, first(%0, :)))))), %qe, t(words(setr(e, u(UFUN`ERCK`STRING, setr(s, %1))))), %qe, lmath(add, foreach(#lambda/words(first(v(FONT`%qf`\[rjust(ord(\%0), 3, 0)\]), |))\%b, %qs))))
    @@
    &UFUN`ERCK`FONT [v(~)]=ifelse(hasattrp(me, FONT`%qf), , u(UFUN`EMSG-1, %qf))
    @@
    &UFUN`ERCK`STRING [v(~)]=localize(foreach(#lambda/\[ifelse(hasattrp(me, FONT`%qf`\[rjust(ord(\%0), 3, 0)\]), , setq(e, \%qe \%0))\], %0)[if(words(%qe), u(UFUN`EMSG-2, %qf, %qe))
    @@
    &UFUN`ESET`ANSI [v(~)]=foreach(#lambda/if(member(v(DATA`ANSIORDS), ord(\%0)), \%0), %0)
    @@
    &UFUN`EMSG-1 [v(~)]=#-1 No such font: %0
    @@
    &UFUN`EMSG-2 [v(~)]=#-2 Unsupported character(s) in font %0: %1
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    &HELP`~LET [v(~)]=%r~let()%r~let(<font\[:<ansi>\]>, <string>)%r%rwith no arguments returns the #dbref of the ~let function object, followed by a list of all installed fonts.%r%rif <font> (optional :<ansi>) and <string> are provided, it returns one of the following...%r%r#-1 if <font> does not exist.%r#-2 if there are characters in <string> which aren't supported in <font>%ror, <string> in <font> with optional <ansi> applied.%r%rFor example, see: +help ~let2
    @@
    &HELP`~let2 [v(~)]=%rExample: think ~let(isometricsm:bh, M U S H)%r[~let(isometricsm:bh, M U S H)]%r
    @@
    &HELP`~letlen [v(~)]=%r~letlen(<font>, <string>)%r%rreturns the actual screen width of <string> displayed in <font>, or the following errors%r%r#-1 if <font> does not exist.%r#-2 if there are characters in <string> which aren't supported in <font>%r
    @@
    @@ ========================================================================
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ------------------------------------------------------------------------
    @@
    @@ From Javelin: add the following to a wiz object's @startup
    @@
    @@ @function ~let=<#dbref>, ufun`~let
    @@ @function ~letlen=<#dbref>, ufun`~letlen
    @@

    unfu~

    unfu~ sad hack Fri, 2009-06-26 17:18

    @@
    @@ ========================================================================
    @@ unfu~
    @@
    @@ A content management system for Pennmush, utilizing:
    @@
    @@ * the many_attribs @power to allow an entire content package, no matter
    @@ how large, to fit on a single object,
    @@ * attribute tree features to facilitate organizational management of
    @@ that content, and
    @@ * side-effect parenting to allow internal, on-the-fly, temporary
    @@ reparenting to any of an unlimited number of potential parents
    @@
    @@ for in-game retrieval of appropriately packaged game content.
    @@ ========================================================================
    @@ FINAL ALPHA RELEASE a.2009.07.14.a
    @@ ========================================================================
    @@

    @@ System Requirements:
    @@
    @@ pennmush-compatible attribute tree-ing.
    @@ many_attribs @power for large content packs.
    @@ side-effects enabled.
    @@ pennmush-compatible align() function.
    @@ pennmush-compatible #lambda.
    @@
    @@ ------------------------------------------------------------------------
    @@ Usage information:
    @@
    @@ The unfu~ command (with no arguments) provides end-user usage info.
    @@ Other documentation is provided at the end of this file.
    @@ A comprehensive documentation of features, foibles, and fun is in the
    @@ works (it'll definitely be included when this moves to beta).
    @@
    @@ ========================================================================
    @@ DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER DISCLAIMER
    @@
    @@ If you do not have either:
    @@
    @@ a. absolute familiarity with the content you are installing to this
    @@ system, or...
    @@
    @@ b. absolute trust in the source of the content you are installing to
    @@ this system
    @@
    @@ then, DO NOT USE IT.
    @@
    @@ This system evaluates package content.
    @@
    @@ You have been warned.
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ AUTHORSHIP
    @@
    @@ Unless otherwise explicitly stated, Trispis is the author of this
    @@ content management system, heretofore referred to as "unfu~".
    @@ To contact the author, send email to: <nemosolid><@><gmail><.><com>
    @@ All content package objects are authored by their respective authors;
    @@ for information regarding content packages, see the respective package
    @@ object.
    @@
    @@ ------------------------------------------------------------------------
    @@ WARPEDcore Softcode and Documentation License
    @@
    @@ Copyright (c) 2009, Chuc McGuire
    @@ All rights reserved.
    @@
    @@ Redistribution and use of WARPEDcore materials (the manifesto, scripts,
    @@ modules, etc.) in text or digital forms, with or without modification,
    @@ are permitted provided that the following conditions are met:
    @@
    @@ * Redistributions in text (paper and ink) form must retain the above
    @@ copyright notice, this list of conditions and the following disclaimer.
    @@ * Redistributions in digital form (http, ftp, etc.) must either retain
    @@ the above copyright notice, this list of conditions and the following
    @@ disclaimer within the distributed copies, or include a URL or hyperlink
    @@ to them.
    @@ * Neither the name of this project (unfu~) nor the names of its
    @@ authors and/or contributors may be used to endorse or promote products
    @@ derived from the herein covered material without specific prior written
    @@ permission.
    @@
    @@
    @@ THIS MATERIAL IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    @@ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    @@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    @@ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
    @@ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    @@ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    @@ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    @@ MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@
    @@ This system evaluates package content!
    @@
    @@ You have been warned, AGAIN!
    @@
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ unfu~
    @@
    @set me=va:[create(unfu~,10)]
    @@
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    &~ %va=[@@(Null)]
    @@
    &~`AUTHOR %va=Unless otherwise explicitly stated, Trispis is the author of this content management system, heretofore referred to as "unfu~".%r To contact the author, send email to: [lit(nemosolid)][lit(@)][lit(gmail)][lit(.)][lit(com)]%r
    @@
    &~`LICENSE %va=WARPED~core Softcode and Documentation License. See: unfu~wsdl
    @@
    &~`VERSION %va=a.2009.07.14.a
    @@
    @set %va=~`DBREF`UNFU~:%va
    @@
    @describe %va=%rA content management system for Pennmush, utilizing:%r%r* the many_attribs @power to allow an entire content package, no matter how large, to fit on a single object, %r%r* attribute tree features to facilitate organizational management of that content, and%r%r* the parent() function to manage an unlimited number of content packages%r%rfor in-game retrieval of appropriately packaged game content.%r%rSee: unfu~%r
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    &~`FUNCTION`UNFU~ %va=ifelse(words(%0), ifelse(words(%1), [null(iter(lnum(0, 4), setq(%i0, v(%i0))))][u(~`U`PATH)], u(~`FUNCTION`UNFU~`PACK, %0)), v(~`DBREF`UNFU~))[@@(%q0=packname, %q1=attrpattrn, %q2=width, %q3=UFUN:usercontent, %q4=UFUN:ansi)]
    @@
    &~`FUNCTION`UNFU~`PACK %va=ifelse(isdbref(setr(d, v(~`PACK`%0))), %qd, u(PACK`ERROR,%0))
    @@
    @function unfu~=%va/~`FUNCTION`UNFU~
    @@
    @@ TEXT: unfu~(<pack>, <tfile>[, <width>
    @@ DATA: unfu~(<pack>, <dfile>[, <width>
    @@ UFUN: unfu~(<pack>, <ufile>[, <width>, <usercontent>, <ansi>
    @@
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    &~`CMND %va=$unfu~*:@pemit %#=[@@(unfu~\[<pack>\[ \[<path> \]<file>\]\])][u(~`U, %0)]
    @@
    @set %va=!NOCOMMAND
    @@
    @@ ------------------------------------------------------------------------
    @@ NOTE: ~`U is gonna change; eventually this will be for package
    @@ navigation and demonstration only. The main functionality of this
    @@ object is in its @function (previous section).
    @@ ------------------------------------------------------------------------
    &~`U %va=[setq(0, first(%0), 1, rest(%0), 2, width(%#))][u(~`U`[switch(words(%0), 0, INFO, 1, PACK, PATH)], %q0, %q1)]
    @@ NOTE: This is gonna change; see ~`CMND note above.
    @@
    &~`U`INFO %va=unfu~ content manager%r%r[iter(lattr(unfu~()/~`U`INFO`?), align(39 39, first(v(%i0), |), rest(v(%i0), |)), %b, %r)]%r%r(path leaf names can be included for specificity).%r%rAvailable Packs: [u(~`U`INFO`MENU)]%r
    &~`U`INFO`1 %va=unfu~|this display
    &~`U`INFO`2 %va=unfu~<pack>|info about a content package
    &~`U`INFO`3 %va=unfu~<pack> [<path> ]<file>|a file from pack
    &~`U`INFO`4 %va=
    &~`U`INFO`5 %va=unfu~()|#dbref of unfu object
    &~`U`INFO`6 %va=unfu~(<pack>)|#dbref of unfu pack <pack>
    &~`U`INFO`7 %va=unfu~(<pack>,<[path] file[, parms]>)|contents of <file> from <pack> with optional path specificity, and optional parms for file
    &~`U`INFO`8 %va=Ex: unfu~wsdl wsdl
    &~`U`INFO`9 %va=Ex: th unfu~(wsdl,wsdl)
    &~`U`INFO`MENU %va=%r[table(setr(t, map(#lambda/last(\%0, `), lattr(unfu~()/~`PACK`*))), inc(lmath(max, map(#lambda/strlen(\%0), %qt))), width(%#))]
    @@
    @@ ------------------------------------------------------------------------
    &~`U`PACK %va=u(~`U`PACK`[ifelse(setr(e, isdbref(setr(d, v(~`PACK`%0)))), DISPLAY, ERROR)], %0, %qd)
    &~`U`PACK`ERROR %va=#-0 No such package as: %0
    &~`U`PACK`DISPLAY %va=ucstr(%0)%r[u(%1/describe)]%r[if(words(setr(z, lattr(%1/CONTENT`TEXT`??*) [lattr(%1/CONTENT`DATA`??*)] [lattr(%1/CONTENT`UFUN`??*)])), u(~`U`TEXT`MENU, %qz))]
    @@
    @@ ------------------------------------------------------------------------
    &~`U`PATH %va=ifelse(isdbref(setr(d, v(~`PACK`%q0))), setq(p, parent(me))[null(parent(me, %qd))][u(~`U`FILE)][null(parent(me, ifelse(isdbref(%qp), %qp, )))], u(PACK`ERROR, %q0))
    @@
    @@ ------------------------------------------------------------------------
    &~`U`FILE %va=u(~`U`FILE`[switch(words(setr(a, lattrp(me/CONTENT`**`[edit(%q1, %b, **)]))), 0, ERROR0, >1, ERROR2,DISPLAY)])
    @@
    @@ %q0=packname,%q1=attrpattrn, %q2=width, %q3=usercontent, %q4=ansi %qa=attrib[s]
    @@
    &~`U`FILE`ERROR0 %va=#-1 No match for %q0 %q1.
    &~`U`FILE`ERROR2 %va=#-2 Too many matches. Choose one:%r[iter(%qa, edit(rest(rest(%i0, `), `), `, %b), %b, %r)]
    @@
    &~`U`FILE`DISPLAY %va=ucstr(%q0)/%qa%r[u(~`U`FILE`HEAD)][u(~`U`FILE`BODY)][u(~`U`FILE`FOOT,%1)]
    &~`U`FILE`HEAD %va=if(hasattrp(me, HEAD), ulocal(HEAD, %1)%r)
    &~`U`FILE`FOOT %va=if(hasattrp(me, FOOT), %r[u(FOOT, %1)])
    &~`U`FILE`BODY %va=u(~`U`[elements(%qa, 2, `)])
    @@
    @@ ------------------------------------------------------------------------
    &~`U`TEXT %va=ulocal(%qa, %qa, %q2)%r[u(~`U`TEXT`MENU, lattrp(me/%qa`??*))]
    @@
    &~`U`TEXT`MENU %va=if(words(%0), %r[table(setr(m, map(#lambda/last(\%0, `), %0)), inc(lmath(max, map(#lambda/strlen(\%0), %qm))), ifelse(isnum(%q2), %q2, width(%#)))])
    @@
    @@ ------------------------------------------------------------------------
    @@
    &~`U`DATA %va=center(ifelse(hasattrpval(me, %qa), ulocal(%qa,%qa,%q2), last(%qa, `)), setr(2,ifelse(isnum(%q2), %q2, dec(width(%#)))))%r%r[u(~`U`DATA`ELEMENTS)]
    @@
    &~`U`DATA`ELEMENTS %va=iter(setr(e, u(CONTENT`DATA`[elements(%qa, 3, `)]))|[setdiff(map(#lambda/last(\%0, `), lattrp(me/%qa`*)), %qe)][setq(r, words(%qe), x, lmath(max, map(#lambda/strlen(\%0), %qe) [dec(div(%q2, 4))]))], iter(%i0, if(hasattrpval(me, %qa`%i0), switch(inum(1)[inum(0)], 2*, %r, 1%qr, %r)[align(>%qx [sub(%q2, inc(%qx))], map(#lambda/capstr(\%0), edit(lcstr(%i0), _, %b)), ulocal(%qa`%i0, %qa`%i0, %q2))]%r), %b, ), |, )
    @@
    @@ ------------------------------------------------------------------------
    &~`U`UFUN %va=ulocal(%qa, %qa, %q2, %q3, %q4)
    @@
    @@ %qa is name of the attrib being called, and... arrives as %0
    @@ %q2 is width in which output must displayb arrives as %1
    @@ %q3 is content sent to function arrives as %2
    @@ %q4 is ansi color arrives as %3
    @@
    @@ NOTE: Once I'm comfortable with my ability to follow this in my brain,
    @@ this will pass additional arguments number for number, for any additonal
    @@ arguments which might be needed. I.e., ...
    @@
    @@ ulocal(%qa, %qa, %q2, %q3, %q4, %4, %5, %6, %7, %8, %9)
    @@
    @@ ------------------------------------------------------------------------
    &~`U`ELSE %va=Not sure what to do with %0 %1.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@
    &~`PACK %va=[@@(Packages of Content. Each ~`PACK`<package> attrib should contain a single #dbref; nothing more, nothing less.)]
    @@
    @@ NOTE: Each content package is installed onto its own separate object.
    @@ The #dbref of this object is stored in the respective ~`PACK`<package>
    @@ attribute on the unfu~ object. <package> must be a single word with no
    @@ spaces ( ), backticks (`), or other dangerous characters.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ p.s. I'm pretty sure someone with SQL knowledge could make an SQL
    @@ content pack which manages translation from MUSH input style (function
    @@ calls) to SQL database lingo (which I currently don't speak, but I have
    @@ seen, and it looks nothing like softcode).
    @@ Since I really don't know the mechanics involved in this, it could very
    @@ well be something as simple as a few function calls which could be
    @@ submitted as a patch to the unfu~ system itself.
    @@ Either way, it seems possible that this could potentially become a
    @@ bridge to virutally any content on any system with which PennMUSH can
    @@ interface.
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ CONTENT
    @@
    @@ unfu~ currently manages content of three types:
    @@
    @@ TEXT, DATA, and UFUNs.
    @@
    @@ Content is separated according to these types in their respective
    @@ attribute branches: CONTENT`TEXT CONTENT`DATA CONTENT`UFUN.
    @@
    @@ Each package object may include HEAD and FOOT attributes to store
    @@ any information which must be displayed before and after (respectively)
    @@ each display of content.
    @@
    @@ The convention. Only material connected to a package object's CONTENT`
    @@ attribute branch is considered content.
    @@ All attributes are evaluated with:
    @@ ulocal(<attr>, <attr>, [other stuff])
    @@ that is, each attribute is evaluated AND told its own path (it knows
    @@ itself). Theoretically, this feature could be used to cross-index data,
    @@ but I don't have any working examples of that (yet).
    @@
    @@ Any TEXT attribute which is both a leaf and branch will be followed by a
    @@ list of its leaf attributes longer than one character (see the notes on
    @@ single-character leaf/branch names, below).
    @@
    @@ DATA content works slightly differently. Any content in the
    @@ CONTENT`DATA branch assumes employment of data structures. For
    @@ example: all weapons will have a common set of data characteristics,
    @@ all spells will have a common set of data characteristics, etc.
    @@ Thus, each leaf of the DATA branch will contain its own data structure
    @@ list. For example:
    @@ CONTENT`DATA`MONSTER will contain the list of data element attribute
    @@ names common to all of its leaf attribs (Monster: Size, HP, etc.),
    @@ resulting in something like:
    @@
    @@ CONTENT`DATA`MONSTER`gremlin
    @@ CONTENT`DATA`MONSTER`gremlin`size
    @@ CONTENT`DATA`MONSTER`gremlin`hp
    @@ etc.
    @@
    @@ Again, there is a single-character exception (see the exception below)
    @@
    @@ and
    @@
    @@ Attribute name segments (leaf/branch-es) longer than one digit are
    @@ automatically considered sub-elements of their parent branch segment
    @@ and processed according to the content type (in TEXT and DATA branches).
    @@
    @@ Single-digit attribute name segments are ignored by the unfu~ system
    @@ when they are part of the immediately succeeding leaf set from the
    @@ current branch.
    @@ Eventually, single digit attribs will be divided into three groups:
    @@ 1. 0-9 and A-Z (unfu~ currently plans to never use these, leaving
    @@ them always available to the packs, invisibly... think similar to the
    @@ single digit %q-registers 0-9 and A-Z).
    @@ 2. all other characters which are valid in attribute names. These will
    @@ be sorted and assessed for internal use.
    @@ 3. (I said three groups, didn't I?)
    @@
    @@ The UFUN branch is, as it appears, a place for UFUNs. The Display
    @@ package (posted alongside this) contains an example of a Display UFUN.
    @@ Not much to explain here. Some values are necessary/optional
    @@ (width/ansi), blah blah blah, but basically unfu~() serves as a single
    @@ function which can call an unlimited number of other functions.
    @@
    @@ These features avail content to both packaged display (what are the
    @@ rules, show me the stats of 'that', and make it look nice, dang it!)
    @@ and individualized feature reference (abilities, durations, whatever
    @@ for softcode automation).
    @@
    @@ Using backticks in the <path> can help distinguish between two attribs
    @@ with similar looking paths.
    @@ Example:
    @@
    @@ unfu~warp~fest attribs
    @@ #-2 Too many matches. Choose one:
    @@ MANIFESTO ATTRIBS
    @@ MANIFESTO REGISTRY ATTRIBS
    @@
    @@ To display the first entry, do:
    @@
    @@ unfu~warp~fest manifesto`attribs
    @@
    @@ (The error message returns the full paths, line by line, of all entries
    @@ matching the query. Use the info to help your query specificity.
    @@ Usually, the backticks are not necessary; but, in some rare instances
    @@ -- like this one, they not only remove uncertainty, but also fill out
    @@ necessity.)
    @@
    @@ FINAL NOTE: There is a difference in spelling between "unfu~" and "UFUN"
    @@ because:
    @@
    @@ UFUN is U[ser-defined] FUN[ction] -- a PennMUSH term/operation.
    @@
    @@ unfu~ is derived from SNAFU: S[ituation] N[ormal], A[ll] F[ouled] U[p]
    @@ i.e., un-FU.
    @@
    @@ As in: unfu~(<this mess>)
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@

    unfu~WSDL

    unfu~WSDL sad hack Sat, 2009-06-27 09:23

    @@
    @@ ========================================================================
    @@ The
    @@ WARPED~core Softcode and Documentation License
    @@ packaged for use with the unfu~ content manager
    @@ and distributed, with permission, therewith.
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@

    @set unfu~()=~`PACK`WSDL:[create(WSDL, 10)]
    @@
    @@ ------------------------------------------------------------------------
    @power unfu~(wsdl)=many_attribs
    @@ Not necessary, but included as SOP.
    @@
    @@ power unfu~(wsdl)=enormousdbsize
    @@ Look this one up.
    @@
    @@ ------------------------------------------------------------------------
    @@ Empty branch attributes.
    &~ unfu~(wsdl)=
    &CONTENT unfu~(wsdl)=
    &CONTENT`TEXT unfu~(wsdl)=
    &CONTENT`DATA unfu~(wsdl)=
    @@
    @@ ------------------------------------------------------------------------
    @describe unfu~(wsdl)=u(~`describe, dec(width(%#)))
    @@
    @@ ------------------------------------------------------------------------
    &~`DESCRIBE unfu~(wsdl)=iter(lattr(me/~`DESCRIBE`?), center(u(%i0), %0), %b, %r)
    &~`DESCRIBE`0 unfu~(wsdl)=The WARPED~core Softcode and Documentation License
    &~`DESCRIBE`1 unfu~(wsdl)=packaged for use with the unfu~ content manager
    &~`DESCRIBE`2 unfu~(wsdl)=and distributed, with permission, therewith.
    @@
    @@ ------------------------------------------------------------------------
    &~`LEGAL unfu~(wsdl)=LEGAL INFORMATION
    &~`LEGAL`1 unfu~(wsdl)=Conversion of content to unfu~ format performed by Trispis.
    &~`LEGAL`2 unfu~(wsdl)=More information available at community.pennmush.org.
    @@
    @@ ------------------------------------------------------------------------
    &CONTENT`TEXT`WSDL unfu~(wsdl)=WARPEDcore Softcode and Documentation License%rCopyright (c) 2009, Chuc McGuire%rAll rights reserved.%r%rRedistribution and use of WARPEDcore materials (the manifesto, scripts, modules, etc.) in text or digital forms, with or without modification, are permitted provided that the following conditions are met:%r%r* Redistributions in text (paper and ink) form must retain the above copyright notice, this list of conditions and the following disclaimer.%r* Redistributions in digital form (http, ftp, etc.) must either retain the above copyright notice, this list of conditions and the following disclaimer within the distributed copies, or include a URL or hyperlink to them.%r* Neither the name of this product (unfu~) nor the names of its authors and/or contributors may be used to endorse or promote products derived from the herein covered material without specific prior written permission.%r%rTHIS MATERIAL IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@

    unfu~display

    unfu~display sad hack Sun, 2009-06-28 13:15

    @@
    @@ ========================================================================
    @@ Display borders for unfu~
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@


    @set unfu~()=~`PACK`DISPLAY:[create(Display Functions,10)]
    @link unfu~(DISPLAY)=unfu~()
    @tel unfu~(DISPLAY)=unfu~()
    @set unfu~(DISPLAY)=no_command
    @@
    @@ ------------------------------------------------------------------------
    @power unfu~(DISPLAY)=many_attribs
    @@
    @@ ------------------------------------------------------------------------
    &~ unfu~(DISPLAY)=
    &CONTENT unfu~(DISPLAY)=
    &CONTENT`UFUN unfu~(DISPLAY)=
    @@
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@

    @@ H ____________________________________
    @@ H(6))                                 )
    @@ H ¯/  Head Text, one line only       /
    @@ H (                                 (
    @@ B  ) First line of body.             )   
    @@ B (  Second line of body.
    @@ B  ) Rest 
    @@ B    of
    @@ B    body.
    @@ F                                     )
    @@ F /__________________________________/_
    @@ F((9) ¯   ¯¯¯¯¯        ¯¯¯¯¯¯¯¯¯¯¯¯¯                                  )
    @@ F ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ F                                   ( 
    @@ F )____                            __)
    @@ F((9)¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯)
    @@ F ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ 


    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @describe unfu~(display)=u(~`describe)
    &~`DESCRIBE unfu~(display)=u(CONTENT`UFUN`SCROLL1, CONTENT`UFUN`SCROLL1, , Display Functions%r[iter(lattrp(me/~`DESCRIBE`?), [u(%i0)], %b, %r)], y)
    &~`DESCRIBE`0 unfu~(display)=[space(5)]This unfu~ content package contains user-defined functions available for use in the display of content. It only takes a few of these, combined with ancestor objects, and voil[chr(225)] ~ instant pretty stuff.
    &~`DESCRIBE`1 unfu~(display)=[space(5)]The quick brown fox jumps over the lazy dog, only to discover that the sixth sick sheik's sixth sheep's sick. One, two, three, four, five, six, seven; all good children will go to heaven.
    &~`DESCRIBE`2 unfu~(display)=[space(5)]Now is the time, and high time at that, for all you peeps to come to the Boston THC party. Dude, it only takes a couple tokes and voil[chr(225)] ~ instant appreciation for pretty stuff. Wow.%R
    &~`DESCRIBE`3 unfu~(display)=Syntax: u\(\, , , \[\%r]\, \)
    &~`DESCRIBE`4 unfu~(display)=Example: think u\([unfu~(DISPLAY)]/CONTENT`UFUN`SCROLL1\,CONTENT`UFUN`SCROLL1\,width\(\%#\)\, Foo\%rBar\%rBaz\%rBlah\, y\)
    @@
    @@ ------------------------------------------------------------------------
    &CONTENT`UFUN`SCROLL1 unfu~(display)=u(%0`SETQ, %1, %2, %3)[u(%0`HEAD)][u(%0`BODY)][u(%0`FOOT)]
    &CONTENT`UFUN`SCROLL1`SETQ unfu~(display)=[setq(y, dec(ifelse(isnum(%0), %0, width(%#))), h, switch(%1, */CONTENT`*, ifelse(hasattrpval(setr(u, localize(unfu~(first(%1, /)))), HEAD), ulocal(%qu/HEAD)[setq(b, after(%1,ulocal(%qu/HEAD)))], first(%1, %r)[setq(b, rest(%1, %r))]),first(%1,%r)[setq(b, rest(%1,%r))]), a, %2, l, ansi(%2, \(), r, ansi(%2, \)), s, ansi(%2h,\)), t, ansi(%2, /))]
    &CONTENT`UFUN`SCROLL1`HEAD unfu~(display)=%b[ansi(%qah, repeat(_, sub(%qy, 2)))]%r[ansi(%qa, \(6)]%qs%qs[space(sub(%qy,5))]%qs%r[align(3 -[sub(%qy,8)] 2,%b [ansi(%qa,/)]%r %ql%b, %qh,%b%qt%r%ql)]%r
    &CONTENT`UFUN`SCROLL1`BODY unfu~(display)=align(3 [sub(%qy,8)] 2,%b %qr%r %ql%b%r%b %qr%r,%qb,%b%qr)
    &CONTENT`UFUN`SCROLL1`FOOT unfu~(display)=%qr%r %qt[ansi(%qah,[repeat(_,sub(%qy,4))])]%qt%r[ansi(%qa,\(6)]%qs[ansi(%qa,repeat(_,sub(%qy,4)))]%qs
    @@
    @@ ------------------------------------------------------------------------
    @@ NOTES: unfu~() always returns the pack/full`attr`path of a successful
    @@ match (i.e., a non-error result) followed by a %r, followed by the
    @@ returned output. To remove these from a display, use:
    @@
    @@ rest(unfu~(blah, blah, blah),%r)
    @@
    @@ Additionally, the display pack has no HEAD attribute and will assume
    @@ that the first %r-delimited item goes in the scroll heading. So, if the
    @@ content being displayed does not include this already, you can place it
    @@ manually, as in:
    @@
    @@ unfu~(display, scroll1, width(%#), this heading%r<this content>)
    @@
    @@ And putting this together, you can package an unfu~() return into a
    @@ display the following ways (referencing the aforementioned tweaks):
    @@
    @@ by default, an unfu~() return will result in it's obj/attr`path being
    @@ the header (obj/attr`path is the first %r-delimited item). If this is
    @@ not desired, do something along one of the following lines...
    @@
    @@ if the unfu~() return has an appropriate %r-delimited header after the
    @@ obj/attr`path, do:
    @@
    @@ unfu~(display, scroll1, <width>, rest(unfu~(blah),%r))
    @@
    @@ if the output doesn't have such a header, do:
    @@
    @@ unfu~(display, scroll1, <width>, this header%r[rest(unfu~(blah),%r)])
    @@
    @@ Last, but not least (or, maybe least?), scroll1 accepts an ansi color
    @@ input as it's 5th parameter:
    @@
    @@ unfu~(display, scroll1, <width>, <header%rcontent>, <ansi>)
    @@
    @@ ... which it will hilite for the "depth/reflection" effect on the
    @@ leading edge of the "scroll" graphic.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ Examples (you should cut these out before quoting this script):
    @@ ------------------------------------------------------------------------
    @@ formatting a room display
    @@
    @descformat here=rest(unfu~(display,scroll1,width(%#),name(me)%r%0,y),%r)
    @@
    @conformat here=align(setr(w, dec(div(width(%#),2))) %qw, rest(unfu~(display, scroll1, dec(%qw), Players%r[map(#lambda/name(\%0)%r, lvplayers(me))], y), %r), rest(unfu~(display, scroll1, dec(%qw), Things%r[map(#lambda/name(\%0)%r, lvthings(me))], y), %r))
    @@
    @exitformat here=rest(unfu~(display, scroll1, width(%#), Exits%r[map(#lambda/align(setr(w, div(sub(width(%#), 10), 2)) 8 %qw, name(\%0), leads to, name(loc(\%0)))%r, %0)], y), %r)
    @@
    @@ ------------------------------------------------------------------------
    @@ formatting help text (someone feel free to write this appropriately)
    @@
    @@ @command/disable help
    @@ @hook/override help= blah
    @@
    @@ rest(unfu~(display, scroll1, <width>, %0%r[textfile(help, %0)], g),%r)
    @@
    @@ resulting in the help text being wrapped in a green scroll1 display.
    @@
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ Below are some display concepts "in the works".
    @@ ------------------------------------------------------------------------
    @@

    @@ Speech bubble
    @@  ________
    @@ ( Trispis says,
    @@  )   __________)
    @@     ( Text .... here )
    @@                 ¯¯¯¯¯
    @@
    @@ Thought Bubble
    @@  ________
    @@ ( Trispis thinks :
    @@  )   ,~~~~~~~~~~~'
    @@     { Text ---- here }
    @@                 ~~~~'
    @@
    @@ Emote... ?
    @@  ________
    @@ ( Trispis  
    @@  )¯¯| text here |
    @@            ¯¯¯¯¯
    @@
    @@ Narration (IC) Emit bubble (bots, weather, ambience)?
    @@  _
    @@ ( Text
    @@  )    here_)
    @@            
    @@
    @@ System Emit?
    @@ +-----
    @@ | Text here. |
    @@        ------+
    @@
    @@ Street signs and shingles.
    @@
    @@ o___________________________,
    @@ | 9   ¿                   ¿ `
    @@ |6    :                   :
    @@ |    _?___________________?_
    @@ |   | Text here             |
    @@ |    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@
    @@ o
    @@ +-----+-------------------+--o
    @@ | 9   ?                   ?
    @@ |6    :                   :
    @@ |    _¿___________________¿_
    @@ |   | Text here             |
    @@ |    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@
    

    unfu~help

    unfu~help sad hack Tue, 2009-07-14 14:29

    @@
    @@ ========================================================================
    @@ ------------------------------------------------------------------------
    @@ ________________________________________________________________________
    @@ .:....1....:....2....:....3....:....4....:....5....:....6....:....7....:
    @@ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    @@ ------------------------------------------------------------------------
    @@ ========================================================================
    @@ unfu~help
    @@ ========================================================================
    @set unfu~()=~`PACK`HELP:[create(unfu~help,10)]
    @set unfu~(HELP)=nocommand
    @link unfu~(HELP)=unfu~()
    @tel unfu~(HELP)=unfu~()
    @@
    @@ ========================================================================
    @@ EMPTY ATTRIBS
    &~ unfu~(HELP)=
    &CONTENT unfu~(HELP)=
    &CONTENT`TEXT unfu~(HELP)=
    &CONTENT`TEXT`HELP unfu~(HELP)=
    @@
    @@ ========================================================================
    @@ CREDITS
    &~`AUTHOR unfu~(HELP)=Unless otherwise explicitly stated, Trispis is the author of the content management system, heretofore referred to as "unfu~".%r To contact the author, send email to: [lit(nemosolid)][lit(@)][lit(gmail)][lit(.)][lit(com)]%r
    &~`AUTHOR2 unfu~(HELP)=Individual content packages, such as this one, are authored by their respective authors. See the individual content package for authorship.
    &~`AUTHOR3 unfu~(HELP)=The distribution version of this package (unfu~help) only contains the unfu~ help file(s), written by Trispis; however, it is intended to allow the addition of an unlimited quantity of other help files, most of which are quite likely written by other people.
    @@
    &~`LICENSE unfu~(HELP)=WARPED~core Softcode and Documentation License. See: unfu~wsdl
    @@
    @@ ------------------------------------------------------------------------
    @describe unfu~(HELP)=The unfu~help package.
    @@
    @@ ------------------------------------------------------------------------
    &CONTENT`TEXT`HELP`UNFU~ unfu~(HELP)=unfu~%runfu~()%r%rSituation Normal All Fouled Up -- SNAFU%runfu~'s intent is to UNdo the "FU" in snafu: unfu~(<this>).%r%rThe command:%r%r[iter(unfu~|returns info about unfu~%runfu~<pack>|returns info about <pack>,align(36 [sub(ifelse(isnum(%1),%1,width(%#)),37)],first(%i0,|),rest(%i0,|)),%r,%r)]%r%rThe function:%r%r[iter(unfu~\(\)|#dbref of unfu~ object%runfu~\(<pack>\)|#dbref of <pack>%runfu~\(<pack>\,<\[path] file\[\, parms]>\)|process <file> from <pack> with optional path and parameters,align(36 [sub(width(%#),37)],first(%i0,|),rest(%i0,|)),%r,%r)%r%rSee also: UNFU~2
    @@
    &CONTENT`TEXT`HELP`UNFU~2 unfu~(HELP)=unfu~%runfu~ example:%r%r unfu~wsdl wsdl%r%runfu~\(\) examples:%r%r th unfu~\(help\, unfu~\)%r th unfu~\(display\, scroll1\, setr\(f\, width\(\%#\)\)\, unfu~\(help\, unfu~2\, sub\(\%qf\, 9\)\)\, y\)%r th unfu~\(display\, scroll1\, setr\(f\,width\(\%#\)\)\, rest\(unfu~\(help\, unfu~2\, sub\(\%qf\,9\)\)\, \%r\)\, y\)
    @@
    &CONTENT`TEXT`HELP`UNFU~3 unfu~(HELP)=unfu~%runfu~ syntax conventions:%r%rThere is one premise on which the input syntax of the unfu~() function is based. Specifically, anything returned by the unfu~() function is intended, in some way, to be displayed; whether it be a display of textual material (rules, help files, descriptions, etc.), data structures (properties/stats of players, mobs, weapons, equipment, etc.), packaging frills (borders, layouts, etc.), or otherwise.%r%rSince unfu~() can self-reference (i.e., it can call itself again to package up some other result it returns), <width> is considered a crucial, primary parameter for all packages. And, since not all unfu~ packages will embrace any sort of user input (unrelated to any internal, stored, information), user input is considered secondary to <width>, with all other inputs following thereafter. Thus, for consistency and uniformity among content packs, the preferred organization of input parameters (i.e., if you want to contribute a package feature) is as follows:%r%runfu~(<pack>, <attr>\[, <width>\[, <user input>\]\[, <other, parms>\]\])
    @@
    @@ Why not have <pack/attrib> as a single input parameter?
    @@ Two reasons:
    @@
    @@ 1. I'm limiting the number of input parameters available to packages to
    @@ a total of 8 (one or two of which have been defined above, leaving 6-7
    @@ to the package feature's additional needs), so that unfu~ itself has
    @@ a limit to what it does, compared to what the package does, and...
    @@ 2. I'm reducing and simplifying the initial errorchecking steps which
    @@ unfu~ needs to perform at the outset. E.g., a single input parameter is
    @@ assumed to be a package name ONLY (rather than a pack/attrib combo which
    @@ must be separated out into parts).
    @@
    @@ The aforementioned points may seem trivial to the casual observer, but
    @@ hey... I'm not Linus Torvalds; and at the time of this writing, I'm still
    @@ developing this thing solo. (Plus, most experienced softcoders know how
    @@ to amplify input parameter capacity by using alternative delimiters
    @@ other than the comma, such as: foo|bar|baz as three parms in one.)
    @@
    @@ Additionally, any input parameters beyond <pack> and <attrib> are
    @@ considered optional to unfu~ (that is, they are not required by unfu~,
    @@ but may be required by the specific content pack being called;
    @@ and if they do exist, regardless of whether they are pack-optional or
    @@ otherwise, they should occur in the order specified above: width, user
    @@ input, other parms). And, since these are considered optional by unfu~,
    @@ well-written packs will embrace assumed defaults (e.g., width(%#) is
    @@ the assumed default for the display pack's scroll1 distributed example).
    @@
    @@ Finally, if the potential for unlimited variations on input seems, at
    @@ the outset, to be somewhat intimidating (see my excuses, above), there
    @@ is a silver lining: This isn't intended to be called manually each time;
    @@ rather, it's intention, like all functions, is to be part of some coded
    @@ thing or other where it can be written and debugged ONCE, and used
    @@ repeatedly thereafter for variations of conditions or user input.
    @@ ------------------------------------------------------------------------
    @@ ========================================================================

    2 - Abandonware?

    2 - Abandonware? Trispis Sun, 2006-09-24 19:56

    In nearly a month, Javelin is the only person who has contributed to this web-book without prompting from me (Mike @ M*U*S*H has been very helpful online! Thanks!).

    As a result, I'm getting the impression that there isn't much interest in this. So, I'm opening this chapter to discuss abandonware status of this project (if I'm the only one actually interested in it, I think I'd rather pursue graphical MUDding).

    Please contribute your thoughts (if another month passes without comments here, I'll interpret that as a sign).