pf2e-sage-stats 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,104 +4,118 @@ sage! macro set name=flat dice="[{o:m} d20 >= {0} flat {...}]" cat=Misc tier=Ser
4
4
  ```
5
5
  ### Strikes
6
6
  ```
7
- sage! macro set name="melee" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::melee.{s:default}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::melee.{s:default}.desc:} {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`({c:+0} AC) `} {ac} {utils::{t:known}:ac} {{t:none}::{r:ac}:} {c} {{p}::melee.{s:default}.damage:} {...}]" cat=Strikes tier=Server -y
7
+ sage! macro set name="melee" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::melee.{s:default}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::melee.{s:default}.desc:} {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`({c:+0} AC) `} {ac} {utils::{t:known}:ac} {{t:none}::{r:ac}:} {c} {{p}::melee.{s:default}.damage:} {...}]" cat=Strikes tier=Server -y
8
8
  ```
9
9
  ```
10
- sage! macro set name="ranged" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::ranged.{s:default}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::ranged.{s:default}.desc:} {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`({c:+0} AC) `} {ac} {utils::{t:known}:ac} {{t:none}::{r:ac}:} {c} {{p}::ranged.{s:default}.damage:} {...}]" cat=Strikes tier=Server -y
10
+ sage! macro set name="ranged" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::ranged.{s:default}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::ranged.{s:default}.desc:} {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`({c:+0} AC) `} {ac} {utils::{t:known}:ac} {{t:none}::{r:ac}:} {c} {{p}::ranged.{s:default}.damage:} {...}]" cat=Strikes tier=Server -y
11
11
  ```
12
12
  ```
13
- sage! macro set name="spell" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::spells:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) Spell Attack {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`({c:+0} AC) `} {ac} {utils::{t:known}:ac} {{t:none}::{r:ac}:} {c} {...}]" cat=Strikes tier=Server -y
13
+ sage! macro set name="spell" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::spells:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) Spell Attack {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`({c:+0} AC) `} {ac} {utils::{t:known}:ac} {{t:none}::{r:ac}:} {c} {...}]" cat=Strikes tier=Server -y
14
14
  ```
15
15
  ### Saves
16
16
  ```
17
- sage! macro set name="fort" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::fort:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::fort.info:} Fortitude Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
17
+ sage! macro set name="fort" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::fort:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::fort.info:} Fortitude Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
18
18
  ```
19
19
  ```
20
- sage! macro set name="fortitude" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::fort:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::fort.info:} Fortitude Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
20
+ sage! macro set name="fortitude" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::fort:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::fort.info:} Fortitude Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
21
21
  ```
22
22
  ```
23
- sage! macro set name="ref" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::reflex:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::reflex.info:} Reflex Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
23
+ sage! macro set name="ref" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::reflex:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::reflex.info:} Reflex Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
24
24
  ```
25
25
  ```
26
- sage! macro set name="reflex" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::reflex:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::reflex.info:} Reflex Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
26
+ sage! macro set name="reflex" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::reflex:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::reflex.info:} Reflex Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
27
27
  ```
28
28
  ```
29
- sage! macro set name="will" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::will:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::will.info:} Will Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
29
+ sage! macro set name="will" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::will:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::will.info:} Will Save {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Saves tier=Server -y
30
30
  ```
31
31
  ### Initiative
32
32
  ```
33
- sage! macro set name="init" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::{s:Perception}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::initiative.info:} Initiative `({s:Perception}) `{...}]" cat=Initiative tier=Server -y
33
+ sage! macro set name="init" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::{s:Perception}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::initiative.info:} Initiative `({s:Perception}) `{...}]" cat=Initiative tier=Server -y
34
34
  ```
35
35
  ```
36
- sage! macro set name="initiative" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::{s:Perception}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::initiative.info:} Initiative `({s:Perception}) `{...}]" cat=Initiative tier=Server -y
36
+ sage! macro set name="initiative" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::{s:Perception}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::initiative.info:} Initiative `({s:Perception}) `{...}]" cat=Initiative tier=Server -y
37
37
  ```
38
- ### Skills
38
+ ### Skills 1
39
39
  ```
40
- sage! macro set name="acrobatics" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::acrobatics:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::acrobatics.info:} Acrobatics Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
40
+ sage! macro set name="acrobatics" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::acrobatics:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::acrobatics.info:} Acrobatics Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
41
41
  ```
42
42
  ```
43
- sage! macro set name="arcana" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::arcana:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::arcana.info:} Arcana Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
43
+ sage! macro set name="arcana" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::arcana:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::arcana.info:} Arcana Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
44
44
  ```
45
45
  ```
46
- sage! macro set name="athletics" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::athletics:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::athletics.info:} Athletics Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
46
+ sage! macro set name="athletics" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::athletics:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::athletics.info:} Athletics Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
47
47
  ```
48
48
  ```
49
- sage! macro set name="crafting" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::crafting:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::crafting.info:} Crafting Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
49
+ sage! macro set name="crafting" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::crafting:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::crafting.info:} Crafting Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
50
50
  ```
51
51
  ```
52
- sage! macro set name="craft" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::crafting:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::crafting.info:} Crafting Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
52
+ sage! macro set name="craft" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::crafting:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::crafting.info:} Crafting Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
53
53
  ```
54
+ ### Skills 2
54
55
  ```
55
- sage! macro set name="deception" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::deception:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::deception.info:} Deception Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
56
+ sage! macro set name="deception" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::deception:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::deception.info:} Deception Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
56
57
  ```
57
58
  ```
58
- sage! macro set name="diplomacy" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::diplomacy:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::diplomacy.info:} Diplomacy Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
59
+ sage! macro set name="diplomacy" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::diplomacy:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::diplomacy.info:} Diplomacy Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
59
60
  ```
60
61
  ```
61
- sage! macro set name="intimidation" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::intimidation:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::intimidation.info:} Intimidation Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
62
+ sage! macro set name="intimidation" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::intimidation:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::intimidation.info:} Intimidation Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
62
63
  ```
63
64
  ```
64
- sage! macro set name="medicine" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::medicine:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::medicine.info:} Medicine Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
65
+ sage! macro set name="medicine" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::medicine:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::medicine.info:} Medicine Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
65
66
  ```
66
67
  ```
67
- sage! macro set name="nature" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::nature:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::nature.info:} Nature Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
68
+ sage! macro set name="nature" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::nature:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::nature.info:} Nature Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
68
69
  ```
70
+ ### Skills 3
69
71
  ```
70
- sage! macro set name="occultism" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::occultism:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::occultism.info:} Occultism Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
72
+ sage! macro set name="occultism" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::occultism:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::occultism.info:} Occultism Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
71
73
  ```
72
74
  ```
73
- sage! macro set name="performance" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::performance:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::performance.info:} Performance Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
75
+ sage! macro set name="performance" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::performance:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::performance.info:} Performance Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
74
76
  ```
75
77
  ```
76
- sage! macro set name="perfomance" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::performance:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::performance.info:} Performance Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
78
+ sage! macro set name="perfomance" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::performance:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::performance.info:} Performance Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
77
79
  ```
78
80
  ```
79
- sage! macro set name="religion" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::religion:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::religion.info:} Religion Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
81
+ sage! macro set name="religion" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::religion:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::religion.info:} Religion Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
80
82
  ```
81
83
  ```
82
- sage! macro set name="society" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::society:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::society.info:} Society Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
84
+ sage! macro set name="society" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::society:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::society.info:} Society Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
83
85
  ```
86
+ ### Skills 4
84
87
  ```
85
- sage! macro set name="stealth" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::stealth:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::stealth.info:} Stealth Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
88
+ sage! macro set name="stealth" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::stealth:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::stealth.info:} Stealth Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
86
89
  ```
87
90
  ```
88
- sage! macro set name="survival" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::survival:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::survival.info:} Survival Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
91
+ sage! macro set name="survival" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::survival:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::survival.info:} Survival Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
89
92
  ```
90
93
  ```
91
- sage! macro set name="thievery" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::thievery:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::thievery.info:} Thievery Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
94
+ sage! macro set name="thievery" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::thievery:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::thievery.info:} Thievery Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
92
95
  ```
93
96
  ```
94
- sage! macro set name="perception" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::perception:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::perception.info:} Perception Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
97
+ sage! macro set name="perception" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::perception:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::perception.info:} Perception Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
95
98
  ```
96
99
  ```
97
- sage! macro set name="lore" dice="[{{p}::out:m} {flat::{f:none}:} {d:1}d20+{{p}::lore.{0}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::lore.{0}.info:} {{p}::lore.{0}.name:} Lore Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
100
+ sage! macro set name="lore" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::lore.{0}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::lore.{0}.info:} {{p}::lore.{0}.name:} Lore Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
98
101
  ```
102
+ ### Skills 5
99
103
  ```
