@maka/maka-cli 5.152.0 → 5.154.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/game/sideQuest/commands/attack.js +15 -8
- package/bundle/typescript/src/commands/game/sideQuest/commands/reload.js +20 -4
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +14 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-dump.js +2 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +9 -0
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.154.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
|
|
6
6
|
"description": "A command line tool for scaffolding Meteor 3.x applications using React.",
|
|
@@ -211,12 +211,15 @@ export class AttackCommand extends Command {
|
|
|
211
211
|
}
|
|
212
212
|
// A deliberately INITIATED attack with a dry gun is blocked with a
|
|
213
213
|
// reload prompt -- the involuntary strikes (retaliation) auto-fall-back
|
|
214
|
-
// to fists instead (see CombatExchange.weaponProfile).
|
|
214
|
+
// to fists instead (see CombatExchange.weaponProfile). Only a DRAWN
|
|
215
|
+
// gun is actually "in play" for this swing (2jbprbSYqF7EPXrkR) -- a
|
|
216
|
+
// holstered dry/jammed piece is not what's being attacked with, so it
|
|
217
|
+
// must not block a bare-fisted attack the player never asked to fail.
|
|
215
218
|
const weaponItem = this.actor.equipment.rightHand?.weapon ?? this.actor.equipment.leftHand?.weapon;
|
|
216
|
-
if (this.usesEquippedWeapon() && weaponItem?.isFirearm() && weaponItem.jammed) {
|
|
219
|
+
if (this.usesEquippedWeapon() && this.actor.weaponDrawn && weaponItem?.isFirearm() && weaponItem.jammed) {
|
|
217
220
|
return `The ${weaponItem.name}'s smartlink is LOCKED -- someone cracked your PAN. "reboot" to clear it, or go in swinging.`;
|
|
218
221
|
}
|
|
219
|
-
if (this.usesEquippedWeapon() && weaponItem?.isFirearm() && weaponItem.ammo <= 0) {
|
|
222
|
+
if (this.usesEquippedWeapon() && this.actor.weaponDrawn && weaponItem?.isFirearm() && weaponItem.ammo <= 0) {
|
|
220
223
|
return `Click -- the ${weaponItem.name} is dry. "reload" (needs ammunition), or go in swinging with something else.`;
|
|
221
224
|
}
|
|
222
225
|
// THE COMBAT TURN (utilities/combat-turn.ts): on the physical planes
|
|
@@ -360,11 +363,15 @@ export class AttackCommand extends Command {
|
|
|
360
363
|
return notYourPhase(enc, actor);
|
|
361
364
|
}
|
|
362
365
|
enc.noteAttack(actor, target);
|
|
363
|
-
//
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
366
|
+
// A holstered weapon doesn't back this attack -- SR5 always allows a
|
|
367
|
+
// bare-handed strike, and weaponProfile() already resolves the punch's
|
|
368
|
+
// own pool/damage the moment the weapon isn't drawn (the character
|
|
369
|
+
// sheet advertises it: "Attack ... (bare fists) -- holstered"). Only a
|
|
370
|
+
// DRAWN weapon is what this swing is actually attacking WITH; want to
|
|
371
|
+
// shoot or swing the blade instead? READY WEAPON (p.165) is its own
|
|
372
|
+
// Simple Action -- "draw" first (2jbprbSYqF7EPXrkR).
|
|
373
|
+
const activeWeapon = this.usesEquippedWeapon() && actor.weaponDrawn ? weaponItem : undefined;
|
|
374
|
+
const isMelee = !activeWeapon || !activeWeapon.isFirearm();
|
|
368
375
|
const report = [];
|
|
369
376
|
// MELEE REACH: ground costs (p.161-162).
|
|
370
377
|
if (isMelee) {
|
|
@@ -2,6 +2,7 @@ import { Command } from './command.js';
|
|
|
2
2
|
import { Category } from '../types/shared/item-enum.js';
|
|
3
3
|
import { Item } from '../models/item.js';
|
|
4
4
|
import { billAction, encounterOf, phaseHint } from '../utilities/action-cost.js';
|
|
5
|
+
import { fuzzyPickName } from '../utilities/fuzzy-match.js';
|
|
5
6
|
/**
|
|
6
7
|
* Refills the equipped firearm's magazine by consuming one
|
|
7
8
|
* Ammunition-category item from the pack. Every shot spends a round --
|
|
@@ -20,7 +21,7 @@ import { billAction, encounterOf, phaseHint } from '../utilities/action-cost.js'
|
|
|
20
21
|
export class ReloadCommand extends Command {
|
|
21
22
|
static verb = 'reload';
|
|
22
23
|
static description = 'Reload your equipped firearm -- consumes one Ammunition item from your pack. In a fight it takes the whole Action Phase (Remove Clip + Insert Clip, SR5 p.163), or a Free + a Simple with a smartgun you\'re linked to (p.164).';
|
|
23
|
-
async execute(
|
|
24
|
+
async execute(args = []) {
|
|
24
25
|
const actor = this.actor;
|
|
25
26
|
if (this.scene.isHumanControlled(actor) && this.scene.isPlayerExchangeActive(actor.name)) {
|
|
26
27
|
return `No time -- the exchange is still resolving. Reload in the lull.`;
|
|
@@ -32,10 +33,25 @@ export class ReloadCommand extends Command {
|
|
|
32
33
|
if (weapon.ammo >= weapon.magazineCapacity) {
|
|
33
34
|
return `The ${weapon.name} is already fully loaded (${weapon.ammo}/${weapon.magazineCapacity}).`;
|
|
34
35
|
}
|
|
35
|
-
// NON-LETHAL STANCE: stun rounds first if you carry any (gel,
|
|
36
|
-
// stick-n-shock -- p.434); otherwise whatever is in the pack.
|
|
37
36
|
const boxes = actor.inventory.getAllItems().filter(i => i.category === Category.Ammunition);
|
|
38
|
-
|
|
37
|
+
// "reload APDS Rounds" names which box to slap home -- the arg was
|
|
38
|
+
// being silently discarded (bktSfejkhvmjFZ5EH), always loading the
|
|
39
|
+
// stance default instead of what the player actually asked for.
|
|
40
|
+
let ammo;
|
|
41
|
+
if (args.length > 0) {
|
|
42
|
+
const requested = args.join(' ');
|
|
43
|
+
const picked = fuzzyPickName(requested, boxes.map(b => b.name));
|
|
44
|
+
ammo = picked ? boxes.find(b => b.name === picked) : undefined;
|
|
45
|
+
if (!ammo) {
|
|
46
|
+
const present = boxes.map(b => b.name).join(', ') || 'none';
|
|
47
|
+
return `You're not carrying any ammunition named "${requested}" -- carrying: ${present}.`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// NON-LETHAL STANCE: stun rounds first if you carry any (gel,
|
|
52
|
+
// stick-n-shock -- p.434); otherwise whatever is in the pack.
|
|
53
|
+
ammo = (actor.autoStance === 'non-lethal' ? boxes.find(b => Item.isStunAmmo(b)) : undefined) ?? boxes[0];
|
|
54
|
+
}
|
|
39
55
|
if (!ammo) {
|
|
40
56
|
return `No ammunition in your pack -- the ${weapon.name} stays at ${weapon.ammo}/${weapon.magazineCapacity}. Find a spare clip.`;
|
|
41
57
|
}
|
|
@@ -592,10 +592,21 @@ export class Scene extends AbstractScene {
|
|
|
592
592
|
this.logger.write(`Removed actor: ${name}`);
|
|
593
593
|
// A fallen participant's Action Phase, if it was live, moves on;
|
|
594
594
|
// the encounter itself re-checks who is still standing on its next
|
|
595
|
-
// step (utilities/combat-turn.ts run).
|
|
595
|
+
// step (utilities/combat-turn.ts run). But run()'s own stillHostile()
|
|
596
|
+
// check only fires from ITS OWN loop, which never runs again while a
|
|
597
|
+
// human's Action Phase stays open (they can still move/loot before
|
|
598
|
+
// "end turn") -- so killing the last hostile mid-phase left the fight
|
|
599
|
+
// "still going" until the human explicitly ended their turn
|
|
600
|
+
// (5aqFRn2xPtRYDvNxR). Mirrors leave()'s own direct stillHostile()
|
|
601
|
+
// check for the same "nobody left to fight" shape.
|
|
596
602
|
const enc = room ? this.encounterIn(room) : undefined;
|
|
597
|
-
if (enc && enc.
|
|
598
|
-
|
|
603
|
+
if (enc && !enc.ended) {
|
|
604
|
+
if (enc.phaseActor === actor) {
|
|
605
|
+
void enc.dropPhaseActor(actor);
|
|
606
|
+
}
|
|
607
|
+
else if (!enc.stillHostile()) {
|
|
608
|
+
void enc.end('over');
|
|
609
|
+
}
|
|
599
610
|
}
|
|
600
611
|
// Tell the Game an actor left the world -- the companion roster
|
|
601
612
|
// (Game.onActorRemoved) prunes shells and settles their bound
|
|
@@ -130,7 +130,7 @@ function renderRow(item) {
|
|
|
130
130
|
// extra steps (user, 2026-08-30).
|
|
131
131
|
const liveReason = liveReasonOf(item.repro);
|
|
132
132
|
Log.plain(liveReason
|
|
133
|
-
? ` ${Log.colors.warn(`${liveReason} -- card: maka play
|
|
133
|
+
? ` ${Log.colors.warn(`${liveReason} -- card: maka play:backlog ${item._id}`)}`
|
|
134
134
|
: ` ${Log.colors.success(`bench: maka play --repro ${item._id}`)}${benchLockNote(item)}`);
|
|
135
135
|
}
|
|
136
136
|
}
|
|
@@ -286,7 +286,7 @@ export async function dumpBacklog(opts = {}) {
|
|
|
286
286
|
if (!found) {
|
|
287
287
|
if (!items.some(it => it._id.startsWith(id))) {
|
|
288
288
|
Log.error(`No item with id "${id}" on the board${filter ? ` in ${filter}` : ''}.`);
|
|
289
|
-
Log.info('`maka play
|
|
289
|
+
Log.info('`maka play:backlog` lists them -- every row carries its id.');
|
|
290
290
|
}
|
|
291
291
|
return;
|
|
292
292
|
}
|
|
@@ -956,6 +956,15 @@ export class CombatExchange {
|
|
|
956
956
|
// icon must drop to ☹ the moment they go down, not on the
|
|
957
957
|
// player's next step.
|
|
958
958
|
this.scene.updateExits(room);
|
|
959
|
+
// Same "combat sat there until 'end turn'" gap as removeActor
|
|
960
|
+
// below (5aqFRn2xPtRYDvNxR): a KO'd-not-killed last hostile also
|
|
961
|
+
// stops being present() (isIncapacitated), but nothing re-runs
|
|
962
|
+
// run()'s own stillHostile() check while the killer's own Action
|
|
963
|
+
// Phase stays open. End it directly, the same way leave() does.
|
|
964
|
+
const koEnc = this.scene.encounterFor?.(fallen);
|
|
965
|
+
if (koEnc && !koEnc.ended && koEnc.phaseActor !== fallen && !koEnc.stillHostile()) {
|
|
966
|
+
void koEnc.end('over');
|
|
967
|
+
}
|
|
959
968
|
return ['', ...lines];
|
|
960
969
|
}
|
|
961
970
|
// A BODY ALWAYS FORMS (except for companion shells, which leave
|
|
@@ -333,7 +333,7 @@ const ShadowrunCommand = Command.create({
|
|
|
333
333
|
}
|
|
334
334
|
if (found.outcome === 'not-found') {
|
|
335
335
|
Log.error(`Nothing in your review queue matches "${reproTarget}".`);
|
|
336
|
-
Log.info('`maka play
|
|
336
|
+
Log.info('`maka play:backlog --filter in-review` lists them, with ids.');
|
|
337
337
|
return;
|
|
338
338
|
}
|
|
339
339
|
if (found.outcome === 'no-repro') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.154.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
|
|
6
6
|
"description": "A command line tool for scaffolding Meteor 3.x applications using React.",
|