@maka/maka-cli 5.64.0 → 5.65.1
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/bundle/typescript/package.json +4 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/backlog.d.ts +29 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/backlog.js +165 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/backlog.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.d.ts +40 -13
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js +107 -25
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/breach.d.ts +11 -15
- package/bundle/typescript/src/commands/game/sideQuest/commands/breach.js +13 -16
- package/bundle/typescript/src/commands/game/sideQuest/commands/breach.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.d.ts +8 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js +30 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.d.ts +40 -49
- package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.js +121 -160
- package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.d.ts +7 -8
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js +13 -13
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/cover.d.ts +30 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/cover.js +65 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/cover.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/dispel.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/dispel.js +2 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/dispel.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +25 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.d.ts +2 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +2 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/job-offer.js +9 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/job-offer.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/jobs.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/jobs.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js +58 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/map.js +18 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/map.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/pick.d.ts +2 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/pick.js +2 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/pick.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/posture.d.ts +45 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/posture.js +115 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/posture.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/say.d.ts +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/say.js +80 -9
- package/bundle/typescript/src/commands/game/sideQuest/commands/say.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/search.js +35 -24
- package/bundle/typescript/src/commands/game/sideQuest/commands/search.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js +12 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/unlock.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/unlock.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/use.d.ts +17 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/use.js +158 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/use.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +15 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.d.ts +82 -43
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +419 -263
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js +82 -84
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.d.ts +23 -4
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.js +95 -79
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/seed-migration.d.ts +30 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/seed-migration.js +176 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/seed-migration.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +21 -5
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/headless.js +24 -0
- package/bundle/typescript/src/commands/game/sideQuest/headless.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/_index.d.ts +0 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/_index.js +0 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/_index.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/device.d.ts +121 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/device.js +145 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/device.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/door.d.ts +27 -8
- package/bundle/typescript/src/commands/game/sideQuest/models/door.js +15 -10
- package/bundle/typescript/src/commands/game/sideQuest/models/door.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.d.ts +81 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +138 -21
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +68 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +102 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/room.d.ts +72 -43
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js +82 -59
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.d.ts +1 -4
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +0 -22
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene1.json +78 -109
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene2.json +4 -101
- package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +24 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/device-seed.d.ts +52 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/device-seed.js +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/device-seed.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/legacy-puzzle-seed.d.ts +63 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/legacy-puzzle-seed.js +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/legacy-puzzle-seed.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/player-seed.d.ts +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/room-seed.d.ts +4 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/scene-seed.d.ts +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/types/shared/abstracts.d.ts +2 -28
- package/bundle/typescript/src/commands/game/sideQuest/types/shared/abstracts.js +1 -14
- package/bundle/typescript/src/commands/game/sideQuest/types/shared/abstracts.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/ui.js +24 -0
- package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/affordances.d.ts +55 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/affordances.js +36 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/affordances.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-review.d.ts +65 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-review.js +137 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-review.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog.d.ts +90 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog.js +103 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +37 -4
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/credentials.d.ts +26 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/credentials.js +48 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/credentials.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/devices.d.ts +23 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/devices.js +55 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/devices.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/fuzzy-match.d.ts +57 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/fuzzy-match.js +46 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/fuzzy-match.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/log-style.d.ts +16 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/log-style.js +18 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/log-style.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +68 -38
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/room-grid.d.ts +3 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/room-grid.js +3 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.d.ts +36 -12
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js +101 -27
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/use-target.d.ts +106 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/use-target.js +184 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/use-target.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +54 -5
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
- package/bundle/typescript/src/maka.js +1 -1
- package/bundle/typescript/src/maka.js.map +1 -1
- package/bundle/typescript/src/tools/sdk-loader/relocate.d.ts +19 -2
- package/bundle/typescript/src/tools/sdk-loader/relocate.js +22 -2
- package/bundle/typescript/src/tools/sdk-loader/relocate.js.map +1 -1
- package/package.json +4 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/solve.d.ts +0 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/solve.js +0 -72
- package/bundle/typescript/src/commands/game/sideQuest/commands/solve.js.map +0 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/puzzle-factory.d.ts +0 -6
- package/bundle/typescript/src/commands/game/sideQuest/factories/puzzle-factory.js +0 -26
- package/bundle/typescript/src/commands/game/sideQuest/factories/puzzle-factory.js.map +0 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.d.ts +0 -152
- package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js +0 -393
- package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js.map +0 -1
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/puzzle-seed.d.ts +0 -28
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/puzzle-seed.js +0 -2
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/puzzle-seed.js.map +0 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const AFFORDANCE_FLAVOR = {
|
|
2
|
+
lock: {
|
|
3
|
+
verb: 'pick',
|
|
4
|
+
verbs: ['pick', 'breach'],
|
|
5
|
+
resists: `It's a mechanism, not a system -- no console to intrude on, no weave to unpick, nobody to talk round. It gives to HANDS: "pick" it quietly, or "breach" it with your shoulder.`,
|
|
6
|
+
failureMessage: `Your pick snaps in the mechanism -- and the lock's alarm isn't silent anymore.`,
|
|
7
|
+
hint: `This looks forceable -- "pick" works it quietly (Agility + locksmith); "breach" forces it with raw muscle (Strength + Body, LOUD even when it works). A key opens it clean, if you can find one.`,
|
|
8
|
+
},
|
|
9
|
+
panel: {
|
|
10
|
+
verb: 'hack',
|
|
11
|
+
verbs: ['hack'],
|
|
12
|
+
resists: `No keyway, no seam, no tumblers to feel for -- it's a sealed SYSTEM, and it only argues with a deck. "hack" it.`,
|
|
13
|
+
failureMessage: `Your intrusion trips a countermeasure -- the system logs the attempt and pings whoever's watching.`,
|
|
14
|
+
hint: `This looks hackable -- try "hack" to skip finding the code (Logic + hacking). Fail, and the system pings whoever's watching.`,
|
|
15
|
+
},
|
|
16
|
+
ward: {
|
|
17
|
+
verb: 'cast',
|
|
18
|
+
verbs: ['cast', 'dispel'],
|
|
19
|
+
resists: `Your hands find nothing to work and your tools find nothing to bite -- the barrier isn't matter. It answers to the Art: "cast" at it, or "dispel" it.`,
|
|
20
|
+
failureMessage: `The weave slips through your fingers -- backlash crackles outward, and something out there felt it.`,
|
|
21
|
+
hint: `This could be unwoven magically -- try "dispel" (Magic + counterspelling) or "cast" (the casting pool). Fail, and the backlash BITES.`,
|
|
22
|
+
},
|
|
23
|
+
person: {
|
|
24
|
+
verb: 'bluff',
|
|
25
|
+
verbs: ['bluff', 'persuade', 'subdue'],
|
|
26
|
+
resists: `There's no lock here at all. There's a PERSON -- and people don't open to tools, they open to a story, an argument, or a shove. "bluff" them, "persuade" them, or "subdue" them.`,
|
|
27
|
+
failureMessage: `The story comes apart mid-sentence -- and now they KNOW someone's running a game on them.`,
|
|
28
|
+
hint: `This one is a person, not a mechanism: "bluff" past them (Charisma + con), "persuade" them (Charisma + negotiation), or put them down with "subdue".`,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
/** The verbs that work a thing of this kind -- used wherever the game
|
|
32
|
+
* has to tell a player exactly what they may type. */
|
|
33
|
+
export function verbsFor(kind) {
|
|
34
|
+
return AFFORDANCE_FLAVOR[kind]?.verbs ?? [];
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=affordances.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"affordances.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/affordances.ts"],"names":[],"mappings":"AAsDA,MAAM,CAAC,MAAM,iBAAiB,GAAwC;IACpE,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;QACzB,OAAO,EAAE,gLAAgL;QACzL,cAAc,EAAE,gFAAgF;QAChG,IAAI,EAAE,kMAAkM;KACzM;IACD,KAAK,EAAE;QACL,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,iHAAiH;QAC1H,cAAc,EAAE,oGAAoG;QACpH,IAAI,EAAE,8HAA8H;KACrI;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;QACzB,OAAO,EAAE,uJAAuJ;QAChK,cAAc,EAAE,qGAAqG;QACrH,IAAI,EAAE,uIAAuI;KAC9I;IACD,MAAM,EAAE;QACN,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC;QACtC,OAAO,EAAE,kLAAkL;QAC3L,cAAc,EAAE,2FAA2F;QAC3G,IAAI,EAAE,sJAAsJ;KAC7J;CACF,CAAC;AAEF;uDACuD;AACvD,MAAM,UAAU,QAAQ,CAAC,IAAoB;IAC3C,OAAO,iBAAiB,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { IReviewItem, BacklogOutcome } from './backlog.js';
|
|
2
|
+
/** Replace the rendered list. Called ONLY when a fresh queue is shown
|
|
3
|
+
* to the player -- that is what makes the numbers theirs. */
|
|
4
|
+
export declare function rememberQueue(items: IReviewItem[]): void;
|
|
5
|
+
/** Exactly what was last rendered, in the order it was rendered. */
|
|
6
|
+
export declare function reviewSnapshot(): IReviewItem[];
|
|
7
|
+
/** 1-based, because the list is printed 1..n to a human. Out of range
|
|
8
|
+
* and non-integers return undefined; the caller names the range. */
|
|
9
|
+
export declare function reviewItemAt(n: number): IReviewItem | undefined;
|
|
10
|
+
export declare function markReviewAnswered(id: string): void;
|
|
11
|
+
export declare function isReviewAnswered(id: string): boolean;
|
|
12
|
+
/** Only for tests and a fresh session. */
|
|
13
|
+
export declare function resetReviewQueue(): void;
|
|
14
|
+
/** How many items were waiting when the session started, or -1 if the
|
|
15
|
+
* probe never answered (offline, logged out, not a play-tester). */
|
|
16
|
+
export declare function pendingReviewCount(): number;
|
|
17
|
+
/**
|
|
18
|
+
* The login-time count, fetched in the background.
|
|
19
|
+
*
|
|
20
|
+
* Same shape as the play-tester probe deliberately -- fire and forget,
|
|
21
|
+
* never block a boot, never throw, and an unanswered probe simply
|
|
22
|
+
* leaves the notice unsaid. Reusing that pattern rather than inventing
|
|
23
|
+
* a second one for the same job.
|
|
24
|
+
*
|
|
25
|
+
* It also folds its outcome into the play-tester standing for free:
|
|
26
|
+
* this endpoint is role-gated exactly like the board, so a 200 proves
|
|
27
|
+
* the role and a 403 disproves it, and a session that runs this probe
|
|
28
|
+
* needs no second request to classify the account.
|
|
29
|
+
*/
|
|
30
|
+
export declare function probeReviewQueue(opts: {
|
|
31
|
+
anonymous: boolean;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* THE NOTICE, one line. "Someone asked about your report" and "this is
|
|
35
|
+
* fixed, can you confirm it" are different requests and must not read
|
|
36
|
+
* identically, but the count alone cannot tell them apart -- so the
|
|
37
|
+
* notice stays neutral about WHICH, and the list itself distinguishes
|
|
38
|
+
* them per item. Empty string when there is nothing to say.
|
|
39
|
+
*/
|
|
40
|
+
export declare function reviewNotice(): string;
|
|
41
|
+
/** Fetch a fresh queue for display, and adopt it as the numbering. */
|
|
42
|
+
export declare function loadReviewQueue(): Promise<{
|
|
43
|
+
outcome: BacklogOutcome;
|
|
44
|
+
items?: IReviewItem[];
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* IS THIS ROW A "GO AND CONFIRM IT" REQUEST, or a question about the
|
|
48
|
+
* report?
|
|
49
|
+
*
|
|
50
|
+
* ONE definition, used by BOTH the renderer and the action, because the
|
|
51
|
+
* cost of them disagreeing is silent and lands on a person: the list
|
|
52
|
+
* says "CAN YOU CONFIRM THIS IN PLAY?" and the keystroke posts a
|
|
53
|
+
* comment that closes nothing. That is exactly what shipped before
|
|
54
|
+
* 2026-08-27 (item jyjMYRXrS4KojAL2W) -- not because either half was
|
|
55
|
+
* wrong, but because only one half existed.
|
|
56
|
+
*
|
|
57
|
+
* The SERVER's `kind` wins. The status fallback is only for a server too
|
|
58
|
+
* old to send one, and it is a guess: deriving the kind from status
|
|
59
|
+
* mislabels a clarifying question asked about an item that happens to be
|
|
60
|
+
* in-review.
|
|
61
|
+
*/
|
|
62
|
+
export declare function isValidationRow(item: {
|
|
63
|
+
kind?: string;
|
|
64
|
+
status?: string;
|
|
65
|
+
}): boolean;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { fetchReviewQueue } from './backlog.js';
|
|
2
|
+
import { noteBacklogOutcome } from './playtester.js';
|
|
3
|
+
/**
|
|
4
|
+
* THE REVIEW QUEUE, AND THE NUMBERS THAT POINT AT IT (user request
|
|
5
|
+
* 2026-08-27: "when they login, they should get a message about a
|
|
6
|
+
* backlog item for review... a simple list (1,2,3,4,etc.) in which they
|
|
7
|
+
* can 'backlog review 1 <test/comment/etc>'").
|
|
8
|
+
*
|
|
9
|
+
* THE ONE INVARIANT THIS MODULE EXISTS TO HOLD: a number means what the
|
|
10
|
+
* player was shown when they read it. The server returns the queue
|
|
11
|
+
* OLDEST FIRST so the ordering is stable, and this keeps the SNAPSHOT
|
|
12
|
+
* that was rendered, so resolving an index never re-sorts, re-filters
|
|
13
|
+
* or refetches. A queue that reshuffles between being read and being
|
|
14
|
+
* answered posts the player's words against the wrong item -- and they
|
|
15
|
+
* would never find out, because the answer lands somewhere plausible.
|
|
16
|
+
*
|
|
17
|
+
* Two consequences that look like fussiness and are not:
|
|
18
|
+
* - Answering does NOT renumber. Item 1 leaving the queue must not
|
|
19
|
+
* silently turn item 2 into item 1 while the list is still on
|
|
20
|
+
* screen; the entry is marked answered and everything keeps its
|
|
21
|
+
* number until the player asks for a fresh list.
|
|
22
|
+
* - Resolving a number with no snapshot does NOT fetch one and guess.
|
|
23
|
+
* A list nobody has read cannot have been the list they counted on,
|
|
24
|
+
* so the caller shows the queue and asks them to pick again.
|
|
25
|
+
*/
|
|
26
|
+
let snapshot = [];
|
|
27
|
+
let answeredIds = new Set();
|
|
28
|
+
/** Count from the background login probe, for the notice. -1 = unknown. */
|
|
29
|
+
let pendingAtLogin = -1;
|
|
30
|
+
let probing;
|
|
31
|
+
/** Replace the rendered list. Called ONLY when a fresh queue is shown
|
|
32
|
+
* to the player -- that is what makes the numbers theirs. */
|
|
33
|
+
export function rememberQueue(items) {
|
|
34
|
+
snapshot = [...items];
|
|
35
|
+
answeredIds = new Set();
|
|
36
|
+
}
|
|
37
|
+
/** Exactly what was last rendered, in the order it was rendered. */
|
|
38
|
+
export function reviewSnapshot() {
|
|
39
|
+
return snapshot;
|
|
40
|
+
}
|
|
41
|
+
/** 1-based, because the list is printed 1..n to a human. Out of range
|
|
42
|
+
* and non-integers return undefined; the caller names the range. */
|
|
43
|
+
export function reviewItemAt(n) {
|
|
44
|
+
if (!Number.isInteger(n) || n < 1 || n > snapshot.length)
|
|
45
|
+
return undefined;
|
|
46
|
+
return snapshot[n - 1];
|
|
47
|
+
}
|
|
48
|
+
export function markReviewAnswered(id) {
|
|
49
|
+
answeredIds.add(id);
|
|
50
|
+
}
|
|
51
|
+
export function isReviewAnswered(id) {
|
|
52
|
+
return answeredIds.has(id);
|
|
53
|
+
}
|
|
54
|
+
/** Only for tests and a fresh session. */
|
|
55
|
+
export function resetReviewQueue() {
|
|
56
|
+
snapshot = [];
|
|
57
|
+
answeredIds = new Set();
|
|
58
|
+
pendingAtLogin = -1;
|
|
59
|
+
probing = undefined;
|
|
60
|
+
}
|
|
61
|
+
/** How many items were waiting when the session started, or -1 if the
|
|
62
|
+
* probe never answered (offline, logged out, not a play-tester). */
|
|
63
|
+
export function pendingReviewCount() {
|
|
64
|
+
return pendingAtLogin;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The login-time count, fetched in the background.
|
|
68
|
+
*
|
|
69
|
+
* Same shape as the play-tester probe deliberately -- fire and forget,
|
|
70
|
+
* never block a boot, never throw, and an unanswered probe simply
|
|
71
|
+
* leaves the notice unsaid. Reusing that pattern rather than inventing
|
|
72
|
+
* a second one for the same job.
|
|
73
|
+
*
|
|
74
|
+
* It also folds its outcome into the play-tester standing for free:
|
|
75
|
+
* this endpoint is role-gated exactly like the board, so a 200 proves
|
|
76
|
+
* the role and a 403 disproves it, and a session that runs this probe
|
|
77
|
+
* needs no second request to classify the account.
|
|
78
|
+
*/
|
|
79
|
+
export function probeReviewQueue(opts) {
|
|
80
|
+
if (opts.anonymous || pendingAtLogin >= 0)
|
|
81
|
+
return Promise.resolve();
|
|
82
|
+
probing ??= fetchReviewQueue()
|
|
83
|
+
.then(res => {
|
|
84
|
+
noteBacklogOutcome(res.outcome);
|
|
85
|
+
if (res.outcome === 'ok')
|
|
86
|
+
pendingAtLogin = res.items?.length ?? 0;
|
|
87
|
+
})
|
|
88
|
+
.catch(() => undefined);
|
|
89
|
+
return probing;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* THE NOTICE, one line. "Someone asked about your report" and "this is
|
|
93
|
+
* fixed, can you confirm it" are different requests and must not read
|
|
94
|
+
* identically, but the count alone cannot tell them apart -- so the
|
|
95
|
+
* notice stays neutral about WHICH, and the list itself distinguishes
|
|
96
|
+
* them per item. Empty string when there is nothing to say.
|
|
97
|
+
*/
|
|
98
|
+
export function reviewNotice() {
|
|
99
|
+
const n = pendingReviewCount();
|
|
100
|
+
if (n <= 0)
|
|
101
|
+
return '';
|
|
102
|
+
return n === 1
|
|
103
|
+
? `{cyan-fg}📋 One backlog item is waiting on you -- somebody needs a word back. ("backlog review"){/cyan-fg}`
|
|
104
|
+
: `{cyan-fg}📋 ${n} backlog items are waiting on you -- somebody needs a word back on each. ("backlog review"){/cyan-fg}`;
|
|
105
|
+
}
|
|
106
|
+
/** Fetch a fresh queue for display, and adopt it as the numbering. */
|
|
107
|
+
export async function loadReviewQueue() {
|
|
108
|
+
const res = await fetchReviewQueue();
|
|
109
|
+
noteBacklogOutcome(res.outcome);
|
|
110
|
+
if (res.outcome === 'ok') {
|
|
111
|
+
rememberQueue(res.items ?? []);
|
|
112
|
+
pendingAtLogin = res.items?.length ?? 0;
|
|
113
|
+
}
|
|
114
|
+
return res;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* IS THIS ROW A "GO AND CONFIRM IT" REQUEST, or a question about the
|
|
118
|
+
* report?
|
|
119
|
+
*
|
|
120
|
+
* ONE definition, used by BOTH the renderer and the action, because the
|
|
121
|
+
* cost of them disagreeing is silent and lands on a person: the list
|
|
122
|
+
* says "CAN YOU CONFIRM THIS IN PLAY?" and the keystroke posts a
|
|
123
|
+
* comment that closes nothing. That is exactly what shipped before
|
|
124
|
+
* 2026-08-27 (item jyjMYRXrS4KojAL2W) -- not because either half was
|
|
125
|
+
* wrong, but because only one half existed.
|
|
126
|
+
*
|
|
127
|
+
* The SERVER's `kind` wins. The status fallback is only for a server too
|
|
128
|
+
* old to send one, and it is a guess: deriving the kind from status
|
|
129
|
+
* mislabels a clarifying question asked about an item that happens to be
|
|
130
|
+
* in-review.
|
|
131
|
+
*/
|
|
132
|
+
export function isValidationRow(item) {
|
|
133
|
+
if (item.kind)
|
|
134
|
+
return item.kind === 'validation';
|
|
135
|
+
return item.status === 'complete' || item.status === 'in-review';
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=backlog-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog-review.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/backlog-review.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `in-review` was missing here until 2026-08-27, and the first
|
|
3
|
+
* populated review payload is what exposed it: the server has been able
|
|
4
|
+
* to park a fixed item in review -- awaiting the reporter's word in
|
|
5
|
+
* play -- while this list did not know the state existed. An unknown
|
|
6
|
+
* status fell to statusMark's default and rendered as "[open]", so the
|
|
7
|
+
* board showed an item awaiting confirmation as though nobody had
|
|
8
|
+
* touched it, and `backlog list in-review` was refused as a typo.
|
|
9
|
+
*/
|
|
10
|
+
export type BacklogStatus = 'open' | 'in-progress' | 'in-review' | 'complete' | 'wont-fix';
|
|
2
11
|
export declare const BACKLOG_STATUSES: BacklogStatus[];
|
|
3
12
|
export interface IBacklogItem {
|
|
4
13
|
_id: string;
|
|
@@ -37,6 +46,86 @@ export interface IBacklogMeta {
|
|
|
37
46
|
platform?: string;
|
|
38
47
|
}
|
|
39
48
|
export declare function submitBacklog(text: string, meta: IBacklogMeta): Promise<BacklogOutcome>;
|
|
49
|
+
/**
|
|
50
|
+
* AN ITEM WAITING ON THE PERSON WHO FILED IT (user request 2026-08-27:
|
|
51
|
+
* "when they login, they should get a message about a backlog item for
|
|
52
|
+
* review... a clarifying question, or playtest validation").
|
|
53
|
+
*
|
|
54
|
+
* `asked` is the last question aimed at this play-tester with no later
|
|
55
|
+
* word from them -- either someone needs the report clarified, or a fix
|
|
56
|
+
* has landed and wants confirming in play. The server models both as a
|
|
57
|
+
* question awaiting the reporter, so there is one mechanism; the two
|
|
58
|
+
* read differently in prose because they are different requests.
|
|
59
|
+
*/
|
|
60
|
+
export interface IReviewItem {
|
|
61
|
+
id: string;
|
|
62
|
+
text: string;
|
|
63
|
+
status: BacklogStatus;
|
|
64
|
+
/** WHICH REQUEST THIS IS, from the server rather than guessed. A
|
|
65
|
+
* clarifying question and "this is fixed, confirm it in play" are
|
|
66
|
+
* different jobs; the client used to infer the difference from
|
|
67
|
+
* `status`, which would mislabel a clarifying question asked about
|
|
68
|
+
* an item that happens to be in-progress. Optional because the
|
|
69
|
+
* client must not break on an older server; see reviewKind. */
|
|
70
|
+
kind?: 'question' | 'validation';
|
|
71
|
+
/** The commits that closed it -- present on a validation request,
|
|
72
|
+
* which is the case where "what changed?" is the player's next
|
|
73
|
+
* thought. */
|
|
74
|
+
commits?: string[];
|
|
75
|
+
/** OPTIONAL on the wire, and handled as such. The review queue only
|
|
76
|
+
* returns items with a question outstanding, so it should always be
|
|
77
|
+
* here -- but "should always" is how a render throws in front of a
|
|
78
|
+
* player, and an item we cannot describe is better skipped than
|
|
79
|
+
* fatal. */
|
|
80
|
+
asked?: {
|
|
81
|
+
by?: string;
|
|
82
|
+
text: string;
|
|
83
|
+
at?: string;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The review queue, OLDEST FIRST. That order is load-bearing and comes
|
|
88
|
+
* from the server: the player answers by NUMBER, so the list they read
|
|
89
|
+
* and the list a number resolves against must be the same list in the
|
|
90
|
+
* same order. Callers must not re-sort, re-filter, or refetch between
|
|
91
|
+
* showing it and resolving an index -- a queue that reshuffles in
|
|
92
|
+
* between posts the answer against the wrong item, and it lands
|
|
93
|
+
* somewhere plausible enough that nobody notices.
|
|
94
|
+
*/
|
|
95
|
+
export declare function fetchReviewQueue(): Promise<{
|
|
96
|
+
outcome: BacklogOutcome;
|
|
97
|
+
items?: IReviewItem[];
|
|
98
|
+
}>;
|
|
99
|
+
/** Answer, ask, or annotate one item. `kind` defaults to a plain note;
|
|
100
|
+
* a play-tester replying to a question posts an 'answer'. */
|
|
101
|
+
export declare function postBacklogComment(itemId: string, text: string, opts?: {
|
|
102
|
+
kind?: 'question' | 'answer' | 'note';
|
|
103
|
+
awaitingReporter?: boolean;
|
|
104
|
+
runnerName?: string;
|
|
105
|
+
}): Promise<BacklogOutcome>;
|
|
106
|
+
/**
|
|
107
|
+
* THE REPORTER CONFIRMS A FIX IN PLAY -- the only thing that closes a
|
|
108
|
+
* validation request.
|
|
109
|
+
*
|
|
110
|
+
* MISSING UNTIL 2026-08-27, and the omission is the whole of backlog
|
|
111
|
+
* item jyjMYRXrS4KojAL2W ("after confirming a review, it should be
|
|
112
|
+
* removed from the review list"). The server has had
|
|
113
|
+
* POST /item/:id/signoff since the sign-off rule landed; the CLIENT
|
|
114
|
+
* never called it. `backlog review <n> <answer>` posted a COMMENT for
|
|
115
|
+
* every row, including the ones asking "can you confirm this in play?"
|
|
116
|
+
*
|
|
117
|
+
* So confirming did exactly nothing to the row. The comment landed, the
|
|
118
|
+
* answer was on the record, `signoff` stayed unset, and the queue kept
|
|
119
|
+
* showing the item because `status === in-review && !signoff` was still
|
|
120
|
+
* true. From the play-tester's chair the confirmation was simply
|
|
121
|
+
* ignored -- and the board could never reach `complete`, because the
|
|
122
|
+
* server refuses that without a sign-off it was never sent.
|
|
123
|
+
*
|
|
124
|
+
* REPORTER-ONLY server-side, which is the point: an admin can stage a
|
|
125
|
+
* fix and attach commits, but only the person who reported it can say
|
|
126
|
+
* it is actually fixed.
|
|
127
|
+
*/
|
|
128
|
+
export declare function postBacklogSignoff(itemId: string, note: string, runnerName?: string): Promise<BacklogOutcome>;
|
|
40
129
|
export interface IRoleHolder {
|
|
41
130
|
email?: string;
|
|
42
131
|
roles: string[];
|
|
@@ -25,7 +25,7 @@ const HOSTNAME = DEV ? 'localhost' : 'www.maka-cli.com';
|
|
|
25
25
|
const PORT = DEV ? Number(process.env.MAKA_DEV_PORT ?? 3000) : 443;
|
|
26
26
|
const API_BASE = 'api/v1/game-backlog';
|
|
27
27
|
const TIMEOUT_MS = 10000;
|
|
28
|
-
export const BACKLOG_STATUSES = ['open', 'in-progress', 'complete', 'wont-fix'];
|
|
28
|
+
export const BACKLOG_STATUSES = ['open', 'in-progress', 'in-review', 'complete', 'wont-fix'];
|
|
29
29
|
function request(method, apiPath, token, body) {
|
|
30
30
|
return new Promise((resolve, reject) => {
|
|
31
31
|
const payload = body === undefined ? undefined : JSON.stringify(body);
|
|
@@ -85,6 +85,108 @@ export async function submitBacklog(text, meta) {
|
|
|
85
85
|
return 'offline';
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* The review queue, OLDEST FIRST. That order is load-bearing and comes
|
|
90
|
+
* from the server: the player answers by NUMBER, so the list they read
|
|
91
|
+
* and the list a number resolves against must be the same list in the
|
|
92
|
+
* same order. Callers must not re-sort, re-filter, or refetch between
|
|
93
|
+
* showing it and resolving an index -- a queue that reshuffles in
|
|
94
|
+
* between posts the answer against the wrong item, and it lands
|
|
95
|
+
* somewhere plausible enough that nobody notices.
|
|
96
|
+
*/
|
|
97
|
+
export async function fetchReviewQueue() {
|
|
98
|
+
const token = authToken();
|
|
99
|
+
if (!token)
|
|
100
|
+
return { outcome: 'no-login' };
|
|
101
|
+
try {
|
|
102
|
+
const res = await request('GET', `/${API_BASE}/review`, token);
|
|
103
|
+
if (res.statusCode === 401)
|
|
104
|
+
return { outcome: 'expired' };
|
|
105
|
+
if (res.statusCode === 403)
|
|
106
|
+
return { outcome: 'forbidden' };
|
|
107
|
+
if (res.statusCode !== 200)
|
|
108
|
+
return { outcome: 'offline' };
|
|
109
|
+
const parsed = parseData(res.data);
|
|
110
|
+
return { outcome: 'ok', items: parsed?.items ?? [] };
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return { outcome: 'offline' };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Answer, ask, or annotate one item. `kind` defaults to a plain note;
|
|
117
|
+
* a play-tester replying to a question posts an 'answer'. */
|
|
118
|
+
export async function postBacklogComment(itemId, text, opts = {}) {
|
|
119
|
+
const token = authToken();
|
|
120
|
+
if (!token)
|
|
121
|
+
return 'no-login';
|
|
122
|
+
try {
|
|
123
|
+
const res = await request('POST', `/${API_BASE}/item/${encodeURIComponent(itemId)}/comment`, token, {
|
|
124
|
+
text,
|
|
125
|
+
kind: opts.kind,
|
|
126
|
+
awaitingReporter: opts.awaitingReporter,
|
|
127
|
+
runnerName: opts.runnerName,
|
|
128
|
+
});
|
|
129
|
+
if (res.statusCode === 200 || res.statusCode === 201)
|
|
130
|
+
return 'ok';
|
|
131
|
+
if (res.statusCode === 401)
|
|
132
|
+
return 'expired';
|
|
133
|
+
if (res.statusCode === 403)
|
|
134
|
+
return 'forbidden';
|
|
135
|
+
if (res.statusCode === 400 || res.statusCode === 404)
|
|
136
|
+
return 'rejected';
|
|
137
|
+
return 'offline';
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return 'offline';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* THE REPORTER CONFIRMS A FIX IN PLAY -- the only thing that closes a
|
|
145
|
+
* validation request.
|
|
146
|
+
*
|
|
147
|
+
* MISSING UNTIL 2026-08-27, and the omission is the whole of backlog
|
|
148
|
+
* item jyjMYRXrS4KojAL2W ("after confirming a review, it should be
|
|
149
|
+
* removed from the review list"). The server has had
|
|
150
|
+
* POST /item/:id/signoff since the sign-off rule landed; the CLIENT
|
|
151
|
+
* never called it. `backlog review <n> <answer>` posted a COMMENT for
|
|
152
|
+
* every row, including the ones asking "can you confirm this in play?"
|
|
153
|
+
*
|
|
154
|
+
* So confirming did exactly nothing to the row. The comment landed, the
|
|
155
|
+
* answer was on the record, `signoff` stayed unset, and the queue kept
|
|
156
|
+
* showing the item because `status === in-review && !signoff` was still
|
|
157
|
+
* true. From the play-tester's chair the confirmation was simply
|
|
158
|
+
* ignored -- and the board could never reach `complete`, because the
|
|
159
|
+
* server refuses that without a sign-off it was never sent.
|
|
160
|
+
*
|
|
161
|
+
* REPORTER-ONLY server-side, which is the point: an admin can stage a
|
|
162
|
+
* fix and attach commits, but only the person who reported it can say
|
|
163
|
+
* it is actually fixed.
|
|
164
|
+
*/
|
|
165
|
+
export async function postBacklogSignoff(itemId, note, runnerName) {
|
|
166
|
+
const token = authToken();
|
|
167
|
+
if (!token)
|
|
168
|
+
return 'no-login';
|
|
169
|
+
try {
|
|
170
|
+
const res = await request('POST', `/${API_BASE}/item/${encodeURIComponent(itemId)}/signoff`, token, {
|
|
171
|
+
note,
|
|
172
|
+
runnerName,
|
|
173
|
+
});
|
|
174
|
+
if (res.statusCode === 200 || res.statusCode === 201)
|
|
175
|
+
return 'ok';
|
|
176
|
+
if (res.statusCode === 401)
|
|
177
|
+
return 'expired';
|
|
178
|
+
// 403 is a REAL answer here, not a role problem: the server is
|
|
179
|
+
// saying this item is not yours to sign off.
|
|
180
|
+
if (res.statusCode === 403)
|
|
181
|
+
return 'forbidden';
|
|
182
|
+
if (res.statusCode === 400 || res.statusCode === 404)
|
|
183
|
+
return 'rejected';
|
|
184
|
+
return 'offline';
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return 'offline';
|
|
188
|
+
}
|
|
189
|
+
}
|
|
88
190
|
/** Who holds what. Admin-only server-side; a non-admin gets 'forbidden'
|
|
89
191
|
* and the command turns that into a sentence. */
|
|
90
192
|
export async function fetchRoles() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backlog.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/backlog.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC;AAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,kBAAkB,CAAC;AACxD,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACnE,MAAM,QAAQ,GAAG,qBAAqB,CAAC;AACvC,MAAM,UAAU,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"backlog.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/backlog.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { NPC } from '../models/npc.js';
|
|
2
2
|
import { rollPool, formatRoll } from './dice.js';
|
|
3
3
|
import { leaveMatrix, leaveDrone } from './planes.js';
|
|
4
|
-
import { spotOf, spotCell, seatingIn, actorCell, OPEN_FLOOR } from './spots.js';
|
|
4
|
+
import { spotOf, spotCell, seatingIn, actorCell, OPEN_FLOOR, isInCover, coverAvailableFor, takeCoverHere } from './spots.js';
|
|
5
|
+
import { heldBy } from './grapple.js';
|
|
5
6
|
import { distanceMeters, coverBetween } from './room-grid.js';
|
|
6
7
|
import { classifyWeapon, rangePenalty, rangeBracketName } from './range.js';
|
|
7
8
|
/**
|
|
@@ -73,6 +74,20 @@ export class CombatExchange {
|
|
|
73
74
|
this._combatants = [this.actor, target];
|
|
74
75
|
this.actor.inExchange = true;
|
|
75
76
|
target.inExchange = true;
|
|
77
|
+
// A COMBATANT USES THE COVER IT IS ALREADY STANDING IN. Cover now
|
|
78
|
+
// costs the Simple Action canon says it does (SR5e p.166/190, see
|
|
79
|
+
// commands/cover.ts), which would otherwise have quietly stripped
|
|
80
|
+
// +2/+4 from every NPC in the game -- their AI has no reason to
|
|
81
|
+
// type "cover", so a rule change meant as a fix would have landed
|
|
82
|
+
// as a balance nerf nobody asked for. Anyone already behind
|
|
83
|
+
// something when the shooting starts is assumed to spend their
|
|
84
|
+
// Simple Action on it, which is what a person does. The PLAYER's
|
|
85
|
+
// choice still matters everywhere it should: taking cover mid-fight
|
|
86
|
+
// after moving, or in a room whose cover they had to cross to.
|
|
87
|
+
for (const c of this._combatants) {
|
|
88
|
+
if (!isInCover(c) && coverAvailableFor(c))
|
|
89
|
+
takeCoverHere(c);
|
|
90
|
+
}
|
|
76
91
|
// Attacking someone whose hands are UP is the kind of story that
|
|
77
92
|
// travels (SR5e p.368: notoriety for callous behavior / killing
|
|
78
93
|
// innocents). Player-only, once per victim -- checked before the
|
|
@@ -416,9 +431,27 @@ export class CombatExchange {
|
|
|
416
431
|
const weaponClass = strike.weaponItem?.isFirearm() ? classifyWeapon(strike.weaponItem) : undefined;
|
|
417
432
|
const range = weaponClass ? rangePenalty(spatial.meters, weaponClass) : 0;
|
|
418
433
|
const rangeMod = range === 'out-of-range' ? -6 : range;
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const
|
|
434
|
+
// p.190 grants the bonus to a defender who "uses a Take Cover
|
|
435
|
+
// action" -- so the dice follow the ACTION, not the address.
|
|
436
|
+
const coverDice = isInCover(defender)
|
|
437
|
+
? (spatial.cover === 'good' ? 4 : spatial.cover === 'partial' ? 2 : 0)
|
|
438
|
+
: 0;
|
|
439
|
+
// POSTURE (SR5e p.187/189, and p.195 for the subdued). Derived at
|
|
440
|
+
// the point of use rather than stored twice: a GRAPPLED actor
|
|
441
|
+
// counts as prone for attacks against them (p.195) without anyone
|
|
442
|
+
// having to set a flag on them that could then disagree with the
|
|
443
|
+
// hold.
|
|
444
|
+
const onTheGround = (who) => who.posture === 'prone' || !!heldBy(who, this.scene);
|
|
445
|
+
// p.187 "Attacker Prone": -1 to a prone attacker's MELEE, cancelled
|
|
446
|
+
// when the opponent is down too.
|
|
447
|
+
const attackerFloor = isMelee && onTheGround(attacker) && !onTheGround(defender) ? -1 : 0;
|
|
448
|
+
// p.187 "Opponent Prone": +1 to hit someone who is down.
|
|
449
|
+
const targetDown = onTheGround(defender) ? 1 : 0;
|
|
450
|
+
// p.189 "Defender Prone": -2 to defend -- but NOT against ranged
|
|
451
|
+
// fire unless the shooter is inside five metres.
|
|
452
|
+
const proneDefence = onTheGround(defender) && (isMelee || spatial.meters <= 5) ? -2 : 0;
|
|
453
|
+
const attack = rollPool(strike.pool + directed + rangeMod + attackerFloor + targetDown);
|
|
454
|
+
const defense = rollPool(defender.getDefensePool() + inspired + counterspell + coverDice + proneDefence);
|
|
422
455
|
const header = `${attacker.name} attacks ${defender.name} ${strike.label}`;
|
|
423
456
|
meta.push(`${header}:`);
|
|
424
457
|
const rangeNote = weaponClass && spatial.meters > 0
|