@prog subway.muf 1 99999 d 1 i var start-station var next-station var station var car var car-exit : min-here-time 10 ; : min-travel-time 15 ; : min-interval 15 ; : say me @ swap notify ; : max over over < if swap then pop ; : into# intostr "#" swap strcat ; : hms-str dup 3600 / dup if intostr "h" strcat else pop "" then swap 3600 % dup 60 / dup if intostr "m" strcat rot swap strcat swap else pop then 60 % dup if intostr "s" strcat strcat else pop then dup not if pop "0s" then ; : timestr dup intostr swap hms-str " (" swap ")" strcat strcat strcat ; : firstpart dup ";" instr dup 1 >= if 1 - strcut pop else pop then ; : sharpmatch dup 1 strcut swap "#" strcmp not if atoi dbref swap pop else pop match then ; : strprefixcmp (str pref -- i) swap over strlen strcut pop swap strcmp ; : dbref-name dup name swap int intostr " (#" swap ")" strcat strcat strcat ; : dbref-name-pref dup name swap int intostr "(#" swap ") " strcat strcat swap strcat ; : set-or-remove (obj prop val -- ) dup if 0 addprop else pop remove_prop then ; : copyprop (from to prop -- ) rot over getpropstr set-or-remove ; : space-token (str -- rest token 1 / str -- 0) do dup not if pop 0 exit then dup " " instr dup not if pop "" swap 1 exit then 1 - strcut 1 strcut swap pop swap dup if 1 exit then loop ; : space-explode (str -- strN ... str1 N) ( Like " " explode save that strings of spaces don't produce null strings. ) " " explode ( sN ... s1 N ) dup 1 -1 for ( sN ... s1 N i ) dup 2 + pick ( sN ... s1 N i si ) not if ( sN ... s1 N i ) swap 1 - swap ( sN ... s1 N-1 i ) 1 + rotate ( sN ... s1 N-1 si ) then ( sN ... s1 new-N junk ) pop loop ; : setprops (obj src prefix -- ) 1 begin (obj src prefix n) over over intostr strcat (obj src prefix n propname) 4 pick swap getpropstr (obj src prefix n propval) dup while (obj src prefix n propval) dup ":" instr (obj src prefix n propval colon-loc) dup 1 >= if (obj src prefix n propval colon-loc) 1 - strcut 1 strcut swap pop (obj src prefix n name val) 6 pick rot rot set-or-remove else pop pop then 1 + loop (obj src prefix n propval) pop pop pop pop pop ; : setprops-sub (obj src prefix sub1a sub1b ... subNa subNb N -- ) 2 * 1 begin (obj src prefix sub1a sub1b ... subNa subNb N n) over 3 + pick over intostr strcat (obj src prefix N n propname) 3 pick 5 + pick swap getpropstr (obj src prefix N n propval) dup while (obj src prefix N n propval) dup ":" instr (obj src prefix N n propval colon-loc) dup 1 >= if (obj src prefix N n propval colon-loc) 1 - strcut 1 strcut swap pop (obj src prefix N n name val-raw) 2 5 pick 2 for (obj src prefix N n name val-raw i) 4 + dup 1 + pick swap pick subst loop (obj src prefix N n name val-substed) 4 pick 7 + pick rot rot set-or-remove else pop pop then 1 + loop (obj src prefix N n propval) pop pop 1 swap 1 for pop pop loop pop pop pop ; : follow-next "_subway-next" getpropstr dup "" strcmp if atoi dbref else pop #-1 then ; : find-previous (r -- r) start-station @ begin dup while dup follow-next dup 4 pick dbcmp if pop swap pop exit then swap pop loop pop pop #-1 ; : die dup "" strcmp if "Subway error: " swap strcat say then 99 pstack daemon kill ; : force-car-empty (car place --) prog "_force-car-empty" getpropstr atoi dbref call ; : eject-die ( The force-car-empty and disaster-room properties had better be right! ) car @ prog "_disaster-room" getpropstr atoi dbref force-car-empty car @ recycle die ; : is-subway? (room -- i) dup ok? not if pop 0 exit then dup room? not if pop 0 exit then "_subway-isa" getpropstr "" strcmp ; : in-this-line? start-station @ begin dup while dup 3 pick dbcmp if pop pop 1 exit then dup is-subway? if follow-next else pop #-1 then loop pop pop 0 ; : clear-subway-properties (room -- ) dup "_subway-isa" remove_prop dup "_subway-train-name" remove_prop dup "_subway-train-parent" remove_prop dup "_subway-train-desc" remove_prop 1 begin (room n) dup intostr "_subway-train-prop-" swap strcat (room n propname) dup 4 pick swap getpropstr (room n propname propval) while (room n propname) 3 pick swap remove_prop 1 + loop pop pop dup "_subway-start" remove_prop dup "_subway-interval" remove_prop dup "_subway-stop" remove_prop dup "_subway-head" remove_prop dup "_subway-name" remove_prop dup "_subway-busy" remove_prop dup "_subway-station" remove_prop dup "_subway-here-time" remove_prop dup "_subway-end" remove_prop dup "_subway-next" remove_prop dup "_subway-travel-time" remove_prop dup "_subway-other" remove_prop dup "_subway-daemon" remove_prop pop ; : end-of-line-say car @ #-1 "The PA system says, \"End of the line!\"" notify_except ; : end-of-line car @ contents if station @ #-1 "Subway staff remove everything and everyone from the train." notify_except then car @ contents begin dup while dup player? if dup "Subway staff politely but firmly eject you from the train." notify then next loop pop car @ station @ force-car-empty station @ #-1 "The train's doors close and it leaves." notify_except station @ "_subway-busy" remove_prop "" eject-die ; : subway-line-ok? ( -- i) start-station @ dup is-subway? not if int into# " is not a subway room!" strcat say 0 exit then dup "_subway-start" getpropstr "" strcmp not if int into# " is not the start of a line!" strcat say 0 exit then dup "_subway-interval" getpropstr atoi 10 < if int into# "'s interval is bad!" strcat say 0 exit then do dup "_subway-head" getpropstr atoi dbref start-station @ dbcmp not if int into# " has a bad head pointer" strcat say 0 exit then dup "_subway-next" getpropstr over "_subway-end" getpropstr "" strcmp if "" strcmp if int into# " has both end and next set!" strcat say 0 exit else pop 1 exit then then dup "" strcmp not if pop int into# " has neither next nor end set!" strcat say 0 exit then dup atoi dbref dup is-subway? not if pop swap int into# "'s next pointer, \"" strcat swap strcat "\", doesn't point to a subway room!" strcat say 0 exit then swap pop swap pop loop ; : subway-daemon (room -- dbref) (#-1 if no daemon) (room) dup ok? not if pop #-1 exit then dup "_subway-daemon" getpropstr dup "" strcmp if (room propstr) atoi dbref dup daemon? if (room daemon) dup "_subway-for" getpropstr dup "" strcmp if (room daemon for-propval) atoi dbref 3 pick dbcmp if swap pop exit else pop pop then else (room daemon for-propval) pop pop pop then else (room daemon) pop pop then else (room propstr) pop pop then #-1 ; : chkdaemon daemon "_subway-for" getpropstr dup if atoi dbref subway-daemon daemon dbcmp then not if daemon kill then ; : clear-line start-station @ do dup "_subway-busy" getpropstr dup "" strcmp if atoi dbref dup ok? if dup "_subway-daemon" getpropstr if car ! dup station ! car @ subway-daemon dup if kill else pop then car @ "_subway-station" station @ int intostr set-or-remove fork not if end-of-line then else pop then else pop then dup "_subway-busy" remove_prop else pop then "_subway-next" getpropstr dup "" strcmp not if pop exit then atoi dbref loop ; : onotify station @ "_subway-other" getpropstr dup "" strcmp if atoi dbref dup is-subway? if #-1 rot notify_except else pop pop then else pop pop then ; : car-doors-open ( we count on there being only one exit from the car ) car @ exits dup unlink dup station @ addlink unlock station @ "train" rmatch dup unlink dup car @ addlink unlock ; : car-doors-closed ( we count on there being only one exit from the car ) car @ exits dup unlink dup car @ addlink dup "Please wait until the train stops at a station." setfail "#0&!#0" lock station @ if ( fortunately rmatch takes exits over objects ) station @ "train" rmatch dup unlink dup station @ addlink dup "There's no train here for you to get on." setfail "#0&!#0" lock then ; : enter-station station @ "_subway-busy" car @ int intostr set-or-remove car @ "_subway-station" station @ int intostr set-or-remove station @ #-1 "A train arrives and its doors open." notify_except car-doors-open car @ #-1 "The train arrives at " station @ "_subway-name" getpropstr strcat " and its doors open." strcat notify_except "A train arrives, going the other way." onotify ; : leave-station station @ "_subway-busy" remove_prop car @ "_subway-station" remove_prop car-doors-closed next-station @ "_subway-busy" car @ int intostr set-or-remove station @ #-1 "The train's doors close and it leaves." notify_except car @ #-1 "The train's doors close and it starts to move." notify_except "The train going the other way leaves." onotify ; : make-exit-aux (prefix exit str -- prefix exit exit prop) over prog 5 pick 4 rotate strcat getpropstr ; : make-exit (name from to prefix -- ) 4 rotate 4 rotate open (to prefix exit) dup 4 rotate addlink (prefix exit) "lock" make-exit-aux dup if lock else pop unlock then "desc" make-exit-aux setdesc "succ" make-exit-aux setsucc "fail" make-exit-aux setfail "osucc" make-exit-aux setosucc "ofail" make-exit-aux setofail "odrop" make-exit-aux setodrop prog rot "prop-" strcat setprops ; : make-exit-aux-sub (sub1 sub2 prefix exit str -- sub1 sub2 prefix exit exit prop) over prog 5 pick 4 rotate strcat getpropstr 6 pick 6 pick subst ; : make-sub-exit (name from to prefix sub1 sub2 -- ) 6 2 roll (sub1 sub2 name from to prefix) 4 rotate 4 rotate open (sub1 sub2 to prefix exit) dup 4 rotate addlink (sub1 sub2 prefix exit) "lock" make-exit-aux dup if lock else pop unlock then "desc" make-exit-aux-sub setdesc "succ" make-exit-aux-sub setsucc "fail" make-exit-aux-sub setfail "osucc" make-exit-aux-sub setosucc "ofail" make-exit-aux-sub setofail "odrop" make-exit-aux-sub setodrop prog rot "prop-" strcat 5 rotate 5 rotate 1 setprops-sub ; : make-car start-station @ "_subway-train-name" getpropstr dup "" strcmp not if "no train room name" die then start-station @ "_subway-train-parent" getpropstr atoi dbref dup ok? not if "no train parent" die then dup room? not if "parent not a room" die then dig pop car ! car @ "_subway-head" start-station @ int intostr set-or-remove car @ start-station @ "_subway-train-desc" getpropstr setdesc car @ start-station @ "_subway-train-prop-" setprops "out;o;exit;leave;off;get off;get out;platform" car @ car @ "_exit-train-" make-exit #-1 station ! car-doors-closed ; : start-train start-station @ "_subway-busy" getpropstr "" strcmp if exit then fork if exit then make-car car @ "_subway-daemon" daemon int intostr set-or-remove daemon "_subway-for" car @ int intostr set-or-remove start-station @ station ! do station @ "_subway-here-time" getpropstr "0" strcmp if enter-station then station @ "_subway-end" getpropstr "" strcmp if end-of-line-say then station @ "_subway-here-time" getpropstr dup "0" strcmp if atoi min-here-time max sleep chkdaemon else pop then station @ "_subway-end" getpropstr "" strcmp if end-of-line then station @ "_subway-next" getpropstr atoi dbref dup is-subway? not if "next pointer not a subway room" eject-die then next-station ! begin next-station @ "_subway-busy" getpropstr "" strcmp while 10 sleep chkdaemon loop station @ "_subway-here-time" getpropstr "0" strcmp if leave-station then station @ "_subway-travel-time" getpropstr atoi min-travel-time max sleep chkdaemon next-station @ station ! loop ; : show-head-verbose " Line head: " over dbref-name strcat say " Train name: " over "_subway-train-name" getpropstr strcat say " Train parent: " over "_subway-train-parent" getpropstr atoi dup dbref dup dup ok? swap room? and if swap pop dbref-name strcat else pop into# strcat then say " Train description: " over "_subway-train-desc" getpropstr strcat say 1 begin (stn n) dup intostr "_subway-train-prop-" swap strcat (stn n propname) 3 pick swap getpropstr dup (stn n propval propval) while (stn n propval) over intostr ": " strcat swap strcat " Train property " swap strcat say 1 + loop pop pop " Train interval: " over "_subway-interval" getpropstr atoi dup min-interval < if pop "not set or too small - " min-interval timestr " used" strcat strcat else timestr then strcat say dup "_subway-stop" getpropstr "" strcmp if " Stop has been requested." say then dup subway-daemon dup if " Line is being run by daemon #" swap int intostr strcat else pop " Line is not running." then say pop ; : show-platform-verbose dup " Station platform: " swap dbref-name strcat say dup is-subway? not if int intostr "*** #" swap strcat " is not a subway room!" strcat say exit then dup "_subway-name" getpropstr dup if " Station name: " swap strcat else pop " No station name set" then say dup "_subway-busy" getpropstr dup if (stn busyprop) atoi dbref dup ok? if (stn busy) dup "_subway-daemon" getpropstr "" strcmp if (stn busy) dup "_subway-station" getpropstr "" strcmp if (stn busy) "" 1 else (stn busy) "the tunnel before " 1 then else (stn busy) pop 0 then else (stn busy) pop 0 then else (stn busyprop) pop 0 then if (car msgfrag) " Car in " swap strcat "the station: " strcat swap dbref-name strcat else " No car in station or tunnel before it" then say dup "_subway-here-time" getpropstr atoi dup min-here-time < if pop "not set or too small - " min-here-time timestr " used" strcat strcat else timestr then " Time in this station: " swap strcat say dup "_subway-other" getpropstr dup if atoi dbref dup is-subway? if dbref-name " Other side of station: " else int into# " Bad other side of station: " then swap strcat else pop " No other side of station defined" then say dup "_subway-end" getpropstr "" strcmp if " End of line" say dup "_subway-next" getpropstr "" strcmp if "*** End marker set but next pointer also set" say then dup "_subway-travel-time" getpropstr "" strcmp if "*** End marker set but travel time also set" say then else dup "_subway-next" getpropstr "" strcmp not if "*** No end marker but no next pointer" say then dup "_subway-travel-time" getpropstr atoi dup min-travel-time < if pop "not set or too small - " min-travel-time timestr " used" strcat strcat else timestr then " Time from this station to the next: " swap strcat say then pop ; : show-head-status dup "_subway-stop" getpropstr "" strcmp if " Stop has been requested." say then dup subway-daemon dup if " Line is being run by daemon #" swap int intostr strcat else pop " Line is not running." then say pop ; : show-line-full start-station @ is-subway? not if pop "#" start-station @ int intostr " is not a subway line!" strcat strcat say exit then start-station @ "_subway-start" getpropstr "" strcmp not if "WARNING: #" start-station @ int intostr " not marked as the head of a line!" strcat strcat say then "Subway line headed by #" start-station @ int intostr strcat ":" strcat say start-station @ show-head-verbose "Stations in subway:" say start-station @ begin dup while dup show-platform-verbose dup is-subway? if follow-next else pop #-1 then loop pop ; : show-line-brief start-station @ is-subway? not if pop "#" start-station @ int intostr " is not a subway line!" strcat strcat say exit then start-station @ "_subway-start" getpropstr "" strcmp not if "WARNING: #" start-station @ int intostr " not marked as the head of a line!" strcat strcat say then start-station @ begin dup while dup dbref-name over is-subway? not if " [NON-SUBWAY ROOM]" strcat then say dup is-subway? if follow-next else pop #-1 then loop pop ; : show-line-status start-station @ is-subway? not if pop "#" start-station @ int intostr " is not a subway line!" strcat strcat say exit then start-station @ "_subway-start" getpropstr "" strcmp not if "WARNING: #" start-station @ int intostr " not marked as the head of a line!" strcat strcat say then start-station @ show-head-status ; : show-line-oneline start-station @ is-subway? not if pop "#" start-station @ int intostr " is not a subway line!" strcat strcat say exit then start-station @ "_subway-start" getpropstr "" strcmp not if "WARNING: #" start-station @ int intostr " not marked as the head of a line!" strcat strcat say then start-station @ begin dup while dup int into# rot " " strcat swap strcat swap dup is-subway? if follow-next else pop #-1 then loop pop say ; : maybesetiprop (ival room propname min-value) dup 5 pick < if (ival room propname min-value) pop rot intostr set-or-remove else (ival room propname min-value) pop remove_prop pop then ; : make-trash (room -- ) pop ; : make-turnstiles (room -- ) pop ; ( prog "_trash-basket-name" getpropstr 1 create dup prog "_trash-basket-desc" getpropstr setdesc dup prog "_thing-lock" getpropstr lock dup prog "_trash-basket-fail" getpropstr setfail dup 3 pick addlink dup 3 pick moveto dup prog "_trash-basket-prop-" setprops pop pop ---- prog "_turnstile-name" getpropstr 1 create dup prog "_turnstile-desc" getpropstr setdesc dup prog "_thing-lock" getpropstr lock dup prog "_turnstile-fail" getpropstr setfail dup 3 pick addlink dup 3 pick moveto dup prog "_turnstile-prop-" setprops pop pop ) : setup-room-aux (prefix name line dir room str -- prefix name line dir room room val) 6 pick swap strcat prog swap getpropstr 5 pick "%S" subst 4 pick "%L" subst 3 pick firstpart "%D" subst over swap ; : setup-room (room prefix name line dir -- ) 5 rotate (prefix name line dir room) "desc" setup-room-aux setdesc prog 6 rotate "prop-" strcat 6 rotate "%S" 7 rotate "%L" 8 rotate firstpart "%D" 3 setprops-sub ; : show-one dup "_subway-start" getpropstr "" strcmp if dup show-head-verbose then show-platform-verbose ; : edit-copyprop 3 pick 3 pick rot copyprop ; : edit-moveprop 3 pick 3 pick 3 pick copyprop 3 pick swap remove_prop ; : edit-moveprops 1 begin (from to prefix n) over over intostr strcat (from to prefix n propname) dup 6 pick swap getpropstr (from to prefix n propname propval) dup while 5 pick 3 pick rot set-or-remove 5 pick swap remove_prop 1 + loop pop pop pop pop ; : reset-head-pointers start-station @ begin dup while dup "_subway-head" start-station @ int intostr set-or-remove follow-next loop pop ; : list-add-dbref (d -- ) 1 begin "_list-" over intostr strcat prog swap getpropstr while 1 + loop "_list-" swap intostr strcat prog swap rot int intostr set-or-remove ; : list-remove-n (n -- ) dup 1 + begin "_list-" over intostr strcat prog swap getpropstr while 1 + loop 1 - ( n last ) over over < ( n last n Add to the line just after " say "prepend Prepend the room to the head of the line" say "del Delete from the line" say "full Show line in full" say "brief Show line briefly" say "head Show info on line in general" say "show Show full info on just " say "set Set various values" say "? Print this list" say "Use `? ' for help on ." say exit then dup "?" strcmp not if "?" say "? " say " By itself, prints the list of commands with brief" say " descriptions. With a command, describes that command." say exit then dup "quit" strcmp not if "quit" say " Quits from the subway line editor." say exit then dup "add" strcmp not if "add " say " Adds the station platform to the line immediately" say " after station platform ." say exit then dup "prepend" strcmp not if "prepend " say " Make the new line head, with the previous line head" say " immediately after it." say exit then dup "del" strcmp not if "del " say " Remove from the line, making appropriate adjustments to" say " the stations before and after it, if any." say exit then dup "full" strcmp not if "full" say " Show the line in full verbose detail." say exit then dup "brief" strcmp not if "brief" say " Show the line briefly, one line of output per station." say exit then dup "head" strcmp not if "head" say " Show info on the line as a whole, independent of any" say " particular station." say exit then dup "show" strcmp not if "show " say " Show full information about a single station. If the station" say " is the line head, information about the line is shown too." say exit then dup "set" strcmp not if "set " say " Set various values. specifies the value; depending" say " on it, the vary." say " What Args" say " -----------------------" say " train-name Name to be used for train-car rooms" say " train-desc Description field for train-car rooms" say " train-prop Property to be put on train-car rooms" say " train-parent Room to be used as parent for train-car rooms" say " interval Time in seconds between starting trains" say " name Platform room, then station name to be used." say " rest Platform room, then time to stay there" say " travel Platform room, then time travel to next platform" say " other Platform room, then `other' platform room" say "For example, \"set name #1234 City Central Station\", to set #1234's name" say "or \"set other #1234 #4321\", to set #1234's other-platform to #4321" say exit then "`" swap strcat "': unrecognized editor command." say ; : do-edit-add pop space-explode 2 = not if "Usage: add " say exit then sharpmatch swap sharpmatch swap dup in-this-line? 3 pick is-subway? not and if "That room is already part of a line." say "Perhaps you have the arguments switched?" say exit then dup is-subway? if "That room is already part of a line." say exit then swap dup in-this-line? not if "That station is not in this line." say exit then swap (after room) dup clear-subway-properties dup "_subway-isa" "yes" set-or-remove "_subway-head" edit-copyprop dup "_subway-name" "" set-or-remove "_subway-end" edit-moveprop "_subway-next" edit-copyprop "_subway-travel-time" edit-moveprop over "_subway-next" 3 pick int intostr set-or-remove ; : do-edit-prepend pop space-explode 1 = not if "Usage: prepend " say exit then sharpmatch dup is-subway? if "That room is already part of a line." say exit then start-station @ swap dup list-add-dbref over list-remove-dbref dup clear-subway-properties dup "_subway-isa" "yes" set-or-remove "_subway-train-name" edit-moveprop "_subway-train-parent" edit-moveprop "_subway-train-desc" edit-moveprop "_subway-train-prop-" edit-moveprops "_subway-start" edit-moveprop "_subway-interval" edit-moveprop dup "_subway-name" "" set-or-remove dup "_subway-next" 4 pick int intostr set-or-remove swap pop dup start-station ! reset-head-pointers ; : do-edit-del pop space-explode 1 = not if "Usage: del " say exit then sharpmatch dup in-this-line? not if "That station is not in this line." say exit then dup start-station @ dbcmp if dup "_subway-end" getpropstr if "That's the only station in the line!" say exit then dup follow-next dup not if 1 else dup is-subway? not then if "INTERNAL ERROR: Not end but bad next pointer" say exit then "_subway-train-name" edit-moveprop "_subway-train-parent" edit-moveprop "_subway-train-desc" edit-moveprop "_subway-train-prop-" edit-moveprops "_subway-start" edit-moveprop "_subway-interval" edit-moveprop dup list-add-dbref over list-remove-dbref start-station ! clear-subway-properties reset-head-pointers else dup find-previous "_subway-next" edit-copyprop "_subway-end" edit-copyprop pop clear-subway-properties then ; : do-edit-full pop space-explode 0 = not if "Usage: full" say exit then show-line-full ; : do-edit-brief pop space-explode 0 = not if "Usage: brief" say exit then show-line-brief ; : do-edit-head pop space-explode 0 = not if "Usage: head" say exit then start-station @ show-head-verbose ; : do-edit-show pop space-explode 1 = not if "Usage: show " say exit then sharpmatch dup is-subway? not if int into# " is not a subway line!" strcat say exit then show-one ; : do-edit-set pop space-token not if "Usage: set " say exit then dup "train-name" strcmp not if pop start-station @ "_subway-train-name" rot set-or-remove exit then dup "train-desc" strcmp not if pop start-station @ "_subway-train-desc" rot set-or-remove exit then dup "train-prop" strcmp not if pop dup ":" instr dup not if pop pop "Missing :" say exit then 1 - strcut 1 strcut swap pop (prop val) dup "" strcmp if (prop val) 1 1 begin while (prop val N) dup intostr "_subway-train-prop-" swap strcat dup start-station @ swap getpropstr (prop val N prop-N val-N) dup if (prop val N prop-N val-N) dup ":" instr dup if (prop val N prop-N val-N :loc) 1 - strcut 1 strcut swap pop (prop val N prop-N vp-N vv-N) 6 pick 3 pick strcmp if pop pop pop 1 else pop pop swap pop start-station @ swap 4 rotate ":" strcat 4 rotate strcat (stn prop-N prop:val) set-or-remove 0 0 then else (prop val N prop-N val-N 0) pop pop pop 1 then else pop (prop val N prop-N) swap pop start-station @ swap 4 rotate ":" strcat 4 rotate strcat (stn prop-N prop:val) set-or-remove 0 0 then (prop val N 1 / 0 0) swap 1 + swap loop else pop (prop) 0 swap 1 1 begin while (ff prop N) dup intostr "_subway-train-prop-" swap strcat dup start-station @ swap getpropstr (ff prop N prop-N val-N) dup if (ff prop N prop-N val-N) dup ":" instr dup if (ff prop N prop-N val-N :loc) 1 - strcut 1 strcut swap pop (ff prop N prop-N vp-N vv-N) 5 pick 3 pick strcmp if pop pop pop 1 else pop pop pop rot pop swap over 1 then else (ff prop N prop-N val-N 0) pop pop pop 1 then else pop (ff prop N prop-N) pop swap pop 1 - (ff N-1) over 0 > if over over < if "_subway-train-prop-" swap intostr strcat swap "_subway-train-prop-" swap intostr strcat swap (prop-ff prop-N-1) dup start-station @ swap getpropstr swap start-station @ swap remove_prop start-station @ rot rot set-or-remove else start-station @ swap "_subway-train-prop-" swap intostr strcat remove_prop then else pop pop then 0 0 then (ff prop val N 1 / 0 0) swap 1 + swap loop then pop exit then dup "train-parent" strcmp not if pop start-station @ "_subway-train-parent" rot sharpmatch int intostr set-or-remove exit then dup "interval" strcmp not if pop start-station @ "_subway-interval" rot atoi min-interval max intostr set-or-remove exit then dup "name" strcmp not if pop space-token not if "Usage: set name " say exit then sharpmatch dup is-subway? not if "That's not a subway room!" say exit then "_subway-name" rot set-or-remove exit then dup "rest" strcmp not if pop space-token not if "Usage: set rest