@maka/maka-cli 5.164.0 → 5.165.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.
|
|
3
|
+
"version": "5.165.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.",
|
|
@@ -28,9 +28,25 @@ export async function runNpcActionPhase(enc, npc) {
|
|
|
28
28
|
const logger = Logger.getInstance();
|
|
29
29
|
if (npc.isIncapacitated() || npc.surrendered)
|
|
30
30
|
return;
|
|
31
|
+
// THE ROOM SEES THE PHASE (aCjJiDDJM9jGZJeER, web run 2026-09-11: "I
|
|
32
|
+
// can't see Hammerhead Joe doing any combat" -- a hostile NPC). The
|
|
33
|
+
// verbs below answer the ACTOR: their return text is second person,
|
|
34
|
+
// goes into the NPC's own history and to a shell's master, and to
|
|
35
|
+
// nobody else. Only an attack that connects narrates through the
|
|
36
|
+
// exchange. So a phase spent readying a gun, reloading, closing the
|
|
37
|
+
// distance or taking cover -- most of a melee NPC's phases -- read to
|
|
38
|
+
// the player as "Joe acts (Initiative 9)." followed by nothing, which
|
|
39
|
+
// is the report. One third-person line per action, room-scoped, the
|
|
40
|
+
// same scope the exchange itself announces on.
|
|
41
|
+
const room = npc.currentLocation;
|
|
42
|
+
const tell = (line) => {
|
|
43
|
+
if (room)
|
|
44
|
+
logger.log(line, { room: room.name });
|
|
45
|
+
};
|
|
31
46
|
const enemies = enc.enemiesOf(npc);
|
|
32
47
|
if (enemies.length === 0) {
|
|
33
48
|
logger.write(`Brain: ${npc.name} has nobody to fight -- phase forfeited.`);
|
|
49
|
+
tell(`${npc.name} looks for a target and finds none.`);
|
|
34
50
|
return;
|
|
35
51
|
}
|
|
36
52
|
const target = pickTarget(npc, enemies);
|
|
@@ -49,8 +65,11 @@ export async function runNpcActionPhase(enc, npc) {
|
|
|
49
65
|
if (weapon && !npc.weaponDrawn) {
|
|
50
66
|
const r = await npc.actInCombat('draw');
|
|
51
67
|
logger.write(`Brain: ${npc.name} draw -> ${r}`);
|
|
52
|
-
if (!npc.weaponDrawn)
|
|
68
|
+
if (!npc.weaponDrawn) {
|
|
69
|
+
tell(`${npc.name} fumbles for ${weapon.name} and comes up empty-handed.`);
|
|
53
70
|
return; // refused -- nothing else will go better
|
|
71
|
+
}
|
|
72
|
+
tell(`${npc.name} readies ${weapon.name}.`);
|
|
54
73
|
continue;
|
|
55
74
|
}
|
|
56
75
|
// 2. A dry gun: reload if the pack allows, else it is a club.
|
|
@@ -58,6 +77,7 @@ export async function runNpcActionPhase(enc, npc) {
|
|
|
58
77
|
if (dry && !weapon.jammed && hasAmmo(npc)) {
|
|
59
78
|
const r = await npc.actInCombat('reload');
|
|
60
79
|
logger.write(`Brain: ${npc.name} reload -> ${r}`);
|
|
80
|
+
tell(`${npc.name} reloads ${weapon.name}.`);
|
|
61
81
|
return; // a reload is the phase (p.163 Reloading Weapons)
|
|
62
82
|
}
|
|
63
83
|
const melee = !firearm || dry || weapon.jammed;
|
|
@@ -68,16 +88,22 @@ export async function runNpcActionPhase(enc, npc) {
|
|
|
68
88
|
logger.write(`Brain: ${npc.name} move to ${targetSpot} -> ${r}`);
|
|
69
89
|
if (!canReach(npc, targetSpot)) {
|
|
70
90
|
// Couldn't close this turn: get behind something and wait.
|
|
91
|
+
tell(`${npc.name} closes on ${target.name} but can't cover the ground this turn.`);
|
|
71
92
|
if (!isInCover(npc) && coverAvailableFor(npc) && (enc.budgetOf(npc)?.simple ?? 0) > 0) {
|
|
72
93
|
await npc.actInCombat('cover');
|
|
94
|
+
if (isInCover(npc))
|
|
95
|
+
tell(`${npc.name} ducks behind cover.`);
|
|
73
96
|
}
|
|
74
97
|
return;
|
|
75
98
|
}
|
|
99
|
+
tell(`${npc.name} closes on ${target.name}.`);
|
|
76
100
|
}
|
|
77
101
|
const b = enc.budgetOf(npc);
|
|
78
102
|
if (b?.complexAvailable) {
|
|
79
103
|
const r = await npc.actInCombat(`attack ${target.name}`);
|
|
80
104
|
logger.write(`Brain: ${npc.name} attack ${target.name} -> ${r.split('\n')[0]}`);
|
|
105
|
+
if (!enc.budgetOf(npc)?.attackTaken)
|
|
106
|
+
tell(`${npc.name} goes for ${target.name} and can't make it count.`);
|
|
81
107
|
}
|
|
82
108
|
return;
|
|
83
109
|
}
|
|
@@ -87,13 +113,18 @@ export async function runNpcActionPhase(enc, npc) {
|
|
|
87
113
|
logger.write(`Brain: ${npc.name} cover -> ${r}`);
|
|
88
114
|
if (!isInCover(npc))
|
|
89
115
|
return;
|
|
116
|
+
tell(`${npc.name} ducks behind cover.`);
|
|
90
117
|
continue;
|
|
91
118
|
}
|
|
92
119
|
if (!budget.attackTaken && budget.simple >= 1) {
|
|
93
120
|
const r = await npc.actInCombat(`attack ${target.name}`);
|
|
94
121
|
logger.write(`Brain: ${npc.name} attack ${target.name} -> ${r.split('\n')[0]}`);
|
|
95
|
-
if (!enc.budgetOf(npc)?.attackTaken)
|
|
122
|
+
if (!enc.budgetOf(npc)?.attackTaken) {
|
|
123
|
+
// The shot was refused (range, line, a jam): the room should
|
|
124
|
+
// see the attempt, not silence.
|
|
125
|
+
tell(`${npc.name} lines up on ${target.name} and the shot doesn't come.`);
|
|
96
126
|
return; // refused: don't loop on it
|
|
127
|
+
}
|
|
97
128
|
continue;
|
|
98
129
|
}
|
|
99
130
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.165.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.",
|