Dynamic Space 2.8

This code lets you set up rectilinear grids of rooms that only exist when needed. This is useful for doing sky areas, oceans, terrain, or even the surfaces of entire planets!

Category: Dynamic Space
Compatibility: TinyBit, TinyMUSH, TinyMUX.


Copy and paste the below code into a compatible MUSH or MUX.

MUSHCode for Dynamic Space 2.8

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Dynamic Space - The Next Generation
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ Release: 2.8
@@ Date: 95-04-14
@@ Requires: TinyMUSH 2.2 or later
@@ mpp MUSH Pre-processor (distributed as mpp.c)
@@ Author: Joshua Bell, jsbell@acs.ucalgary.ca
@@ Algol@NarniaGolden, dobest.lib.virginia.edu 6250

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Changes:
@@ ~~~~~~~~
@@ 2.8
@@ - Rewrote the whole damn exit-display stuff
@@ - Made dimension-locks easier to add
@@ - Lots of internal reorganizations of comments and config stuff
@@ - Conversion to TinyMUSH 2.2isms (NOT COMPLETE!)
@@ See "HISTORY" section at end of file for a complete list.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Dynamic Space:
@@ ~~~~~~~~~~~~~~
@@ This code lets you set up rectilinear grids of rooms that only
@@ exist when needed. This is useful for doing sky areas, oceans,
@@ terrain, or even the surfaces of entire planets!
@@ This code runs under TinyMUSH 2.2 or later, and does NOT require
@@ Wizard powers. Its internal recycling queue allows it to operate
@@ with limited quota or limited funds (although having lots of
@@ money is a major advantage), and for the technically inclined,
@@ requires only two queue cycles per movement inside the semaphore
@@ protection.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Installation notes:
@@ ~~~~~~~~~~~~~~~~~~~
@@ The script will have to be piped through my mpp.c "MUSH Pre-
@@ Processor" to get rid of the comments and formatting.
@@ The source code is available from the MUSHcode archive site
@@ located at: ftp://caisr2.caisr.cwru.edu/pub/mush/mushcode
@@ section *before* running this script!
@@ The script as written will run without changes, but it is
@@ doubtful that you will like, or be able to use the results.
@@ You may also want to grab and read: Dynamic_Space_Map-1.2
@@ which is the optional map module.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Features:
@@ ~~~~~~~~~
@@ - Up to three dimensions of movement. Locks can be applied to any
@@ direction of travel.
@@ - Space can be limited to a fixed size, made to wrap around, or extended
@@ infinitely in each dimension.
@@ - Individual exits within a room can be blocked or hidden.
@@ - Exits are transparent to those who pass them.
@@ - The desc, succ, name, parent, and transient-status of a room can be
@@ altered using simple commands within the DS.
@@ - Permission to alter the DS can be granted via as something as simple
@@ as a flag or lock, or any function you wish.
@@ - Administrators can teleport to any valid location within the DS
@@ volume.
@@ - The size of the room queue (used to avoid actual creation/destruction
@@ of rooms) can be adjusted to suit the traffic expected.
@@ - An optional map module which allows you to "sketch" areas in ASCII
@@ and have them realized in the DS.
@@ - Using the map, rooms can be eliminated entirely leaving "walls"
@@ behind in the space.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Conditions of use and disclaimer
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ I make no claims as to the safety, reliability, or usefulness
@@ of this code, other than: it has worked for me, and has not caused
@@ any harm to the MUSHes I have tried it on. There are probably
@@ still bugs in it, although I attempt to patch these as I find them.
@@ I'm willing to answer questions about setting up DS, modifying it
@@ for custom use, or how portions of the code work. I'm not willing
@@ to set it up for you, or to teach you everything required to
@@ do it yourself (this is not for the beginner!).
@@ Permission is granted to run this code on any platform you chose,
@@ with the provision that you let me know if you port it to another
@@ server platform, find bugs, patch bugs, or add functionality that
@@ may be of interest to others.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Available Ports
@@ ~~~~~~~~~~~~~~~
@@ TinyMUSH 2.0.9p2
@@ ~~~~~~~~~~~~~~~~
@@ The last dedicated code for the 2.0 line of TinyMUSH
@@ is Dynamic_Space-2.7p2. Look for it where you found this code.
@@ Development on this line probably won't continue.
@@ PennMUSH 1.5p10
@@ ~~~~~~~~~~~~~~~
@@ Joe Bui <jsb11@dewey.EEAP.CWRU.Edu> has ported DS 2.7 to PennMUSH.
@@ "I doubt that it will work with lower versions of PennMUSH since I
@@ used db-modifying functions."
@@ Joshua Bell has applied patches to bring it in line with 2.7p2
@@ code but these have not been tested.
@@ TinyMUSE
@@ ~~~~~~~~
@@ A MUSE port (of sorts) is also available. Contact
@@ czar@Wittenberg.EDU for more information

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Credits:
@@ ~~~~~~~~
@@ Code: Algol@NarniaGolden (was Tash@Narnia)
@@ Concept: Talek@PernMUSH
@@ Instigator: Ehlrick@TooMUSH
@@ Suggestions: The Hermit@Narnia, Tangent@TooMUSH, Edmund@Narnia,
@@ Pomona@TooMUSH, Talek@PernMUSH, Fumblethumb@Narnia,
@@ Andrew Molitor, Rilian@Narnia, Maud@Narnia,
@@ Drayton@Narnia, Frank@Narnia, Kent Jenkins
@@ PennMUSH Ports: Rilian@Narnia (2.3)
@@ Joe Bui <jsb11@dewey.EEAP.CWRU.Edu> (2.7)
@@ TinyMUSE Port: czar@Wittenberg.EDU (2.?)