100
- sage! macro set name="assurance" dice="[{{p}::out:m} {flat::{f:none}:} (10)d20+{0:0}-10 {v} {{p}::name:} Assurance Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
104
+ sage! macro set name="assurance" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} (10)d20+{0:0}-10 {v} {{p}::name:} Assurance Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
101
105
  ```
102
106
  ```
103
- sage! macro set name="skill" dice="[{{p}::out:m} {flat::{f:none}:} d20+{0:0} {v} {{p}::name:} Skill Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
107
+ sage! macro set name="skill" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} d20+{0:0} {v} {{p}::name:} Skill Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
104
108
  ```
105
109
  ```
106
- sage! macro set name="secret" dice="[{{p}::out:m} {flat::{f:none}:} d20+{{p}::{0}:{a:0}} {v} {{p}::name:} Secret {0} Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
110
+ sage! macro set name="secret" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} d20+{{p}::{0}:{a:0}} {v} {{p}::name:} Secret {0} Check {utils::{t:known}:vs} {{t:none}::name:} {utils::{t:known}:`{r:Spell} DC ({c:+0} DC) `} {dc} {utils::{t:known}:dc} {{t:none}::dc.{r:spells}:} {c} {...}]" cat=Skills tier=Server -y
111
+ ```
112
+ ### Legacy
113
+ ```
114
+ sage! macro set name="mstrike" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::melee.{s:default}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::melee.{s:default}.desc:} vs {{0}::name:} `({c:+0} AC) ` ac {{0}::{r:ac}:} {c} {{p}::melee.{s:default}.damage:} {...}]" cat=Strikes tier=Server -y
115
+ ```
116
+ ```
117
+ sage! macro set name="rstrike" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::ranged.{s:default}:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) {{p}::ranged.{s:default}.desc:} vs {{0}::name:} `({c:+0} AC) ` ac {{0}::{r:ac}:} {c} {{p}::ranged.{s:default}.damage:} {...}]" cat=Strikes tier=Server -y
118
+ ```
119
+ ```
120
+ sage! macro set name="sstrike" dice="[{{p}::{o:out}:{o:m}} {x} {flat::{f:none}:{f}} {dice::{d:none}:{d:1}}d20+{{p}::spells:{a:0}} {m} {v} {{p}::name:} (mod `{m:+0}`) Spell Attack vs {{0}::name:} `({c:+0} AC) ` ac {{0}::{r:ac}:} {c} {...}]" cat=Strikes tier=Server -y
107
121
  ```
package/dist/app.js CHANGED
@@ -12,13 +12,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.sortFolder = exports.formatTracker = exports.newtracker = exports.formatHP = exports.formatTable = exports.formatCommand = exports.formatTSV = exports.flatten = exports.parseStatblock = exports.parseTracker = exports.parseJSON = exports.formatJSON = exports.fromatMap = exports.adjustmentMap = exports.prediceateMap = exports.stub = void 0;
15
+ exports.screenPlay = exports.sortFolder = exports.formatTracker = exports.newtracker = exports.formatHP = exports.formatTable = exports.formatCommand = exports.formatTSV = exports.flatten = exports.parseStatblock = exports.parseTracker = exports.parseJSON = exports.formatJSON = exports.fromatMap = exports.diceMap = exports.flatMap = exports.stub = void 0;
16
16
  const zod_1 = __importDefault(require("zod"));
17
17
  const tsv_1 = require("tsv");
18
18
  const lodash_1 = require("lodash");
19
19
  const dedent_js_1 = __importDefault(require("dedent-js"));
20
20
  const abbreviate_1 = __importDefault(require("abbreviate"));
21
21
  const pluralize_1 = __importDefault(require("pluralize"));
22
+ const jsdom_1 = require("jsdom");
22
23
  const promises_1 = require("fs/promises");
23
24
  const schema = zod_1.default.object({
24
25
  name: zod_1.default.string(),
@@ -201,16 +202,8 @@ const charSchema = zod_1.default.object({
201
202
  conditions: zod_1.default.string().default(''),
202
203
  children: zod_1.default.array(childSchema).default([]),
203
204
  });
204
- exports.prediceateMap = Object.assign(Object.assign({}, ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map((v) => ([`${v}`, `d20 >= ${v} flat;`])).reduce((p, [k, v]) => { p[k] = v; return p; }, {}))), { c: 'd20 >= 5 flat;', concealed: 'd20 >= 5 flat;', h: 'd20 >= 11 flat;', hidden: 'd20 >= 11 flat;' });
205
- const adjustmentMap = () => ({
206
- 'incredibly-easy': '`(Incredibly Easy)`',
207
- 'very-easy': '`(Very Easy)`',
208
- 'easy': '`(Easy)`',
209
- 'hard': '`(Hard)`',
210
- 'very-hard': '`(Very Easy)`',
211
- 'incredibly-hard': '`(Incredibly Hard)`',
212
- });
213
- exports.adjustmentMap = adjustmentMap;
205
+ exports.flatMap = Object.assign(Object.assign({}, ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map((v) => ([`${v}`, `d20 >= ${v} flat;`])).reduce((p, [k, v]) => { p[k] = v; return p; }, {}))), { c: 'd20 >= 5 flat;', concealed: 'd20 >= 5 flat;', h: 'd20 >= 11 flat;', hidden: 'd20 >= 11 flat;' });
206
+ exports.diceMap = Object.assign(Object.assign({}, ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map((v) => ([`${v}`, `(${v})`])).reduce((p, [k, v]) => { p[k] = v; return p; }, {}))), { a: '+2', adv: '+2', advantage: '+2', d: '-2', dis: '-2', disadvantage: '-2', f: '+2', for: '+2', fort: '+2', fortune: '+2', m: '-2', mis: '-2', misfortune: '-2' });
214
207
  const fromatMap = (name, map) => {
215
208
  return tsv_1.TSV.stringify([Object.assign({ name }, map)]);
216
209
  };
@@ -283,10 +276,7 @@ const locateStrikes = (statblock, alias) => {
283
276
  .replace(/\+\d/g, '')
284
277
  .replace(/Weapon\s+Striking(\s+\((Greater|Major)\))?/gi, '')
285
278
  .replace(/((Greater|Major)\s+)?Striking/gi, '')
286
- .replace(/\(Agile\)/gi, '')
287
- .replace(/\(Finesse\)/gi, '')
288
- .replace(/\(\+\)/gi, '')
289
- .replace(/\(\)/gi, '')
279
+ .replace(/\(.*\)/gi, '')
290
280
  .replace(/\s+/g, ' ')
291
281
  .trim();
292
282
  const bps = /(?<=[^\w']|^)[BbPpSs](?=[^\w]|$)/g;
@@ -305,6 +295,8 @@ const locateStrikes = (statblock, alias) => {
305
295
  .replace(/Electricity/, 'electricity')
306
296
  .replace(/Sonic/, 'sonic')
307
297
  .replace(/Spirit/, 'spirit')
298
+ .replace(/Acid/, 'acid')
299
+ .replace(/[pP]lus\s(\d+d)/, '+$1')
308
300
  .trim();
309
301
  const twoHand = _traits.match(/(two-hand|two-handed)\s+(d\d+)/);
310
302
  if (twoHand && twoHand[2]) {
@@ -379,17 +371,7 @@ const toRanged = ([key, value]) => [
379
371
  [`ranged.${key}.desc`, value.desc],
380
372
  ...(value.damage ? [[`ranged.${key}.damage`, value.damage]] : []),
381
373
  ];
382
- const recallDCs = (level, secret, bump) => ((value) => [
383
- ['dc.recall.incredibly-easy', secret ? `||${value - 10}||` : `${value - 10}`],
384
- ['dc.recall.very-easy', secret ? `||${value - 5}||` : `${value - 5}`],
385
- ['dc.recall.easy', secret ? `||${value - 2}||` : `${value - 2}`],
386
- ['dc.recall.default', secret ? `||${value}||` : `${value}`],
387
- ['dc.recall', secret ? `||${value}||` : `${value}`],
388
- ['dc.recall.hard', secret ? `||${value + 2}||` : `${value + 2}`],
389
- ['dc.recall.very-hard', secret ? `||${value + 5}||` : `${value + 5}`],
390
- ['dc.recall.incredibly-hard', secret ? `||${value + 10}||` : `${value + 10}`],
391
- ])(dcByLevel[Math.max(Math.min(level + 1, dcByLevel.length - 1), 0)] + bump);
392
- const flatten = (stats, secretDC = false, defaultSkills = false, recallDC = false) => {
374
+ const flatten = (stats, secretDC = false, defaultSkills = false) => {
393
375
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
394
376
  const untrained = stats.untrained;
395
377
  const skills = defaultSkills ? Object.assign({ acrobatics: untrained + stats.attributes.dexterity, arcana: untrained + stats.attributes.intelligence, athletics: untrained + stats.attributes.strength, crafting: untrained + stats.attributes.intelligence, deception: untrained + stats.attributes.charisma, diplomacy: untrained + stats.attributes.charisma, intimidation: untrained + stats.attributes.charisma, medicine: untrained + stats.attributes.wisdom, nature: untrained + stats.attributes.wisdom, occultism: untrained + stats.attributes.intelligence, performance: untrained + stats.attributes.charisma, religion: untrained + stats.attributes.wisdom, society: untrained + stats.attributes.intelligence, stealth: untrained + stats.attributes.dexterity, survival: untrained + stats.attributes.wisdom, thievery: untrained + stats.attributes.dexterity }, stats.skills) : stats.skills;
@@ -469,9 +451,6 @@ const flatten = (stats, secretDC = false, defaultSkills = false, recallDC = fals
469
451
  ...(0, lodash_1.entries)(skills).map(mod2DC(true, ((_m = stats.bump.skills) !== null && _m !== void 0 ? _m : stats.bump.default))),
470
452
  ...(0, lodash_1.entries)(stats.extra).map(mod2DC(true, stats.bump.default)),
471
453
  ] : []),
472
- ...(recallDC ? [
473
- ...recallDCs(stats.level, secretDC, stats.bump.default),
474
- ] : []),
475
454
  ...(stats.perceptionInfo.length > 0 ? [
476
455
  [`perception.info`, `\`(${stats.perceptionInfo.join(', ')})\``]
