@maka/maka-cli 5.7.0 → 5.9.0
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 +1 -1
- package/bundle/typescript/src/commands/deploy/ubuntu.sub.cmd.js +16 -31
- package/bundle/typescript/src/commands/deploy/ubuntu.sub.cmd.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js +6 -4
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js +19 -7
- package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/assense.js +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/assense.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/attack.js +35 -9
- package/bundle/typescript/src/commands/game/sideQuest/commands/attack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.js +31 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/bypass-command.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/call.js +16 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/call.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.d.ts +7 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js +118 -29
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.d.ts +33 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js +138 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/contacts.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/contacts.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/equip.js +5 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/equip.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/give.js +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/give.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.d.ts +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +138 -19
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/grapple.d.ts +38 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/grapple.js +178 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/grapple.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +14 -5
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js +7 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hints.d.ts +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hints.js +24 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hints.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/jump.js +25 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/jump.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/lifestyle.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/lifestyle.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js +53 -8
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/map.js +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/map.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.d.ts +41 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js +160 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/order.d.ts +19 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/order.js +152 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/order.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/persuade.js +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/persuade.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/pick.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/pick.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/project.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/project.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/quality-trade.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/quality-trade.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/say.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/say.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/search.js +24 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/search.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sell.js +7 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sell.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/silent.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/silent.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sneak.js +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/sneak.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/solve.js +11 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/solve.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/spells.js +24 -13
- package/bundle/typescript/src/commands/game/sideQuest/commands/spells.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/summon.d.ts +19 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/summon.js +113 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/summon.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/surrender.js +4 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/surrender.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js +37 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/talk.js +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/talk.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/treat.js +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/treat.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/unlock.js +9 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/unlock.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/work.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/work.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/item-factory.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/item-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/puzzle-factory.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/puzzle-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/room-factory.js +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/room-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.d.ts +11 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +138 -23
- 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 +12 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +91 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +501 -23
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/item.d.ts +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.d.ts +44 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +349 -9
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +10 -2
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +36 -7
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.d.ts +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js +9 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/puzzle.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/room.d.ts +13 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js +57 -4
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.d.ts +28 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +172 -4
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene1.json +76 -20
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene2.json +157 -34
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/exit-seed.d.ts +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/item-seed.d.ts +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/player-seed.d.ts +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/puzzle-seed.d.ts +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/room-seed.d.ts +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/ui.js +81 -5
- package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/auto-fight.js +21 -5
- package/bundle/typescript/src/commands/game/sideQuest/utilities/auto-fight.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.d.ts +25 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +128 -28
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.d.ts +7 -4
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js +8 -5
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grapple.d.ts +36 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grapple.js +57 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grapple.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/hints.d.ts +4 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/hints.js +55 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/hints.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/log-style.d.ts +14 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/log-style.js +15 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/log-style.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/logger.d.ts +16 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/logger.js +49 -4
- package/bundle/typescript/src/commands/game/sideQuest/utilities/logger.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +31 -7
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.d.ts +121 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js +315 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js.map +1 -0
- package/bundle/typescript/src/commands/ssl.js +10 -15
- package/bundle/typescript/src/commands/ssl.js.map +1 -1
- package/bundle/typescript/src/templates/react/kit/mui/auth/password-reset/basic-password-reset-page.js.tsx +3 -4
- package/bundle/typescript/src/tools/ssl/ssl.class.d.ts +8 -0
- package/bundle/typescript/src/tools/ssl/ssl.class.js +53 -0
- package/bundle/typescript/src/tools/ssl/ssl.class.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,10 +7,46 @@ import { getArchetype, outfitArchetype } from './archetypes.js';
|
|
|
7
7
|
import { STANCE_CYCLE } from './models/player.js';
|
|
8
8
|
import { AutoFight } from './utilities/auto-fight.js';
|
|
9
9
|
import { TERMINAL_RESET_SEQUENCE } from './utilities/terminal-reset.js';
|
|
10
|
+
// Windows Terminal draws astral-plane emoji (📞 call icon, 📍 HUD pin,
|
|
11
|
+
// 👥 companions, 💀) TWO columns wide, but blessed's 2015-era unicode
|
|
12
|
+
// tables predate emoji being classified wide and count them as ONE. The
|
|
13
|
+
// one-cell drift on every icon row pushed box borders sideways into the
|
|
14
|
+
// next panel and left smartCSR's partial redraws smearing stray orphan
|
|
15
|
+
// characters (two player screenshots; the text-presentation ⚔, one cell
|
|
16
|
+
// on both sides, stayed flush). Teaching charWidth the pictograph blocks
|
|
17
|
+
// fixes the model: strWidth (wrapping) and the cell renderer both route
|
|
18
|
+
// through this same export. BMP dingbats stay untouched -- the terminal
|
|
19
|
+
// really does draw those narrow.
|
|
20
|
+
// TWO patches, and they only work as a pair (blessed's own draw comment:
|
|
21
|
+
// "eat the next character which should be a space due to parseContent's
|
|
22
|
+
// behavior"): charWidth makes wrapping count 2 and the emitter skip the
|
|
23
|
+
// filler cell; chars.all makes parseContent actually INSERT that \x03
|
|
24
|
+
// filler after each pictograph. Either alone leaves rows misaligned or
|
|
25
|
+
// eats a real character.
|
|
26
|
+
{
|
|
27
|
+
const uni = blessed.unicode;
|
|
28
|
+
const origCharWidth = uni.charWidth;
|
|
29
|
+
uni.charWidth = function (text, i) {
|
|
30
|
+
const point = typeof text === 'number' ? text : uni.codePointAt(text, i ?? 0);
|
|
31
|
+
if (point >= 0x1F300 && point <= 0x1FAFF)
|
|
32
|
+
return 2;
|
|
33
|
+
return origCharWidth.call(this, text, i);
|
|
34
|
+
};
|
|
35
|
+
// U+1F300-1FAFF as surrogate pairs. Wrapped in a fresh outer group so
|
|
36
|
+
// parseContent's "$1\x03" replacement still means "the whole match".
|
|
37
|
+
const pictographs = '\\ud83c[\\udf00-\\udfff]|\\ud83d[\\udc00-\\udfff]|\\ud83e[\\udc00-\\udeff]';
|
|
38
|
+
uni.chars.all = new RegExp(`(${uni.chars.all.source}|${pictographs})`, 'g');
|
|
39
|
+
}
|
|
10
40
|
export async function main(playerName, sceneSeed, options) {
|
|
11
41
|
// Create a screen object
|
|
12
42
|
const screen = blessed.screen({
|
|
13
43
|
smartCSR: true,
|
|
44
|
+
// Without this, blessed strips every astral-plane character (all
|
|
45
|
+
// modern emoji -- the 📞 call icon, companion icons) to "?" during
|
|
46
|
+
// content parsing, no matter what the terminal can render. BMP
|
|
47
|
+
// symbols like ⚔ slipped through, which is why a session showed
|
|
48
|
+
// swords but question-mark phones.
|
|
49
|
+
fullUnicode: true,
|
|
14
50
|
title: 'Side Quest Adventure Game',
|
|
15
51
|
});
|
|
16
52
|
// TERMINAL HYGIENE: blessed arms xterm modes (mouse tracking, alt
|
|
@@ -75,6 +111,7 @@ export async function main(playerName, sceneSeed, options) {
|
|
|
75
111
|
? `{yellow-fg}${options.generationNotice}{/yellow-fg}\n\n`
|
|
76
112
|
: '';
|
|
77
113
|
game.logBox.setContent(notice + ready); // getWelcomeMessage should return the initial game introduction or room description
|
|
114
|
+
gameLog.transcript(notice + ready); // the transcript opens the way the session did
|
|
78
115
|
game.updateEquipment(game.player.equipment);
|
|
79
116
|
game.updateInventory(game.player.inventory, capitalCase(game.scene.getCurrencyType()));
|
|
80
117
|
game.updateExits(game.player.currentLocation);
|
|
@@ -101,8 +138,10 @@ export async function main(playerName, sceneSeed, options) {
|
|
|
101
138
|
game.autoFight.cancelPending();
|
|
102
139
|
// white for manual, not gray -- gray is ANSI bright-black, illegible
|
|
103
140
|
// on stock dark palettes (same fix as the HUD stance in game.ts).
|
|
141
|
+
// Mechanics ticker, not the narrative: the HUD already shows the
|
|
142
|
+
// standing stance; this is the change notice (readability pass).
|
|
104
143
|
const color = next === 'aggressive' ? 'red' : next === 'guarded' ? 'yellow' : 'white';
|
|
105
|
-
gameLog.
|
|
144
|
+
gameLog.meta(`⚔ Stance: ${next.toUpperCase()} -- ${AutoFight.describe(next)}.`, color);
|
|
106
145
|
game.updateStatus();
|
|
107
146
|
screen.render();
|
|
108
147
|
});
|
|
@@ -121,6 +160,30 @@ export async function main(playerName, sceneSeed, options) {
|
|
|
121
160
|
// whatever the player had started typing NEXT during the wait.
|
|
122
161
|
game.inputBox.clearValue();
|
|
123
162
|
screen.render();
|
|
163
|
+
// The transcript reads like the session: the typed command
|
|
164
|
+
// first, the game's answer after (see Logger.transcript).
|
|
165
|
+
if (input.trim().length > 0)
|
|
166
|
+
gameLog.transcript(`> ${input}`);
|
|
167
|
+
// TURN BLOCKS (readability pass): echo the command into the
|
|
168
|
+
// visible log too, behind a blank line, so each command's
|
|
169
|
+
// output reads as its own block -- BEFORE handleInput, so a
|
|
170
|
+
// slow command (AI round trip, combat beats) shows what was
|
|
171
|
+
// asked while it works. Cyan: blessed has no dim tag and gray
|
|
172
|
+
// is banned; cyan is already this game's machine voice.
|
|
173
|
+
// pushLine, not Logger -- the transcript line above already
|
|
174
|
+
// recorded it. "clear" is exempt (echo-then-wipe is noise),
|
|
175
|
+
// and "say" keeps only the blank separator -- your words
|
|
176
|
+
// already land as the yellow speech line, and "> say hoi"
|
|
177
|
+
// above "hoi" read as a stutter (playtest note).
|
|
178
|
+
const echoVerb = input.trim().split(' ')[0]?.toLowerCase();
|
|
179
|
+
if (input.trim().length > 0 && echoVerb !== 'clear') {
|
|
180
|
+
game.logBox.pushLine('');
|
|
181
|
+
if (echoVerb !== 'say') {
|
|
182
|
+
game.logBox.pushLine(`{cyan-fg}> ${input.trim()}{/cyan-fg}`);
|
|
183
|
+
}
|
|
184
|
+
game.followLog();
|
|
185
|
+
screen.render();
|
|
186
|
+
}
|
|
124
187
|
const response = await game.handleInput(input); // handleInput is the method that processes commands
|
|
125
188
|
if (['take', 'equip', 'unequip'].includes(input.split(' ')[0])) {
|
|
126
189
|
// Example usage: update the inventory with a new list of items
|
|
@@ -137,15 +200,28 @@ export async function main(playerName, sceneSeed, options) {
|
|
|
137
200
|
game.updateStatus();
|
|
138
201
|
if (input.split(' ')[0] === 'clear') {
|
|
139
202
|
game.logBox.setContent('');
|
|
203
|
+
game.metaBox.setContent('');
|
|
204
|
+
// Blessed repositions a box's LABEL on 'scroll' events --
|
|
205
|
+
// setContent('') resets the scroll base without firing one,
|
|
206
|
+
// stranding the title mid-box (screenshot bug: "Game Log"
|
|
207
|
+
// sitting at the bottom after "clear"). Scrolling home
|
|
208
|
+
// fires the event and the label snaps back to the border.
|
|
209
|
+
game.logBox.scrollTo(0);
|
|
210
|
+
game.metaBox.scrollTo(0);
|
|
140
211
|
}
|
|
141
|
-
|
|
212
|
+
if (response)
|
|
213
|
+
gameLog.transcript(response);
|
|
142
214
|
if (response === null) {
|
|
143
215
|
screen.render();
|
|
144
216
|
gameLog.write(`<<<<<<<<--------- Terminating game`);
|
|
145
217
|
process.exit(0); // Exit the game
|
|
146
218
|
}
|
|
147
|
-
|
|
148
|
-
|
|
219
|
+
// Empty responses stop printing blank filler -- the turn-block
|
|
220
|
+
// echo above is the separator now.
|
|
221
|
+
if (response) {
|
|
222
|
+
game.logBox.pushLine(response);
|
|
223
|
+
game.followLog();
|
|
224
|
+
}
|
|
149
225
|
}
|
|
150
226
|
catch (error) {
|
|
151
227
|
// A crashed command must FAIL VISIBLY -- the old silent
|
|
@@ -155,7 +231,7 @@ export async function main(playerName, sceneSeed, options) {
|
|
|
155
231
|
// only in the log file).
|
|
156
232
|
gameLog.error(`Error handling input: ${error}`);
|
|
157
233
|
game.logBox.pushLine(`{red-fg}Something glitched handling that command -- it's been logged. The game is still running.{/red-fg}`);
|
|
158
|
-
game.
|
|
234
|
+
game.followLog();
|
|
159
235
|
}
|
|
160
236
|
finally {
|
|
161
237
|
// Focus restoration runs on EVERY path -- the same real session
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../../../src/commands/game/sideQuest/ui.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EACL,MAAM,EACN,IAAI,GACL,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAG/C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../../../../src/commands/game/sideQuest/ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -90,10 +90,24 @@ export class AutoFight {
|
|
|
90
90
|
// onExchangeSettled reschedules us. No waiting here.
|
|
91
91
|
if (player.inExchange || target.inExchange)
|
|
92
92
|
return;
|
|
93
|
-
// Guarded honors a surrender --
|
|
94
|
-
//
|
|
95
|
-
//
|
|
93
|
+
// Guarded honors a surrender -- but doesn't trust it: the final
|
|
94
|
+
// action is a RESTRAIN (player request; SR5e Subduing p.195, the
|
|
95
|
+
// surrendered branch is an automatic no-roll hold). Hands-up
|
|
96
|
+
// prisoners get zip-tied, not taken at their word. One-shot: an
|
|
97
|
+
// already-held target (by anyone) means truly stand down, and off
|
|
98
|
+
// the meat plane there are no hands to hold with.
|
|
96
99
|
if (player.autoStance === 'guarded' && target.surrendered) {
|
|
100
|
+
if (player.plane === 'meat' && target.plane === 'meat'
|
|
101
|
+
&& player.grappling !== target.name && !target.grappledBy) {
|
|
102
|
+
const cmd = `restrain ${target.name}`;
|
|
103
|
+
logger.meta(`⚔ [guarded] ${cmd}`, 'cyan');
|
|
104
|
+
const result = await this.game.handleInput(cmd);
|
|
105
|
+
if (result) {
|
|
106
|
+
logger.log(result);
|
|
107
|
+
}
|
|
108
|
+
this.game.updateStatus();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
97
111
|
logger.logWithColor(`⚔ ${target.name} has surrendered -- you hold fire. (guarded)`, 'yellow');
|
|
98
112
|
this.game.updateStatus();
|
|
99
113
|
return;
|
|
@@ -101,7 +115,9 @@ export class AutoFight {
|
|
|
101
115
|
const cmd = this.chooseAction(player, target);
|
|
102
116
|
// Cyan, not gray: the autopilot announcing it acted must be legible on
|
|
103
117
|
// stock dark palettes (gray = ANSI bright-black, near-invisible there).
|
|
104
|
-
|
|
118
|
+
// Mechanics ticker, not the narrative -- the strike it triggers tells
|
|
119
|
+
// the story in the world log (readability pass).
|
|
120
|
+
logger.meta(`⚔ [${player.autoStance}] ${cmd}`, 'cyan');
|
|
105
121
|
const result = await this.game.handleInput(cmd);
|
|
106
122
|
// Player-initiated exchanges self-announce ('' result); anything else
|
|
107
123
|
// (a dry-gun reload prompt, a refusal) is information the player needs.
|
|
@@ -141,7 +157,7 @@ export class AutoFight {
|
|
|
141
157
|
static describe(stance) {
|
|
142
158
|
switch (stance) {
|
|
143
159
|
case 'manual': return 'counters when struck (every stance does) -- but pressing the fight is yours to type';
|
|
144
|
-
case 'guarded': return 'presses the fight for you; subdues instead of killing when they are nearly down,
|
|
160
|
+
case 'guarded': return 'presses the fight for you; subdues instead of killing when they are nearly down, and RESTRAINS them when they surrender';
|
|
145
161
|
case 'aggressive': return 'presses the fight to the death; surrender means nothing';
|
|
146
162
|
}
|
|
147
163
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-fight.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/auto-fight.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,OAAO,SAAS;IAKA;IAJpB,MAAM,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAExB,OAAO,CAAiC;IAEhD,YAAoB,IAAU;QAAV,SAAI,GAAJ,IAAI,CAAM;IAAG,CAAC;IAElC,iFAAiF;IACjF,aAAa;QACX,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,UAA4B;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QAChC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO;QACzC,IAAI,MAAM,CAAC,UAAU,KAAK,QAAQ;YAAE,OAAO;QAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;YACzB,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,IAAI,CAAC,MAAoB;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,UAAU,KAAK,QAAQ;YAAE,OAAO;QAC3C,IAAI,MAAM,CAAC,eAAe,EAAE,IAAI,MAAM,CAAC,eAAe,EAAE;YAAE,OAAO;QACjE,IAAI,MAAM,CAAC,eAAe,KAAK,MAAM,CAAC,eAAe;YAAE,OAAO;QAC9D,mEAAmE;QACnE,gEAAgE;QAChE,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;YAAE,OAAO;QAC1C,4DAA4D;QAC5D,qDAAqD;QACrD,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU;YAAE,OAAO;QAEnD,kEAAkE;QAClE,
|
|
1
|
+
{"version":3,"file":"auto-fight.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/auto-fight.ts"],"names":[],"mappings":"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"}
|
|
@@ -91,6 +91,7 @@ export declare class CombatExchange {
|
|
|
91
91
|
second: Player | NPC;
|
|
92
92
|
extraStriker: Player | NPC | null;
|
|
93
93
|
lines: string[];
|
|
94
|
+
metaLines: string[];
|
|
94
95
|
};
|
|
95
96
|
/**
|
|
96
97
|
* The player should see a fight's blow-by-blow only when they're actually
|
|
@@ -108,7 +109,7 @@ export declare class CombatExchange {
|
|
|
108
109
|
* fight an NPC started. The status box refreshes with every block so the
|
|
109
110
|
* condition monitor visibly ticks as damage lands.
|
|
110
111
|
*/
|
|
111
|
-
announce(lines: string[]): Promise<void>;
|
|
112
|
+
announce(lines: string[], meta?: string[]): Promise<void>;
|
|
112
113
|
/**
|
|
113
114
|
* The default, weapon-based strike profile. A firearm with a dry
|
|
114
115
|
* magazine automatically falls back to bare fists -- this covers the
|
|
@@ -117,8 +118,19 @@ export declare class CombatExchange {
|
|
|
117
118
|
* blocked with a reload prompt before ever reaching here (attack.ts).
|
|
118
119
|
*/
|
|
119
120
|
weaponProfile(attacker: Player | NPC, defender: Player | NPC): IStrikeProfile;
|
|
120
|
-
/**
|
|
121
|
-
|
|
121
|
+
/**
|
|
122
|
+
* One directed strike: attack vs defense, then soak. Mutates the
|
|
123
|
+
* defender. Readability split: `meta` carries the dice anatomy
|
|
124
|
+
* (Attack/Defense/Soak rolls, net-hit math) for the Mechanics ticker;
|
|
125
|
+
* `world` carries the narrative -- one compact header with the
|
|
126
|
+
* outcome, then the damage/flavor lines the player feels. Callers
|
|
127
|
+
* rebuild AI-history reports as [...world, ...meta] so an NPC's
|
|
128
|
+
* memory of the fight keeps the dice.
|
|
129
|
+
*/
|
|
130
|
+
resolveStrike(attacker: Player | NPC, defender: Player | NPC, profile?: IStrikeProfile): {
|
|
131
|
+
world: string[];
|
|
132
|
+
meta: string[];
|
|
133
|
+
};
|
|
122
134
|
/**
|
|
123
135
|
* Death/knockout narration is announced BEFORE the removal side effects
|
|
124
136
|
* run -- removeActor() fires the "drops what they carried" observer line
|
|
@@ -128,6 +140,16 @@ export declare class CombatExchange {
|
|
|
128
140
|
* full STUN track -- see cast.ts drain) rather than a death: same
|
|
129
141
|
* out-of-the-run consequences, honestly narrated as unconsciousness.
|
|
130
142
|
*/
|
|
143
|
+
/**
|
|
144
|
+
* The PLAYER dropped from a full STUN track: out of the fight, not out
|
|
145
|
+
* of the game (RAW p.379 "out of action for the rest of the fight";
|
|
146
|
+
* instant death is physical overflow only, p.170). No endGame here --
|
|
147
|
+
* Scene.beginPlayerKnockout defers judgment until the room settles:
|
|
148
|
+
* hostiles all down/surrendered/gone means the player comes to with a
|
|
149
|
+
* Body + Willpower recovery (p.207); a hostile left standing over them
|
|
150
|
+
* with nobody fighting for them means the street decides, as ever.
|
|
151
|
+
*/
|
|
152
|
+
resolvePlayerKnockout(killer: Player | NPC): Promise<string[]>;
|
|
131
153
|
resolveDeath(fallen: Player | NPC, killer: Player | NPC, opts?: {
|
|
132
154
|
fallLine?: string;
|
|
133
155
|
gameOverLine?: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NPC } from '../models/npc.js';
|
|
1
2
|
import { rollPool, formatRoll } from './dice.js';
|
|
2
3
|
import { leaveMatrix, leaveDrone } from './planes.js';
|
|
3
4
|
/**
|
|
@@ -87,13 +88,21 @@ export class CombatExchange {
|
|
|
87
88
|
// not every exchange of it -- "fresh" meaning this pairing wasn't
|
|
88
89
|
// already trading blows moments ago. Armed here (before the opponent
|
|
89
90
|
// bookkeeping overwrites the evidence), cashed in by rollInitiative.
|
|
91
|
+
// The same freshness check prices a SPIRIT companion's combat: one
|
|
92
|
+
// service per FIGHT joined (RAW p.302), ticked when the fight opens.
|
|
90
93
|
const FIGHT_GAP_MS = 60000;
|
|
91
94
|
for (const [combatant, other] of [[this.actor, target], [target, this.actor]]) {
|
|
92
|
-
if (!combatant.hasQuality('combat-paralysis'))
|
|
93
|
-
continue;
|
|
94
95
|
const freshFight = combatant.combatOpponent !== other || now - combatant.lastExchangeAt > FIGHT_GAP_MS;
|
|
95
|
-
if (freshFight)
|
|
96
|
+
if (freshFight && combatant.hasQuality('combat-paralysis'))
|
|
96
97
|
combatant.paralysisFreeze = true;
|
|
98
|
+
if (freshFight) {
|
|
99
|
+
const spiritEntry = this.scene.ownerGame?.companions?.find(c => c.npc === combatant && c.kind === 'spirit');
|
|
100
|
+
if (spiritEntry && (spiritEntry.services ?? 0) > 0) {
|
|
101
|
+
spiritEntry.services = (spiritEntry.services ?? 0) - 1;
|
|
102
|
+
// Resource arithmetic -- Mechanics ticker (readability pass).
|
|
103
|
+
this.logger.meta(`👥 ${combatant.name} joins the fight -- one service spent (${spiritEntry.services} left).`, 'green');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
97
106
|
}
|
|
98
107
|
this.actor.combatOpponent = target;
|
|
99
108
|
this.actor.lastExchangeAt = now;
|
|
@@ -161,12 +170,22 @@ export class CombatExchange {
|
|
|
161
170
|
const net = Math.abs(aggRoll.hits - defRoll.hits);
|
|
162
171
|
const extraStriker = net >= 3 ? first : null;
|
|
163
172
|
this.logger.write(`Initiative: ${aggressor.name} ${aggRoll.hits} vs ${defender.name} ${defRoll.hits} -- ${first.name} first${extraStriker ? ' with an extra strike' : ''}.`);
|
|
173
|
+
// Readability split: the dice anatomy is Mechanics-ticker material
|
|
174
|
+
// (metaLines); the world log keeps only what the player FEELS --
|
|
175
|
+
// who froze, who moves first (lines). Callers rebuild AI-history
|
|
176
|
+
// reports as [...lines, ...metaLines] so NPC memories keep the dice.
|
|
177
|
+
// One line per roller (playtest note: the single "A vs B" line was
|
|
178
|
+
// hard to read) -- each carries its own right-justified wave.
|
|
179
|
+
const metaLines = [
|
|
180
|
+
`Initiative:`,
|
|
181
|
+
` ${aggressor.name}: ${formatRoll(aggRoll)}`,
|
|
182
|
+
` ${defender.name}: ${formatRoll(defRoll)}`,
|
|
183
|
+
];
|
|
164
184
|
const lines = [
|
|
165
185
|
...freezeLines,
|
|
166
|
-
|
|
167
|
-
` ${first.name} moves first.${extraStriker ? ` And they're FAST -- an extra strike this exchange.` : ''}`,
|
|
186
|
+
`${first.name} moves first.${extraStriker ? ` And they're FAST -- an extra strike this exchange.` : ''}`,
|
|
168
187
|
];
|
|
169
|
-
return { first, second, extraStriker, lines };
|
|
188
|
+
return { first, second, extraStriker, lines, metaLines };
|
|
170
189
|
}
|
|
171
190
|
/**
|
|
172
191
|
* The player should see a fight's blow-by-blow only when they're actually
|
|
@@ -190,10 +209,16 @@ export class CombatExchange {
|
|
|
190
209
|
* fight an NPC started. The status box refreshes with every block so the
|
|
191
210
|
* condition monitor visibly ticks as damage lands.
|
|
192
211
|
*/
|
|
193
|
-
async announce(lines) {
|
|
194
|
-
if (lines.length === 0 || !this.playerWitnesses())
|
|
212
|
+
async announce(lines, meta = []) {
|
|
213
|
+
if ((lines.length === 0 && meta.length === 0) || !this.playerWitnesses())
|
|
195
214
|
return;
|
|
196
|
-
|
|
215
|
+
// Dice anatomy ticks in the Mechanics panel; the world log gets the
|
|
216
|
+
// narrative behind a leading blank line -- the per-block separator
|
|
217
|
+
// the old wall-of-text never had (readability pass).
|
|
218
|
+
for (const m of meta)
|
|
219
|
+
this.logger.meta(m);
|
|
220
|
+
if (lines.length > 0)
|
|
221
|
+
this.logger.log(`\n${lines.join('\n')}`);
|
|
197
222
|
this.scene.updateStatus();
|
|
198
223
|
await new Promise(resolve => setTimeout(resolve, CombatExchange.BEAT_MS));
|
|
199
224
|
}
|
|
@@ -254,10 +279,20 @@ export class CombatExchange {
|
|
|
254
279
|
dealStun: fistsAreStun,
|
|
255
280
|
};
|
|
256
281
|
}
|
|
257
|
-
/**
|
|
282
|
+
/**
|
|
283
|
+
* One directed strike: attack vs defense, then soak. Mutates the
|
|
284
|
+
* defender. Readability split: `meta` carries the dice anatomy
|
|
285
|
+
* (Attack/Defense/Soak rolls, net-hit math) for the Mechanics ticker;
|
|
286
|
+
* `world` carries the narrative -- one compact header with the
|
|
287
|
+
* outcome, then the damage/flavor lines the player feels. Callers
|
|
288
|
+
* rebuild AI-history reports as [...world, ...meta] so an NPC's
|
|
289
|
+
* memory of the fight keeps the dice.
|
|
290
|
+
*/
|
|
258
291
|
resolveStrike(attacker, defender, profile) {
|
|
259
292
|
const strike = profile ?? this.weaponProfile(attacker, defender);
|
|
260
|
-
const
|
|
293
|
+
const world = [];
|
|
294
|
+
const meta = [];
|
|
295
|
+
const lines = world; // the damage branches below narrate into the world
|
|
261
296
|
// Firing costs a round; the last one gets a warning line.
|
|
262
297
|
if (strike.weaponItem?.isFirearm()) {
|
|
263
298
|
strike.weaponItem.fireRound();
|
|
@@ -265,29 +300,61 @@ export class CombatExchange {
|
|
|
265
300
|
}
|
|
266
301
|
const attack = rollPool(strike.pool);
|
|
267
302
|
const defense = rollPool(defender.getDefensePool());
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
303
|
+
const header = `${attacker.name} attacks ${defender.name} ${strike.label}`;
|
|
304
|
+
meta.push(`${header}:`);
|
|
305
|
+
meta.push(` Attack: ${formatRoll(attack)}`);
|
|
306
|
+
meta.push(` Defense: ${formatRoll(defense)}`);
|
|
271
307
|
const dryWarning = strike.weaponItem?.isFirearm() && strike.weaponItem.ammo === 0
|
|
272
308
|
? [` ${attacker.name}'s ${strike.weaponItem.name} clicks empty -- that was the last round.`]
|
|
273
309
|
: [];
|
|
274
310
|
const netHits = attack.hits - defense.hits;
|
|
275
311
|
if (attack.criticalGlitch) {
|
|
276
|
-
|
|
277
|
-
return [...
|
|
312
|
+
world.push(`${header} -- and it goes catastrophically wrong: a clean miss, and everyone nearby heard it.`);
|
|
313
|
+
return { world: [...world, ...dryWarning], meta };
|
|
278
314
|
}
|
|
279
315
|
if (netHits <= 0) {
|
|
280
|
-
|
|
281
|
-
return [...
|
|
316
|
+
world.push(`${header} -- ${defender.name} evades.`);
|
|
317
|
+
return { world: [...world, ...dryWarning], meta };
|
|
282
318
|
}
|
|
283
319
|
const incoming = strike.damageBase + netHits;
|
|
284
320
|
const soak = rollPool(strike.soakPool);
|
|
285
321
|
const dealt = Math.max(0, incoming - soak.hits);
|
|
286
|
-
|
|
287
|
-
|
|
322
|
+
meta.push(` Hit! ${netHits} net -- ${incoming} damage incoming.`);
|
|
323
|
+
meta.push(` Soak: ${formatRoll(soak)}`);
|
|
288
324
|
if (dealt === 0) {
|
|
289
|
-
|
|
290
|
-
return [...
|
|
325
|
+
world.push(`${header} -- ${defender.name} shrugs it off; nothing gets through.`);
|
|
326
|
+
return { world: [...world, ...dryWarning], meta };
|
|
327
|
+
}
|
|
328
|
+
world.push(`${header} -- HIT:`);
|
|
329
|
+
// A COMPANION SHELL routes damage into its persistent DEVICE: an
|
|
330
|
+
// autonomous drone's hull (Item.droneDamage), an agent's deck (RAW
|
|
331
|
+
// p.246: attacks on the agent damage the deck -- shared monitor).
|
|
332
|
+
// No biofeedback -- nobody's brain rides a dog-brain. When the
|
|
333
|
+
// device dies, the shell's own track is filled so the caller's
|
|
334
|
+
// normal death flow (resolveDeath -> removeActor -> onActorRemoved)
|
|
335
|
+
// fires without a parallel path.
|
|
336
|
+
if (defender instanceof NPC && defender.boundDevice) {
|
|
337
|
+
const device = defender.boundDevice;
|
|
338
|
+
if (device.isDrone()) {
|
|
339
|
+
device.takeDroneDamage(dealt);
|
|
340
|
+
this.logger.write(`${attacker.name} dealt ${dealt} HULL damage to companion ${defender.name} (${device.droneDamage}/${device.maxDroneBoxes}).`);
|
|
341
|
+
lines.push(` ${defender.name} takes ${dealt} box${dealt === 1 ? '' : 'es'} to the airframe: ${device.droneSummary()}`);
|
|
342
|
+
if (device.isWrecked) {
|
|
343
|
+
defender.takeDamage(defender.maxConditionBoxes);
|
|
344
|
+
lines.push(` The frame comes apart -- rotors, casing, sparks.`);
|
|
345
|
+
}
|
|
346
|
+
return { world: [...lines, ...dryWarning], meta };
|
|
347
|
+
}
|
|
348
|
+
if (device.isCyberdeck()) {
|
|
349
|
+
device.takeDeckDamage(dealt);
|
|
350
|
+
this.logger.write(`${attacker.name} dealt ${dealt} MATRIX damage to agent ${defender.name}'s host deck (${device.deckDamage}/${device.maxDeckBoxes}).`);
|
|
351
|
+
lines.push(` The hit lands on the deck the agent runs on: ${device.deckSummary()}`);
|
|
352
|
+
if (device.isBricked) {
|
|
353
|
+
defender.takeDamage(defender.maxConditionBoxes);
|
|
354
|
+
lines.push(` The deck BRICKS -- the agent derezzes mid-instruction.`);
|
|
355
|
+
}
|
|
356
|
+
return { world: [...lines, ...dryWarning], meta };
|
|
357
|
+
}
|
|
291
358
|
}
|
|
292
359
|
// A JUMPED-IN RIGGER's presence is the airframe: every box lands on
|
|
293
360
|
// the drone's hull monitor, and HALF (rounded up) bleeds through the
|
|
@@ -315,7 +382,7 @@ export class CombatExchange {
|
|
|
315
382
|
lines.push(` ${drone.name} comes apart mid-air -- rotors, casing, sparks --`);
|
|
316
383
|
lines.push(...leaveDrone(this.scene, defender, { forced: true, reason: `The airframe dies around you.` }));
|
|
317
384
|
}
|
|
318
|
-
return [...lines, ...dryWarning];
|
|
385
|
+
return { world: [...lines, ...dryWarning], meta };
|
|
319
386
|
}
|
|
320
387
|
// A jacked-in visitor takes MATRIX damage (only visitors have a
|
|
321
388
|
// simMode -- native ice's normal track IS its integrity, so it takes
|
|
@@ -344,7 +411,7 @@ export class CombatExchange {
|
|
|
344
411
|
lines.push(` ${deck.name} BRICKS -- the persona collapses into static --`);
|
|
345
412
|
lines.push(...leaveMatrix(this.scene, defender, { forced: true, reason: `The ice burns your deck out from under you.` }));
|
|
346
413
|
}
|
|
347
|
-
return [...lines, ...dryWarning];
|
|
414
|
+
return { world: [...lines, ...dryWarning], meta };
|
|
348
415
|
}
|
|
349
416
|
// Deckless: the living persona. Fall through to the stun branch.
|
|
350
417
|
}
|
|
@@ -363,7 +430,7 @@ export class CombatExchange {
|
|
|
363
430
|
this.logger.write(`${attacker.name} dealt ${dealt} boxes to ${defender.name} (${defender.damageTaken}/${defender.maxConditionBoxes}).`);
|
|
364
431
|
lines.push(` ${defender.name} takes ${dealt} box${dealt === 1 ? '' : 'es'}: ${defender.conditionSummary()}`);
|
|
365
432
|
}
|
|
366
|
-
return [...lines, ...dryWarning];
|
|
433
|
+
return { world: [...lines, ...dryWarning], meta };
|
|
367
434
|
}
|
|
368
435
|
/**
|
|
369
436
|
* Death/knockout narration is announced BEFORE the removal side effects
|
|
@@ -374,6 +441,23 @@ export class CombatExchange {
|
|
|
374
441
|
* full STUN track -- see cast.ts drain) rather than a death: same
|
|
375
442
|
* out-of-the-run consequences, honestly narrated as unconsciousness.
|
|
376
443
|
*/
|
|
444
|
+
/**
|
|
445
|
+
* The PLAYER dropped from a full STUN track: out of the fight, not out
|
|
446
|
+
* of the game (RAW p.379 "out of action for the rest of the fight";
|
|
447
|
+
* instant death is physical overflow only, p.170). No endGame here --
|
|
448
|
+
* Scene.beginPlayerKnockout defers judgment until the room settles:
|
|
449
|
+
* hostiles all down/surrendered/gone means the player comes to with a
|
|
450
|
+
* Body + Willpower recovery (p.207); a hostile left standing over them
|
|
451
|
+
* with nobody fighting for them means the street decides, as ever.
|
|
452
|
+
*/
|
|
453
|
+
async resolvePlayerKnockout(killer) {
|
|
454
|
+
const p = this.scene.getPlayer();
|
|
455
|
+
this.logger.write(`CombatExchange: ${killer.name} knocked out ${p.name} (stun-full) -- judgment deferred to the room.`);
|
|
456
|
+
const lines = [`The world tilts and goes dark -- you're out cold on the floor, breathing shallow. The fight goes on without you.`];
|
|
457
|
+
await this.announce(lines);
|
|
458
|
+
this.scene.beginPlayerKnockout([killer.name]);
|
|
459
|
+
return ['', ...lines];
|
|
460
|
+
}
|
|
377
461
|
async resolveDeath(fallen, killer, opts) {
|
|
378
462
|
const room = fallen.currentLocation;
|
|
379
463
|
const isPlayer = fallen === this.scene.getPlayer();
|
|
@@ -405,9 +489,22 @@ export class CombatExchange {
|
|
|
405
489
|
});
|
|
406
490
|
return ['', ...lines];
|
|
407
491
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
492
|
+
// Companions don't die like meat. A spirit's condition track filling
|
|
493
|
+
// is a DISRUPTION -- the vessel ruptures and the spirit snaps back to
|
|
494
|
+
// its own plane (SR5e p.303). An agent derezzes with the deck it runs
|
|
495
|
+
// on, and a drone shell is just machinery coming apart -- none of
|
|
496
|
+
// them have a corpse or gear to scatter (a real session's ice kill
|
|
497
|
+
// read "gear scatters across Grid Vault" for a program).
|
|
498
|
+
const companionKind = fallen instanceof NPC ? fallen.companionKind : undefined;
|
|
499
|
+
const npcFall = companionKind === 'spirit'
|
|
500
|
+
? `${fallen.name} ruptures -- a pressure-drop like the room exhaling -- DISRUPTED, snapped back to its own plane. The binding is over.`
|
|
501
|
+
: companionKind === 'agent'
|
|
502
|
+
? `${fallen.name} DEREZZES -- its icon shears into static and rains out of the grid, gone with the deck that ran it.`
|
|
503
|
+
: companionKind === 'drone'
|
|
504
|
+
? `${fallen.name} comes apart -- rotors, plating, and sparks skidding across ${room.name}. The frame is wrecked.`
|
|
505
|
+
: (opts?.fatal ?? true)
|
|
506
|
+
? `${fallen.name} goes down -- dead before they hit the floor. Their gear scatters across ${room.name}.`
|
|
507
|
+
: `${fallen.name} collapses, out cold -- down for the count. Their gear scatters across ${room.name}.`;
|
|
411
508
|
const lines = [opts?.fallLine ?? npcFall];
|
|
412
509
|
await this.announce(lines);
|
|
413
510
|
// scene.removeActor drops everything they carried AND wore where they
|
|
@@ -432,6 +529,9 @@ export class CombatExchange {
|
|
|
432
529
|
// The fight autopilot's trigger: a settled exchange involving the
|
|
433
530
|
// player schedules their next auto action (see utilities/auto-fight.ts).
|
|
434
531
|
this.scene.notifyExchangeSettled(this._combatants);
|
|
532
|
+
// A spirit whose services ran out departs once the dust settles
|
|
533
|
+
// (RAW p.302: the bargain is spent).
|
|
534
|
+
this.scene.ownerGame?.settleSpiritServices?.();
|
|
435
535
|
if (this.actor === this.scene.getPlayer()) {
|
|
436
536
|
return '';
|
|
437
537
|
}
|