@@ -----8<----CUT HERE----8<--------8<--------8<--------8<--------8<----

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Create the Origin Room
@@ ~~~~~~~~~~~~~~~~~~~~~~

@dig/tel Center of a Vast Plane
&XCOOR here=0
&YCOOR here=0
&ZCOOR here=0
@set here=FLOATING

@@ Create the relevant objects
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~

@create Dynamic Room Parent
@create Dynamic Exit Parent
@create Dynamic Array Object

@parent here=Dynamic Room Parent

@set Dynamic Room Parent=SAFE
@set Dynamic Room Parent=HALTED
@set Dynamic Exit Parent=SAFE
@set Dynamic Array Object=SAFE

@@ Store object dbref#s
@@ ~~~~~~~~~~~~~~~~~~~~

@fo me=&NAME-0.0.0 Dynamic Array Object=[name(here)]
@fo me=&NUM-0.0.0 Dynamic Array Object=[num(here)]

@fo me=&ARRAY Dynamic Room Parent=[num(Dynamic Array Object)]
@fo me=&ARRAY Dynamic Exit Parent=[num(Dynamic Array Object)]
@fo me=@va Dynamic Room Parent=[num(Dynamic Array Object)]
@fo me=@va Dynamic Exit Parent=[num(Dynamic Array Object)]

@fo me=&ROOM_PARENT Dynamic Exit Parent=[num(Dynamic Room Parent)]
@fo me=&EXIT_PARENT Dynamic Room Parent=[num(Dynamic Exit Parent)]

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Entry and Exit to/from a DS
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ ...should be done via normal exits linked to/from the DS, or
@@ teleportation to rooms which are "fixed" using the "fix here"
@@ building command.
@@ All non-dynamic exits in a DS should be set DARK; use the
@@ "hide exit=<exitname>" building command to conceal them.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Set up the Inherited Exits
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ Note: If you only want N/S/E/W, just delete the NE/NW/SE/SW code.
@@ Similarly, if you only want two dimensions, delete out U/D

@@ If you want more exits (to have the 26 possible 3D directions, say)
@@ add lines to make and parent the new exits, and just add the
@@ appropriate X/Y/ZNEW attributes. North, East, and Up should be
@@ add(), South, West, and Down should be sub(). All exits need to
@@ be set DARK. To hide exits (say, Up and Down) add:
@@ &DARK_EXITS Dynamic Room Parent=|Up|Down

@@ @Succ, @Osucc, @Odrop work like they normally do, but %0 is the
@@ dbref# of the player attempting the exit; to emulate %p you need
@@ to use [poss(%0)]. FAKE_FAIL is the same as @fail (which cannot
@@ be used!), again with %0 being the player dbref#.

@@ The exits attempt to be transparent to those who can pass through;
@@ NO_DESC is seen if the target room is out of range, and the
@@ FAIL_DESC is seen if the exit is blocked or not passable.

drop Dynamic Room Parent
enter Dynamic Room Parent

@open Up;u
@set Up=DARK
@parent Up=Dynamic Exit Parent
@lock Up=me&!me
@link Up=here
&ZNEW Up=add(get(%0/ZCOOR),1)
@set Up=DARK
@Succ Up=You head upwards.
@Osucc Up=heads upwards.
@Odrop Up=comes up from below.
&FAKE_FAIL Up=You find you cannot travel further upward.
&NO_DESC Up=You cannot discern anything further above you.
&FAIL_DESC Up=It appears impossible to travel further upwards.

