commit 963004b

zzo38  ·  2023-06-01 04:39:21 +0000 UTC
parent 6615d46
Add prg/uhsmake.tal (make UHS hint file) and the documentation of it
2 files changed,  +397, -0
+51, -0
 1@@ -0,0 +1,51 @@
 2+Give two command-line arguments, being the input file name and the output
 3+file name. (This program does not operate in GUI mode or interactive mode.)
 4+
 5+Each line of the input file contains a command, indicated by the first
 6+character. The possible commands are:
 7+
 8+#  Comment in the input file; not written to the output. (This is not the
 9+same as a comment block.)
10+
11+.  A line of text. Only allowed inside of a () or <> or [] block; cannot be
12+used at the top level or inside of a {} block.
13+
14+&  Define the title of the hint file. Should occur exactly once.
15+
16+-  A separator line (which should not include any text). Only allowed
17+inside of a {} block or a [] block. In a [] block, it will hide all further
18+text in this block until the user tells to reveal the next part (you can
19+have more than one separator; each one stops output until the user tells to
20+continue further output). In a {} block, just makes a blank line.
21+
22+:  A link to some other block in the file. Follow by the target label name
23+(which is the label name of any block in the file) and then . and the text
24+of the link.
25+
26+There are also blocks. The characters [ ( < { indicate the beginning of a
27+block and ] ) > } indicate the end of a block. The begin block line will
28+also have the label name (which can be blank if there is no label name)
29+and then . and then the text which is the title of that block. The end
30+block line should not have any text.
31+
32+()  Comment: A block of text which is not a hint, but just text. Cannot
33+contain any other blocks, and cannot contain links. (This is not the same
34+as the # command.)
35+
36+<>  Credit: Works like comment blocks.
37+
38+{}  Subject: A menu block. Can include other blocks but not text lines.
39+(Normally used for grouping hints by the section in the game.)
40+
41+[]  Hint: This block can contain text and other blocks. This is used for a
42+game hint and the title is usually a question that will be answered by the
43+text in this block. You can add separator lines so that only one part of
44+the text is revealed at a time.
45+
46+Any line in the input file can optionally be indented by spaces and/or tabs
47+at the beginning of the line; any such indentation is ignored. (You can use
48+this to indent blocks if you wish.)
49+
50+This program will not calculate the checksum of the UHS file; however, the
51+FOSS implementations do not care about the checksum, so it isn't a problem.
52+
+346, -0
  1@@ -0,0 +1,346 @@
  2+\\ UHS make (public domain)
  3+\\ Requires some nonstandard features of uxn38.
  4+
  5+|0000
  6+  @X $1 @Y $1
  7+  $2 \\ padding, used when a block is not given a label name
  8+  @Name $2
  9+  @Line $2
 10+  @LineIn $2
 11+  @Tlength $1
 12+  @Tend $1
 13+|0028 \\ note that this number is on purpose, for purpose of making the key
 14+  @Title
 15+
 16+|0100
 17+  \\ Check arguments
 18+  #17 DEI [? error "usage: 20 "uhsmake.rom 20 "<inputfile> 20 "<outputfile> 0a ]@
 19+  \\ Input file name
 20+  LIT2r :filename DUP2r
 21+  [; #10 DEO2 BRK ]@
 22+  #17 DEI #02 GTH [? #12 DEI STH2rk INC2r STA BRK ]@
 23+  #00 STH2r STA
 24+  DUP2rk LITr a8 DEO2r
 25+  \\ Output file name
 26+  [; #10 DEO2 BRK ]@
 27+  #17 DEI #02 GTH [? #12 DEI STH2rk INC2r STA BRK ]@
 28+  #00 DUPk STH2r STA
 29+  LITr b8 DEO2r
 30+  #10 DEO2
 31+  \\ Write the 88a format heading of the hint file
 32+  ;uhshlen #ba DEO2
 33+  ;uhshead #be DEO2
 34+  \\ Initialize variables
 35+  ;firstname .Name STZ2
 36+
 37+\\ First pass
 38+  #0003 .Line STZ2
 39+  LIT2r :heap DUP2r \\ keep it for later too
 40+  #00 DUPk INC \\ the first entry has 0 to keep track of misnesting
 41+  \\ stack entry: ( line-number* block-entry* type )
 42+  \\ 00=hint/nesthint 01=subject ff=comment/credit
 43+@pass1
 44+  GTH2rk STHr ?overflow
 45+  nxline [:
 46+    ". :p1text
 47+    "- :p1brk
 48+    "( :p1cc
 49+    "< :p1cc
 50+    "{ :p1sub
 51+    "[ :p1hint
 52+    ": :p1link
 53+    ") :p1close
 54+    "} :p1close
 55+    "] :p1close
 56+    "> :p1close
 57+    "# :p1ign
 58+    "& :p1title
 59+  00 ]@
 60+
 61+\\ Second pass
 62+  POP2r
 63+  POP #0000 EQU [? error "Unterminated 20 "block 0a ]@
 64+  #00a7 DEO ( rewind )
 65+  \\ Send first block heading
 66+  ;typ/subject .Line LDZ2 #0001 SUB2 nodehead
 67+  \\ Send title
 68+  ;Tlength LDZ
 69+  DUP [? error "Missing 20 "title 0a ]@
 70+  #ba DEO2 ;Title #be DEO2 crlf
 71+  \\ Make key
 72+  \\  In C codes:  k[i]+="key"[i%3]^(i+40); while(k[i]>127) k[i]-=96;
 73+  LIT2 -Title -Tlength LDZ ADDk .Tend STZ POP
 74+  [@
 75+    LDZk STH LIT2r :key STHk LITr 03 DIVrk MULr SUBr ADDr LDAr STHk EORr ADDr
 76+    STHrk #80 LTH [? DUPr LITr df GTHr INCr LITr 60 MULr SUBr ]@ STHk STZr
 77+    INC DUP
 78+  ]?
 79+  \\ stack entry: ( type )
 80+  \\ 00=subject/comment/credit 01=hint ff=nesthint
 81+  \\ (The appropriate value is already in the stack)
 82+@pass2
 83+  nxline [:
 84+    ". :p2text
 85+    "- :p2brk
 86+    "( :p2com
 87+    "< :p2cred
 88+    "{ :p2sub
 89+    "[ :p2hint
 90+    ": :p2link
 91+    ") :p2close
 92+    "} :p2close
 93+    "] :p2close
 94+    "> :p2close
 95+    "# :p2ign
 96+    "& :p2ign
 97+  00 ]@
 98+
 99+\\ Finished
100+  ;verlen #ba DEO2
101+  ;version #be DEO2
102+  #800f DEO
103+
104+\_@2+fe'&(@2+!) \\ alignment
105+@key "yke
106+
107+@overflow
108+  error "Heap 20 "overflow 0a
109+
110+@error
111+  \\ Line number
112+  LIT2r 19 DEO LIT LIT ;number/em STH2k STA INC2r STA2r
113+  .LineIn LDZ2 number #2019 DEO
114+  \\ Text
115+  [@ STH2rk INC2r LDA DUP #19 DEO #0a EOR ]?
116+  #010f DEO BRK
117+
118+@p1link
119+  need95a
120+  DUP [? add1line STH LITr 01 STH2k STAr STHr ]@
121+  badcontext
122+  rname1 ORA [? error "Name 20 "required 20 "for 20 "link 0a ]@
123+  add2line
124+@p1text
125+  DUP #01 NEQ [? error "Text 20 "line 20 "not 20 "allowed 20 "in 20 "subject 20 "block 0a ]@
126+  add1line
127+@p1ign
128+  skline !pass1
129+@p1title
130+  LITr 00 .Title
131+  [@
132+    #ac DEI
133+    DUP #1f GTH [?
134+      LITr -Tlength STZr
135+      POP2 !pass1
136+    ]@
137+    OVR STZ INC INCr
138+  ]!
139+@p1cc
140+  #ff !p1open
141+@p1sub
142+  #01 !p1open
143+@p1hint
144+  #00
145+@p1open
146+  ,&kind STR
147+  badcontext
148+  DUP [? need95a add1line STH LITr 01 STH2k STAr STHr ]@
149+  .Line LDZ2 DUP2 rname1 INC2 INC2
150+  LDA2k DUP2k EOR2 EQU2 [? error "Duplicate 20 "label 0a ]@
151+  STA2 STH2rk LIT &kind $1
152+  #00 DUPk #02 STZ2 STH2rk STA ( nest flag )
153+  INC2r INC2r INC2r ( skip past the newly added record )
154+  add2line !p1ign
155+@p1close
156+  POP ORAk [? error "Block 20 "ended 20 "without 20 "beginning 0a ]@
157+  \\ Set the number of lines in the block record
158+  INC2 SWP2 LITr -Line LDZ2r STH2 SUB2r STH2 STA2r
159+  !p1ign
160+@p1brk
161+  badcontext
162+  LIT2r :p1ign DUP ?add2line !add1line
163+
164+@p2brk
165+  DUP [? ;typ/blank #0002 nodehead ]@
166+  LIT "- emit crlf
167+@p2ign
168+  skline !pass2
169+@p2com
170+  p2open :typ/comment
171+@p2cred
172+  p2open :typ/credit
173+@p2sub
174+  p2open :typ/subject
175+@p2hint
176+  p2open 0000
177+@p2open
178+  INCk [? LIT "= emit crlf ]@
179+  STH2r LDA2
180+  rname2 POP2 \\ ignore the label name, if any
181+  ORAk [?
182+    \\ Read nest flag of current record
183+    LDArk STHr [? POP INC ;typ/hint ][ INC SUB ;typ/nesthint ]@
184+  ][
185+    #00 ROT ROT
186+  ]@
187+  INC2r STH2rk LDA2 nodehead INC2r INC2r
188+@p2plain
189+  plain !pass2
190+@p2close
191+  POP !p2ign
192+@p2link
193+  INCk [? LIT "= emit crlf ]@
194+  ;typ/link #0003 nodehead
195+  rname2 plain
196+  INC2 INC2 LDA2 ORAk [? error "Undefined 20 "label 0a ]@
197+  number crlf !pass2
198+@p2text
199+  INCk [?
200+    \\ Encryption for "nesthint" block
201+    LIT2 -Tend -Title STHk
202+    [@
203+      #ac DEI DUP #20 LTH ?&n
204+      OVR LDZ STHrk EOR ADD
205+      DUP #20 SUB #60 DIVk MUL NIP SUB
206+      emit
207+      INCr INC EQUk .Tlength LDZ MUL SUB
208+    ]!
209+  ]@
210+  DUP ?&h !p2plain
211+  \\ Encryption for "hint" block
212+  [@ DUP #01 AND #5f MUL ADD #20 ADD #01 SFT emit
213+  &h #ac DEI DUP #1f GTH ]? &z POP crlf !pass2
214+  &n POP2 POPr !&z
215+
216+@add2line ( -- ) add1line ( fall through )
217+@add1line ( -- ) .Line LDZ2k INC2 ROT STZ2 JMP2r
218+
219+[@ emit @plain ( -- ) #ac DEI DUP #1f GTH ]? POP !crlf
220+
221+@badcontext ( type -- type )
222+  INCk STH2r JCN2
223+  error "Not 20 "valid 20 "in 20 "this 20 "context 0a
224+
225+@nxline
226+  ;LineIn LDZ2k INC2 ROT STZ2
227+  [@ POP #ac DEI DUP #00 EQU ?&zero DUP #21 LTH ]?
228+  [@ INC2r INC2r
229+    LDArk STHr [? error "Unrecognized 20 "command 0a ]@
230+    STH2rk INC2r LDA OVR NEQ
231+  ]? &zero POP LDA2r JMP2r
232+
233+@skline ( -- )
234+  #ac DEI DUP #0a NEQ MUL ?skline JMP2r
235+
236+@need95a ( -- )
237+  LIT "5 ;version/0 STA JMP2r
238+
239+@rname1 ( -- nameptr* )
240+  LIT2 ". ac DEI NEQk [? EOR DUP JMP2r ]@
241+  ( dot char // heap* return* )
242+  SWP2r DUP2r LIT2r 0006 ADD2r STH2rk ;&ns STA2
243+  ( dot char // return* heap* stringptr* )
244+  [@
245+    STH2rk INC2r STA #ac DEI
246+    DUP #20 GTH [? error "Invalid 20 "character 20 "in 20 "label 20 "name 0a ]@
247+    NEQk
248+  ]?
249+  EOR STH2rk STA ( null terminator )
250+  ( // return* heap* endstr* )
251+  ;firstname &find
252+  LDA2 ORAk [?
253+    \\ Not found; add a new one
254+    INC2r ROT2r ROT2r
255+    INC2rk INC2r SWP2r STA2rk LDA2r
256+    STH2rk STA2k INC2 INC2 STA2
257+    STH2rk .Name STHk LDZ2 STA2 STZ2r STH2r JMP2r
258+  ]@
259+  LIT2r &ns $2 INC2k INC2 INC2 INC2
260+  ( namerec* str1* // return* heap* endstr* str2* )
261+  [@
262+    INC2k SWP2 LDA LDArk STHr INC2r
263+    ( namerec* str1n* char1 char2 // return* heap* endstr* str2n* )
264+    EQUk [? POP2 POP2 POP2r !&find ]@
265+    POP
266+  ]?
267+  \\ Found
268+  POP2r POP2r POP2 DUP2 STH2rk STA2 INC2r INC2r SWP2r JMP2r
269+
270+@rname2 ( -- nameptr* )
271+  LIT2 ". ac DEI NEQ [? #0000 JMP2r ]@
272+  [@ LIT2 ". ac DEI NEQ ]?
273+  STH2r \\ save return address
274+  STH2rk INC2r INC2r LDA2
275+  ( return* nameptr* // newheap* )
276+  \\ Skip past the name record if it is this address
277+  DUP2 STH2rk NEQ2 [?
278+    LIT2r 0004 ADD2r
279+    [@ LDArk STHr INC2r ]?
280+  ]@
281+  SWP2 JMP2
282+
283+@number ( number* -- )
284+  LITr 00
285+  [@
286+    #000a DIV2k STH2k MUL2 SUB2
287+    STH2 SWP2r STH2r
288+    NIPr LITr 30 ADDr
289+  ORAk ]?
290+  POP2
291+  [@ STHr &em emit STHrk ]?
292+  POPr JMP2r
293+
294+@emit ( char -- ) LIT2r 0001 DUP2r STHrk STZ LITr ba DEO2r LITr be DEO2r JMP2r
295+
296+@nodehead ( type* lines* -- )
297+  number #2001 STZ #01bf DEO
298+  #bb DEO #00 SWP ;nodetypes ADD2 #be DEO2
299+  \\ Fallthrough
300+@crlf ( -- ) #0002 #ba DEO2 [; #be DEO2 JMP2r ]@ 0d0a
301+
302+@nodetypes
303+  "nesthint
304+  "subject
305+  "credit
306+  "comment
307+  "link
308+  "blank
309+
310+@version
311+  \_@
312+  "3 20 "version 0d0a
313+  "9 &0 "1a 0d0a
314+  "Compiled 20 "using 20 "uhsmake 20 "of 20 "uxn. 0d0a
315+  1a 0000 ( checksum )
316+  \_@,- \@verlen
317+
318+\\ Name entry format:
319+\\   next name entry address (16-bits)
320+\\   line number (16-bits)
321+\\   name (null-terminated text)
322+@firstname 0000 0001 ( this one doesn't need text )
323+\\ These following things share the same memory, since @uhshead and
324+\\ @filename are both only used once, so they can be reused to store
325+\\ the heap after initialization.
326+@heap
327+@uhshead \_@ \~not88aonly.uhs \_@,- \@uhshlen
328+@filename
329+
330+\\ Record types (in heap):
331+
332+\\ label/link:
333+\\   address of name entry (16-bits)
334+\\   (if the name entry immediately follows, skip past it)
335+\\ credit/comment/subject/hint/nesthint:
336+\\   nest flag (8-bits; 0=not nest, 1=nest)
337+\\   number of lines (16-bits)
338+
339+@typ
340+  |0008 &nesthint
341+  |0404 &hint
342+  |0807 &subject
343+  |0f06 &credit
344+  |1507 &comment
345+  |1c04 &link
346+  |2005 &blank
347+