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 client/src/adapter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ export type WaitingFor =
// "unless they X or Y" punisher class.
| { type: "UnlessPaymentChooseCost"; data: { player: PlayerId; costs: UnlessCost[]; pending_effect: unknown; trigger_event?: unknown; effect_description?: string } }
| { type: "WardDiscardChoice"; data: { player: PlayerId; cards: ObjectId[]; pending_effect: unknown; remaining: number; filter?: unknown } }
| { type: "WardSacrificeChoice"; data: { player: PlayerId; permanents: ObjectId[]; pending_effect: unknown; remaining: number } }
| { type: "WardSacrificeChoice"; data: { player: PlayerId; permanents: ObjectId[]; pending_effect: unknown; remaining: number; min_total_power?: number | null } }
| { type: "UnlessBounceChoice"; data: { player: PlayerId; permanents: ObjectId[]; pending_effect: unknown; remaining: number } }
| { type: "ChooseRingBearer"; data: { player: PlayerId; candidates: ObjectId[] } }
| { type: "RevealUntilKeptChoice"; data: { player: PlayerId; hit_card: ObjectId; source_id: ObjectId; accept_zone: string; decline_zone: string; enter_tapped: boolean; enters_attacking: boolean; revealed_misses: ObjectId[]; rest_destination: string } }
Expand Down
20 changes: 20 additions & 0 deletions client/src/components/board/BattlefieldZoneOverflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,11 @@ function ZoneSummaryTile({ groups, objectIds, zone, onOpen }: ZoneSummaryTilePro
const combatMode = useUiStore((s) => s.combatMode);
const {
activatableObjectIds,
boardChoiceObjectIds,
committedAttackerIds,
incomingAttackerCounts,
manaTappableObjectIds,
selectableSacrificeObjectIds,
validAttackerIds,
validTargetObjectIds,
} = useBoardInteractionState();
Expand All @@ -321,6 +323,8 @@ function ZoneSummaryTile({ groups, objectIds, zone, onOpen }: ZoneSummaryTilePro
let attacking = 0;
let incoming = 0;
let mana = 0;
let boardChoice = 0;
let sacrifice = 0;
let selected = 0;
let validAttackers = 0;
let validTargets = 0;
Expand All @@ -330,6 +334,8 @@ function ZoneSummaryTile({ groups, objectIds, zone, onOpen }: ZoneSummaryTilePro
if (committedAttackerIds.has(id)) attacking++;
incoming += incomingAttackerCounts.get(id) ?? 0;
if (manaTappableObjectIds.has(id)) mana++;
if (boardChoiceObjectIds.has(id)) boardChoice++;
if (selectableSacrificeObjectIds.has(id)) sacrifice++;
if (validAttackerIds.has(id)) validAttackers++;
if (validTargetObjectIds.has(id)) validTargets++;
if (
Expand All @@ -346,18 +352,22 @@ function ZoneSummaryTile({ groups, objectIds, zone, onOpen }: ZoneSummaryTilePro
attacking,
incoming,
mana,
boardChoice,
sacrifice,
selected,
validAttackers: combatMode === "attackers" ? validAttackers : 0,
validTargets,
};
}, [
activatableObjectIds,
boardChoiceObjectIds,
blockerAssignments,
combatMode,
committedAttackerIds,
incomingAttackerCounts,
manaTappableObjectIds,
objectIds,
selectableSacrificeObjectIds,
selectedAttackers,
selectedCardIds,
validAttackerIds,
Expand Down Expand Up @@ -401,6 +411,8 @@ function ZoneSummaryTile({ groups, objectIds, zone, onOpen }: ZoneSummaryTilePro
|| interaction.attacking > 0
|| interaction.incoming > 0
|| interaction.mana > 0
|| interaction.boardChoice > 0
|| interaction.sacrifice > 0
|| interaction.selected > 0
|| interaction.validAttackers > 0
|| interaction.validTargets > 0;
Expand Down Expand Up @@ -494,6 +506,8 @@ interface InteractionSummary {
attacking: number;
incoming: number;
mana: number;
boardChoice: number;
sacrifice: number;
selected: number;
validAttackers: number;
validTargets: number;
Expand All @@ -505,6 +519,12 @@ function InteractionBadges({ interaction }: { interaction: InteractionSummary })
interaction.validTargets > 0
? { key: "target", label: t("battlefieldOverflow.badges.target"), tooltip: t("battlefieldOverflow.badgeTooltips.target"), count: interaction.validTargets, className: "bg-lime-300 text-lime-950" }
: null,
interaction.sacrifice > 0
? { key: "sacrifice", label: t("battlefieldOverflow.badges.sacrifice"), tooltip: t("battlefieldOverflow.badgeTooltips.sacrifice"), count: interaction.sacrifice, className: "bg-red-500 text-white" }
: null,
interaction.boardChoice > interaction.sacrifice
? { key: "choice", label: t("battlefieldOverflow.badges.choice"), tooltip: t("battlefieldOverflow.badgeTooltips.choice"), count: interaction.boardChoice - interaction.sacrifice, className: "bg-sky-400 text-sky-950" }
: null,
interaction.validAttackers > 0
? { key: "attack", label: t("battlefieldOverflow.badges.attack"), tooltip: t("battlefieldOverflow.badgeTooltips.attack"), count: interaction.validAttackers, className: "bg-orange-500 text-white" }
: null,
Expand Down
4 changes: 4 additions & 0 deletions client/src/components/board/BoardInteractionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { createContext, useContext } from "react";

interface BoardInteractionState {
activatableObjectIds: Set<number>;
boardChoiceObjectIds: Set<number>;
committedAttackerIds: Set<number>;
/** Per-permanent count of attackers targeting it (Planeswalker / Battle
* attack targets). Computed once in GameBoard; each card reads O(1). */
incomingAttackerCounts: ReadonlyMap<number, number>;
manaTappableObjectIds: Set<number>;
selectableSacrificeObjectIds: Set<number>;
selectableManaCostCreatureIds: Set<number>;
undoableTapObjectIds: Set<number>;
validAttackerIds: Set<number>;
Expand All @@ -18,9 +20,11 @@ const EMPTY_MAP: ReadonlyMap<number, number> = new Map();

const EMPTY_STATE: BoardInteractionState = {
activatableObjectIds: EMPTY_SET,
boardChoiceObjectIds: EMPTY_SET,
committedAttackerIds: EMPTY_SET,
incomingAttackerCounts: EMPTY_MAP,
manaTappableObjectIds: EMPTY_SET,
selectableSacrificeObjectIds: EMPTY_SET,
selectableManaCostCreatureIds: EMPTY_SET,
undoableTapObjectIds: EMPTY_SET,
validAttackerIds: EMPTY_SET,
Expand Down
22 changes: 22 additions & 0 deletions client/src/components/board/GameBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { sortCreaturesForBlockers } from "../../viewmodel/blockerSorting.ts";
import { isManaObjectAction } from "../../viewmodel/cardActionChoice.ts";
import {
buildPlayerBattlefieldView,
getBoardChoiceView,
getBattlefieldSacrificeChoice,
getWaitingForObjectChoiceIds,
getOpponentIds,
isOneOnOne,
Expand Down Expand Up @@ -70,7 +72,9 @@ export const GameBoard = memo(function GameBoard({ oppHud, playerHud }: GameBoar
const validTargetObjectIds = new Set<number>();
const validAttackerIds = new Set<number>();
const activatableObjectIds = new Set<number>();
const boardChoiceObjectIds = new Set<number>();
const manaTappableObjectIds = new Set<number>();
const selectableSacrificeObjectIds = new Set<number>();
const selectableManaCostCreatureIds = new Set<number>();
const undoableTapObjectIds = new Set<number>();
const committedAttackerIds = new Set<number>();
Expand Down Expand Up @@ -119,6 +123,20 @@ export const GameBoard = memo(function GameBoard({ oppHud, playerHud }: GameBoar
validTargetObjectIds.add(objectId);
}

const sacrificeChoice = getBattlefieldSacrificeChoice(waitingFor);
if (sacrificeChoice && canActForWaitingState) {
for (const objectId of sacrificeChoice.objectIds) {
selectableSacrificeObjectIds.add(objectId);
}
}

const boardChoice = getBoardChoiceView(waitingFor);
if (boardChoice && canActForWaitingState) {
for (const objectId of boardChoice.objectIds) {
boardChoiceObjectIds.add(objectId);
}
}

if (waitingFor?.type === "EquipTarget") {
for (const objectId of waitingFor.data.valid_targets) {
validTargetObjectIds.add(objectId);
Expand All @@ -134,9 +152,11 @@ export const GameBoard = memo(function GameBoard({ oppHud, playerHud }: GameBoar
if (!gameState?.objects) {
return {
activatableObjectIds,
boardChoiceObjectIds,
committedAttackerIds,
incomingAttackerCounts,
manaTappableObjectIds,
selectableSacrificeObjectIds,
selectableManaCostCreatureIds,
undoableTapObjectIds,
validAttackerIds,
Expand Down Expand Up @@ -186,9 +206,11 @@ export const GameBoard = memo(function GameBoard({ oppHud, playerHud }: GameBoar

return {
activatableObjectIds,
boardChoiceObjectIds,
committedAttackerIds,
incomingAttackerCounts,
manaTappableObjectIds,
selectableSacrificeObjectIds,
selectableManaCostCreatureIds,
undoableTapObjectIds,
validAttackerIds,
Expand Down
Loading
Loading