3 # Enhance adventure.yaml entries with explicit properties based on Section 3
6 # This script is meant to be gotten right, used once, and then discarded.
7 # We'll leave a copy in the repository history for reference
9 # When in doubt, make the code dumber and the data smarter.
11 # Here's the original format description:
13 # Section 3: Travel table. Each line contains a location number (X), a second
14 # location number (Y), and a list of motion numbers (see section 4).
15 # each motion represents a verb which will go to Y if currently at X.
16 # Y, in turn, is interpreted as follows. Let M=Y/1000, N=Y mod 1000.
17 # If N<=300 it is the location to go to.
18 # If 300<N<=500 N-300 is used in a computed goto to
19 # a section of special code.
20 # If N>500 message N-500 from section 6 is printed,
21 # and he stays wherever he is.
22 # Meanwhile, M specifies the conditions on the motion.
23 # If M=0 it's unconditional.
24 # If 0<M<100 it is done with M% probability.
25 # If M=100 unconditional, but forbidden to dwarves.
26 # If 100<M<=200 he must be carrying object M-100.
27 # If 200<M<=300 must be carrying or in same room as M-200.
28 # If 300<M<=400 game.prop(M % 100) must *not* be 0.
29 # If 400<M<=500 game.prop(M % 100) must *not* be 1.
30 # If 500<M<=600 game.prop(M % 100) must *not* be 2, etc.
31 # If the condition (if any) is not met, then the next different
32 # "destination" value is used (unless it fails to meet *its* conditions,
33 # in which case the next is found, etc.). Typically, the next dest will
34 # be for one of the same verbs, so that its only use is as the alternate
35 # destination for those verbs. For instance:
36 # 15 110022 29 31 34 35 23 43
38 # This says that, from loc 15, any of the verbs 29, 31, etc., will take
39 # him to 22 if he's carrying object 10, and otherwise will go to 14.
42 # This says that, from 11, 49 takes him to 8 unless game.prop(3)=0, in which
43 # case he goes to 9. Verb 50 takes him to 9 regardless of game.prop(3).
45 # In addition, it looks as though the action verb value 1 is a sentinel used
46 # when a table entry would have no motions at all in it.
50 # This is the original travel table from section 3 of adventure.text
53 (1, 3, 3, 12, 19, 43),
54 (1, 4, 5, 13, 14, 46, 30),
84 (7, 8, 5, 16, 46, 63),
85 (7, 595, 60, 14, 30, 19, 3),
91 (8, 303009, 3, 19, 30),
95 (9, 10, 17, 18, 19, 44),
98 (10, 9, 11, 20, 21, 43),
99 (10, 11, 19, 22, 44, 51),
103 (11, 10, 17, 18, 23, 24, 43),
104 (11, 12, 25, 19, 29, 44),
109 (12, 11, 30, 43, 51),
110 (12, 13, 19, 29, 44),
116 (13, 14, 23, 31, 44),
121 (14, 150020, 30, 31, 34),
126 (15, 19, 10, 30, 45),
127 (15, 150022, 29, 31, 34, 35, 23, 43),
134 (17, 412597, 41, 42, 44, 69),
136 (18, 15, 38, 11, 45),
137 (19, 15, 10, 29, 43),
138 (19, 311028, 45, 37),
139 (19, 311029, 46, 36),
159 (27, 412597, 41, 42, 43, 69),
163 (28, 19, 38, 11, 46),
166 (29, 19, 38, 11, 45),
167 (30, 19, 38, 11, 43),
174 (33, 34, 43, 53, 54),
187 (37, 38, 30, 31, 56),
188 (38, 37, 56, 29, 11),
189 (38, 595, 60, 14, 30, 4, 5, 3, 19),
191 (39, 64, 30, 52, 58),
194 (41, 42, 46, 29, 23, 56),
250 (60, 41, 43, 29, 17),
252 (60, 62, 45, 30, 52),
261 (64, 39, 29, 56, 59),
305 (73, 72, 46, 17, 11),
333 (88, 25, 30, 56, 43),
338 (91, 95, 45, 73, 23),
343 (93, 92, 46, 27, 11),
344 (94, 92, 46, 27, 23),
345 (94, 309095, 45, 3, 73),
353 (97, 98, 29, 45, 73),
359 (100, 301, 44, 23, 11),
364 (101, 100, 46, 71, 11),
365 (102, 103, 30, 74, 11),
388 (108, 95556, 43, 45, 46, 47, 48, 49, 50, 29, 30),
396 (111, 40050, 30, 39, 56),
410 (113, 445552, 45, 42, 69),
417 (117, 233660, 41, 42, 69, 47),
431 (122, 233660, 41, 42, 69, 49),
443 (124, 128, 48, 37, 30),
449 (126, 125, 46, 23, 11),
453 (127, 125, 44, 11, 17),
456 (128, 124, 45, 29, 15),
457 (128, 129, 46, 30, 40),
461 (129, 130, 43, 19, 40, 3),
651 (169, 445552, 46, 42, 69),
653 (169, 170, 50, 29, 11),
667 (177, 176, 49, 11, 17),
677 def destdecode(dest):
678 "Decode a destinatio nnumber"
680 return '["goto", %s]' % locnames[dest]
682 return '["special", %s]' % (dest - 300)
684 return '["speak", %s]' % (msgnames[dest - 500])
686 def conddecode(cond):
687 # If M=0 it's unconditional.
688 # If 0<M<100 it is done with M% probability.
689 # If M=100 unconditional, but forbidden to dwarves.
690 # If 100<M<=200 he must be carrying object M-100.
691 # If 200<M<=300 must be carrying or in same room as M-200.
692 # If 300<M<=400 game.prop(M % 100) must *not* be 0.
693 # If 400<M<=500 game.prop(M % 100) must *not* be 1.
694 # If 500<M<=600 game.prop(M % 100) must *not* be 2, etc.
698 return "cond: [pct %d], " % cond
700 return "cond: [carry %s], " % objnames[cond-100]
702 return "cond: [with %s], " % objnames[cond-200]
704 return "cond: [not %s %d], " % (objnames[cond % 100], (cond - 300) // 100)
708 sys.stdout.write(" travel: [\n")
715 if t.index(1) == len(t) - 1:
718 sys.stderr.write("%s (%d): action value 1 in unexpected place\n" %\
719 (locnames[loc], loc))
725 t = [verbs[e] for e in t]
726 sys.stdout.write(" {verbs: %s, %saction: %s},\n" %\
727 (t, conddecode(cond), destdecode(dest)))
728 sys.stdout.write(" ]\n")
730 if __name__ == "__main__":
731 with open("adventure.yaml", "r") as fp:
734 locnames = [el[0] for el in db["locations"]]
735 objnames = [el[0] for el in db["object_descriptions"]]
736 msgnames = [el[0] for el in db["arbitrary_messages"]]
738 for entry in db["vocabulary"]:
739 if entry["type"] == "motion" and entry["value"] not in verbs:
740 verbs[entry["value"]] = entry["word"]
746 if line.startswith("- LOC"):
750 sys.stdout.write(line)