@open Down;d
@set Down=DARK
@parent Down=Dynamic Exit Parent
@lock Down=me&!me
@link Down=here
&ZNEW Down=sub(get(%0/ZCOOR),1)
@set Down=DARK
@Succ Down=You head downwards.
@Osucc Down=heads downwards.
@Odrop Down=comes down from above.
&FAKE_FAIL Down=You find you cannot travel further downward.
&NO_DESC Down=You cannot discern anything further below you.
&FAIL_DESC Down=It appears impossible to descend further.

@open Northwest;nw
@set Northwest=DARK
@parent Northwest=Dynamic Exit Parent
@lock Northwest=me&!me
@link Northwest=here
&YNEW Northwest=add(get(%0/YCOOR),1)
&XNEW Northwest=sub(get(%0/XCOOR),1)
@Succ Northwest=You head northwest.
@Osucc Northwest=heads northwest.
@Odrop Northwest=comes in from the southeast.
&FAKE_FAIL Northwest=You find you cannot travel further northwest.
&NO_DESC Northwest=You cannot discern anything further to the northwest.
&FAIL_DESC Northwest=Travel to the northwest appears blocked.

@open North;n
@set North=DARK
@parent North=Dynamic Exit Parent
@lock North=me&!me
@link North=here
&YNEW North=add(get(%0/YCOOR),1)
@Succ North=You head north.
@Osucc North=heads north.
@Odrop North=comes in from the south.
&FAKE_FAIL North=You find you cannot travel further north.
&NO_DESC North=You cannot discern anything further to the north.
&FAIL_DESC North=Travel to the north appears blocked.

@open Northeast;ne
@set Northeast=DARK
@parent Northeast=Dynamic Exit Parent
@lock Northeast=me&!me
@link Northeast=here
&YNEW Northeast=add(get(%0/YCOOR),1)
&XNEW Northeast=add(get(%0/XCOOR),1)
@Succ Northeast=You head northeast.
@Osucc Northeast=heads northeast.
@Odrop Northeast=comes in from the southwest.
&FAKE_FAIL Northeast=You find you cannot travel further northeast.
&NO_DESC Northeast=You cannot discern anything further to the northeast.
&FAIL_DESC Northeast=Travel to the northeast appears blocked.

@open East;e
@set East=DARK
@parent East=Dynamic Exit Parent
@lock East=me&!me
@link East=here
&XNEW East=add(get(%0/XCOOR),1)
@Succ East=You head east.
@Osucc East=heads east.
@Odrop East=comes in from the west.
&FAKE_FAIL East=You find you cannot travel further east.
&NO_DESC East=You cannot discern anything further to the east.
&FAIL_DESC East=Travel to the east appears blocked.

@open Southeast;se
@set Southeast=DARK
@parent Southeast=Dynamic Exit Parent
@lock Southeast=me&!me
@link Southeast=here
&XNEW Southeast=add(get(%0/XCOOR),1)
&YNEW Southeast=sub(get(%0/YCOOR),1)
@Succ Southeast=You head southeast.
@Osucc Southeast=heads southeast.
@Odrop Southeast=comes in from the northwest.
&FAKE_FAIL Southeast=You find you cannot travel further southeast.
&NO_DESC Southeast=You cannot discern anything further to the southeast.
&FAIL_DESC Southeast=Travel to the southeast appears blocked.

@open South;s
@set South=DARK
@parent South=Dynamic Exit Parent
@lock South=me&!me
@link South=here
&YNEW South=sub(get(%0/YCOOR),1)
@Succ South=You head south.
@Osucc South=heads south.
@Odrop South=comes in from the north.
&FAKE_FAIL South=You find you cannot travel further south.
&NO_DESC South=You cannot discern anything further to the south.
&FAIL_DESC South=Travel to the south appears blocked.

@open Southwest;sw
@set Southwest=DARK
@parent Southwest=Dynamic Exit Parent
@lock Southwest=me&!me
@link Southwest=here
&XNEW Southwest=sub(get(%0/XCOOR),1)
&YNEW Southwest=sub(get(%0/YCOOR),1)
@Succ Southwest=You head southwest.
@Osucc Southwest=heads southwest.
@Odrop Southwest=comes in from the northeast.
&FAKE_FAIL Southwest=You find you cannot travel further southwest.
&NO_DESC Southwest=You cannot discern anything further to the southwest.
&FAIL_DESC Southwest=Travel to the southwest appears blocked.

@open West;w
@set West=DARK
@parent West=Dynamic Exit Parent
@lock West=me&!me
@link West=here
&XNEW West=sub(get(%0/XCOOR),1)
@Succ West=You head west.
@Osucc West=heads west.
@Odrop West=comes in from the east.
&FAKE_FAIL West=You find you cannot travel further west.
&NO_DESC West=You cannot discern anything further to the west.
&FAIL_DESC West=Travel to the west appears blocked.


