Resolve Family Atomics with concealed No-Field forces
This commit is contained in:
1 parent
28df687bf9
commit
57a59c1663
13 files changed
+511
-24
No files matched your search
+14
-4
@@ -1,6 +1,7 @@
|
||||
import { fighterCount, isAdvisor } from './advisors';
|
||||
import { splitLocation, TERRITORIES } from './board';
|
||||
import type { OrdinaryCardPlayer } from './card-availability';
|
||||
import { presenceByLocation } from './force-presence';
|
||||
|
||||
export type FamilyAtomicsState = {
|
||||
advanced?: boolean;
|
||||
@@ -12,7 +13,7 @@ export type FamilyAtomicsState = {
|
||||
stormCardWindowOpen?: boolean;
|
||||
stormResolution?: unknown;
|
||||
};
|
||||
export type FamilyAtomicsPlayer = Pick<OrdinaryCardPlayer, 'id' | 'faction' | 'forces' | 'advisors'>;
|
||||
export type FamilyAtomicsPlayer = Pick<OrdinaryCardPlayer, 'id' | 'faction' | 'forces' | 'advisors' | 'noField'>;
|
||||
|
||||
const wall = TERRITORIES.find(territory => territory.id === 'shield_wall')!;
|
||||
const nearby = TERRITORIES.filter(territory => territory.id === wall.id || territory.neighbors.includes(wall.id));
|
||||
@@ -24,8 +25,17 @@ const nearby = TERRITORIES.filter(territory => territory.id === wall.id || terri
|
||||
export function familyAtomicsBlock(state: FamilyAtomicsState, player: FamilyAtomicsPlayer): string | null {
|
||||
if (state.shieldWallDestroyed || state.phase !== 0 || state.stormCardWindowOpen === false || state.stormResolution)
|
||||
return 'Play Family Atomics before storm movement.';
|
||||
// A concealed No-Field is one force for all effects (supplied physical36 B),
|
||||
// including denomination0. Its public location suffices; never read private
|
||||
// value, reserve capacity or token inventory merely to qualify this card.
|
||||
const marker = player.noField?.deployed;
|
||||
const markerHere = marker?.controller === player.id && nearby.some(territory =>
|
||||
territory.id === marker.location.territory && territory.sectors.includes(marker.location.sector));
|
||||
const forces = presenceByLocation({ forces: player.forces,
|
||||
noField: markerHere ? { deployed: { location: marker!.location } } : null });
|
||||
const effective = { faction: player.faction, advisors: player.advisors, forces };
|
||||
if (!state.advanced)
|
||||
return nearby.some(territory => fighterCount(player, territory.id) > 0)
|
||||
return nearby.some(territory => fighterCount(effective, territory.id) > 0)
|
||||
? null : 'You need forces on or adjacent to the Shield Wall.';
|
||||
if (!Number.isSafeInteger(state.turn) || (state.turn ?? 0) <= 1)
|
||||
return 'Play Family Atomics after the first game turn.';
|
||||
@@ -35,7 +45,7 @@ export function familyAtomicsBlock(state: FamilyAtomicsState, player: FamilyAtom
|
||||
if (!Number.isSafeInteger(state.storm) || (state.storm ?? -1) < 0 || (state.storm ?? 19) > 18)
|
||||
return 'Family Atomics needs the current storm position.';
|
||||
const storm = state.storm!;
|
||||
const qualified = Object.entries(player.forces).some(([key, amount]) => {
|
||||
const qualified = Object.entries(forces).some(([key, amount]) => {
|
||||
if (!Number.isSafeInteger(amount) || amount <= 0) return false;
|
||||
const source = splitLocation(key);
|
||||
const territory = nearby.find(candidate => candidate.id === source.territory);
|
||||
@@ -48,5 +58,5 @@ export function familyAtomicsBlock(state: FamilyAtomicsState, player: FamilyAtom
|
||||
return !(storm > first && storm < last);
|
||||
});
|
||||
});
|
||||
return qualified ? null : 'You need physical fighters on or adjacent to the Shield Wall with no intervening storm.';
|
||||
return qualified ? null : 'You need fighters on or adjacent to the Shield Wall with no intervening storm.';
|
||||
}
|
||||
Reference in new issue
Block a user