@maka/maka-cli 5.152.0 → 5.153.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.152.0",
3
+ "version": "5.153.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
- // READY WEAPON (p.165) is an action, not a beat.
364
- if (this.usesEquippedWeapon() && weaponItem && !actor.weaponDrawn) {
365
- return `The ${weaponItem.name} is holstered -- "draw" it first (Ready Weapon, a Simple Action, SR5 p.165).${phaseHint(this.scene, actor)}`;
366
- }
367
- const isMelee = !this.usesEquippedWeapon() || !weaponItem?.isFirearm();
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) {
@@ -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.phaseActor === actor) {
598
- void enc.dropPhaseActor(actor);
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
@@ -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.152.0",
3
+ "version": "5.153.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.",