Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/design/ACTION_VOCABULARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
- シンボル・コストの変更は `timedEffect` の内容 `symbolAdd`(同じ色を1つ追加)/`symbolSet { color, count }`(◯色◯つとして扱う)/`symbolLoss { color? }`(指定色を1つ失う。省くと使う人が選ぶ)/`cost { amount }`(増減。元のコストは残らない)。「すべて」のシンボル喪失は `all: true` で、Lv と同じく後から場に出た個体にも書き込む(2026-09-24)
- アタック時⇔ブロック時の効果の付け替えは `timedEffect` の内容 `{ type: "triggerSwap"; from }`。1体は個体の印、`all: true` は `side: "both"`=ゲーム全体の印・`side: "own"`=プレイヤーに掛かる制約(どちらも判定のたびに見るので後から出たスピリットにも効く)(2026-09-24)
- 「このバトルの間、BPの代わりに Lv/コアの数/コストを比べる」は `timedEffect` の内容 `{ type: "compareBy"; by }`、「BPの高い方が破壊される」は `{ type: "invertBattleWinner" }`(期間 `battle`・対象はバトル)。印は `state.battle` に置き、バトル外は不発(2026-09-25)
- 「このターンの間、可能ならば必ずアタックする」は `timedEffect` の内容 `{ type: "mustAttack" }`(期間 `turn`)。1体は個体の印 `mustAttackThisTurn`(既に印がある個体は候補にしない)、「すべて」は `timedRule` で後から出たスピリットにも効く。判定は `shared/rules.ts` の `mustAttackThisTurn`。「好きなだけ指定」(BS12-079)だけ旧 `forceAttackThisTurn` に残す(2026-09-25)
- 「このターンの間、可能ならば必ずアタックする」は `timedEffect` の内容 `{ type: "mustAttack" }`(期間 `turn`)。1体は個体の印 `mustAttackThisTurn`(既に掛かっている個体もそのまま選べる。トリガー抑止も同じ。2026-09-25 ユーザー確認)、「すべて」は `timedRule` で後から出たスピリットにも効く。判定は `shared/rules.ts` の `mustAttackThisTurn`。「好きなだけ指定」(BS12-079)だけ旧 `forceAttackThisTurn` に残す(2026-09-25)
- 「このターンの間、〜の効果は発揮されない」は `timedEffect` の内容 `{ type: "suppressTrigger"; trigger }`(期間 `turn`)。1体は個体の `suppressedTriggersThisTurn`、`all: true` は陣営ごとの `state.triggerSuppressionThisTurn`(陣営は `side`、絞り込みは未対応)。判定は `triggers.ts` の `isTriggerSuppressed`(2026-09-25)
- 「このターンの間、疲労状態でもブロックできる」は `timedEffect` の内容 `{ type: "canBlockWhileRested" }`(期間 `turn`・`side: "own"`)。1体は自分のスピリットから選んで個体の印 `canBlockWhileRestedThisTurn`、`all: true` は `timedRule`。判定は `shared/rules.ts` の `canBlockWhileRestedThisTurn`(2026-09-25)
- 「このターンの間、自分のスピリットに“誘発効果”を与える」は `timedEffect` の内容 `{ type: "grantTrigger"; trigger; action; battleRole? }`(期間 `turn`・`side: "own"`)。1体は自分のスピリットから選んで個体の `tempGrantedTriggers`(`triggers.ts` の `fireTrigger` が静的な効果と合わせて読む)。「すべてに与える」はステップの見出しを期間とする継続効果 `effectGrant`(`phaseTurn`)で書き、`timedEffect` の `all` は未対応(2026-09-25)
Expand Down
7 changes: 5 additions & 2 deletions scripts/smoke/part377.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ console.log("=== 1. 1体:合体していないスピリットだけが候補
assert(combined.mustAttackThisTurn !== true, "合体スピリットは選ばれない")
}

console.log("=== 2. 1体:既に印がある個体は候補にしない(機械神の加護を2回) ===")
console.log("=== 2. 1体:既に掛かっている個体も選べる(機械神の加護を2回。2026-09-25 ユーザー確認) ===")
{
const s = game()
const strong = createInstance(VANILLA, 1, 3)
Expand All @@ -60,7 +60,10 @@ console.log("=== 2. 1体:既に印がある個体は候補にしない(機
refreshLevelAsOverrides(s)
resolveAction(s, "p1", null, mustAttackAction("SD01-032"))
resolveAction(s, "p1", null, mustAttackAction("SD01-032"))
assert(strong.mustAttackThisTurn === true && weak.mustAttackThisTurn === true, "2回目は別の1体に付く")
assert(strong.mustAttackThisTurn === true && weak.mustAttackThisTurn !== true, "自動選択では2回目も実効BP最大の同じ1体")
s.interactiveTargets = true
resolveAction(s, "p1", null, mustAttackAction("SD01-032"))
assert(s.pendingChoice?.candidates.includes(strong.instanceId) === true, "対話では既に掛かっている個体も候補に出る")
}

console.log("=== 3. すべて:解決後に場に出たコスト3以下にも効く(アンブッシュブロッカー) ===")
Expand Down
3 changes: 2 additions & 1 deletion scripts/smoke/part378.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ console.log("=== 2. 1体:月光姫マーニ=実効BP最大の相手1体の
resolveAction(s, "p1", null, suppressAction("BS14-043"))
assert(strong.suppressedTriggersThisTurn?.includes("onAttack") === true, "実効BP最大の1体に印が付く")
assert(weak.suppressedTriggersThisTurn === undefined, "もう1体には付かない")
s.interactiveTargets = true
resolveAction(s, "p1", null, suppressAction("BS14-043"))
assert(weak.suppressedTriggersThisTurn?.includes("onAttack") === true, "既に印がある個体は候補にしない")
assert(s.pendingChoice?.candidates.includes(strong.instanceId) === true, "既に止められている個体も候補に出る(2026-09-25 ユーザー確認)")
}

console.log("すべてのチェックに合格しました 🎉(part378)")
3 changes: 2 additions & 1 deletion server/src/logic/actions/timedEffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ function flagOf(content: Content, duration: TimedEffect["duration"]) {
}

// BP は重ねがけできるので「既に持つ」とは見ない
// 強制アタック・トリガー抑止は、既に掛かっている個体もそのまま選べる(2026-09-25 ユーザー確認)
function has(inst: CardInstance, action: TimedEffect): boolean {
return action.content.every((c) => {
if (c.type === "suppressTrigger") return inst.suppressedTriggersThisTurn?.includes(c.trigger) === true
if (c.type === "mustAttack" || c.type === "suppressTrigger") return false
const flag = flagOf(c, action.duration)
return flag !== null && inst[flag] === true
})
Expand Down
Loading