Skip to content

Commit

Permalink
improve bestiary formatting
Browse files Browse the repository at this point in the history
We use `group` in a few places already to create a choice between
`(flatten doc)` and `doc`, where `flatten` squeezes content onto one
line. Yet `flatten` can only handle soft newlines, and we've been using
the v family (`v-concat`, `v-append`/`<$*>`) which adds hard newlines.
This results in layouts that are more vertical than intended with long
monster stat blocks.

Create a v* family which is like the v family but with soft newlines,
and use it anywhere we use `group`.

Also, use the pretty-printer on the testfiles (even though those were
also useful for guaranteeing string case was ignored and now aren't
because they have consistent case).
  • Loading branch information
benknoble committed Oct 26, 2024
1 parent cc2360a commit a46ecaf
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 122 deletions.
20 changes: 16 additions & 4 deletions pp/bestiary.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
name->set)
frosthaven-manager/parsers/monster)

(module pp-extras racket/base
(provide <$*>)
(require pretty-expressive)

;; like the v- family, but with soft newlines
(define (v*-append/bin x y)
(<> x nl y))
(define+provide-family v* v*-append/bin)
(define <$*> v*-append))

(require 'pp-extras)

(define lang-line (text "#lang frosthaven-manager/bestiary"))

(define (pretty-bestiary bestiary #:lang-line? [lang-line? #t])
Expand Down Expand Up @@ -87,16 +99,16 @@
(match-define (monster-stats max-hp move attack bonuses effects immunities) stats)
(<+> lbrack
(group
(<$>
(<$*>
(text (~a level))
(text label)
(group
(<$>
(<$*>
(labelled-value "HP" (aligned max-hp max-hp-width))
(labelled-value "Move" (aligned (or move '-) max-move-width))
(labelled-value "Attack" (aligned attack max-attack-width))))
(group
(<$>
(<$*>
(empty-or bonuses (labelled-value "Bonuses" (pretty-list (map pretty-string bonuses))))
(empty-or effects (labelled-value "Effects" (pretty-list (map pretty-string effects))))
(empty-or immunities (labelled-value "Immunities" (pretty-list (map pretty-string immunities))))))))
Expand Down Expand Up @@ -133,7 +145,7 @@
(<+> lbrack (text label) space value-doc rbrack))

(define (pretty-list docs)
(<+> lbrace (group (v-concat docs)) rbrace))
(<+> lbrace (group (v*-concat docs)) rbrace))

(define (pretty-string x)
(text (~s x)))
Expand Down
98 changes: 45 additions & 53 deletions testfiles/archers.rkt
Original file line number Diff line number Diff line change
@@ -1,58 +1,50 @@
#lang frosthaven-manager/bestiary

begin-ability-deck
"archer"

["double-shot" 25 {"attack +2, range 5" "attack +2, range 3, +1 if same target"}]
["double-shot" 25 {"attack +2, range 5" "attack +2, range 3, +1 if same target"}]
["double-shot" 25 {"attack +2, range 5" "attack +2, range 3, +1 if same target"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["take aim" 80 shuffle {"move +2" "strengthen self"}]
end-ability-deck

begin-monster
"hynox archer"

[0 normal [hp 2] [move 2] [attack 2]]
[1 normal [hp 3] [move 3] [attack 3] [effects {"wound"}]]
[2 normal [hp 4] [move 4] [attack 4] [effects {"wound"}]]
[3 normal [hp 5] [move 5] [attack 5] [effects {"wound" "muddle"}]]
[4 normal [hp 6] [move 6] [attack 6]]
[5 normal [hp 7] [move 7] [attack 7]]
[6 normal [hp 8] [move 8] [attack 8]]
[7 normal [hp 9] [move 9] [attack 9]]

[0 elite [HP 4] [Move 2] [Attack 3] [Bonuses {"shield 1"}] [effects {"wound"}]]
[1 elite [HP 5] [Move 3] [Attack 4] [Bonuses {"shield 1"}] [effects {"wound"}]]
[2 elite [HP 6] [Move 4] [Attack 5] [Bonuses {"shield 1"}] [effects {"wound" "stun"}]]
[3 elite [HP 7] [Move 5] [Attack 6] [Bonuses {"shield 2"}] [effects {"wound" "stun"}]]
[4 elite [HP 8] [Move 6] [Attack 7] [Bonuses {"shield 2"}]]
[5 elite [HP 9] [Move 7] [Attack 8] [Bonuses {"shield 2"}]]
[6 elite [HP 10] [Move 8] [Attack 9] [Bonuses {"shield 3"}]]
[7 elite [HP 11] [Move 9] [Attack 10] [Bonuses {"shield 3"}]]
begin-monster "hynox archer"
[0 normal [HP 2] [Move 2] [Attack 2] ]
[0 elite [HP 4] [Move 2] [Attack 3] [Bonuses {"shield 1"}] [Effects {"wound"}] ]
[1 normal [HP 3] [Move 3] [Attack 3] [Effects {"wound"}] ]
[1 elite [HP 5] [Move 3] [Attack 4] [Bonuses {"shield 1"}] [Effects {"wound"}] ]
[2 normal [HP 4] [Move 4] [Attack 4] [Effects {"wound"}] ]
[2 elite [HP 6] [Move 4] [Attack 5] [Bonuses {"shield 1"}] [Effects {"wound" "stun"}] ]
[3 normal [HP 5] [Move 5] [Attack 5] [Effects {"wound" "muddle"}] ]
[3 elite [HP 7] [Move 5] [Attack 6] [Bonuses {"shield 2"}] [Effects {"wound" "stun"}] ]
[4 normal [HP 6] [Move 6] [Attack 6] ]
[4 elite [HP 8] [Move 6] [Attack 7] [Bonuses {"shield 2"}] ]
[5 normal [HP 7] [Move 7] [Attack 7] ]
[5 elite [HP 9] [Move 7] [Attack 8] [Bonuses {"shield 2"}] ]
[6 normal [HP 8] [Move 8] [Attack 8] ]
[6 elite [HP 10] [Move 8] [Attack 9] [Bonuses {"shield 3"}] ]
[7 normal [HP 9] [Move 9] [Attack 9] ]
[7 elite [HP 11] [Move 9] [Attack 10] [Bonuses {"shield 3"}] ]
end-monster

begin-monster
"wyrmling archer" ("archer")

[0 normal [hp 1] [move 1] [attack 1]]
[1 normal [hp 2] [move 2] [attack 2]]
[2 normal [hp 3] [move 3] [attack 3]]
[3 normal [hp 4] [move 4] [attack 4]]
[4 normal [hp 5] [move 5] [attack 5]]
[5 normal [hp 6] [move 6] [attack 6]]
[6 normal [hp 7] [move 7] [attack 7]]
[7 normal [hp 8] [move 8] [attack 8]]

[0 elite [hp 3] [move 1] [attack 2] [Bonuses {"shield 1"}]]
[1 elite [hp 4] [move 2] [attack 3] [Bonuses {"shield 1"}]]
[2 elite [hp 5] [move 3] [attack 4] [Bonuses {"shield 1"}]]
[3 elite [hp 6] [move 4] [attack 5] [Bonuses {"shield 2"}]]
[4 elite [hp 7] [move 5] [attack 6] [Bonuses {"shield 2"}]]
[5 elite [hp 8] [move 6] [attack 7] [Bonuses {"shield 2"}]]
[6 elite [hp 9] [move 7] [attack 8] [Bonuses {"shield 3"}]]
[7 elite [hp 10] [move 8] [attack 9] [Bonuses {"shield 3"}]]
begin-monster "wyrmling archer"
[0 normal [HP 1] [Move 1] [Attack 1] ]
[0 elite [HP 3] [Move 1] [Attack 2] [Bonuses {"shield 1"}] ]
[1 normal [HP 2] [Move 2] [Attack 2] ]
[1 elite [HP 4] [Move 2] [Attack 3] [Bonuses {"shield 1"}] ]
[2 normal [HP 3] [Move 3] [Attack 3] ]
[2 elite [HP 5] [Move 3] [Attack 4] [Bonuses {"shield 1"}] ]
[3 normal [HP 4] [Move 4] [Attack 4] ]
[3 elite [HP 6] [Move 4] [Attack 5] [Bonuses {"shield 2"}] ]
[4 normal [HP 5] [Move 5] [Attack 5] ]
[4 elite [HP 7] [Move 5] [Attack 6] [Bonuses {"shield 2"}] ]
[5 normal [HP 6] [Move 6] [Attack 6] ]
[5 elite [HP 8] [Move 6] [Attack 7] [Bonuses {"shield 2"}] ]
[6 normal [HP 7] [Move 7] [Attack 7] ]
[6 elite [HP 9] [Move 7] [Attack 8] [Bonuses {"shield 3"}] ]
[7 normal [HP 8] [Move 8] [Attack 8] ]
[7 elite [HP 10] [Move 8] [Attack 9] [Bonuses {"shield 3"}] ]
end-monster

begin-ability-deck "archer"
["double-shot" 25 {"attack +2, range 5" "attack +2, range 3, +1 if same target"}]
["double-shot" 25 {"attack +2, range 5" "attack +2, range 3, +1 if same target"}]
["double-shot" 25 {"attack +2, range 5" "attack +2, range 3, +1 if same target"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["explosive" 60 {"attack -1, range 3, aoe(aoes/ring1.rkt)"}]
["take aim" 80 shuffle {"move +2" "strengthen self"}]
end-ability-deck
59 changes: 27 additions & 32 deletions testfiles/bosses.rkt
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
#lang frosthaven-manager/bestiary

begin-ability-deck
"boss"
begin-monster "giant squid" ("boss")
[0 normal [HP "C * 10"] [Move 3] [Attack "C"] ]
[0 elite [HP "C * 10"] [Move 3] [Attack "C"] ]
[1 normal [HP "C * 12"] [Move 3] [Attack "C + 1"] ]
[1 elite [HP "C * 12"] [Move 3] [Attack "C + 1"] ]
[2 normal [HP "C * 15"] [Move 3] [Attack "C + 1"] ]
[2 elite [HP "C * 15"] [Move 3] [Attack "C + 1"] ]
[3 normal [HP "C * 17"] [Move 3] [Attack "C + 2"] ]
[3 elite [HP "C * 17"] [Move 3] [Attack "C + 2"] ]
[4 normal [HP "C * 22"] [Move 3] [Attack "C + 2"] ]
[4 elite [HP "C * 22"] [Move 3] [Attack "C + 2"] ]
[5 normal [HP "C * 25"] [Move 3] [Attack "C + 3"] ]
[5 elite [HP "C * 25"] [Move 3] [Attack "C + 3"] ]
[6 normal [HP "C * 35"] [Move 3] [Attack "C + 4"] ]
[6 elite [HP "C * 35"] [Move 3] [Attack "C + 4"] ]
[7 normal [HP "C * 35"] [Move 3] [Attack "C + 5"] ]
[7 elite [HP "C * 35"] [Move 3] [Attack "C + 5"] ]
end-monster

["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["Special" 11 shuffle {"move +1" "attack +3"}]
begin-ability-deck "boss"
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["I'm a boss" 45 {"move +1" "attack -1 aoe(aoes/ring1.rkt)"}]
["Special" 11 shuffle {"move +1" "attack +3"}]
end-ability-deck

begin-monster
"giant squid" ("boss")

[0 normal [hp "C * 10"] [move 3] [attack "C"]]
[1 normal [hp "C * 12"] [move 3] [attack "C + 1"]]
[2 normal [hp "C * 15"] [move 3] [attack "C + 1"]]
[3 normal [hp "C * 17"] [move 3] [attack "C + 2"]]
[4 normal [hp "C * 22"] [move 3] [attack "C + 2"]]
[5 normal [hp "C * 25"] [move 3] [attack "C + 3"]]
[6 normal [hp "C * 35"] [move 3] [attack "C + 4"]]
[7 normal [hp "C * 35"] [move 3] [attack "C + 5"]]

[0 elite [hp "C * 10"] [move 3] [attack "C"]]
[1 elite [hp "C * 12"] [move 3] [attack "C + 1"]]
[2 elite [hp "C * 15"] [move 3] [attack "C + 1"]]
[3 elite [hp "C * 17"] [move 3] [attack "C + 2"]]
[4 elite [hp "C * 22"] [move 3] [attack "C + 2"]]
[5 elite [hp "C * 25"] [move 3] [attack "C + 3"]]
[6 elite [hp "C * 35"] [move 3] [attack "C + 4"]]
[7 elite [hp "C * 35"] [move 3] [attack "C + 5"]]
end-monster
60 changes: 27 additions & 33 deletions testfiles/guards.rkt
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
#lang frosthaven-manager/bestiary

begin-monster "hynox guard"
[0 normal [HP 2] [Move 2] [Attack 2] ]
[0 elite [HP 2] [Move 2] [Attack 3] [Bonuses {"shield 1"}] ]
[1 normal [HP 3] [Move 3] [Attack 3] ]
[1 elite [HP 3] [Move 3] [Attack 4] [Bonuses {"shield 1"}] ]
[2 normal [HP 4] [Move 4] [Attack 4] ]
[2 elite [HP 4] [Move 4] [Attack 5] [Bonuses {"shield 1"}] ]
[3 normal [HP 5] [Move 5] [Attack 5] ]
[3 elite [HP 5] [Move 5] [Attack 6] [Bonuses {"shield 2"}] ]
[4 normal [HP 6] [Move 6] [Attack 6] ]
[4 elite [HP 6] [Move 6] [Attack 7] [Bonuses {"shield 2"}] ]
[5 normal [HP 7] [Move 7] [Attack 7] ]
[5 elite [HP 7] [Move 7] [Attack 8] [Bonuses {"shield 2"}] ]
[6 normal [HP 8] [Move 8] [Attack 8] ]
[6 elite [HP 8] [Move 8] [Attack 9] [Bonuses {"shield 3"}] ]
[7 normal [HP 9] [Move 9] [Attack 9] ]
[7 elite [HP 9] [Move 9] [Attack 10] [Bonuses {"shield 3"}] ]
end-monster

begin-ability-deck
"guard"

["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["stand tall" 80 shuffle {"shield 3"}]
begin-ability-deck "guard"
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["rushing charge" 25 {"move +3" "attack +2 + number of spaces moved towards target"}]
["stand tall" 80 shuffle {"shield 3"}]
end-ability-deck

begin-monster
"hynox guard"

[0 normal [hp 2] [move 2] [attack 2]]
[1 normal [hp 3] [move 3] [attack 3]]
[2 normal [hp 4] [move 4] [attack 4]]
[3 normal [hp 5] [move 5] [attack 5]]
[4 normal [hp 6] [move 6] [attack 6]]
[5 normal [hp 7] [move 7] [attack 7]]
[6 normal [hp 8] [move 8] [attack 8]]
[7 normal [hp 9] [move 9] [attack 9]]

[0 elite [hp 2] [move 2] [attack 3] [Bonuses {"shield 1"}]]
[1 elite [hp 3] [move 3] [attack 4] [Bonuses {"shield 1"}]]
[2 elite [hp 4] [move 4] [attack 5] [Bonuses {"shield 1"}]]
[3 elite [hp 5] [move 5] [attack 6] [Bonuses {"shield 2"}]]
[4 elite [hp 6] [move 6] [attack 7] [Bonuses {"shield 2"}]]
[5 elite [hp 7] [move 7] [attack 8] [Bonuses {"shield 2"}]]
[6 elite [hp 8] [move 8] [attack 9] [Bonuses {"shield 3"}]]
[7 elite [hp 9] [move 9] [attack 10] [Bonuses {"shield 3"}]]
end-monster

0 comments on commit a46ecaf

Please sign in to comment.