gdritter repos potrero / b24996b
Implemented escaped table references, add more stuff Getty Ritter 5 years ago
4 changed file(s) with 285 addition(s) and 33 deletion(s). Collapse all Expand all
4949 12: unknown/mystery
5050
5151 theme
52 1-5: @dungeon/theme/mundane
53 6-9: @dungeon/theme/unusual
54 10-12: @dungeon/theme/extraordinary
52 1-5: @{self/mundane}
53 6-9: @{self/unusual}
54 10-12: @{self/extraordinary}
5555 mundane
5656 1: rot/decay
5757 2: torture/agony
9393 12: holy war
9494
9595 discovery
96 1-3: @dungeon/discovery/dressing
96 1-3: @{self/dressing}
97 4-9: @{self/feature}
98 10-12: @{self/find}
9799 dressing
98100 1: junk/debris
99101 2: tracks/marks
106108 9: broken door/wall
107109 10: breeze/wind/smell
108110 11: lichen/moss/fungus
109 12: @details/oddity
111 12: @{details/oddity}
112 feature
113 1: cave-in/collapse
114 2: pit/shaft/column
115 3: pillars/columns
116 4: locked door/gate
117 5: alcoves/niches
118 6: bridge/stairs/ramp
119 7: fountain/well/pool
120 8: puzzle
121 9: altar/dais/platform
122 10: statue/idol
123 11: magic pool/statue/idol
124 12: connection to another dungeon
125 find
126 1: trinkets
127 2: tools
128 3: weapons/armor
129 4: supplies/trade goods
130 5: coins/gems/jewelry
131 6: poisons/potions
132 7: adventurer/captive
133 8: magic item
134 9: scroll/book
135 10: magic weapon/armor
136 11: artifact
137 12: @{self} and @{self}
138
139 danger
140 1-4: @{self/trap}
141 5-11: @{self/creature}
142 12: @{self/entity}
143 trap
144 1: alarm
145 2: ensnaring/paralyzing
146 3: pit
147 4: crushing
148 5: piercing/puncturing
149 6: chopping/slashing
150 7: confusing (maze, etc.)
151 8: gas (poison, etc.)
152 9: element
153 10: ambush
154 11: magical
155 12: @{self} and @{self}
156 creature:
157 1: waiting in ambush
158 2: fighting/squabbling
159 3: prowling/on patrol
160 4: looking for food
161 5: eating/resting
162 6: guarding
163 7: on the move
164 8: searching/scavenging
165 9: returning to den
166 10: making plans
167 11: sleeping
168 12: dying
169 entity:
170 1: alien interloper
171 2: vermin lord
172 3: criminal mastermind
173 4: warlord
174 5: high priest
175 6: oracle
176 7: wizard/witch/alchemist
177 8: monster lord
178 9: evil spirit/ghost
179 10: undead lord
180 11: demon
181 12: dark god
182
183 creature
184 beast
185 1-7: @{self/earthbound}
186 8-10: @{self/airborne}
187 11-12: @{self/aquatic}
188 earthbound
189 1: termite/tick/louse
190 2: snail/slug/worm
191 3: ant/centipede/scorpion
192 4: snake/lizard
193 5: vole/rat/weasel
194 6: boar/pig
195 7: dog/fox/wolf
196 8: cat/lion/panther
197 9: deer/horse/camel
198 10: ox/rhino
199 11: bear/ape/gorilla
200 12: mammoth/dinosaur
201
202 airborne
203 1: mosquito/firefly
204 2: locust/dragonfly/moth
205 3: bee/wasp
206 4: chicken/duck/goose
207 5: songbird/parrot
208 6: gull/waterbird
209 7: heron/crane/stork
210 8: crow/raven
211 9: hawk/falcon
212 10: eagle/owl
213 11: condor
214 12: pteranodon
215
216 aquatic
217 1: insect
218 2: jelly/anemone
219 3: clam/oyster/snail
220 4: eel/snake
221 5: frog/toad
222 6: fish
223 7: crab/lobster
224 8: turtle
225 9: alligator/crocodile
226 10: dolphin/shark
227 11: squid/octopus
228 12: whale
229
230 humanoid
231 1-7: @{self/common}
232 8-10: @{self/uncommon}
233 11-12: @{self/hybrid}
234
235 common
236 1-3: halfling (small)
237 4-5: goblin/kobold (small)
238 6-7: dwarf/gnome (small)
239 8-9: orc/hobgoblin/gnoll
240 10-11: half-elf/half-orc, etc.
241 12: elf
242
243 uncommon
244 1: fey (tiny)
245 2-3: catfolk/dogfolk
246 4-6: lizardfolk/merfolk
247 7: birdfolk
248 8-10: ogre/troll (large)
249 11-12: cycops/giant (large)
250
251 hybrid
252 1-2: centaur
253 3-5: werewolf/werebear
254 6: were-@{creature/beast}
255 7-10: human and a @{creature/beast}
256 11-12: human and two @{creature/beast}s
257
258 monster
259 1-7: @{self/unusual}
260 8-10: @{self/rare}
261 11-12: @{self/legendary}
262 unusual
263 1-3: plant/fungus
264 4-5: undead human
265 6: undead @{creature/humanoid}
266 7-8: @{creature/beast} + @{creature/beast}
267 9-10: @{creature/beast} with the @{details/ability} ability
268 11-12: @{details/feature} @{creature/beast}
269
270 rare
271 1-3: slime/ooze (amorphous)
272 4-6: creation (construct)
273 7-9: @{creature/beast}, with oddity @{details/oddity}
274 10-12: UNNATURAL ENTITY
275
276 legendary
277 1-3: dragon/colossus (huge)
278 4-6: huge @{creature/monster/unusual}
279 7-9: huge @{creature/monster/rare}
280 10: @{creature/beast}-dragon
281 11: @{creature/monster/unusual}-dragon
282 12: @{creature/monster/rare}-dragon
110283
111284 details
285 ability
286 1: bless/curse
287 2: entagle/trap/snare
288 3: poison/disease
289 4: paralyze/petrify
290 5: mimic/camouflage
291 6: seduce/hypnotize
292 7: dissolve/disintegrate
293 8: @{details/magic type}
294 9: drain life/magic
295 10: immunity to @{details/element}
296 11: read/control minds
297 12: both @{self} and @{self}
298
299 element
300 1: air
301 2: earth
302 3: fire
303 4: water
304 5: light
305 6: dark
306
307 magic type
308 1: divination
309 2: enchantment
310 3: evocation
311 4: illusion
312 5: necromancy
313 6: summoning
314
112315 oddity
113316 1: weird color/smell/sound
114317 2: geometric
121324 9: magnetic/repellant
122325 10: devoid of life
123326 11: unexpectedly alive
124 12: roll twice
327 12: @{self} and @{self}
328
329 feature
330 1: heavily armored
331 2-3: winged/flying
332 4: many-headed
333 5: many-eyed or one-eyed
334 6: many-limbed or many-tailed
335 7: tentacled
336 8: ASPECT
337 9: @{details/element}
338 10: @{details/magic type}
339 11: @{details/oddity}
340 12: @{self} and @{self}
4040 Nothing -> do
4141 putStrLn "farewell"
4242 Exit.exitSuccess
43 Just ":q" -> do
44 putStrLn "farewell"
45 Exit.exitSuccess
46
4347 Just "" -> pure ()
48
4449 Just ":l" -> do
4550 tables <- IO.readIORef tablesRef
4651 Text.putStrLn "Available tables: "
4752 Text.putStrLn (" " <> Text.unwords (Map.keys tables))
4853 Just ":r" ->
4954 IO.writeIORef tablesRef =<< readMap "perilous-wilds.txt"
55
5056 Just choice -> do
5157 tables <- IO.readIORef tablesRef
5258 let names = Text.unwords (Map.keys tables)
5561 Nothing -> do
5662 Text.putStrLn ("table not found: " <> Text.pack (show choice))
5763 Text.putStrLn (" valid tables include: " <> names)
58 Just t -> Types.rollTable tables t
64 Just t -> Types.rollTable tables t >>= (Text.putStrLn . Types.valueMsg)
2525 m = read (Text.unpack (Text.tail y))
2626 in Range n m
2727
28 parseResult :: Text.Text -> Result
29 parseResult t
30 | "@" `Text.isPrefixOf` Text.strip t =
31 ResultRoll (Text.tail (Text.strip t))
32 | otherwise =
33 ResultText (Text.strip t)
28 parseFragments :: Text.Text -> [Fragment]
29 parseFragments t =
30 let (frag, roll) = Text.breakOn "@{" t
31 in case roll of
32 "" -> [FragText frag]
33 _ ->
34 let (name, rest) = Text.breakOn "}" (Text.drop 2 roll)
35 in FragText frag : FragRoll name : parseFragments (Text.tail rest)
3436
3537 parseLines :: [Text.Text] -> [LineType]
3638 parseLines = go
4143 | Text.any (== ':') t =
4244 let (rangeTxt, message) = Text.breakOn ":" t
4345 range = parseRange rangeTxt
44 msg = parseResult (Text.tail message)
45 in TableEntry range msg : go ts
46 msg = parseFragments (Text.tail message)
47 in TableEntry range (Result msg) : go ts
4648 | otherwise =
4749 TableDecl (indentAmount t) (Text.strip t) : go ts
4850
1717 , tableChoices :: [(Range, Result)]
1818 } deriving (Eq, Show)
1919
20 data Result
21 = ResultText Text.Text
22 | ResultRoll Text.Text
20 data Fragment
21 = FragText Text.Text
22 | FragRoll Text.Text
2323 deriving (Eq, Show)
2424
25 computeResult :: Int -> TableMap -> Result -> IO ()
26 computeResult r _ (ResultText msg) = do
27 Text.putStr ("\x1b[36m" <> Text.pack (show r) <> ":\x1b[39m ")
28 Text.putStrLn msg
29 computeResult r ts (ResultRoll name)
30 | Just t <- Map.lookup name ts = do
31 Text.putStr ("\x1b[36m" <> Text.pack (show r))
32 Text.putStrLn (": (roll " <> name <> ")\x1b[39m")
33 rollTable ts t
34 | otherwise = Text.putStrLn ("error: no such table: " <> name)
25 data Result = Result { fromResult :: [Fragment] }
26 deriving (Eq, Show)
27
28 data Value = Value
29 { valueMsg :: Text.Text
30 } deriving (Eq, Show)
31
32 stripValue :: Value -> Value
33 stripValue = Value . Text.strip . valueMsg
34
35 data Context = Context
36 { ctxMap :: TableMap
37 , ctxRoll :: Int
38 , ctxSelf :: Text.Text
39 }
40
41 findTable :: Text.Text -> Context -> Maybe Table
42 findTable name ctx = Map.lookup name (ctxMap ctx)
43
44 computeFragments :: Context -> Fragment -> IO Value
45 computeFragments _ (FragText msg) = pure (Value msg)
46 computeFragments ctx (FragRoll name) =
47 let absolute = case Text.stripPrefix "self" name of
48 Just rest -> ctxSelf ctx <> rest
49 Nothing -> name
50 in case findTable absolute ctx of
51 Just t -> rollTable (ctxMap ctx) t
52 Nothing -> error ("no such table: " ++ show absolute)
53
54 computeResult :: Context -> Result -> IO Value
55 computeResult ctx (Result msgs) = do
56 vs <- mapM (computeFragments ctx) msgs
57 pure (Value (foldMap valueMsg vs))
3558
3659 tableDie :: Table -> Int
3760 tableDie t = maximum [ x | (Range _ x, _) <- tableChoices t ]
3861
39 rollTable :: TableMap -> Table -> IO ()
62 rollTable :: TableMap -> Table -> IO Value
4063 rollTable tables t = do
4164 roll <- Rand.randomRIO (1, tableDie t)
65 let ctx = Context
66 { ctxMap = tables
67 , ctxRoll = roll
68 , ctxSelf = tableName t
69 }
4270 case [ result
4371 | (range, result) <- tableChoices t
4472 , roll >= rFrom range && roll <= rTo range
4573 ] of
46 [choice] -> computeResult roll tables choice
47 _ -> Text.putStrLn $ Text.unwords
74 [choice] -> stripValue <$> computeResult ctx choice
75 _ -> error $ unwords
4876 [ "bad table "
49 , tableName t
77 , Text.unpack (tableName t)
5078 , "(roll of"
51 , Text.pack (show roll)
79 , show roll
5280 , "has no matching result)"
5381 ]