pf2e-sage-stats 0.2.4 → 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 +48 -34
- package/dist/app.js +60 -37
- package/dist/index.js +306 -44
- package/package.json +6 -2
- package/src/app.ts +97 -40
- package/src/index.ts +334 -47
- package/status.txt +0 -5
- package/tracker.json +0 -62
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({
|
|
@@ -172,6 +173,7 @@ export const stub: Required<Schema> = {
|
|
|
172
173
|
const childSchema = zod.object({
|
|
173
174
|
name: zod.string().default(""),
|
|
174
175
|
alias: zod.string().default(""),
|
|
176
|
+
id: zod.string().default(""),
|
|
175
177
|
hp: zod.coerce.number().default(0),
|
|
176
178
|
temphp: zod.coerce.number().default(0),
|
|
177
179
|
maxhp: zod.coerce.number().default(10),
|
|
@@ -186,6 +188,7 @@ const charSchema = zod.object({
|
|
|
186
188
|
state: zod.union([zod.literal('empty'), zod.literal('arrow'), zod.literal('check'), zod.literal('cross')]).default('empty'),
|
|
187
189
|
name: zod.string().default(""),
|
|
188
190
|
alias: zod.string().default(""),
|
|
191
|
+
id: zod.string().default(""),
|
|
189
192
|
hp: zod.coerce.number().default(0),
|
|
190
193
|
temphp: zod.coerce.number().default(0),
|
|
191
194
|
maxhp: zod.coerce.number().default(10),
|
|
@@ -195,7 +198,7 @@ const charSchema = zod.object({
|
|
|
195
198
|
|
|
196
199
|
export type CharSchema = zod.infer<typeof charSchema>;
|
|
197
200
|
|
|
198
|
-
export const
|
|
201
|
+
export const flatMap: Record<string, string> = {
|
|
199
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] => (
|
|
200
203
|
[`${v}`, `d20 >= ${v} flat;`]
|
|
201
204
|
)).reduce<Record<string, string>>((p, [k, v]) => { p[k] = v; return p }, {})),
|
|
@@ -205,14 +208,24 @@ export const prediceateMap: Record<string, string> = {
|
|
|
205
208
|
hidden: 'd20 >= 11 flat;',
|
|
206
209
|
};
|
|
207
210
|
|
|
208
|
-
export const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
+
};
|
|
216
229
|
|
|
217
230
|
export const fromatMap = (name: string, map: Record<string, string>) => {
|
|
218
231
|
return TSV.stringify([{
|
|
@@ -306,10 +319,7 @@ const locateStrikes = (statblock: string, alias: string): Record<string, Schema[
|
|
|
306
319
|
.replace(/\+\d/g, '')
|
|
307
320
|
.replace(/Weapon\s+Striking(\s+\((Greater|Major)\))?/gi, '')
|
|
308
321
|
.replace(/((Greater|Major)\s+)?Striking/gi, '')
|
|
309
|
-
.replace(/\(
|
|
310
|
-
.replace(/\(Finesse\)/gi, '')
|
|
311
|
-
.replace(/\(\+\)/gi, '')
|
|
312
|
-
.replace(/\(\)/gi, '')
|
|
322
|
+
.replace(/\(.*\)/gi, '')
|
|
313
323
|
.replace(/\s+/g, ' ')
|
|
314
324
|
.trim();
|
|
315
325
|
|
|
@@ -320,6 +330,7 @@ const locateStrikes = (statblock: string, alias: string): Record<string, Schema[
|
|
|
320
330
|
.replace(/\s+/g, ' ')
|
|
321
331
|
.replace(bps, (m) => m.toUpperCase())
|
|
322
332
|
.replace(/1d/, 'd')
|
|
333
|
+
.replace(/jousting\s+d\d+/g, 'jousting')
|
|
323
334
|
.trim();
|
|
324
335
|
|
|
325
336
|
const _dice = dice
|
|
@@ -328,6 +339,10 @@ const locateStrikes = (statblock: string, alias: string): Record<string, Schema[
|
|
|
328
339
|
.replace(/Fire/, 'fire')
|
|
329
340
|
.replace(/Cold/, 'cold')
|
|
330
341
|
.replace(/Electricity/, 'electricity')
|
|
342
|
+
.replace(/Sonic/, 'sonic')
|
|
343
|
+
.replace(/Spirit/, 'spirit')
|
|
344
|
+
.replace(/Acid/, 'acid')
|
|
345
|
+
.replace(/[pP]lus\s(\d+d)/, '+$1')
|
|
331
346
|
.trim();
|
|
332
347
|
|
|
333
348
|
const twoHand = _traits.match(/(two-hand|two-handed)\s+(d\d+)/);
|
|
@@ -479,18 +494,7 @@ const toRanged = ([key, value]: [string, Schema['ranged'][string]]): [string, nu
|
|
|
479
494
|
...(value.damage ? [[`ranged.${key}.damage`, value.damage] as [string, string]] : []),
|
|
480
495
|
];
|
|
481
496
|
|
|
482
|
-
const
|
|
483
|
-
['dc.recall.incredibly-easy', secret ? `||${value - 10}||` : `${value - 10}`],
|
|
484
|
-
['dc.recall.very-easy', secret ? `||${value - 5}||` : `${value - 5}`],
|
|
485
|
-
['dc.recall.easy', secret ? `||${value - 2}||` : `${value - 2}`],
|
|
486
|
-
['dc.recall.default', secret ? `||${value}||` : `${value}`],
|
|
487
|
-
['dc.recall', secret ? `||${value}||` : `${value}`],
|
|
488
|
-
['dc.recall.hard', secret ? `||${value + 2}||` : `${value + 2}`],
|
|
489
|
-
['dc.recall.very-hard', secret ? `||${value + 5}||` : `${value + 5}`],
|
|
490
|
-
['dc.recall.incredibly-hard', secret ? `||${value + 10}||` : `${value + 10}`],
|
|
491
|
-
])(dcByLevel[Math.max(Math.min(level + 1, dcByLevel.length - 1), 0)] + bump);
|
|
492
|
-
|
|
493
|
-
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> => {
|
|
494
498
|
const untrained = stats.untrained;
|
|
495
499
|
const skills = defaultSkills ? {
|
|
496
500
|
acrobatics: untrained + stats.attributes.dexterity,
|
|
@@ -595,9 +599,6 @@ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills:
|
|
|
595
599
|
...entries(skills).map(mod2DC(true, (stats.bump.skills ?? stats.bump.default))),
|
|
596
600
|
...entries(stats.extra).map(mod2DC(true, stats.bump.default)),
|
|
597
601
|
] : []),
|
|
598
|
-
...(recallDC ? [
|
|
599
|
-
...recallDCs(stats.level, secretDC, stats.bump.default),
|
|
600
|
-
] : []),
|
|
601
602
|
...(stats.perceptionInfo.length > 0 ? [
|
|
602
603
|
[`perception.info`, `\`(${stats.perceptionInfo.join(', ')})\``]
|
|
603
604
|
] : []),
|
|
@@ -610,12 +611,12 @@ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills:
|
|
|
610
611
|
].reduce<Record<string | number, string | number>>((p, [key, value]) => { p[key] = value; return p }, {});
|
|
611
612
|
}
|
|
612
613
|
|
|
613
|
-
export const formatTSV = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false
|
|
614
|
-
TSV.stringify([flatten(stats, secretDC, defaultSkills
|
|
614
|
+
export const formatTSV = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false): string => (
|
|
615
|
+
TSV.stringify([flatten(stats, secretDC, defaultSkills)])
|
|
615
616
|
);
|
|
616
617
|
|
|
617
|
-
export const formatCommand = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false
|
|
618
|
-
Object.entries(flatten(stats, secretDC, defaultSkills
|
|
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(' ')
|
|
619
620
|
);
|
|
620
621
|
|
|
621
622
|
export const formatTable = (table: string, season: string, scenario: string, _name: string, gm: string, players: string) => {
|
|
@@ -629,7 +630,7 @@ export const formatTable = (table: string, season: string, scenario: string, _na
|
|
|
629
630
|
@TableBot create "${gameName}" --gm ${gm} --players ${players} --table-name ${tableName} --ooc-table-name ooc-${tableName} --category Game Tables
|
|
630
631
|
\`\`\`
|
|
631
632
|
\`\`\`
|
|
632
|
-
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="Хронист"
|
|
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="Хронист"
|
|
633
634
|
\`\`\`
|
|
634
635
|
`;
|
|
635
636
|
};
|
|
@@ -697,8 +698,11 @@ export const newtracker = (status: string) => {
|
|
|
697
698
|
};
|
|
698
699
|
|
|
699
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
|
+
|
|
700
704
|
const nameLength = tracker.reduce((p, c) => {
|
|
701
|
-
const length = c.children.reduce((pp, cc) => pp > cc
|
|
705
|
+
const length = c.children.reduce((pp, cc) => pp > nameLengthWithAlias(cc) ? pp : nameLengthWithAlias(cc), nameLengthWithAlias(c));
|
|
702
706
|
|
|
703
707
|
return p > length ? p : length;
|
|
704
708
|
}, 0);
|
|
@@ -737,10 +741,12 @@ export const formatTracker = (tracker: CharSchema[]) => {
|
|
|
737
741
|
ls.push('')
|
|
738
742
|
}
|
|
739
743
|
|
|
740
|
-
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 ? (
|
|
741
747
|
`-${char.maxhp - char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)
|
|
742
748
|
) : (
|
|
743
|
-
`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}
|
|
749
|
+
`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)
|
|
744
750
|
);
|
|
745
751
|
|
|
746
752
|
const hpBar = (value: number, max: number) => (
|
|
@@ -754,7 +760,7 @@ export const formatTracker = (tracker: CharSchema[]) => {
|
|
|
754
760
|
);
|
|
755
761
|
|
|
756
762
|
ls.push((
|
|
757
|
-
`${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)} `
|
|
758
764
|
))
|
|
759
765
|
|
|
760
766
|
if (char.conditions.length > 0) {
|
|
@@ -762,14 +768,16 @@ export const formatTracker = (tracker: CharSchema[]) => {
|
|
|
762
768
|
}
|
|
763
769
|
|
|
764
770
|
for (const child of char.children) {
|
|
765
|
-
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 ? (
|
|
766
774
|
`-${child.maxhp - child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)
|
|
767
775
|
) : (
|
|
768
|
-
`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}
|
|
776
|
+
`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)
|
|
769
777
|
);
|
|
770
778
|
|
|
771
779
|
ls.push((
|
|
772
|
-
`:smallnode
|
|
780
|
+
`:smallnode:**\` ${child.name.padEnd(nameLength + aliasSpace(child))}${child.alias.length > 0 ? ` ▏${child.alias.padEnd(3)}` : ''} ▏${hhp} \`** ${hpBar(child.hp, child.maxhp)} `
|
|
773
781
|
))
|
|
774
782
|
|
|
775
783
|
if (child.conditions.length > 0) {
|
|
@@ -808,3 +816,52 @@ export const sortFolder = async () => {
|
|
|
808
816
|
|
|
809
817
|
return transformed;
|
|
810
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
|
+
}
|