"MISC for PLANETFALL
(c) Copyright 1983 Infocom, Inc. All Rights Reserved."
^L
"old MACROS file"
<SETG C-ENABLED? 0>
<SETG C-ENABLED 1>
<SETG C-DISABLED 0>
<DEFMAC TELL ("ARGS" A)
<FORM PROG ()
!<MAPF ,LIST
<FUNCTION ("AUX" E P O)
<COND (<EMPTY? .A> <MAPSTOP>)
(<SET E <NTH .A 1>>
<SET A <REST .A>>)>
<COND (<TYPE? .E ATOM>
<COND (<OR <=? <SET P <SPNAME .E>>
"CRLF">
<=? .P "CR">>
<MAPRET '<CRLF>>)
(<EMPTY? .A>
<ERROR INDICATOR-AT-END? .E>)
(ELSE
<SET O <NTH .A 1>>
<SET A <REST .A>>
<COND (<OR <=? <SET P <SPNAME .E>>
"DESC">
<=? .P "D">
<=? .P "OBJ">
<=? .P "O">>
<MAPRET <FORM PRINTD .O>>)
(<OR <=? .P "NUM">
<=? .P "N">>
<MAPRET <FORM PRINTN .O>>)
(<OR <=? .P "CHAR">
<=? .P "CHR">
<=? .P "C">>
<MAPRET <FORM PRINTC .O>>)
(ELSE
<MAPRET
<FORM PRINT
<FORM GETP .O .E>>>)>)>)
(<TYPE? .E STRING>
<MAPRET <FORM PRINTI .E>>)
(<TYPE? .E FORM>
<MAPRET <FORM PRINT .E>>)
(ELSE <ERROR UNKNOWN-TYPE .E>)>>>>>
<DEFMAC VERB? ("TUPLE" ATMS "AUX" (O ()) (L ()))
<REPEAT ()
<COND (<EMPTY? .ATMS>
<RETURN!- <COND (<LENGTH? .O 1> <NTH .O 1>)
(ELSE <FORM OR !.O>)>>)>
<REPEAT ()
<COND (<EMPTY? .ATMS> <RETURN!->)>
<SET ATM <NTH .ATMS 1>>
<SET L
(<FORM GVAL <PARSE <STRING "V?" <SPNAME .ATM>>>>
!.L)>
<SET ATMS <REST .ATMS>>
<COND (<==? <LENGTH .L> 3> <RETURN!->)>>
<SET O (<FORM EQUAL? ',PRSA !.L> !.O)>
<SET L ()>>>
<DEFMAC RFATAL ()
'<PROG () <PUSH 2> <RSTACK>>>
<DEFMAC PROB ('BASE?)
<FORM NOT <FORM L? .BASE? '<RANDOM 100>>>>
<ROUTINE PICK-ONE (FROB)
<GET .FROB <RANDOM <GET .FROB 0>>>>
<DEFMAC OPENABLE? ('OBJ)
<FORM OR <FORM FSET? .OBJ ',DOORBIT>
<DEFMAC ABS ('NUM)
<FORM COND (<FORM L? .NUM 0> <FORM - 0 .NUM>)
(T .NUM)>>
^L
"old MAIN or VERMONT file"
Set if the parser successfully parsed a command. (As opposed to a blank line or an error.)
No relation to whether the player has won.
<GLOBAL P-WON <>>
<CONSTANT M-FATAL 2>
<CONSTANT M-HANDLED 1>
<CONSTANT M-NOT-HANDLED <>>
<CONSTANT M-BEG 1>
<CONSTANT M-END 6>
<CONSTANT M-OBJECT <>>
<CONSTANT M-ENTER 2>
<CONSTANT M-LOOK 3>
<CONSTANT M-FLASH 4>
<CONSTANT M-OBJDESC 5>
Set up the world at the start of the game. Start the timers. Print the banner. Set all those useful globals like HERE and WINNER.
<ROUTINE GO ()
<CRLF>
<TELL
"Another routine day of drudgery aboard the Stellar Patrol Ship Feinstein.
This morning's assignment for a certain lowly Ensign Seventh Class: scrubbing
the filthy metal deck at the port end of Level Nine. With your Patrol-issue
self-contained multi-purpose all-weather scrub brush you shine the floor with
a diligence born of the knowledge that at any moment dreaded Ensign First
Class Blather, the bane of your shipboard existence, could appear." CR CR>)>
<AGAIN>>
This timer sets up various random factors (the explosion timer, the combination lock, etc) – but only after the player’s first move.
Why? Almost certainly to get better random numbers. On an eight-bit home computer, the only decent source of randomness is human input. (See the Apple II manual for an example.) On such machines, the RANDOM opcode relies on keyboard timing to ensure that random numbers really are unpredictable.
(In this exhibit, RANDOM uses Javascript’s Math.random() function, so the issue doesn’t arise.)
<ROUTINE I-RANDOM-INTERRUPTS ()
<ROUTINE MAIN-LOOP ("AUX" ICNT OCNT NUM CNT OBJ TBL V PTBL OBJ1 TMP)
<REPEAT ()
<SET CNT 0>
<SET OBJ <>>
<SET PTBL T>
<SET TMP <>>
<REPEAT ()
<COND (<G? <SET CNT <+ .CNT 1>> .ICNT>
<RETURN>)
(T
<SET TMP T>
<RETURN>)>)>>
<COND (<NOT .TMP>
<SET CNT 0>
<REPEAT ()
<COND (<G? <SET CNT <+ .CNT 1>> .OCNT>
<RETURN>)
(T
<RETURN>)>)>>)>
<SET CNT 0>)>
<SET NUM
<COND (<0? .OCNT> .OCNT)
(<G? .OCNT 1>
<COND (<0? .ICNT> <SET OBJ <>>)
(T <SET OBJ <GET ,P-PRSI 1>>)>
.OCNT)
(<G? .ICNT 1>
<SET PTBL <>>
.ICNT)
(T 1)>>
<COND (<AND <NOT .OBJ> <1? .ICNT>> <SET OBJ <GET ,P-PRSI 1>>)>
(<0? .NUM>
(T
<TELL "There isn't anything to ">
<PRINTB <GET .TMP 0>>)
(T
<GETB .TMP 3>>)>
<TELL "!" CR>
<SET V <>>)>)
(T
<SET TMP 0>
<SET ICNT <>>
<REPEAT ()
<COND (<G? <SET CNT <+ .CNT 1>> .NUM>
<COND (<G? .TMP 0>
<TELL "The ">
<COND (<NOT <EQUAL? .TMP .NUM>>
<TELL "other ">)>
<TELL "object">
<COND (<NOT <EQUAL? .TMP 1>>
<TELL "s">)>
<TELL " that you mentioned ">
<COND (<NOT <EQUAL? .TMP 1>>
<TELL "are">)
(T <TELL "is">)>
<TELL "n't here." CR>)
(<NOT .ICNT>
<TELL "There's nothing there." CR>)>
<RETURN>)
(T
<COND (.PTBL <SET OBJ1 <GET ,P-PRSO .CNT>>)
(T <SET OBJ1 <GET ,P-PRSI .CNT>>)>
<SETG PRSO <COND (.PTBL .OBJ1) (T .OBJ)>>
<SETG PRSI <COND (.PTBL .OBJ) (T .OBJ1)>>
<COND (<OR <G? .NUM 1>
0>
,W?ALL>>
<COND (<EQUAL? .OBJ1
<SET TMP
<+ .TMP 1>>
<AGAIN>)
(<AND <VERB? TAKE>
0>
,W?ALL>
<AGAIN>)
<VERB? TAKE>
<NOT <EQUAL?
<LOC .OBJ1>
<AGAIN>)
(T
<COND (<EQUAL? .OBJ1 ,IT>
(T <PRINTD .OBJ1>)>
<TELL ": ">)>)>
<SET ICNT T>
<COND (<==? .V ,M-FATAL> <RETURN>)>)>>)>
<COND (<NOT <==? ,PRSA ,V?AGAIN>>
(<OR <VERB? TELL>
(<AND <VERB? AGAIN>
(T
<SETG MOVES 0>)
(T
Out-of-game actions like SCORE and VERBOSE take no game time. This routine checks which verbs get this treatment.
Interestingly, during the escape pod ride and the shuttle ride, TIMELESS-VERB? is not checked. Even out-of-game verbs advance the clock during those trips.
<ROUTINE TIMELESS-VERB? (VRB)
<COND (<OR <EQUAL? .VRB ,V?BRIEF ,V?SUPER-BRIEF ,V?VERBOSE>
<EQUAL? .VRB ,V?SAVE ,V?RESTORE ,V?SCORE>
<EQUAL? .VRB ,V?SCRIPT ,V?UNSCRIPT ,V?TIME>
<EQUAL? .VRB ,V?QUIT ,V?RESTART ,V?VERSION>
<EQUAL? .VRB ,V?$RANDOM ,V?$RECORD ,V?$UNRECORD>
<EQUAL? .VRB ,V?$COMMAND>>
<RTRUE>)
(T
<RFALSE>)>>
<GLOBAL L-PRSA <>>
<GLOBAL L-PRSO <>>
<GLOBAL L-PRSI <>>
%<COND (<GASSIGNED? PREDGEN>
'<ROUTINE PERFORM (A "OPTIONAL" (O <>) (I <>) "AUX" V OA OO OI)
<COND (<EQUAL? ,IT .I .O>
<TELL "I don't see what you are referring to." CR>
<RFATAL>)>
<COND (<AND ,PRSO <NOT <VERB? WALK>>>
.V)
<TELL "[in case last clause changed PRSx]">)
(<SET V <APPLY <GET ,PREACTIONS .A>>> .V)
(<AND .I <SET V <APPLY <GETP .I ,P?ACTION>>>> .V)
(<AND .O
<NOT <==? .A ,V?WALK>>
.V)
(<SET V <APPLY <GET ,ACTIONS .A>>> .V)>
.V>)
(T
'<PROG ()
<SETG PDEBUG <>>
<ROUTINE PERFORM (A "OPTIONAL" (O <>) (I <>) "AUX" V OA OO OI)
<COND (,PDEBUG
<TELL "** PERFORM: PRSA = ">
<PRINC <NTH ,ACTIONS <+ <* .A 2> 1>>>
<COND (<AND .O <NOT <==? .A ,V?WALK>>>
<TELL " | PRSO = " D .O>)>
<COND (.I <TELL " | PRSI = " D .I>)>)>
<SET OA ,PRSA>
<SET OO ,PRSO>
<SET OI ,PRSI>
<COND (<EQUAL? ,IT .I .O>
;<AND <EQUAL? ,IT .I .O>
<OR <NOT <EQUAL? ,P-IT-LOC ,HERE>>
<EQUAL? <LOC ,P-IT-OBJECT> <>>>>
<TELL "I don't see what you are referring to." CR>
<SETG P-IT-OBJECT <>>
<RFATAL>)>
;<COND (<==? .O ,IT> <SET O ,P-IT-OBJECT>)>
;<COND (<==? .I ,IT> <SET I ,P-IT-OBJECT>)>
<SETG PRSA .A>
<SETG PRSO .O>
<COND (<AND ,PRSO <NOT <VERB? WALK>>>
<SETG P-IT-OBJECT ,PRSO>
<SETG P-IT-LOC ,HERE>)>
<SETG PRSI .I>
<COND (<SET V <D-APPLY "Actor"
<GETP ,WINNER ,P?ACTION>>> .V)
(<SET V <D-APPLY "Room (M-BEG)"
<GETP <LOC ,WINNER> ,P?ACTION>
,M-BEG>> .V)
(<SET V <D-APPLY "Preaction"
<GET ,PREACTIONS .A>>> .V)
(<AND .I <SET V <D-APPLY "PRSI"
<GETP .I ,P?ACTION>>>> .V)
(<AND .O
<NOT <==? .A ,V?WALK>>
<LOC .O>
<SET V <D-APPLY "Container"
<GETP <LOC .O> ,P?CONTFCN>>>>
.V)
(<AND .O
<NOT <==? .A ,V?WALK>>
<SET V <D-APPLY "PRSO"
<GETP .O ,P?ACTION>>>>
.V)
(<SET V <D-APPLY <>
<GET ,ACTIONS .A>>> .V)>
<COND (<NOT <==? .V ,M-FATAL>>
;<COND (<==? <LOC ,WINNER> ,PRSO>
<SETG PRSO <>>)>
<SET V <D-APPLY "Room (M-END)"
<GETP <LOC ,WINNER> ,P?ACTION> ,M-END>>)>
<SETG PRSA .OA>
<SETG PRSO .OO>
<SETG PRSI .OI>
.V>
<DEFINE D-APPLY (STR FCN "OPTIONAL" FOO "AUX" RES)
<COND (<NOT .FCN> <>)
(T
<COND (,PDEBUG
<COND (<NOT .STR>
<TELL CR " Default ->" CR>)
(T <TELL CR " " .STR " -> ">)>)>
<SET RES
<COND (<ASSIGNED? FOO>
<APPLY .FCN .FOO>)
(T <APPLY .FCN>)>>
<COND (<AND ,PDEBUG .STR>
<COND (<==? .RES 2>
<TELL "Fatal" CR>)
(<NOT .RES>
<TELL "Not handled">)
(T <TELL "Handled" CR>)>)>
.RES)>>
>)>
<ROUTINE META-LOC (OBJ)
<REPEAT ()
<COND (<NOT .OBJ> <RFALSE>)
<RETURN .OBJ>)
(ELSE
<SET OBJ <LOC .OBJ>>)>>>
^L
"old CLOCK file"
<CONSTANT C-TABLELEN 240>
The timer table. See the “Timers” tab for a current listing.
<GLOBAL C-TABLE %<COND (<GASSIGNED? PREDGEN>
'<ITABLE NONE 120>)
(T
'<ITABLE NONE 240>)>>
Indicates how much of the timer table is used for daemons.
The difference between daemons and timers is that timers run every turn; daemons run every input, even if no turn passes. But Planetfall does not use daemons.
<GLOBAL C-DEMONS 300>
Indicates how much of the timer table (C-TABLE) is used. This counts down from C-TABLELEN, which is 240.
<GLOBAL C-INTS 240>
The amount of time (in millichrons) taken by the current turn. This can range from 7 up to 150 or more.
However, the variable is set back to 7 at the start of each turn. So the State tab will always show it as 7, regardless of how long the last turn took. Sorry about that.
<GLOBAL C-ELAPSED 7>
<CONSTANT C-ELAPSED-DEFAULT 7>
<CONSTANT C-INTLEN 6>
<CONSTANT C-ENABLED? 0>
<CONSTANT C-TICK 1>
<CONSTANT C-RTN 2>
<ROUTINE QUEUE (RTN TICK "AUX" CINT)
.CINT>
<ROUTINE INT (RTN "OPTIONAL" (DEMON <>) E C INT)
<REPEAT ()
<COND (<==? .C .E>
<RETURN .INT>)
(<EQUAL? <GET .C ,C-RTN> .RTN> <RETURN .C>)>
<ROUTINE CLOCKER ("AUX" C E TICK (FLG <>))
<REPEAT ()
<COND (<==? .C .E> <RETURN .FLG>)
<COND (<0? .TICK>)
(<==? .TICK -1>
<COND (<APPLY <GET .C ,C-RTN>>
<SET FLG T>)>)
(T
<COND (<NOT <G? .TICK 1>>
<COND (<APPLY <GET .C ,C-RTN>>
<SET FLG T>)>)>)>)>
<ROUTINE NULL-F ("OPTIONAL" A1 A2)
<RFALSE>>