477
456
  ] : []),
@@ -484,9 +463,9 @@ const flatten = (stats, secretDC = false, defaultSkills = false, recallDC = fals
484
463
  ].reduce((p, [key, value]) => { p[key] = value; return p; }, {});
485
464
  };
486
465
  exports.flatten = flatten;
487
- const formatTSV = (stats, secretDC = false, defaultSkills = false, recallDC = false) => (tsv_1.TSV.stringify([(0, exports.flatten)(stats, secretDC, defaultSkills, recallDC)]));
466
+ const formatTSV = (stats, secretDC = false, defaultSkills = false) => (tsv_1.TSV.stringify([(0, exports.flatten)(stats, secretDC, defaultSkills)]));
488
467
  exports.formatTSV = formatTSV;
489
- const formatCommand = (stats, secretDC = false, defaultSkills = false, recallDC = false) => (Object.entries((0, exports.flatten)(stats, secretDC, defaultSkills, recallDC)).map(([k, v]) => `${k}="${v}"`).join(' '));
468
+ const formatCommand = (stats, secretDC = false, defaultSkills = false) => (Object.entries((0, exports.flatten)(stats, secretDC, defaultSkills)).map(([k, v]) => `${k}="${v}"`).join(' '));
490
469
  exports.formatCommand = formatCommand;
491
470
  const formatTable = (table, season, scenario, _name, gm, players) => {
492
471
  const name = _name.replace(/[\s-_]/g, ' ').replace(/[^a-zA-Z0-9 ]/g, '');
@@ -497,7 +476,7 @@ const formatTable = (table, season, scenario, _name, gm, players) => {
497
476
  @TableBot create "${gameName}" --gm ${gm} --players ${players} --table-name ${tableName} --ooc-table-name ooc-${tableName} --category Game Tables
498
477
  \`\`\`
499
478
  \`\`\`
500
- sage! game create name="${gameName}" gameSystem="pf2e" ic=" #${tableName} " ooc=" #ooc-${tableName} " gms=" ${gm} " players=" @${gameName} " dialogPost="post" diceSecret="gm" diceCrit="timestwo" diceOutput=M gmCharName="Хронист" diceSecret="gm"
479
+ sage! game create name="${gameName}" gameSystem="pf2e" ic=" #${tableName} " ooc=" #ooc-${tableName} " gms=" ${gm} " players=" @${gameName} " dialogPost="post" diceSecret="gm" diceCrit="timestwo" diceOutput=M gmCharName="Хронист"
501
480
  \`\`\`
502
481
  `;
503
482
  };
@@ -550,8 +529,10 @@ const newtracker = (status) => {
550
529
  };
551
530
  exports.newtracker = newtracker;
552
531
  const formatTracker = (tracker) => {
532
+ const aliasSpace = (t) => (t.alias.length > 0 ? 0 : 5);
533
+ const nameLengthWithAlias = (t) => t.name.length - aliasSpace(t);
553
534
  const nameLength = tracker.reduce((p, c) => {
554
- const length = c.children.reduce((pp, cc) => pp > cc.name.length ? pp : cc.name.length, c.name.length);
535
+ const length = c.children.reduce((pp, cc) => pp > nameLengthWithAlias(cc) ? pp : nameLengthWithAlias(cc), nameLengthWithAlias(c));
555
536
  return p > length ? p : length;
556
537
  }, 0);
557
538
  const hpLength = tracker.reduce((p, c) => {
@@ -580,15 +561,15 @@ const formatTracker = (tracker) => {
580
561
  if (tracker[index - 1] && tracker[index - 1].foe !== char.foe) {
581
562
  ls.push('');
582
563
  }
583
- const hp = char.foe ? (`-${char.maxhp - char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)) : (`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}/${char.maxhp}`.padStart(hpLength));
564
+ const hp = !char.foe && char.hp > 0 ? (`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}/${char.maxhp}`.padStart(hpLength)) : char.hp > 0 ? (`-${char.maxhp - char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)) : (`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength));
584
565
  const hpBar = (value, max) => (value <= 0 ? (':crossed:') : value >= max ? (':healthy:') : (hpMap[Math.round((hpMap.length - 1) * value / max)]));
585
- ls.push((`${stateMap[char.state]}**\` ${char.name.padEnd(nameLength)} ▏${char.alias.padEnd(3)} ▏${hp} \`** ${hpBar(char.hp, char.maxhp)} `));
566
+ ls.push((`${stateMap[char.hp > 0 ? char.state : 'cross']}**\` ${char.name.padEnd(nameLength + aliasSpace(char))}${char.alias.length > 0 ? ` ▏${char.alias.padEnd(3)}` : ''} ▏${hp} \`** ${hpBar(char.hp, char.maxhp)} `));
586
567
  if (char.conditions.length > 0) {
587
568
  ls.push(`-# ${char.conditions}`);
588
569
  }
589
570
  for (const child of char.children) {
590
- const hhp = char.foe ? (`-${child.maxhp - child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)) : (`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}/${child.maxhp}`.padStart(hpLength));
591
- ls.push((`:smallnode:**\` ${child.name.padEnd(nameLength)} ▏${child.alias.padEnd(3)} ▏${hhp} \`** ${hpBar(child.hp, child.maxhp)} `));
571
+ const hhp = !char.foe && child.hp > 0 ? (`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}/${child.maxhp}`.padStart(hpLength)) : child.hp > 0 ? (`-${child.maxhp - child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)) : (`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength));
572
+ ls.push((`:smallnode:**\` ${child.name.padEnd(nameLength + aliasSpace(child))}${child.alias.length > 0 ? ` ▏${child.alias.padEnd(3)}` : ''} ▏${hhp} \`** ${hpBar(child.hp, child.maxhp)} `));
592
573
  if (child.conditions.length > 0) {
593
574
  ls.push(`-# ${child.conditions}`);
594
575
  }
@@ -615,3 +596,40 @@ const sortFolder = () => __awaiter(void 0, void 0, void 0, function* () {
615
596
  return transformed;
616
597
  });
617
598
  exports.sortFolder = sortFolder;