@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Builder Lock
@@ ~~~~~~~~~~~~
@@ Look at the ISBUILDER code - anything for which that function
@@ returns a 1 is allowed to use the commands in the next section.
@@ You could do a member list, or whatever.

&ISBUILDER Dynamic Room Parent=[hasflag(%#,builder)]
@lock/UseLock Dynamic Room Parent=ISBUILDER/1

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Limits
@@ ~~~~~~
@@ You can define the limits of the Dynamic Space in three ways for
@@ each of the three dimensions. Set the corresponding *-LIMITS to:
@@ 0 - No Limits. Object may travel forever in that direction.
@@ 1 - Hard Limits. Objects hit a 'wall' when they reach the boundary.
@@ 2 - Wrapping. Objects that reach one edge pass through to the opposite
@@ edge of the plane.

&X-LIMITS Dynamic Array Object=2
&Y-LIMITS Dynamic Array Object=1
&Z-LIMITS Dynamic Array Object=1

&MAXX Dynamic Array Object=10
&MINX Dynamic Array Object=-10
&MAXY Dynamic Array Object=10
&MINY Dynamic Array Object=-10
&MAXZ Dynamic Array Object=5
&MINZ Dynamic Array Object=0

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Room Queue
@@ ~~~~~~~~~~
@@ The default is between 3 and 6 rooms on the queue at any one time,
@@ create or destroy any extra as needed. If you anticipate heavy use,
@@ you can up the lower end. I don't think more than 5 will ever be
@@ needed. The maximum limit is just an 'in case', and should never be
@@ set too high, although it should be at least 3 more than the minimum.

&QUEUE-MIN Dynamic Array Object=3
&QUEUE-MAX Dynamic Array Object=6

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Dimension Locks
@@ ~~~~~~~~~~~~~~~
@@ The default to allow anyone to move in any direction. To restrict
@@ motion in certain directions, do something like this:
@@ &DIM_LOCK Up=strmatch(get(%#/HAS_WINGS),Yes)
@@ Travel is permitted if this function returns a true value (non-0)

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Null Rooms
@@ ~~~~~~~~~~
@@ While the code for these is built in here, the best description
@@ and implementation is in the optional Map Module. If you want to
@@ use this feature without maps, you need to write something like this:
@@ &ISNULL Dynamic Exit Parent=<MyFunction>
@@ %0, %1 and %2 are preset to the X, Y and Z coords of the target room.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ ~~~~~~~~~
@@ There's a section later in the code titled "Generic Attributes" that
@@ you should look at.

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Description Generation
@@ ~~~~~~~~~~~~~~~~~~~~~~
@@ All exits must be kept dark, so the Adesc provides both the
@@ exit list and instructions on how builders can see a command
@@ list. TERSE players see neither, you may want to alter that.

@Desc Dynamic Room Parent=The plane is featureless.

@Adesc Dynamic Room Parent=@pemit %#=[switch(hasflag(%#,TERSE),0,[setq(1,setunion(v(DARK_EXITS),u(DE_HIDE_BORDER),|))][setq(0,filter(DE_FILTER,lexits(%!)))][switch(words(%q0),0,,Obvious exits:%r[iter(%q0,name(##)%b)])][switch(u(ISBUILDER),1,%rType "DS Help" for DS Builder commands.)])]

&DE_FILTER Dynamic Room Parent=switch(member(lcstr(%q1),lcstr(name(%0)),|),0,1,0)

@@ Border exits are hidden if you're using hard limits.
@@ If you don't want this. just remove DE_HIDE_BORDER

&DE_HIDE_BORDER Dynamic Room Parent=edit(trim(squish([switch(11,[get(%va/X-LIMITS)][eq(v(XCOOR),get(%va/MAXX))],East|Northeast|Southeast)]%b[switch(11,[get(%va/X-LIMITS)][eq(v(XCOOR),get(%va/MINX))],West|Northwest|Southwest)]%b [switch(11,[get(%va/Y-LIMITS)][eq(v(YCOOR),get(%va/MAXY))],North|Northwest|Northeast)]%b[switch(11,[get(%va/Y-LIMITS)][eq(v(YCOOR),get(%va/MINY))],South|Southwest|Southeast)]%b[switch(11,[get(%va/Z-LIMITS)][eq(v(ZCOOR),get(%va/MAXZ))],Up)]%b[switch(11,[get(%va/Z-LIMITS)][eq(v(ZCOOR),get(%va/MINZ))],Down)])),%b,|)

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Building Commands
@@ ~~~~~~~~~~~~~~~~~
@@ You can add to these, just remember to add code to the Afail code
@@ of the Exit Parent.

&DESC_HERE Dynamic Room Parent=$desc here=*:@desc me=%0;&desc-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=%0;@pemit %#=Desc set.

&SUCC_HERE Dynamic Room Parent=$succ here=*:@succ me=%0;&succ-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=%0;@pemit %#=Succ set.

&NAME_HERE Dynamic Room Parent=$name here=*:@name me=%0;&name-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=%0;@pemit %#=Name set.

&COORDS_HERE Dynamic Room Parent=$coords:@pemit %#=X coordinate = [v(XCOOR)], Y coordinate = [v(YCOOR)], Z coordinate = [v(ZCOOR)]

&FIX_HERE Dynamic Room Parent=$fix here:@aleave me=@@;@pemit %#=Room fixed.

&PARENT_HERE Dynamic Room Parent=$parent here=*:@parent me=%0;&parent-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=%0;@pemit %#=Parent set.

@@ WARNING! If you change the Parent on a room, you MUST be sure that
@@ the Dynamic Room Parent (or a close copy) occurs SOMEWHERE in the
@@ new Parent chain, otherwise the room will not have the proper exits.

@@ You'll also want to make sure you change the GETDESC function
@@ and replace the {Default description.} with {}

&CMD_HIDE_EXIT Dynamic Room Parent=$hide exit=*:@switch locate(%L,%0,c)=#-1,{@pemit %#=I don't see that exit here.},#-2,{@pemit %#=I don't know which exit you mean!},{&DARK_EXITS %!=setunion(v(DARK_EXITS),lcstr(name(locate(%L,%0,c))),|);&DARK_EXITS-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=v(DARK_EXITS);@pemit %#=Exit hidden. }

&CMD_SHOW_EXIT Dynamic Room Parent=$show exit=*:@switch locate(%L,%0,c)=#-1,{@pemit %#=I don't see that exit here.},#-2,{@pemit %#=I don't know which exit you mean!},{&DARK_EXITS %!=setdiff(v(DARK_EXITS),lcstr(name(locate(%L,%0,c))),|);&DARK_EXITS-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=v(DARK_EXITS);@pemit %#=Exit revealed.}

&CMD_HIDDEN_EXITS Dynamic Room Parent=$list hidden exits:@pemit %#=Hidden exits: [edit(v(DARK_EXITS),|,%b%b)]

&CMD_BLOCK_EXIT Dynamic Room Parent=$BLOCK exit=*:@switch locate(%L,%0,c)=#-1,{@pemit %#=I don't see that exit here.},#-2,{@pemit %#=I don't know which exit you mean!},{&BLOCKED_EXITS %!=setunion(v(BLOCKED_EXITS),lcstr(name(locate(%L,%0,c))),|);&BLOCKED_EXITS-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=v(BLOCKED_EXITS);@pemit %#=Exit blocked. }

&CMD_OPEN_EXIT Dynamic Room Parent=$OPEN exit=*:@switch locate(%L,%0,c)=#-1,{@pemit %#=I don't see that exit here.},#-2,{@pemit %#=I don't know which exit you mean!},{&BLOCKED_EXITS %!=setdiff(v(BLOCKED_EXITS),lcstr(name(locate(%L,%0,c))),|);&BLOCKED_EXITS-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=v(BLOCKED_EXITS);@pemit %#=Exit opened.}

&CMD_BLOCKED_EXITS Dynamic Room Parent=$list BLOCKED exits:@pemit %#=Blocked exits: [edit(v(BLOCKED_EXITS),|,%b%b)]

@parent Dynamic Room Parent=Dynamic Exit Parent

&CMD_TELTO Dynamic Room Parent=$telto * * *:@wait %va={@trigger v(EXIT_PARENT)/[setq(7,add(%0,0))][setq(8,add(%1,0))][setq(9,add(%2,0))][switch(0,u(INBOUNDS,%q7,%q8,%q9),DUMMY,comp(get(%va/NUM-%q7.%q8.%q9),),ALLOC_ROOM,TEL_TO_ROOM)]=%#,%L,%N,%q7,%q8,%q9}

&CMD_DS_HELP Dynamic Room Parent=$DS Help:@pemit %#={%rYou can use the following commands:%r%b'name here=<new name>'%b %b'coords' - find out your current coordinates%r%b'desc here=<new desc>'%b %b'fix here' - stop this room from being recycled%r%b'succ here=<new succ>'%b %b'parent here=<new parent>' - be careful!!%r%b'hide exit=<exitname>'%b %b'show exit=<exitname>' %b 'list hidden exits'%r%b'block exit=<exitname>'%b 'open exit=<exitname>' %b 'list blocked exits'%r%b'telto <x> <y> <z>' - teleport to those coordinates, if they're valid%r}

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Recycling Code
@@ ~~~~~~~~~~~~~~
@@ This code allows you to get away with not @digging at every step.
@@ The system keeps a short queue of rooms to reuse.

@@ Rooms get recycled when they have no contents, and only their
@@ inherited exits remain, unless they have been 'fixed'.

@Aleave Dynamic Room Parent=@switch and(eq(words(lcon(me)),0),eq(words(lexits(me)),words(lexits(parent(me)))))=1,{&num-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)] %va=setdiff(get(%va/num-[v(XCOOR)].[v(YCOOR)].[v(ZCOOR)]),num(me));&recycle_list %va=setunion(get(%va/RECYCLE_LIST),num(me));@name me=DS Recycled Room;@parent me;@dolist lattr(me)={&## me};@trigger %va/RECYCLE}

@@ In case of spurious rooms, force a check on startup.

@Startup Dynamic Room Parent=@trigger me/Aleave

@@ The Array Object itself handles the queue, creation and destruction
@@ of rooms as needed.

&RECYCLE Dynamic Array Object=@switch words(v(RECYCLE_LIST))=<[v(QUEUE-MIN)],{@dig DS Recycled Room;@trigger me/RECYCLE},>[v(QUEUE-MAX)],{@destroy first(v(RECYCLE_LIST));&recycle_list me=rest(v(RECYCLE_LIST));@trigger me/RECYCLE}

@Listen Dynamic Array Object=* created with room number *.
@Amhear Dynamic Array Object=&RECYCLE_LIST me=cat(v(RECYCLE_LIST),#%1);@set #%1=FLOATING

@@ Generate an Initial Queue
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~

@trigger Dynamic Array Object/RECYCLE

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Locks and Defaults
@@ ~~~~~~~~~~~~~~~~~~

@@ No Fail message - the &FAKE_FAIL takes care of that.

@Fail Dynamic Exit Parent=\

@@ The lock for exits - non-blocked and non-null and valid dimension lock

&PASS_LOCK Dynamic Exit Parent=[and(not(member(lcstr(get(%L/BLOCKED_EXITS)),lcstr(name(%!)),|)),not(u(ISNULL,%q7,%q8,%q9)),u(DIM_LOCK))]

@@ Default dimension lock, everyone passes

&DIM_LOCK Dynamic Exit Parent=1

@@ Default null-room status

&ISNULL Dynamic Exit Parent=0

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Transparent Exit Description
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ The desc and succ are seen if the exit is passable to the looker,
@@ defaulting to the parent room if nothing can be found in the array.
@@ The NO_DESC attrib is seen if the target room is out of range, and
@@ the FAIL_DESC is seen if the exit is blocked or not passable.
@@ If you are modelling sky, you may wish to copy the @desc attribute to
@@ your up/down exits, and comment out the chunk:
@@ not(u(PASS_LOCK)),v(FAIL_DESC),
@@ This will allow unpassable exits (eg, to non-fliers) to be seen
@@ from the ground.

@@ The second [setq(... line handles the @succ view. Remove if unwanted.

@Desc Dynamic Exit Parent=[setq(7,u(DXNEW,u(XNEW,%L)))][setq(8,u(DYNEW,u(YNEW,%L)))][setq(9,u(DZNEW,u(ZNEW,%L)))][switch(1,not(u(INRANGE,%q7,%q8,%q9)),v(NO_DESC),not(u(PASS_LOCK)),v(FAIL_DESC),[setq(0,s(u(GETDESC,%q7,%q8,%q9)))][switch(%q0,,get_eval(u(GETPARENT,%q7,%q8,%q9)/Desc),%q0)][setq(0,s(u(GETSUCC,%q7,%q8,%q9)))][switch(%q0,,setq(0,get_eval(u(GETPARENT,%q7,%q8,%q9)/Succ)))][switch(%q0,,,%r%q0)])]

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Target Room Calculation Functions
@@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

&INRANGE Dynamic Exit Parent=and(or(neq(get(%va/X-LIMITS),1),u(IS_IN_X,%0)),or(neq(get(%va/Y-LIMITS),1),u(IS_IN_Y,%1)),or(neq(get(%va/Z-LIMITS),1),u(IS_IN_Z,%2)))

&INBOUNDS Dynamic Exit Parent=and(or(not(get(%va/X-LIMITS)),u(IS_IN_X,%0)),or(not(get(%va/Y-LIMITS)),u(IS_IN_Y,%1)),or(not(get(%va/Z-LIMITS)),u(IS_IN_Z,%2)))

&IS_IN_X Dynamic Exit Parent=and(lte(%0,get(%va/MAXX)),gte(%0,get(%va/MINX)))

&IS_IN_Y Dynamic Exit Parent=and(lte(%0,get(%va/MAXY)),gte(%0,get(%va/MINY)))

&IS_IN_Z Dynamic Exit Parent=and(lte(%0,get(%va/MAXZ)),gte(%0,get(%va/MINZ)))

@@ These three are generic, actual exits modify the values with add/sub

&XNEW Dynamic Exit Parent=get(%0/XCOOR)
&YNEW Dynamic Exit Parent=get(%0/YCOOR)
&ZNEW Dynamic Exit Parent=get(%0/ZCOOR)

@@ Compute the new location, if wrapping is enabled and relevant.

&DXNEW Dynamic Exit Parent=

&DYNEW Dynamic Exit Parent=switch(get(%va/Y-LIMITS),2,switch(1,gt(%0,get(%va/MAXY)),get(%va/MINY),lt(%0,get(%va/MINY)),get(%va/MAXY),%0),%0)

&DZNEW Dynamic Exit Parent=switch(get(%va/Z-LIMITS),2,switch(1,gt(%0,get(%va/MAXZ)),get(%va/MINZ),lt(%0,get(%va/MINZ)),get(%va/MAXZ),%0),%0)

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Do the Dynamic Thing
@@ ~~~~~~~~~~~~~~~~~~~~
@@ ALLOC_ROOM is responsible for the snatching of new rooms from the
@@ queue, if necessary. Semaphores are used on the internal loop here;
@@ when the Afail is called upon, it puts the commands on the semaphore
@@ queue and uses the Array Object as the file lock. When the Array
@@ Object gets @notified, one batch of waiting commands gets run.

@Afail Dynamic Exit Parent=@wait %va={@trigger me/[setq(7,u(DXNEW,u(XNEW,%L)))][setq(8,u(DYNEW,u(YNEW,%L)))][setq(9,u(DZNEW,u(ZNEW,%L)))][switch(0,u(INRANGE,%q7,%q8,%q9),DUMMY,u(PASS_LOCK),DUMMY,comp(get(%va/NUM-%q7.%q8.%q9),),ALLOC_ROOM,TEL_TO_ROOM)]=%#,%L,%N,%q7,%q8,%q9}

&DUMMY Dynamic Exit Parent=@pemit %0=u(FAKE_FAIL,%0,%3,%4,%5);@notify %va

@@ This FAKE_FAIL is seen by admins trying to teleport.

&FAKE_FAIL Dynamic Exit Parent=Sorry, you can't go to (%1,%2,%3).

&ALLOC_ROOM Dynamic Exit Parent=@VN me=first(cat(get(%va/num-%3.%4.%5),get(%va/recycle_list)));&RECYCLE_LIST %va=setdiff(get(%va/RECYCLE_LIST),%vn);@trigger %va/RECYCLE;&num-%3.%4.%5 %va=%vn;&XCOOR %vn=%3;&YCOOR %vn=%4;&ZCOOR %vn=%5;@set %vn=FLOATING;@name %vn=u(GETNAME,%3,%4,%5);@desc %vn=u(GETDESC,%3,%4,%5);@succ %vn=u(GETSUCC,%3,%4,%5);@parent %vn=u(GETPARENT,%3,%4,%5);&DARK_EXITS %vn=u(GETDARKEXITS,%3,%4,%5);&BLOCKED_EXITS %vn=u(GETBLOCKEDEXITS,%3,%4,%5);@pemit %0=switch(hasflag(%0,TERSE),1,,u(Succ,%0));@tel %0=%vn;@pemit/contents %1=%2 [u(Osucc,%0)];@notify %va

&TEL_TO_ROOM Dynamic Exit Parent=@VN me=get(%va/num-%3.%4.%5);@pemit/contents %vn=%2 [u(Odrop,%0)];@pemit %0=switch(hasflag(%0,TERSE),1,,u(Succ,%0));@tel %0=%vn;@pemit/contents %1=%2 [u(Osucc,%0)];@notify %va

@@ Since we need it to run the first time through, notify the Array Object.

@notify Dynamic Array Object

@@ And on each startup. Also attempt to purge rooms.

@Startup Dynamic Array Object=@drain me;@notify me;@wait 1200={@dolist lattr(%!/NUM-*)={@trigger v(##)/Aleave}}

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Generic Attributes
@@ ~~~~~~~~~~~~~~~~~~

@@ These functions are used to grab names, descs, etc from the Array
@@ Object. If nothing is present, they default to something silly.

@@ To customize, modify whatever is in the {} inside the [switch()].
@@ %0, %1 and %2 hold the X, Y, and Z coordinates.

@@ A common thing to do is have an auto-name function, or even an
@@ auto-desc, that uses a map or other form of table instead of the
@@ array storage, and allows a more intuitive customization. If many
@@ rooms will have the same desc, however, the use of parents to
@@ provide the descs will lighten the load on the server.

@@ SHAMELESS PLUG: See the Dynamic Space Mapping Module add on!

&GETNAME Dynamic Exit Parent=[setq(1,get(%va/NAME-%0.%1.%2))][switch(%q1,,{Dynamic Room %0 %1 %2},%q1)]

&GETDESC Dynamic Exit Parent=[setq(1,get(%va/DESC-%0.%1.%2))][switch(%q1,,{Default description.},%q1)]

&GETSUCC Dynamic Exit Parent=[setq(1,get(%va/SUCC-%0.%1.%2))][switch(%q1,,{},%q1)]

&GETPARENT Dynamic Exit Parent=[setq(1,get(%va/PARENT-%0.%1.%2))][switch(%q1,,v(ROOM_PARENT),%q1)]

&GETDARKEXITS Dynamic Exit Parent=[setq(1,get(%va/DARK_EXITS-%0.%1.%2))][switch(%q1,,{},%q1)]

&GETBLOCKEDEXITS Dynamic Exit Parent=[setq(1,get(%va/BLOCKED_EXITS-%0.%1.%2))][switch(%q1,,{},%q1)]

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ Cleanup
@@ ~~~~~~~
@@ Set these to point to somewhere Safe and Inaccessable. You DON'T
@@ want people screwing with these. Do NOT put the Array Object inside
@@ anything that will do @digging.

@tel Dynamic Room Parent=me
@tel Dynamic Exit Parent=me
@tel Dynamic Array Object=me

@@ If you aren't planning to open an exit from 0,0,0, or fix it manually,
@@ make sure you link or fix SOMEWHERE in the Dynamic Space, or it will
@@ all vanish when you leave it. For safety, you might want to uncomment
@@ the following line:

@aleave here=@@

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@pemit me=Script Complete at [time()]

@@ -----8<----CUT HERE----8<--------8<--------8<--------8<--------8<----

@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@ 2.8
@@ - Changed exit locks to me&!me from #0
@@ - Made dimension-locks easier to add
@@ - Lots of internal reorganizations of comments and config stuff
@@ - Rewrote the whole damn exit-display stuff
@@ - Conversion to TinyMUSH 2.2isms (NOT COMPLETE!)

@@ 2.7p2
@@ - Exit-display patch retrofit from 2.8
@@ 2.7p1
@@ - DE_FILTER buglet (hides all owned local exits) fixed
@@ 2.7
@@ - "Null rooms" added, which allow things like mazes or
@@ impassable terrain (or terrain passable only by certain
@@ types of creatures).
@@ - use of %va, setq() and r() to minimize DB accesses
@@ (although that could doubtless be improved further)
@@ - telto <x> <y> <z> admin command added
@@ - hide/show/block/open exit commands actually error check
@@ their arguments now. Oooooh. Ooooh. :)
@@ - border exits (for areas with limits) automagically hidden,
@@ if desired

@@ 2.6
@@ - Descs added to exits (semi-transparency)
@@ - Patched some silly bugs in the block/hide code
@@ - Rooms now wipe attributes/parent upon recycling

@@ 2.5
@@ - Startup purge of misplaced rooms added
@@ - Converted to MPP format
@@ - Room Parent created HALTED for safety
@@ - Added blocked and darkened exits (doc'd in header)
@@ - Patched DE_FILTER to handle non-dynamic exits properly

@@ 2.4
@@ - Sempahores added - slightly slower but MUCH more secure
@@ - Internal allocation error protection
@@ - Improved/added commenting all over the code
@@ - SUCC/OSUCC/ODROP/FAIL messages redone, pros and cons
@@ - Some internals changed to speed up the code
@@ - Optional Map Module

@@ 2.3
@@ - Problem with room allocation patched. (Afail)
@@ - Room recycling loophole fixed. (Aleave)
@@ - Various typos fixed and some small code bits enhanced.
@@ - A few new comments.

@@ 2.2p1
@@ - Problem with room allocation patched. (Afail)
@@ - Room recycling loophole fixed. (Aleave)
@@ 2.2
@@ - Third dimension (Z) added.
@@ - "Locks" on parent exits can restrict travel.
@@ - Limits can now wrap in X, Y or Z.
@@ - The initial room is set FLOATING.
@@ - Parent exits are linked to something (security).

@@ 2.1
@@ - Limits can now wrap in X or Y.
@@ - The initial room is set FLOATING
@@ - Parent exits are linked to something (security)