pf2e-sage-stats 0.2.5 → 0.2.7
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 +54 -34
- package/dist/app.js +67 -43
- package/dist/index.js +186 -19
- package/package.json +6 -2
- package/src/app.ts +103 -41
- package/src/index.ts +197 -14
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({
|
|
@@ -45,6 +46,8 @@ const schema = zod.object({
|
|
|
45
46
|
stealth: zod.coerce.number().optional(),
|
|
46
47
|
survival: zod.coerce.number().optional(),
|
|
47
48
|
thievery: zod.coerce.number().optional(),
|
|
49
|
+
piloting: zod.coerce.number().optional(),
|
|
50
|
+
computers: zod.coerce.number().optional(),
|
|
48
51
|
}).default({}),
|
|
49
52
|
lores: zod.record(zod.string(), zod.object({
|
|
50
53
|
mod: zod.coerce.number().default(0),
|
|
@@ -103,6 +106,8 @@ const schema = zod.object({
|
|
|
103
106
|
stealth: zod.array(zod.string()).optional(),
|
|
104
107
|
survival: zod.array(zod.string()).optional(),
|
|
105
108
|
thievery: zod.array(zod.string()).optional(),
|
|
109
|
+
piloting: zod.array(zod.string()).optional(),
|
|
110
|
+
computers: zod.array(zod.string()).optional(),
|
|
106
111
|
}).default({}),
|
|
107
112
|
})
|
|
108
113
|
|
|
@@ -147,6 +152,8 @@ export const stub: Required<Schema> = {
|
|
|
147
152
|
stealth: 0,
|
|
148
153
|
survival: 0,
|
|
149
154
|
thievery: 0,
|
|
155
|
+
piloting: 0,
|
|
156
|
+
computers: 0,
|
|
150
157
|
},
|
|
151
158
|
lores: {},
|
|
152
159
|
melee: {
|
|
@@ -181,7 +188,7 @@ const childSchema = zod.object({
|
|
|
181
188
|
|
|
182
189
|
export type ChildSchema = zod.infer<typeof childSchema>;
|
|
183
190
|
|
|
184
|
-
const charSchema = zod.object({
|
|
191
|
+
export const charSchema = zod.object({
|
|
185
192
|
init: zod.coerce.number().default(0),
|
|
186
193
|
foe: zod.boolean().default(false),
|
|
187
194
|
state: zod.union([zod.literal('empty'), zod.literal('arrow'), zod.literal('check'), zod.literal('cross')]).default('empty'),
|
|
@@ -197,7 +204,7 @@ const charSchema = zod.object({
|
|
|
197
204
|
|
|
198
205
|
export type CharSchema = zod.infer<typeof charSchema>;
|
|
199
206
|
|
|
200
|
-
export const
|
|
207
|
+
export const flatMap: Record<string, string> = {
|
|
201
208
|
...([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
209
|
[`${v}`, `d20 >= ${v} flat;`]
|
|
203
210
|
)).reduce<Record<string, string>>((p, [k, v]) => { p[k] = v; return p }, {})),
|
|
@@ -207,14 +214,24 @@ export const prediceateMap: Record<string, string> = {
|
|
|
207
214
|
hidden: 'd20 >= 11 flat;',
|
|
208
215
|
};
|
|
209
216
|
|
|
210
|
-
export const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
export const diceMap: Record<string, string> = {
|
|
218
|
+
...([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map((v): [string, string] => (
|
|
219
|
+
[`${v}`, `(${v})`]
|
|
220
|
+
)).reduce<Record<string, string>>((p, [k, v]) => { p[k] = v; return p }, {})),
|
|
221
|
+
a: '+2',
|
|
222
|
+
adv: '+2',
|
|
223
|
+
advantage: '+2',
|
|
224
|
+
d: '-2',
|
|
225
|
+
dis: '-2',
|
|
226
|
+
disadvantage: '-2',
|
|
227
|
+
f: '+2',
|
|
228
|
+
for: '+2',
|
|
229
|
+
fort: '+2',
|
|
230
|
+
fortune: '+2',
|
|
231
|
+
m: '-2',
|
|
232
|
+
mis: '-2',
|
|
233
|
+
misfortune: '-2',
|
|
234
|
+
};
|
|
218
235
|
|
|
219
236
|
export const fromatMap = (name: string, map: Record<string, string>) => {
|
|
220
237
|
return TSV.stringify([{
|
|
@@ -308,10 +325,7 @@ const locateStrikes = (statblock: string, alias: string): Record<string, Schema[
|
|
|
308
325
|
.replace(/\+\d/g, '')
|
|
309
326
|
.replace(/Weapon\s+Striking(\s+\((Greater|Major)\))?/gi, '')
|
|
310
327
|
.replace(/((Greater|Major)\s+)?Striking/gi, '')
|
|
311
|
-
.replace(/\(
|
|
312
|
-
.replace(/\(Finesse\)/gi, '')
|
|
313
|
-
.replace(/\(\+\)/gi, '')
|
|
314
|
-
.replace(/\(\)/gi, '')
|
|
328
|
+
.replace(/\(.*\)/gi, '')
|
|
315
329
|
.replace(/\s+/g, ' ')
|
|
316
330
|
.trim();
|
|
317
331
|
|
|
@@ -333,6 +347,8 @@ const locateStrikes = (statblock: string, alias: string): Record<string, Schema[
|
|
|
333
347
|
.replace(/Electricity/, 'electricity')
|
|
334
348
|
.replace(/Sonic/, 'sonic')
|
|
335
349
|
.replace(/Spirit/, 'spirit')
|
|
350
|
+
.replace(/Acid/, 'acid')
|
|
351
|
+
.replace(/[pP]lus\s(\d+d)/, '+$1')
|
|
336
352
|
.trim();
|
|
337
353
|
|
|
338
354
|
const twoHand = _traits.match(/(two-hand|two-handed)\s+(d\d+)/);
|
|
@@ -440,6 +456,8 @@ export const parseStatblock = (name: string | null, _statblock: string, alias: s
|
|
|
440
456
|
...locateInt('stealth', statblock, 'Skills'),
|
|
441
457
|
...locateInt('survival', statblock, 'Skills'),
|
|
442
458
|
...locateInt('thievery', statblock, 'Skills'),
|
|
459
|
+
...locateInt('piloting', statblock, 'Skills'),
|
|
460
|
+
...locateInt('computers', statblock, 'Skills'),
|
|
443
461
|
},
|
|
444
462
|
lores: {
|
|
445
463
|
...locateInts(statblock, 'Skills', 'Lore'),
|
|
@@ -484,18 +502,7 @@ const toRanged = ([key, value]: [string, Schema['ranged'][string]]): [string, nu
|
|
|
484
502
|
...(value.damage ? [[`ranged.${key}.damage`, value.damage] as [string, string]] : []),
|
|
485
503
|
];
|
|
486
504
|
|
|
487
|
-
const
|
|
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> => {
|
|
505
|
+
export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false): Record<string, string | number> => {
|
|
499
506
|
const untrained = stats.untrained;
|
|
500
507
|
const skills = defaultSkills ? {
|
|
501
508
|
acrobatics: untrained + stats.attributes.dexterity,
|
|
@@ -514,6 +521,8 @@ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills:
|
|
|
514
521
|
stealth: untrained + stats.attributes.dexterity,
|
|
515
522
|
survival: untrained + stats.attributes.wisdom,
|
|
516
523
|
thievery: untrained + stats.attributes.dexterity,
|
|
524
|
+
piloting: untrained + stats.attributes.dexterity,
|
|
525
|
+
computers: untrained + stats.attributes.intelligence,
|
|
517
526
|
...stats.skills,
|
|
518
527
|
} : stats.skills;
|
|
519
528
|
|
|
@@ -600,9 +609,6 @@ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills:
|
|
|
600
609
|
...entries(skills).map(mod2DC(true, (stats.bump.skills ?? stats.bump.default))),
|
|
601
610
|
...entries(stats.extra).map(mod2DC(true, stats.bump.default)),
|
|
602
611
|
] : []),
|
|
603
|
-
...(recallDC ? [
|
|
604
|
-
...recallDCs(stats.level, secretDC, stats.bump.default),
|
|
605
|
-
] : []),
|
|
606
612
|
...(stats.perceptionInfo.length > 0 ? [
|
|
607
613
|
[`perception.info`, `\`(${stats.perceptionInfo.join(', ')})\``]
|
|
608
614
|
] : []),
|
|
@@ -615,12 +621,12 @@ export const flatten = (stats: Schema, secretDC: boolean = false, defaultSkills:
|
|
|
615
621
|
].reduce<Record<string | number, string | number>>((p, [key, value]) => { p[key] = value; return p }, {});
|
|
616
622
|
}
|
|
617
623
|
|
|
618
|
-
export const formatTSV = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false
|
|
619
|
-
TSV.stringify([flatten(stats, secretDC, defaultSkills
|
|
624
|
+
export const formatTSV = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false): string => (
|
|
625
|
+
TSV.stringify([flatten(stats, secretDC, defaultSkills)])
|
|
620
626
|
);
|
|
621
627
|
|
|
622
|
-
export const formatCommand = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false
|
|
623
|
-
Object.entries(flatten(stats, secretDC, defaultSkills
|
|
628
|
+
export const formatCommand = (stats: Schema, secretDC: boolean = false, defaultSkills: boolean = false): string => (
|
|
629
|
+
Object.entries(flatten(stats, secretDC, defaultSkills)).map(([k, v]) => `${k}="${v}"`).join(' ')
|
|
624
630
|
);
|
|
625
631
|
|
|
626
632
|
export const formatTable = (table: string, season: string, scenario: string, _name: string, gm: string, players: string) => {
|
|
@@ -634,7 +640,7 @@ export const formatTable = (table: string, season: string, scenario: string, _na
|
|
|
634
640
|
@TableBot create "${gameName}" --gm ${gm} --players ${players} --table-name ${tableName} --ooc-table-name ooc-${tableName} --category Game Tables
|
|
635
641
|
\`\`\`
|
|
636
642
|
\`\`\`
|
|
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="Хронист"
|
|
643
|
+
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
644
|
\`\`\`
|
|
639
645
|
`;
|
|
640
646
|
};
|
|
@@ -702,8 +708,11 @@ export const newtracker = (status: string) => {
|
|
|
702
708
|
};
|
|
703
709
|
|
|
704
710
|
export const formatTracker = (tracker: CharSchema[]) => {
|
|
711
|
+
const aliasSpace = (t: { alias: string }) => (t.alias.length > 0 ? 0 : 5);
|
|
712
|
+
const nameLengthWithAlias = (t: { name: string, alias: string }) => t.name.length - aliasSpace(t);
|
|
713
|
+
|
|
705
714
|
const nameLength = tracker.reduce((p, c) => {
|
|
706
|
-
const length = c.children.reduce((pp, cc) => pp > cc
|
|
715
|
+
const length = c.children.reduce((pp, cc) => pp > nameLengthWithAlias(cc) ? pp : nameLengthWithAlias(cc), nameLengthWithAlias(c));
|
|
707
716
|
|
|
708
717
|
return p > length ? p : length;
|
|
709
718
|
}, 0);
|
|
@@ -742,10 +751,12 @@ export const formatTracker = (tracker: CharSchema[]) => {
|
|
|
742
751
|
ls.push('')
|
|
743
752
|
}
|
|
744
753
|
|
|
745
|
-
const hp = char.foe ? (
|
|
754
|
+
const hp = !char.foe && char.hp > 0 ? (
|
|
755
|
+
`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}/${char.maxhp}`.padStart(hpLength)
|
|
756
|
+
) : char.hp > 0 ? (
|
|
746
757
|
`-${char.maxhp - char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)
|
|
747
758
|
) : (
|
|
748
|
-
`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}
|
|
759
|
+
`${char.hp}${char.temphp > 0 ? `+${char.temphp}` : ''}`.padStart(hpLength)
|
|
749
760
|
);
|
|
750
761
|
|
|
751
762
|
const hpBar = (value: number, max: number) => (
|
|
@@ -759,7 +770,7 @@ export const formatTracker = (tracker: CharSchema[]) => {
|
|
|
759
770
|
);
|
|
760
771
|
|
|
761
772
|
ls.push((
|
|
762
|
-
`${stateMap[char.state]}**\` ${char.name.padEnd(nameLength)} ▏${char.alias.padEnd(3)} ▏${hp} \`** ${hpBar(char.hp, char.maxhp)} `
|
|
773
|
+
`${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
774
|
))
|
|
764
775
|
|
|
765
776
|
if (char.conditions.length > 0) {
|
|
@@ -767,14 +778,16 @@ export const formatTracker = (tracker: CharSchema[]) => {
|
|
|
767
778
|
}
|
|
768
779
|
|
|
769
780
|
for (const child of char.children) {
|
|
770
|
-
const hhp = char.foe ? (
|
|
781
|
+
const hhp = !char.foe && child.hp > 0 ? (
|
|
782
|
+
`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}/${child.maxhp}`.padStart(hpLength)
|
|
783
|
+
) : child.hp > 0 ? (
|
|
771
784
|
`-${child.maxhp - child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)
|
|
772
785
|
) : (
|
|
773
|
-
`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}
|
|
786
|
+
`${child.hp}${child.temphp > 0 ? `+${child.temphp}` : ''}`.padStart(hpLength)
|
|
774
787
|
);
|
|
775
788
|
|
|
776
789
|
ls.push((
|
|
777
|
-
`:smallnode:**\` ${child.name.padEnd(nameLength)} ▏${child.alias.padEnd(3)} ▏${hhp} \`** ${hpBar(child.hp, child.maxhp)} `
|
|
790
|
+
`:smallnode:**\` ${child.name.padEnd(nameLength + aliasSpace(child))}${child.alias.length > 0 ? ` ▏${child.alias.padEnd(3)}` : ''} ▏${hhp} \`** ${hpBar(child.hp, child.maxhp)} `
|
|
778
791
|
))
|
|
779
792
|
|
|
780
793
|
if (child.conditions.length > 0) {
|
|
@@ -813,3 +826,52 @@ export const sortFolder = async () => {
|
|
|
813
826
|
|
|
814
827
|
return transformed;
|
|
815
828
|
};
|
|
829
|
+
|
|
830
|
+
export const screenPlay = (htmlContent: string) => {
|
|
831
|
+
const dom = new JSDOM(htmlContent);
|
|
832
|
+
const document = dom.window.document;
|
|
833
|
+
|
|
834
|
+
const outputLines = [];
|
|
835
|
+
|
|
836
|
+
const preambleEntry = document.querySelector('.preamble__entry');
|
|
837
|
+
if (preambleEntry) {
|
|
838
|
+
outputLines.push(`SCENE: ${preambleEntry.textContent}`);
|
|
839
|
+
outputLines.push('');
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Process all chatlog messages
|
|
843
|
+
const messages = document.querySelectorAll('.chatlog__message');
|
|
844
|
+
|
|
845
|
+
messages.forEach(message => {
|
|
846
|
+
const authorElement = message.querySelector('.chatlog__author');
|
|
847
|
+
const contentElement = message.querySelector('.chatlog__content');
|
|
848
|
+
|
|
849
|
+
if (!authorElement || !contentElement) return;
|
|
850
|
+
|
|
851
|
+
const author = authorElement.textContent?.trim() ?? '';
|
|
852
|
+
const content = contentElement.textContent?.trim() ?? '';
|
|
853
|
+
|
|
854
|
+
// Skip bot tags in character names
|
|
855
|
+
const characterName = author.replace(/\s*BOT$/, '');
|
|
856
|
+
|
|
857
|
+
// Add character line
|
|
858
|
+
outputLines.push(`${characterName.toUpperCase()}`);
|
|
859
|
+
|
|
860
|
+
// Add dialogue/content (wrap long lines)
|
|
861
|
+
const lines = content.split('\n').map((c) => (
|
|
862
|
+
c
|
|
863
|
+
.replace(/(—|--)/g, '-')
|
|
864
|
+
// eslint-disable-next-line no-irregular-whitespace
|
|
865
|
+
.replace(/(|)/g, '')
|
|
866
|
+
.trim()
|
|
867
|
+
)).filter((c) => c.length);
|
|
868
|
+
|
|
869
|
+
for (const line of lines) {
|
|
870
|
+
outputLines.push(` ${line}`);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
outputLines.push('');
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
return outputLines.join('\n');
|
|
877
|
+
}
|
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,
|
|
11
|
+
import { sortFolder, formatCommand, formatJSON, formatTSV, fromatMap, parseJSON, parseStatblock, stub, flatMap, formatTable, formatHP, newtracker, parseTracker, formatTracker, screenPlay, diceMap, charSchema } 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',
|
|
81
|
+
await fs.writeFile(option.output, fromatMap(option.name ?? 'flat', flatMap), { encoding: 'utf-8' })
|
|
67
82
|
} else {
|
|
68
|
-
console.log(fromatMap(option.name ?? 'flat',
|
|
83
|
+
console.log(fromatMap(option.name ?? 'flat', flatMap));
|
|
69
84
|
}
|
|
70
85
|
});
|
|
71
86
|
|
|
72
|
-
program.command('
|
|
73
|
-
.description('Generte a special
|
|
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 ?? '
|
|
93
|
+
await fs.writeFile(option.output, fromatMap(option.name ?? 'dice', diceMap), { encoding: 'utf-8' })
|
|
79
94
|
} else {
|
|
80
|
-
console.log(fromatMap(option.name ?? '
|
|
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
|
|
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
|
|
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
|
-
|
|
209
|
+
|
|
210
|
+
const track = formatTracker(tracker);
|
|
211
|
+
clipboardy.writeSync(track)
|
|
212
|
+
console.log(track);
|
|
197
213
|
}
|
|
198
214
|
}
|
|
199
215
|
|
|
@@ -224,6 +240,15 @@ program.command('track')
|
|
|
224
240
|
}, {
|
|
225
241
|
regex: /^\s*reset/i,
|
|
226
242
|
map: () => ({ command: 'reset' as const })
|
|
243
|
+
}, {
|
|
244
|
+
regex: /^\s*purge/i,
|
|
245
|
+
map: () => ({ command: 'purge' as const })
|
|
246
|
+
}, {
|
|
247
|
+
regex: /^\s*blank/i,
|
|
248
|
+
map: () => ({ command: 'blank' as const })
|
|
249
|
+
}, {
|
|
250
|
+
regex: /^\s*foe(\s+(\S+))?(\s+(\S+))?(\s+(\d+))?/i,
|
|
251
|
+
map: (match: RegExpMatchArray) => ({ command: 'foe' as const, name: match[2], alias: match[4], hp: match[6] && parseInt(match[6], 10) })
|
|
227
252
|
}, {
|
|
228
253
|
regex: /^\s*heal/i,
|
|
229
254
|
map: () => ({ command: 'heal' as const })
|
|
@@ -258,19 +283,73 @@ program.command('track')
|
|
|
258
283
|
}
|
|
259
284
|
},
|
|
260
285
|
}, {
|
|
261
|
-
regex: /^\s*(
|
|
286
|
+
regex: /^\s*([^\s="+-]+)\s*=?"([^"]*)"/,
|
|
262
287
|
map: (match: RegExpMatchArray) => {
|
|
263
288
|
return { command: 'set-conditions' as const, tag: match[1], value: match[2] };
|
|
264
289
|
},
|
|
290
|
+
}, {
|
|
291
|
+
regex: /^\s*([^\s="+-]+)\s*\+"([^"]*)"/,
|
|
292
|
+
map: (match: RegExpMatchArray) => {
|
|
293
|
+
return { command: 'add-conditions' as const, tag: match[1], value: match[2] };
|
|
294
|
+
},
|
|
295
|
+
}, {
|
|
296
|
+
regex: /^\s*([^\s="+-]+)\s*-"([^"]*)"/,
|
|
297
|
+
map: (match: RegExpMatchArray) => {
|
|
298
|
+
return { command: 'rem-conditions' as const, tag: match[1], value: match[2] };
|
|
299
|
+
},
|
|
300
|
+
}, {
|
|
301
|
+
regex: /^\s*([^\s="+-]+)\s*\+\+"([^"]*)"/,
|
|
302
|
+
map: (match: RegExpMatchArray) => {
|
|
303
|
+
return { command: 'inc-conditions' as const, tag: match[1], value: match[2] };
|
|
304
|
+
},
|
|
305
|
+
}, {
|
|
306
|
+
regex: /^\s*([^\s="+-]+)\s*--"([^"]*)"/,
|
|
307
|
+
map: (match: RegExpMatchArray) => {
|
|
308
|
+
return { command: 'dec-conditions' as const, tag: match[1], value: match[2] };
|
|
309
|
+
},
|
|
310
|
+
}, {
|
|
311
|
+
regex: /^\s*(\S+)\s+[sS]?\s*=?"([^"]*)"/,
|
|
312
|
+
map: (match: RegExpMatchArray) => {
|
|
313
|
+
return { command: 'set-conditions' as const, tag: match[1], value: match[2] };
|
|
314
|
+
},
|
|
315
|
+
}, {
|
|
316
|
+
regex: /^\s*(\S+)\s+[sS]?\s*\+"([^"]*)"/,
|
|
317
|
+
map: (match: RegExpMatchArray) => {
|
|
318
|
+
return { command: 'add-conditions' as const, tag: match[1], value: match[2] };
|
|
319
|
+
},
|
|
320
|
+
}, {
|
|
321
|
+
regex: /^\s*(\S+)\s+[sS]?\s*-"([^"]*)"/,
|
|
322
|
+
map: (match: RegExpMatchArray) => {
|
|
323
|
+
return { command: 'rem-conditions' as const, tag: match[1], value: match[2] };
|
|
324
|
+
},
|
|
325
|
+
}, {
|
|
326
|
+
regex: /^\s*(\S+)\s+[sS]?\s*\+\+"([^"]*)"/,
|
|
327
|
+
map: (match: RegExpMatchArray) => {
|
|
328
|
+
return { command: 'inc-conditions' as const, tag: match[1], value: match[2] };
|
|
329
|
+
},
|
|
330
|
+
}, {
|
|
331
|
+
regex: /^\s*(\S+)\s+[sS]?\s*--"([^"]*)"/,
|
|
332
|
+
map: (match: RegExpMatchArray) => {
|
|
333
|
+
return { command: 'dec-conditions' as const, tag: match[1], value: match[2] };
|
|
334
|
+
},
|
|
265
335
|
}, {
|
|
266
336
|
regex: /^\s*(\S+)\s+[cC]/,
|
|
267
337
|
map: (match: RegExpMatchArray) => ({ command: 'check' as const, tag: match[1] }),
|
|
268
338
|
}, {
|
|
269
339
|
regex: /^\s*(\S+)\s+[aA]/,
|
|
270
340
|
map: (match: RegExpMatchArray) => ({ command: 'arrow' as const, tag: match[1] }),
|
|
341
|
+
}, {
|
|
342
|
+
regex: /^\s*(\S+)\s+[eE]/,
|
|
343
|
+
map: (match: RegExpMatchArray) => ({ command: 'empty' as const, tag: match[1] }),
|
|
344
|
+
}, {
|
|
345
|
+
regex: /^\s*(\S+)\s+[xX]/,
|
|
346
|
+
map: (match: RegExpMatchArray) => ({ command: 'cross' as const, tag: match[1] }),
|
|
271
347
|
}, {
|
|
272
348
|
regex: /^\s*(\S+)\s+[dD]/,
|
|
273
349
|
map: (match: RegExpMatchArray) => ({ command: 'delete' as const, tag: match[1] }),
|
|
350
|
+
}, {
|
|
351
|
+
regex: /^\s*(\S+)\s+[wW]/,
|
|
352
|
+
map: (match: RegExpMatchArray) => ({ command: 'wait' as const, tag: match[1] }),
|
|
274
353
|
}];
|
|
275
354
|
|
|
276
355
|
const actions: ReturnType<typeof commands[number]['map']>[] = [];
|
|
@@ -322,6 +401,26 @@ program.command('track')
|
|
|
322
401
|
blocks[i].forEach((b) => b.state = 'empty')
|
|
323
402
|
}
|
|
324
403
|
}
|
|
404
|
+
} else if (action.command === 'wait') {
|
|
405
|
+
const sorted = [...tracker].sort((a, b) => (a.init === b.init) ? (b.foe ? 1 : 0) - (a.foe ? 1 : 0) : b.init - a.init);
|
|
406
|
+
|
|
407
|
+
const blocks = [[sorted[0]]];
|
|
408
|
+
|
|
409
|
+
for (let i=1; i < sorted.length; ++i) {
|
|
410
|
+
if (sorted[i].foe === blocks[blocks.length-1][0].foe) {
|
|
411
|
+
blocks[blocks.length-1].push(sorted[i])
|
|
412
|
+
} else {
|
|
413
|
+
blocks.push([sorted[i]])
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const blockIndex = blocks.findIndex((b) => b.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag))
|
|
418
|
+
const block = blocks[blockIndex + 1]
|
|
419
|
+
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
420
|
+
|
|
421
|
+
if (block && item) {
|
|
422
|
+
item.init = (block[block.length - 1]?.init ?? 0) - 1;
|
|
423
|
+
}
|
|
325
424
|
} else if (action.command === 'check') {
|
|
326
425
|
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
327
426
|
|
|
@@ -334,11 +433,25 @@ program.command('track')
|
|
|
334
433
|
if (item) {
|
|
335
434
|
item.state = "arrow"
|
|
336
435
|
}
|
|
436
|
+
} else if (action.command === 'empty') {
|
|
437
|
+
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
438
|
+
|
|
439
|
+
if (item) {
|
|
440
|
+
item.state = "empty"
|
|
441
|
+
}
|
|
442
|
+
} else if (action.command === 'cross') {
|
|
443
|
+
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
444
|
+
|
|
445
|
+
if (item) {
|
|
446
|
+
item.state = "cross"
|
|
447
|
+
}
|
|
337
448
|
} else if (action.command === 'delete') {
|
|
338
449
|
tracker = tracker.filter((c) => !(c.id === action.tag || c.alias === action.tag || c.name == action.tag)).map((p) => ({
|
|
339
450
|
...p,
|
|
340
451
|
children: p.children.filter((c) => !(c.id === action.tag || c.alias === action.tag || c.name == action.tag)),
|
|
341
452
|
}))
|
|
453
|
+
} else if (action.command === 'purge') {
|
|
454
|
+
tracker = tracker.filter((c) => !c.foe)
|
|
342
455
|
} else if (action.command === 'exit') {
|
|
343
456
|
process.exit(0)
|
|
344
457
|
} else if (action.command === 'heal') {
|
|
@@ -375,13 +488,81 @@ program.command('track')
|
|
|
375
488
|
if (item) {
|
|
376
489
|
item.init = Math.max(0, action.value)
|
|
377
490
|
}
|
|
491
|
+
} else if (action.command === 'blank') {
|
|
492
|
+
tracker.forEach((item) => {
|
|
493
|
+
item.conditions = ""
|
|
494
|
+
})
|
|
378
495
|
} else if (action.command === 'set-conditions') {
|
|
379
496
|
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
|
|
380
497
|
tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
381
498
|
)
|
|
382
499
|
|
|
383
500
|
if (item) {
|
|
384
|
-
item.conditions = action.value
|
|
501
|
+
item.conditions = action.value.trim()
|
|
502
|
+
}
|
|
503
|
+
} else if (action.command === 'add-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), action.value.toLowerCase().trim()];
|
|
510
|
+
|
|
511
|
+
item.conditions = conditions.join(', ')
|
|
512
|
+
}
|
|
513
|
+
} else if (action.command === 'rem-conditions') {
|
|
514
|
+
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
|
|
515
|
+
tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
if (item) {
|
|
519
|
+
const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).filter((c) => !c.includes(action.value.toLowerCase().trim()));
|
|
520
|
+
|
|
521
|
+
item.conditions = conditions.join(', ')
|
|
522
|
+
}
|
|
523
|
+
} else if (action.command === 'inc-conditions') {
|
|
524
|
+
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
|
|
525
|
+
tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
if (item) {
|
|
529
|
+
const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).map((c) => {
|
|
530
|
+
if (c.includes(action.value.toLowerCase().trim())) {
|
|
531
|
+
const match = c.match(/(.*)\s+(\d+)/);
|
|
532
|
+
|
|
533
|
+
if (match && match[1] && match[2]) {
|
|
534
|
+
return `${match[1].trim()} ${parseInt(match[2]) + 1}`
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return c;
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
item.conditions = conditions.join(', ')
|
|
542
|
+
}
|
|
543
|
+
} else if (action.command === 'dec-conditions') {
|
|
544
|
+
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
|
|
545
|
+
tracker.flatMap((c) => c.children).find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag)
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
if (item) {
|
|
549
|
+
const conditions = item.conditions.split(',').map((c) => c.toLowerCase().trim()).filter((c) => c.length).map((c) => {
|
|
550
|
+
if (c.includes(action.value.toLowerCase().trim())) {
|
|
551
|
+
const match = c.match(/(.*)\s+(\d+)/);
|
|
552
|
+
|
|
553
|
+
if (match && match[1] && match[2]) {
|
|
554
|
+
if (parseInt(match[2]) > 1) {
|
|
555
|
+
return `${match[1].trim()} ${parseInt(match[2]) - 1}`
|
|
556
|
+
} else {
|
|
557
|
+
return match[1].trim()
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return c;
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
item.conditions = conditions.join(', ')
|
|
385
566
|
}
|
|
386
567
|
} else if (action.command === 'mod-thp') {
|
|
387
568
|
const item = tracker.find((c) => c.id === action.tag || c.alias === action.tag || c.name == action.tag) ?? (
|
|
@@ -416,6 +597,8 @@ program.command('track')
|
|
|
416
597
|
if (item) {
|
|
417
598
|
item.init = Math.max(0, item.init + action.value)
|
|
418
599
|
}
|
|
600
|
+
} else if (action.command === 'foe') {
|
|
601
|
+
tracker.push(charSchema.parse({ foe: true, name: action.name, alias: action.alias, maxhp: action.hp, hp: action.hp }))
|
|
419
602
|
}
|
|
420
603
|
}
|
|
421
604
|
|