599
+ const screenPlay = (htmlContent) => {
600
+ const dom = new jsdom_1.JSDOM(htmlContent);
601
+ const document = dom.window.document;
602
+ const outputLines = [];
603
+ const preambleEntry = document.querySelector('.preamble__entry');
604
+ if (preambleEntry) {
605
+ outputLines.push(`SCENE: ${preambleEntry.textContent}`);
606
+ outputLines.push('');
607
+ }
608
+ // Process all chatlog messages
609
+ const messages = document.querySelectorAll('.chatlog__message');
610
+ messages.forEach(message => {
611
+ var _a, _b, _c, _d;
612
+ const authorElement = message.querySelector('.chatlog__author');
613
+ const contentElement = message.querySelector('.chatlog__content');
614
+ if (!authorElement || !contentElement)
615
+ return;
616
+ const author = (_b = (_a = authorElement.textContent) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
617
+ const content = (_d = (_c = contentElement.textContent) === null || _c === void 0 ? void 0 : _c.trim()) !== null && _d !== void 0 ? _d : '';
618
+ // Skip bot tags in character names
619
+ const characterName = author.replace(/\s*BOT$/, '');
620
+ // Add character line
621
+ outputLines.push(`${characterName.toUpperCase()}`);
622
+ // Add dialogue/content (wrap long lines)
623
+ const lines = content.split('\n').map((c) => (c
624
+ .replace(/(—|--)/g, '-')
625
+ // eslint-disable-next-line no-irregular-whitespace
626
+ .replace(/(​|​)/g, '')
627
+ .trim())).filter((c) => c.length);
628
+ for (const line of lines) {
629
+ outputLines.push(` ${line}`);
630
+ }
631
+ outputLines.push('');
632
+ });
633
+ return outputLines.join('\n');
634
+ };
635
+ exports.screenPlay = screenPlay;
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ const commander_1 = require("commander");
24
24
  const promises_1 = __importDefault(require("fs/promises"));
25
25
  const path_1 = __importDefault(require("path"));
26
26
  const readline_1 = __importDefault(require("readline"));
27
+ const clipboardy_1 = __importDefault(require("clipboardy"));
27
28
  const package_json_1 = __importDefault(require("../package.json"));
28
29
  const app_1 = require("./app");
29
30
  const program = new commander_1.Command(package_json_1.default.name);
@@ -71,6 +72,19 @@ program.command('sort')
71
72
  .action(() => __awaiter(void 0, void 0, void 0, function* () {
72
73
  console.log(yield (0, app_1.sortFolder)());
73
74
  }));
75
+ program.command('convert')
76
+ .description('Convert a discord export file into a txt log')
77
+ .argument('<file>', 'input file')
78
+ .option('-o, --output <file>', 'output file')
79
+ .action((argument, option) => __awaiter(void 0, void 0, void 0, function* () {
80
+ const file = yield promises_1.default.readFile(argument, { encoding: 'utf-8' });
81
+ if (option.output) {
82
+ yield promises_1.default.writeFile(option.output, (0, app_1.screenPlay)(file), { encoding: 'utf-8' });
83
+ }
84
+ else {
85
+ console.log((0, app_1.screenPlay)(file));
86
+ }
87
+ }));
74
88
  program.command('flat')
75
89
  .description('Generte a special flat npc tsv')
76
90
  .option('-n, --name <string>', 'npc name')
@@ -78,23 +92,23 @@ program.command('flat')
78
92
  .action((option) => __awaiter(void 0, void 0, void 0, function* () {
79
93
  var _a, _b;
80
94
  if (option.output) {
81
- yield promises_1.default.writeFile(option.output, (0, app_1.fromatMap)((_a = option.name) !== null && _a !== void 0 ? _a : 'flat', app_1.prediceateMap), { encoding: 'utf-8' });
95
+ yield promises_1.default.writeFile(option.output, (0, app_1.fromatMap)((_a = option.name) !== null && _a !== void 0 ? _a : 'flat', app_1.flatMap), { encoding: 'utf-8' });
82
96
  }
83
97
  else {
84
- console.log((0, app_1.fromatMap)((_b = option.name) !== null && _b !== void 0 ? _b : 'flat', app_1.prediceateMap));
98
+ console.log((0, app_1.fromatMap)((_b = option.name) !== null && _b !== void 0 ? _b : 'flat', app_1.flatMap));
85
99
  }
86
100
  }));
87
- program.command('adjustment')
88
- .description('Generte a special adjustment npc tsv')
101
+ program.command('dice')
102
+ .description('Generte a special dice npc tsv')
89
103
  .option('-n, --name <string>', 'npc name')
90
104
  .option('-o, --output <file>', 'output json')
91
105
  .action((option) => __awaiter(void 0, void 0, void 0, function* () {
92
106
  var _a, _b;
93
107
  if (option.output) {
94
- yield promises_1.default.writeFile(option.output, (0, app_1.fromatMap)((_a = option.name) !== null && _a !== void 0 ? _a : 'adjustment', (0, app_1.adjustmentMap)()), { encoding: 'utf-8' });
108
+ yield promises_1.default.writeFile(option.output, (0, app_1.fromatMap)((_a = option.name) !== null && _a !== void 0 ? _a : 'dice', app_1.diceMap), { encoding: 'utf-8' });
95
109
  }
96
110
  else {
97
- console.log((0, app_1.fromatMap)((_b = option.name) !== null && _b !== void 0 ? _b : 'adjustment', (0, app_1.adjustmentMap)()));
111
+ console.log((0, app_1.fromatMap)((_b = option.name) !== null && _b !== void 0 ? _b : 'dice', app_1.diceMap));
98
112
  }
99
113
  }));
100
114
  program.command('statblock')
@@ -131,26 +145,24 @@ program.command('tsv')
131
145
  .argument('<file>', 'input json')
132
146
  .option('-o, --output <file>', 'output tsv')
133
147
  .option('-s, --secretDC', 'produce secret DCs')
134
- .option('-r, --recallDC', 'produce recall DCs')
135
148
  .option('-d, --defaultSkills', 'produce values for untrained skills')
136
149
  .action((argument, option) => __awaiter(void 0, void 0, void 0, function* () {
137
150
  const file = yield promises_1.default.readFile(argument, { encoding: 'utf-8' });
138
151
  const stats = (0, app_1.parseJSON)(file);
139
152
  const output = option.output ? option.output : path_1.default.join(path_1.default.parse(argument).dir, path_1.default.parse(argument).name + '.tsv');
140
- yield promises_1.default.writeFile(output, (0, app_1.formatTSV)(stats, option.secretDC, option.defaultSkills, option.recallDC), { encoding: 'utf-8' });
153
+ yield promises_1.default.writeFile(output, (0, app_1.formatTSV)(stats, option.secretDC, option.defaultSkills), { encoding: 'utf-8' });
141
154
  }));
142
155
  program.command('command')
143
156
  .description('Generte a creation command file from JSON')
144
157
  .argument('<file>', 'input json')
145
158
  .option('-o, --output <file>', 'output txt')
146
159
  .option('-s, --secretDC', 'produce secret DCs')
147
- .option('-r, --recallDC', 'produce recall DCs')
148
160
  .option('-d, --defaultSkills', 'produce values for untrained skills')
149
161
  .action((argument, option) => __awaiter(void 0, void 0, void 0, function* () {
150
162
  const file = yield promises_1.default.readFile(argument, { encoding: 'utf-8' });
151
163
  const stats = (0, app_1.parseJSON)(file);
152
164
  const output = option.output ? option.output : path_1.default.join(path_1.default.parse(argument).dir, path_1.default.parse(argument).name + '-command.txt');
153
- yield promises_1.default.writeFile(output, (0, app_1.formatCommand)(stats, option.secretDC, option.defaultSkills, option.recallDC), { encoding: 'utf-8' });
165
+ yield promises_1.default.writeFile(output, (0, app_1.formatCommand)(stats, option.secretDC, option.defaultSkills), { encoding: 'utf-8' });
154
166
  }));
155
167
  program.command('newtracker')
156
168
  .argument('<file>', 'input text file')
@@ -191,7 +203,9 @@ program.command('track')
191
203
  }
192
204
  else {
193
205
  console.clear();
194
- console.log((0, app_1.formatTracker)(tracker));
206
+ const track = (0, app_1.formatTracker)(tracker);
207
+ clipboardy_1.default.writeSync(track);
208
+ console.log(track);
195
209
  }
196
210
  });
197
211
  yield invoke(argument);
@@ -216,7 +230,7 @@ program.command('track')
216
230
  }
217
231
  }))(),
