import { BallState, Player, PlayerPhantom } from "../model/tactic/Player" import { TacticComponent, TacticContent } from "../model/tactic/Tactic" import { removeComponent, updateComponent } from "./TacticContentDomains" import { removeAllActionsTargeting, spreadNewStateFromOriginStateChange, } from "./ActionsDomains" import { ActionKind } from "../model/tactic/Action" export function getOrigin( pathItem: PlayerPhantom, components: TacticComponent[], ): Player { // Trust the components to contains only phantoms with valid player origin identifiers return components.find((c) => c.id == pathItem.originPlayerId)! as Player } export function areInSamePath( a: Player | PlayerPhantom, b: Player | PlayerPhantom, ) { if (a.type === "phantom" && b.type === "phantom") { return a.originPlayerId === b.originPlayerId } if (a.type === "phantom") { return b.id === a.originPlayerId } if (b.type === "phantom") { return a.id === b.originPlayerId } return false } /** * @param origin * @param other * @param components * @returns true if the `other` player is the phantom next-to the origin's path. */ export function isNextInPath( origin: Player | PlayerPhantom, other: Player | PlayerPhantom, components: TacticComponent[], ): boolean { if (origin.type === "player") { return origin.path?.items[0] === other.id } const originPath = getOrigin(origin, components).path! return ( originPath.items!.indexOf(origin.id) === originPath.items!.indexOf(other.id) - 1 ) } export function removePlayerPath( player: Player, content: TacticContent, ): TacticContent { if (player.path == null) { return content } for (const pathElement of player.path.items) { content = removeComponent(pathElement, content) content = removeAllActionsTargeting(pathElement, content) } return updateComponent( { ...player, path: null, }, content, ) } export function removePlayer( player: Player | PlayerPhantom, content: TacticContent, ): TacticContent { content = removeAllActionsTargeting(player.id, content) if (player.type == "phantom") { const origin = getOrigin(player, content.components) return truncatePlayerPath(origin, player, content) } content = removePlayerPath(player, content) content = removeComponent(player.id, content) for (const action of player.actions) { if (action.type !== ActionKind.SHOOT) { continue } const actionTarget = content.components.find( (c) => c.id === action.target, )! as Player | PlayerPhantom return spreadNewStateFromOriginStateChange( actionTarget, BallState.NONE, content, ) } return content } export function truncatePlayerPath( player: Player, phantom: PlayerPhantom, content: TacticContent, ): TacticContent { if (player.path == null) return content const path = player.path! const truncateStartIdx = path.items.indexOf(phantom.id) for (let i = truncateStartIdx; i < path.items.length; i++) { const pathPhantomId = path.items[i] //remove the phantom from the tactic content = removeComponent(pathPhantomId, content) content = removeAllActionsTargeting(pathPhantomId, content) } return updateComponent( { ...player, path: truncateStartIdx == 0 ? null : { ...path, items: path.items.toSpliced(truncateStartIdx), }, }, content, ) } export function changePlayerBallState( player: Player | PlayerPhantom, newState: BallState, content: TacticContent, ): TacticContent { return spreadNewStateFromOriginStateChange(player, newState, content) }