Mega-Monster offers its choice
"Doubles the existing life-points OR movement rate" — the engine always took the OR's left side because the client never asked. With Mega-Monster selected, the hint bar now offers the choice (hit points lit by default), and the pick rides the cast as params.boost — its own field, freeing params.cardId for the name-a-card spells it belongs to. Both halves of the OR are pinned in the creature suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4e365c168f
commit
fb2266b401
@@ -199,6 +199,8 @@ export interface CastParams {
|
|||||||
cardId?: string;
|
cardId?: string;
|
||||||
points?: number;
|
points?: number;
|
||||||
clockwise?: boolean;
|
clockwise?: boolean;
|
||||||
|
/** MEGA-MONSTER: which stat doubles. */
|
||||||
|
boost?: "life" | "movement";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GameConfig {
|
export interface GameConfig {
|
||||||
@@ -1465,7 +1467,7 @@ const CARD_EFFECTS: Record<string, AttackEffect | NeutralEffect | CounterEffect>
|
|||||||
if (!creature) return "no such monster";
|
if (!creature) return "no such monster";
|
||||||
if (creature.kind === "shadow" || creature.kind === "alter-ego") return "that is no monster";
|
if (creature.kind === "shadow" || creature.kind === "alter-ego") return "that is no monster";
|
||||||
if (!gameLos(state, caster.position, creature.position)) return "no line of sight";
|
if (!gameLos(state, caster.position, creature.position)) return "no line of sight";
|
||||||
const boost = cmd.params?.cardId === "movement" ? "movement" : "life";
|
const boost = cmd.params?.boost === "movement" ? "movement" : "life";
|
||||||
if (boost === "movement") creature.movesPerTurn *= 2;
|
if (boost === "movement") creature.movesPerTurn *= 2;
|
||||||
else creature.maxDamage *= 2;
|
else creature.maxDamage *= 2;
|
||||||
events.push({ type: "monsterBoosted", creatureId: creature.id, boost });
|
events.push({ type: "monsterBoosted", creatureId: creature.id, boost });
|
||||||
|
|||||||
@@ -205,6 +205,16 @@ describe("monsters", () => {
|
|||||||
});
|
});
|
||||||
expect(state.creatures[0]!.maxDamage).toBe(8);
|
expect(state.creatures[0]!.maxDamage).toBe(8);
|
||||||
|
|
||||||
|
// "Doubles the existing life-points OR movement rate" — the other choice.
|
||||||
|
const movesBefore = state.creatures[0]!.movesPerTurn;
|
||||||
|
const mm2 = giveCard(state, me, "mega-monster", "MM2", 3);
|
||||||
|
state = must(state, me, {
|
||||||
|
type: "cast", instanceId: mm2.instanceId, target: { kind: "creature", creatureId: id },
|
||||||
|
params: { boost: "movement" },
|
||||||
|
});
|
||||||
|
expect(state.creatures[0]!.movesPerTurn).toBe(movesBefore * 2);
|
||||||
|
expect(state.creatures[0]!.maxDamage).toBe(8);
|
||||||
|
|
||||||
const dc = giveCard(state, me, "dispel-creation", "DC", 2);
|
const dc = giveCard(state, me, "dispel-creation", "DC", 2);
|
||||||
state = must(state, me, {
|
state = must(state, me, {
|
||||||
type: "cast", instanceId: dc.instanceId, target: { kind: "cell", cell: state.creatures[0]!.position },
|
type: "cast", instanceId: dc.instanceId, target: { kind: "cell", cell: state.creatures[0]!.position },
|
||||||
|
|||||||
@@ -88,6 +88,8 @@
|
|||||||
let tradeFrom = $state<{ x: number; y: number } | null>(null);
|
let tradeFrom = $state<{ x: number; y: number } | null>(null);
|
||||||
/** rotate-sector direction. */
|
/** rotate-sector direction. */
|
||||||
let rotateCW = $state(true);
|
let rotateCW = $state(true);
|
||||||
|
/** mega-monster: which stat the chosen monster doubles. */
|
||||||
|
let megaBoost = $state<"life" | "movement">("life");
|
||||||
/** Cards marked for discard. */
|
/** Cards marked for discard. */
|
||||||
let discardSelection = $state<Set<string>>(new Set());
|
let discardSelection = $state<Set<string>>(new Set());
|
||||||
/** Voluntary discard mode: hand clicks mark cards instead of playing them. */
|
/** Voluntary discard mode: hand clicks mark cards instead of playing them. */
|
||||||
@@ -226,6 +228,7 @@
|
|||||||
tradeFrom = null;
|
tradeFrom = null;
|
||||||
selectedCreature = null;
|
selectedCreature = null;
|
||||||
selectedCard = null;
|
selectedCard = null;
|
||||||
|
megaBoost = "life";
|
||||||
attachedNumber = null;
|
attachedNumber = null;
|
||||||
attachedMods = [];
|
attachedMods = [];
|
||||||
wbDamage = 0;
|
wbDamage = 0;
|
||||||
@@ -614,6 +617,7 @@
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: "cast", instanceId: selectedCard.instanceId,
|
type: "cast", instanceId: selectedCard.instanceId,
|
||||||
target: { kind: "creature", creatureId },
|
target: { kind: "creature", creatureId },
|
||||||
|
...(selectedCard.cardId === "mega-monster" ? { params: { boost: megaBoost } } : {}),
|
||||||
...(attachedNumber ? { numberInstanceIds: [attachedNumber.instanceId] } : {}),
|
...(attachedNumber ? { numberInstanceIds: [attachedNumber.instanceId] } : {}),
|
||||||
});
|
});
|
||||||
clearSelection();
|
clearSelection();
|
||||||
@@ -1378,6 +1382,14 @@
|
|||||||
{:else if selectedCard && TWO_CELL_CARDS.has(selectedCard.cardId)}
|
{:else if selectedCard && TWO_CELL_CARDS.has(selectedCard.cardId)}
|
||||||
<span>{tradeFrom ? "— now the second square" : "— click the first square"}</span>
|
<span>{tradeFrom ? "— now the second square" : "— click the first square"}</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if selectedCard?.cardId === "mega-monster"}
|
||||||
|
<span>— double its</span>
|
||||||
|
<button class="stamp tiny" class:lit={megaBoost === "life"}
|
||||||
|
onclick={() => (megaBoost = "life")}>hit points</button>
|
||||||
|
<button class="stamp tiny" class:lit={megaBoost === "movement"}
|
||||||
|
onclick={() => (megaBoost = "movement")}>movement</button>
|
||||||
|
<span>— then tap the monster</span>
|
||||||
|
{/if}
|
||||||
{#if selectedCard?.cardId === "rotate-sector"}
|
{#if selectedCard?.cardId === "rotate-sector"}
|
||||||
<label class="inline"><input type="checkbox" bind:checked={rotateCW} /> clockwise</label>
|
<label class="inline"><input type="checkbox" bind:checked={rotateCW} /> clockwise</label>
|
||||||
<span>— click the sector</span>
|
<span>— click the sector</span>
|
||||||
@@ -1857,6 +1869,10 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.35);
|
box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.35);
|
||||||
}
|
}
|
||||||
|
.stamp.lit {
|
||||||
|
background: #43331f;
|
||||||
|
color: #e9e1cb;
|
||||||
|
}
|
||||||
.stamp:hover:not(:disabled) { background: #f4eede; }
|
.stamp:hover:not(:disabled) { background: #f4eede; }
|
||||||
.stamp:active:not(:disabled) { transform: translate(1px, 1px); box-shadow: 1px 1px 0 rgba(0,0,0,0.35); }
|
.stamp:active:not(:disabled) { transform: translate(1px, 1px); box-shadow: 1px 1px 0 rgba(0,0,0,0.35); }
|
||||||
.stamp:disabled { opacity: 0.45; cursor: default; }
|
.stamp:disabled { opacity: 0.45; cursor: default; }
|
||||||
|
|||||||
Reference in New Issue
Block a user