218
232
  (() => __awaiter(void 0, void 0, void 0, function* () {
219
- var _a, _b, _c, _d, _e;
233
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
220
234
  const rl = readline_1.default.createInterface({
221
235
  input: process.stdin,
222
236
  output: process.stdout
@@ -267,19 +281,48 @@ program.command('track')
267
281
  }
268
282
  },
269
283
  }, {
270
- regex: /^\s*(\S+)\s+[sS]\s*"(.*)"/,
284
+ regex: /^\s*(\S+)\s+[sS]?\s*=?"([^"]*)"/,
271
285
  map: (match) => {
272
286
  return { command: 'set-conditions', tag: match[1], value: match[2] };
273
287
  },
288
+ }, {
289
+ regex: /^\s*(\S+)\s+[sS]?\s*\+"([^"]*)"/,
290
+ map: (match) => {
291
+ return { command: 'add-conditions', tag: match[1], value: match[2] };
292
+ },
293
+ }, {
294
+ regex: /^\s*(\S+)\s+[sS]?\s*-"([^"]*)"/,
295
+ map: (match) => {
296
+ return { command: 'rem-conditions', tag: match[1], value: match[2] };
297
+ },
298
+ }, {
299
+ regex: /^\s*(\S+)\s+[sS]?\s*\+\+"([^"]*)"/,
300
+ map: (match) => {
301
+ return { command: 'inc-conditions', tag: match[1], value: match[2] };
302
+ },
303
+ }, {
304
+ regex: /^\s*(\S+)\s+[sS]?\s*--"([^"]*)"/,
305
+ map: (match) => {
306
+ return { command: 'dec-conditions', tag: match[1], value: match[2] };
307
+ },
274
308
  }, {
275
309
  regex: /^\s*(\S+)\s+[cC]/,
276
310
  map: (match) => ({ command: 'check', tag: match[1] }),
277
311
  }, {
278
312
  regex: /^\s*(\S+)\s+[aA]/,
279
313
  map: (match) => ({ command: 'arrow', tag: match[1] }),
314
+ }, {
315
+ regex: /^\s*(\S+)\s+[eE]/,
316
+ map: (match) => ({ command: 'empty', tag: match[1] }),
317
+ }, {
318
+ regex: /^\s*(\S+)\s+[xX]/,
319
+ map: (match) => ({ command: 'cross', tag: match[1] }),
280
320
  }, {
281
321
  regex: /^\s*(\S+)\s+[dD]/,
282
322
  map: (match) => ({ command: 'delete', tag: match[1] }),
323
+ }, {
324
+ regex: /^\s*(\S+)\s+[wW]/,
325
+ map: (match) => ({ command: 'wait', tag: match[1] }),
283
326
  }];
284
327
  const actions = [];
285
328
  while (true) {
@@ -321,6 +364,24 @@ program.command('track')
321
364
  }
322
365
  }
323
366
  }
367
+ else if (action.command === 'wait') {
368
+ const sorted = [...tracker].sort((a, b) => (a.init === b.init) ? (b.foe ? 1 : 0) - (a.foe ? 1 : 0) : b.init - a.init);
369
+ const blocks = [[sorted[0]]];
370
+ for (let i = 1; i < sorted.length; ++i) {
371
+ if (sorted[i].foe === blocks[blocks.length - 1][0].foe) {
372
+ blocks[blocks.length - 1].push(sorted[i]);
373
+ }
374
+ else {
375
+ blocks.push([sorted[i]]);
376
+ }
377
+ }
378
+ const blockIndex = blocks.findIndex((b) => b.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
379
+ const block = blocks[blockIndex + 1];
380
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag);
381
+ if (block && item) {
382
+ item.init = ((_b = (_a = block[block.length - 1]) === null || _a === void 0 ? void 0 : _a.init) !== null && _b !== void 0 ? _b : 0) - 1;
383
+ }
384
+ }
324
385
  else if (action.command === 'check') {
325
386
  const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag);
326
387
  if (item) {
@@ -333,6 +394,18 @@ program.command('track')
333
394
  item.state = "arrow";
334
395
  }
335
396
  }
397
+ else if (action.command === 'empty') {
398
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag);
399
+ if (item) {
400
+ item.state = "empty";
401
+ }
402
+ }
403
+ else if (action.command === 'cross') {
404
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag);
405
+ if (item) {
406
+ item.state = "cross";
407
+ }
408
+ }
336
409
  else if (action.command === 'delete') {
337
410
  tracker = tracker.filter((c) => !(c.id === action.tag || c.alias === action.tag || c.name == action.tag)).map((p) => (Object.assign(Object.assign({}, p), { children: p.children.filter((c) => !(c.id === action.tag || c.alias === action.tag || c.name == action.tag)) })));
338
411
  }
@@ -353,13 +426,13 @@ program.command('track')
353
426
  });
354
427
  }
355
428
  else if (action.command === 'set-thp') {
356
- const item = (_a = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _a !== void 0 ? _a : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
429
+ const item = (_c = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _c !== void 0 ? _c : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
357
430
  if (item) {
358
431
  item.temphp = Math.max(0, action.value);
359
432
  }
360
433
  }
361
434
  else if (action.command === 'set-hp') {
362
- const item = (_b = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _b !== void 0 ? _b : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
435
+ const item = (_d = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _d !== void 0 ? _d : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
363
436
  if (item) {
364
437
  item.hp = Math.min(item.maxhp, Math.max(0, action.value));
365
438
  }
@@ -371,19 +444,68 @@ program.command('track')
371
444
  }
372
445
  }
373
446
  else if (action.command === 'set-conditions') {
374
- const item = (_c = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _c !== void 0 ? _c : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
447
+ const item = (_e = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _e !== void 0 ? _e : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
375
448
  if (item) {
376
- item.conditions = action.value;
449
+ item.conditions = action.value.trim();
450
+ }
451
+ }
452
+ else if (action.command === 'add-conditions') {
453
+ const item = (_f = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _f !== void 0 ? _f : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
454
+ if (item) {
455
+ const conditions = [...item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length), action.value.toLowerCase().trim()];
456
+ item.conditions = conditions.join(', ');
457
+ }
458
+ }
459
+ else if (action.command === 'rem-conditions') {
460
+ const item = (_g = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _g !== void 0 ? _g : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
461
+ if (item) {
462
+ const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).filter((c) => !c.includes(action.value.toLowerCase().trim()));
463
+ item.conditions = conditions.join(', ');
464
+ }
465
+ }
466
+ else if (action.command === 'inc-conditions') {
467
+ const item = (_h = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _h !== void 0 ? _h : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
468
+ if (item) {
469
+ const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).map((c) => {
470
+ if (c.includes(action.value.toLowerCase().trim())) {
471
+ const match = c.match(/(.*)\s+(\d+)/);
472
+ if (match && match[1] && match[2]) {
473
+ return `${match[1].trim()} ${parseInt(match[2]) + 1}`;
474
+ }
475
+ }
476
+ return c;
477
+ });
478
+ item.conditions = conditions.join(', ');
479
+ }
480
+ }
481
+ else if (action.command === 'dec-conditions') {
482
+ const item = (_j = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _j !== void 0 ? _j : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
483
+ if (item) {
484
+ const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).map((c) => {
485
+ if (c.includes(action.value.toLowerCase().trim())) {
486
+ const match = c.match(/(.*)\s+(\d+)/);
487
+ if (match && match[1] && match[2]) {
488
+ if (parseInt(match[2]) > 1) {
489
+ return `${match[1].trim()} ${parseInt(match[2]) - 1}`;
490
+ }
491
+ else {
492
+ return match[1].trim();
493
+ }
494
+ }
495
+ }
496
+ return c;
497
+ });
498
+ item.conditions = conditions.join(', ');
377
499
  }
378
500
  }
379
501
  else if (action.command === 'mod-thp') {
380
- const item = (_d = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _d !== void 0 ? _d : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
502
+ const item = (_k = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _k !== void 0 ? _k : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
381
503
  if (item) {
382
504
  item.temphp = Math.max(0, item.temphp + action.value);
383
505
  }
384
506
  }
385
507
  else if (action.command === 'mod-hp') {
386
- const item = (_e = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _e !== void 0 ? _e : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
508
+ const item = (_l = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)) !== null && _l !== void 0 ? _l : (tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag));
387
509
  if (item) {
388
510
  let hp = item.hp;
389
511
  let thp = item.temphp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pf2e-sage-stats",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "An RPG Sage's .tsv stat generation tool",
5
5
  "main": "dist/index.js",
6
6
  "author": "ikariott@gmail.com",
@@ -17,6 +17,7 @@
17
17
  "devDependencies": {
18
18
  "@eslint/js": "^9.17.0",
19
19
  "@types/jest": "^29.5.14",
20
+ "@types/jsdom": "^27.0.0",
20
21
  "@types/lodash": "^4.17.13",
21
22
  "@types/pluralize": "^0.0.33",
22
23
  "@types/tsv": "^0.2.4",
@@ -30,11 +31,14 @@
30
31
  },
31
32
  "dependencies": {
32
33
  "abbreviate": "^0.0.3",
34
+ "clipboardy": "^5.1.0",
33
35
  "commander": "^12.1.0",
34
36
  "dedent-js": "^1.0.1",
37
+ "jsdom": "^28.0.0",
35
38
  "lodash": "^4.17.21",
36
39
  "pluralize": "^8.0.0",
37
40
  "tsv": "^0.2.0",
38
41
  "zod": "^3.24.1"
39
- }
42
+ },
43
+ "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72"
40
44
  }
package/src/app.ts CHANGED
@@ -4,6 +4,7 @@ import { capitalize, entries, startCase, toLower, kebabCase, keys, difference, g
4
4
  import dedent from 'dedent-js';
5
5
  import abbreviate from 'abbreviate';
6
6
  import pluralize from 'pluralize';
7
+ import { JSDOM } from 'jsdom';
7
8
  import { readdir, rename, stat } from 'fs/promises';
8
9
 
9
10
  const schema = zod.object({
@@ -197,7 +198,7 @@ const charSchema = zod.object({
197
198
 
198
199
  export type CharSchema = zod.infer<typeof charSchema>;
199
200
 
200
- export const prediceateMap: Record<string, string> = {
201
+ export const flatMap: Record<string, string> = {
201
202
  ...([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map((v): [string, string] => (
202
203
  [`${v}`, `d20 >= ${v} flat;`]
203
204
  )).reduce<Record<string, string>>((p, [k, v]) => { p[k] = v; return p }, {})),
@@ -207,14 +208,24 @@ export const prediceateMap: Record<string, string> = {
207
208
  hidden: 'd20 >= 11 flat;',
208
209
  };
209
210
 
210
- export const adjustmentMap: () => Record<string, string> = () => ({
211
- 'incredibly-easy': '`(Incredibly Easy)`',
212
- 'very-easy': '`(Very Easy)`',
213
- 'easy': '`(Easy)`',
214
- 'hard': '`(Hard)`',
215
- 'very-hard': '`(Very Easy)`',
216
- 'incredibly-hard': '`(Incredibly Hard)`',
217
- });
211
+ export const diceMap: Record<string, string> = {
212
+ ...([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map((v): [string, string] => (
213
+ [`${v}`, `(${v})`]
214
+ )).reduce<Record<string, string>>((p, [k, v]) => { p[k] = v; return p }, {})),
215
+ a: '+2',
216
+ adv: '+2',
217
+ advantage: '+2',
218
+ d: '-2',
219
+ dis: '-2',
220
+ disadvantage: '-2',
221
+ f: '+2',
222
+ for: '+2',
223
+ fort: '+2',
224
+ fortune: '+2',
225
+ m: '-2',
226
+ mis: '-2',
227
+ misfortune: '-2',
228
+ };
218
229
 
219
230
  export const fromatMap = (name: string, map: Record<string, string>) => {
220
231
  return TSV.stringify([{
@@ -308,10 +319,7 @@ const locateStrikes = (statblock: string, alias: string): Record<string, Schema[
308
319
  .replace(/\+\d/g, '')
309
320
  .replace(/Weapon\s+Striking(\s+\((Greater|Major)\))?/gi, '')
310
321
  .replace(/((Greater|Major)\s+)?Striking/gi, '')
311
- .replace(/\(Agile\)/gi, '')
312
- .replace(/\(Finesse\)/gi, '')
313
- .replace(/\(\+\)/gi, '')
314
- .replace(/\(\)/gi, '')
322
+ .replace(/\(.*\)/gi, '')
315
323
  .replace(/\s+/g, ' ')
316
324
  .trim();
317
325
 
@@ -333,6 +341,8 @@ const locateStrikes = (statblock: string, alias: string): Record<string, Schema[
333
341
  .replace(/Electricity/, 'electricity')
334
342
  .replace(/Sonic/, 'sonic')
335
343
  .replace(/Spirit/, 'spirit')
344
+ .replace(/Acid/, 'acid')
345
+ .replace(/[pP]lus\s(\d+d)/, '+$1')
336
346
  .trim();
337
347
 
338
348
  const twoHand = _traits.match(/(two-hand|two-handed)\s+(d\d+)/);
@@ -484,18 +494,7 @@ const toRanged = ([key, value]: [string, Schema['ranged'][string]]): [string, nu
484
494
  ...(value.damage ? [[`ranged.${key}.damage`, value.damage] as [string, string]] : []),
485
495
  ];
486
496
 
487
- const recallDCs = (level: number, secret: boolean, bump: number): [string, string][] => ((value) => [
488
- ['dc.recall.incredibly-easy', secret ? `||${value - 10}||` : `${value - 10}`],
489
- ['dc.recall.very-easy', secret ? `||${value - 5}||` : `${value - 5}`],
490
- ['dc.recall.easy', secret ? `||${value - 2}||` : `${value - 2}`],
491
- ['dc.recall.default', secret ? `||${value}||` : `${value}`],
492
- ['dc.recall', secret ? `||${value}||` : `${value}`],
493
- ['dc.recall.hard', secret ? `||${value + 2}||` : `${value + 2}`],
494
- ['dc.recall.very-hard', secret ? `||${value + 5}||` : `${value + 5}`],
495
- ['dc.recall.incredibly-hard', secret ? `||${value + 10}||` : `${value + 10}`],
496
- ])(dcByLevel[Math.max(Math.min(level + 1, dcByLevel.length - 1), 0)] + bump);
497
-
498
- export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false, recallDC: boolean = false): Record<string, string | number> => {
497
+ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false): Record<string, string | number> => {
499
498
  const untrained = stats.untrained;
500
499
  const skills = defaultSkills ? {
501
500
  acrobatics: untrained + stats.attributes.dexterity,
@@ -600,9 +599,6 @@ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills:
600
599
  ...entries(skills).map(mod2DC(true, (stats.bump.skills ?? stats.bump.default))),
601
600
  ...entries(stats.extra).map(mod2DC(true, stats.bump.default)),
602
601
  ] : []),
603
- ...(recallDC ? [
604
- ...recallDCs(stats.level, secretDC, stats.bump.default),
605
- ] : []),
606
602
  ...(stats.perceptionInfo.length > 0 ? [
607
603
  [`perception.info`, `\`(${stats.perceptionInfo.join(', ')})\``]
608
604
  ] : []),
@@ -615,12 +611,12 @@ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills:
615
611
  ].reduce<Record<string | number, string | number>>((p, [key, value]) => { p[key] = value; return p }, {});
616
612
  }
617
613
 
618
- export const formatTSV = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false, recallDC: boolean = false): string => (
619
- TSV.stringify([flatten(stats, secretDC, defaultSkills, recallDC)])
614
+ export const formatTSV = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false): string => (
615
+ TSV.stringify([flatten(stats, secretDC, defaultSkills)])
620
616
  );
621
617
 
622
- export const formatCommand = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false, recallDC: boolean = false): string => (
623
- Object.entries(flatten(stats, secretDC, defaultSkills, recallDC)).map(([k, v]) => `${k}="${v}"`).join(' ')
618
+ export const formatCommand = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false): string => (
619
+ Object.entries(flatten(stats, secretDC, defaultSkills)).map(([k, v]) => `${k}="${v}"`).join(' ')
624
620
  );
625
621
 
626
622
  export const formatTable = (table: string, season: string, scenario: string, _name: string, gm: string, players: string) => {
@@ -634,7 +630,7 @@ export const formatTable = (table: string, season: string, scenario: string, _na
634
630
  @TableBot create "${gameName}" --gm ${gm} --players ${players} --table-name ${tableName} --ooc-table-name ooc-${tableName} --category Game Tables
635
631
  \`\`\`
636
632
  \`\`\`
637
- sage! game create name="${gameName}" gameSystem="pf2e" ic=" #${tableName} " ooc=" #ooc-${tableName} " gms=" ${gm} " players=" @${gameName} " dialogPost="post" diceSecret="gm" diceCrit="timestwo" diceOutput=M gmCharName="Хронист" diceSecret="gm"
633
+ sage! game create name="${gameName}" gameSystem="pf2e" ic=" #${tableName} " ooc=" #ooc-${tableName} " gms=" ${gm} " players=" @${gameName} " dialogPost="post" diceSecret="gm" diceCrit="timestwo" diceOutput=M gmCharName="Хронист"
638
634
  \`\`\`
639
635
  `;
640
636
  };
@@ -702,8 +698,11 @@ export const newtracker = (status: string) => {
702
698
  };
703
699
 
704
700
  export const formatTracker = (tracker: CharSchema[]) => {
701
+ const aliasSpace = (t: { alias: string }) => (t.alias.length > 0 ? 0 : 5);
702
+ const nameLengthWithAlias = (t: { name: string, alias: string }) => t.name.length - aliasSpace(t);
703
+
705
704
  const nameLength = tracker.reduce((p, c) => {
706
- const length = c.children.reduce((pp, cc) => pp > cc.name.length ? pp : cc.name.length, c.name.length);
705
+ const length = c.children.reduce((pp, cc) => pp > nameLengthWithAlias(cc) ? pp : nameLengthWithAlias(cc), nameLengthWithAlias(c));
707
706
 
708
707
  return p > length ? p : length;
709
708
  }, 0);
@@ -742,10 +741,12 @@ export const formatTracker = (tracker: CharSchema[]) => {
742
741
  ls.push('')
743
742
  }
744
743
 
745
- const hp = char.foe ? (
744
+ const hp = !char.foe && char.hp > 0 ? (
745
+ `${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}/${char.maxhp}`.padStart(hpLength)
746
+ ) : char.hp > 0 ? (
746
747
  `-${char.maxhp - char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)
747
748
  ) : (
748
- `${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}/${char.maxhp}`.padStart(hpLength)
749
+ `${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)
749
750
  );
750
751
 
751
752
  const hpBar = (value: number, max: number) => (
@@ -759,7 +760,7 @@ export const formatTracker = (tracker: CharSchema[]) => {
759
760
  );
760
761
 
761
762
  ls.push((
762
- `${stateMap[char.state]}**\` ${char.name.padEnd(nameLength)} ▏${char.alias.padEnd(3)} ▏${hp} \`** ${hpBar(char.hp, char.maxhp)} `
763
+ `${stateMap[char.hp > 0 ? char.state : 'cross']}**\` ${char.name.padEnd(nameLength + aliasSpace(char))}${char.alias.length > 0 ? ` ▏${char.alias.padEnd(3)}` : ''} ▏${hp} \`** ${hpBar(char.hp, char.maxhp)} `
763
764
  ))
764
765
 
765
766
  if (char.conditions.length > 0) {
@@ -767,14 +768,16 @@ export const formatTracker = (tracker: CharSchema[]) => {
767
768
  }
768
769
 
769
770
  for (const child of char.children) {
770
- const hhp = char.foe ? (
771
+ const hhp = !char.foe && child.hp > 0 ? (
772
+ `${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}/${child.maxhp}`.padStart(hpLength)
773
+ ) : child.hp > 0 ? (
771
774
  `-${child.maxhp - child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)
772
775
  ) : (
773
- `${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}/${child.maxhp}`.padStart(hpLength)
776
+ `${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)
774
777
  );
775
778
 
776
779
  ls.push((
777
- `:smallnode:**\` ${child.name.padEnd(nameLength)} ▏${child.alias.padEnd(3)} ▏${hhp} \`** ${hpBar(child.hp, child.maxhp)} `
780
+ `:smallnode:**\` ${child.name.padEnd(nameLength + aliasSpace(child))}${child.alias.length > 0 ? ` ▏${child.alias.padEnd(3)}` : ''} ▏${hhp} \`** ${hpBar(child.hp, child.maxhp)} `
778
781
  ))
779
782
 
780
783
  if (child.conditions.length > 0) {
@@ -813,3 +816,52 @@ export const sortFolder = async () => {
813
816
 
814
817
  return transformed;
815
818
  };
819
+
820
+ export const screenPlay = (htmlContent: string) => {
821
+ const dom = new JSDOM(htmlContent);
822
+ const document = dom.window.document;
823
+
824
+ const outputLines = [];
825
+
826
+ const preambleEntry = document.querySelector('.preamble__entry');
827
+ if (preambleEntry) {
828
+ outputLines.push(`SCENE: ${preambleEntry.textContent}`);
829
+ outputLines.push('');
830
+ }
831
+
832
+ // Process all chatlog messages
833
+ const messages = document.querySelectorAll('.chatlog__message');
834
+
835
+ messages.forEach(message => {
836
+ const authorElement = message.querySelector('.chatlog__author');
837
+ const contentElement = message.querySelector('.chatlog__content');
838
+
839
+ if (!authorElement || !contentElement) return;
840
+
841
+ const author = authorElement.textContent?.trim() ?? '';
842
+ const content = contentElement.textContent?.trim() ?? '';
843
+
844
+ // Skip bot tags in character names
845
+ const characterName = author.replace(/\s*BOT$/, '');
846
+
847
+ // Add character line
848
+ outputLines.push(`${characterName.toUpperCase()}`);
849
+
850
+ // Add dialogue/content (wrap long lines)
851
+ const lines = content.split('\n').map((c) => (
852
+ c
853
+ .replace(/(—|--)/g, '-')
854
+ // eslint-disable-next-line no-irregular-whitespace
855
+ .replace(/(​|​)/g, '')
856
+ .trim()
857
+ )).filter((c) => c.length);
858
+
859
+ for (const line of lines) {
860
+ outputLines.push(` ${line}`);
861
+ }
862
+
863
+ outputLines.push('');
864
+ });
865
+
866
+ return outputLines.join('\n');
867
+ }
package/src/index.ts CHANGED
@@ -4,10 +4,11 @@ import { Command } from 'commander';
4
4
  import fs from 'fs/promises';
5
5
  import path from 'path';
6
6
  import readline from 'readline';
7
+ import clipboardy from 'clipboardy';
7
8
 
8
9
  import pack from '../package.json';
9
10
 
10
- import { sortFolder, formatCommand, formatJSON, formatTSV, fromatMap, parseJSON, parseStatblock, stub, adjustmentMap, prediceateMap, formatTable, formatHP, newtracker, parseTracker, formatTracker } from './app';
11
+ import { sortFolder, formatCommand, formatJSON, formatTSV, fromatMap, parseJSON, parseStatblock, stub, flatMap, formatTable, formatHP, newtracker, parseTracker, formatTracker, screenPlay, diceMap } from './app';
11
12
 
12
13
  const program = new Command(pack.name);
13
14
 
@@ -57,27 +58,41 @@ program.command('sort')
57
58
  console.log(await sortFolder());
58
59
  });
59
60
 
61
+ program.command('convert')
62
+ .description('Convert a discord export file into a txt log')
63
+ .argument('<file>', 'input file')
64
+ .option('-o, --output <file>', 'output file')
65
+ .action(async (argument, option) => {
66
+ const file = await fs.readFile(argument, { encoding: 'utf-8' });
67
+
68
+ if (option.output) {
69
+ await fs.writeFile(option.output, screenPlay(file), { encoding: 'utf-8' })
70
+ } else {
71
+ console.log(screenPlay(file));
72
+ }
73
+ });
74
+
60
75
  program.command('flat')
61
76
  .description('Generte a special flat npc tsv')
62
77
  .option('-n, --name <string>', 'npc name')
63
78
  .option('-o, --output <file>', 'output json')
64
79
  .action(async (option) => {
65
80
  if (option.output) {
66
- await fs.writeFile(option.output, fromatMap(option.name ?? 'flat', prediceateMap), { encoding: 'utf-8' })
81
+ await fs.writeFile(option.output, fromatMap(option.name ?? 'flat', flatMap), { encoding: 'utf-8' })
67
82
  } else {
68
- console.log(fromatMap(option.name ?? 'flat', prediceateMap));
83
+ console.log(fromatMap(option.name ?? 'flat', flatMap));
69
84
  }
70
85
  });
71
86
 
72
- program.command('adjustment')
73
- .description('Generte a special adjustment npc tsv')
87
+ program.command('dice')
88
+ .description('Generte a special dice npc tsv')
74
89
  .option('-n, --name <string>', 'npc name')
75
90
  .option('-o, --output <file>', 'output json')
76
91
  .action(async (option) => {
77
92
  if (option.output) {
78
- await fs.writeFile(option.output, fromatMap(option.name ?? 'adjustment', adjustmentMap()), { encoding: 'utf-8' })
93
+ await fs.writeFile(option.output, fromatMap(option.name ?? 'dice', diceMap), { encoding: 'utf-8' })
79
94
  } else {
80
- console.log(fromatMap(option.name ?? 'adjustment', adjustmentMap()));
95
+ console.log(fromatMap(option.name ?? 'dice', diceMap));
81
96
  }
82
97
  });
83
98
 
@@ -119,7 +134,6 @@ program.command('tsv')
119
134
  .argument('<file>', 'input json')
120
135
  .option('-o, --output <file>', 'output tsv')
121
136
  .option('-s, --secretDC', 'produce secret DCs')
122
- .option('-r, --recallDC', 'produce recall DCs')
123
137
  .option('-d, --defaultSkills', 'produce values for untrained skills')
124
138
  .action(async (argument, option) => {
125
139
  const file = await fs.readFile(argument, { encoding: 'utf-8' });
@@ -128,7 +142,7 @@ program.command('tsv')
128
142
 
129
143
  const output = option.output ? option.output : path.join(path.parse(argument).dir, path.parse(argument).name + '.tsv');
130
144
 
131
- await fs.writeFile(output, formatTSV(stats, option.secretDC, option.defaultSkills, option.recallDC), { encoding: 'utf-8' });
145
+ await fs.writeFile(output, formatTSV(stats, option.secretDC, option.defaultSkills), { encoding: 'utf-8' });
132
146
  });
133
147
 
134
148
  program.command('command')
@@ -136,7 +150,6 @@ program.command('command')
136
150
  .argument('<file>', 'input json')
137
151
  .option('-o, --output <file>', 'output txt')
138
152
  .option('-s, --secretDC', 'produce secret DCs')
139
- .option('-r, --recallDC', 'produce recall DCs')
140
153
  .option('-d, --defaultSkills', 'produce values for untrained skills')
141
154
  .action(async (argument, option) => {
142
155
  const file = await fs.readFile(argument, { encoding: 'utf-8' });
@@ -145,7 +158,7 @@ program.command('command')
145
158
 
146
159
  const output = option.output ? option.output : path.join(path.parse(argument).dir, path.parse(argument).name + '-command.txt');
147
160
 
148
- await fs.writeFile(output, formatCommand(stats, option.secretDC, option.defaultSkills, option.recallDC), { encoding: 'utf-8' });
161
+ await fs.writeFile(output, formatCommand(stats, option.secretDC, option.defaultSkills), { encoding: 'utf-8' });
149
162
  });
150
163
 
151
164
  program.command('newtracker')
@@ -193,7 +206,10 @@ program.command('track')
193
206
  await fs.writeFile(option.output, formatTracker(tracker), { encoding: 'utf-8' })
194
207
  } else {
195
208
  console.clear();
196
- console.log(formatTracker(tracker));
209
+
210
+ const track = formatTracker(tracker);
211
+ clipboardy.writeSync(track)
212
+ console.log(track);
197
213
  }
198
214
  }
199
215
 
@@ -258,19 +274,48 @@ program.command('track')
258
274
  }
259
275
  },
260
276
  }, {
261
- regex: /^\s*(\S+)\s+[sS]\s*"(.*)"/,
277
+ regex: /^\s*(\S+)\s+[sS]?\s*=?"([^"]*)"/,
262
278
  map: (match: RegExpMatchArray) => {
263
279
  return { command: 'set-conditions' as const, tag: match[1], value: match[2] };
264
280
  },
281
+ }, {
282
+ regex: /^\s*(\S+)\s+[sS]?\s*\+"([^"]*)"/,
283
+ map: (match: RegExpMatchArray) => {
284
+ return { command: 'add-conditions' as const, tag: match[1], value: match[2] };
285
+ },
286
+ }, {
287
+ regex: /^\s*(\S+)\s+[sS]?\s*-"([^"]*)"/,
288
+ map: (match: RegExpMatchArray) => {
289
+ return { command: 'rem-conditions' as const, tag: match[1], value: match[2] };
290
+ },
291
+ }, {
292
+ regex: /^\s*(\S+)\s+[sS]?\s*\+\+"([^"]*)"/,
293
+ map: (match: RegExpMatchArray) => {
294
+ return { command: 'inc-conditions' as const, tag: match[1], value: match[2] };
295
+ },
296
+ }, {
297
+ regex: /^\s*(\S+)\s+[sS]?\s*--"([^"]*)"/,
298
+ map: (match: RegExpMatchArray) => {
299
+ return { command: 'dec-conditions' as const, tag: match[1], value: match[2] };
300
+ },
265
301
  }, {
266
302
  regex: /^\s*(\S+)\s+[cC]/,
267
303
  map: (match: RegExpMatchArray) => ({ command: 'check' as const, tag: match[1] }),
268
304
  }, {
269
305
  regex: /^\s*(\S+)\s+[aA]/,
270
306
  map: (match: RegExpMatchArray) => ({ command: 'arrow' as const, tag: match[1] }),
307
+ }, {
308
+ regex: /^\s*(\S+)\s+[eE]/,
309
+ map: (match: RegExpMatchArray) => ({ command: 'empty' as const, tag: match[1] }),
310
+ }, {
311
+ regex: /^\s*(\S+)\s+[xX]/,
312
+ map: (match: RegExpMatchArray) => ({ command: 'cross' as const, tag: match[1] }),
271
313
  }, {
272
314
  regex: /^\s*(\S+)\s+[dD]/,
273
315
  map: (match: RegExpMatchArray) => ({ command: 'delete' as const, tag: match[1] }),
316
+ }, {
317
+ regex: /^\s*(\S+)\s+[wW]/,
318
+ map: (match: RegExpMatchArray) => ({ command: 'wait' as const, tag: match[1] }),
274
319
  }];
275
320
 
276
321
  const actions: ReturnType<typeof commands[number]['map']>[] = [];
@@ -322,6 +367,26 @@ program.command('track')
322
367
  blocks[i].forEach((b) => b.state = 'empty')
323
368
  }
324
369
  }
370
+ } else if (action.command === 'wait') {
371
+ const sorted = [...tracker].sort((a, b) => (a.init === b.init) ? (b.foe ? 1 : 0) - (a.foe ? 1 : 0) : b.init - a.init);
372
+
373
+ const blocks = [[sorted[0]]];
374
+
375
+ for (let i=1; i < sorted.length; ++i) {
376
+ if (sorted[i].foe === blocks[blocks.length-1][0].foe) {
377
+ blocks[blocks.length-1].push(sorted[i])
378
+ } else {
379
+ blocks.push([sorted[i]])
380
+ }
381
+ }
382
+
383
+ const blockIndex = blocks.findIndex((b) => b.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag))
384
+ const block = blocks[blockIndex + 1]
385
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
386
+
387
+ if (block && item) {
388
+ item.init = (block[block.length - 1]?.init ?? 0) - 1;
389
+ }
325
390
  } else if (action.command === 'check') {
326
391
  const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
327
392
 
@@ -334,6 +399,18 @@ program.command('track')
334
399
  if (item) {
335
400
  item.state = "arrow"
336
401
  }
402
+ } else if (action.command === 'empty') {
403
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
404
+
405
+ if (item) {
406
+ item.state = "empty"
407
+ }
408
+ } else if (action.command === 'cross') {
409
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
410
+
411
+ if (item) {
412
+ item.state = "cross"
413
+ }
337
414
  } else if (action.command === 'delete') {
338
415
  tracker = tracker.filter((c) => !(c.id === action.tag || c.alias === action.tag || c.name == action.tag)).map((p) => ({
339
416
  ...p,
@@ -381,7 +458,71 @@ program.command('track')
381
458
  )
382
459
 
383
460
  if (item) {
384
- item.conditions = action.value
461
+ item.conditions = action.value.trim()
462
+ }
463
+ } else if (action.command === 'add-conditions') {
464
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
465
+ tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
466
+ )
467
+
468
+ if (item) {
469
+ const conditions = [...item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length), action.value.toLowerCase().trim()];
470
+
471
+ item.conditions = conditions.join(', ')
472
+ }
473
+ } else if (action.command === 'rem-conditions') {
474
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
475
+ tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
476
+ )
477
+
478
+ if (item) {
479
+ const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).filter((c) => !c.includes(action.value.toLowerCase().trim()));
480
+
481
+ item.conditions = conditions.join(', ')
482
+ }
483
+ } else if (action.command === 'inc-conditions') {
484
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
485
+ tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
486
+ )
487
+
488
+ if (item) {
489
+ const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).map((c) => {
490
+ if (c.includes(action.value.toLowerCase().trim())) {
491
+ const match = c.match(/(.*)\s+(\d+)/);
492
+
493
+ if (match && match[1] && match[2]) {
494
+ return `${match[1].trim()} ${parseInt(match[2]) + 1}`
495
+ }
496
+ }
497
+
498
+ return c;
499
+ });
500
+
501
+ item.conditions = conditions.join(', ')
502
+ }
503
+ } else if (action.command === 'dec-conditions') {
504
+ const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
505
+ tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
506
+ )
507
+
508
+ if (item) {
509
+ const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).map((c) => {
510
+ if (c.includes(action.value.toLowerCase().trim())) {
511
+ const match = c.match(/(.*)\s+(\d+)/);
512
+
513
+ if (match && match[1] && match[2]) {
514
+ if (parseInt(match[2]) > 1) {
515
+ return `${match[1].trim()} ${parseInt(match[2]) - 1}`
516
+ } else {
517
+ return match[1].trim()
518
+ }
519
+ }
520
+ }
521
+
522
+ return c;
523
+ });
524
+
525
+ item.conditions = conditions.join(', ')
385
526
  }
386
527
  } else if (action.command === 'mod-thp') {
387
528
  const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (