import {Pos, ratioWithinBase} from "../geo/Pos" import {BallState, Player, PlayerInfo, PlayerTeam,} from "../model/tactic/Player" import {Ball, BALL_ID, BALL_TYPE, CourtObject,} from "../model/tactic/CourtObjects" import {ComponentId, TacticComponent, TacticContent,} from "../model/tactic/Tactic" import {overlaps} from "../geo/Box" import {RackedCourtObject, RackedPlayer} from "./RackedItems" import {changePlayerBallState} from "./PlayerDomains" export function placePlayerAt( refBounds: DOMRect, courtBounds: DOMRect, element: RackedPlayer, ): Player { const {x, y} = ratioWithinBase(refBounds, courtBounds) return { type: "player", id: "player-" + element.key + "-" + element.team, team: element.team, role: element.key, rightRatio: x, bottomRatio: y, ballState: BallState.NONE, path: null, actions: [], } } export function placeObjectAt( refBounds: DOMRect, courtBounds: DOMRect, rackedObject: RackedCourtObject, content: TacticContent, ): TacticContent { const {x, y} = ratioWithinBase(refBounds, courtBounds) let courtObject: CourtObject switch (rackedObject.key) { case BALL_TYPE: const playerCollidedIdx = getComponentCollided( refBounds, content.components, BALL_ID, ) if (playerCollidedIdx != -1) { return dropBallOnComponent(playerCollidedIdx, content, true) } courtObject = { type: BALL_TYPE, id: BALL_ID, rightRatio: x, bottomRatio: y, actions: [], } break default: throw new Error("unknown court object " + rackedObject.key) } return { ...content, components: [...content.components, courtObject], } } export function dropBallOnComponent( targetedComponentIdx: number, content: TacticContent, setAsOrigin: boolean ): TacticContent { const component = content.components[targetedComponentIdx] if ((component.type == 'player' || component.type == 'phantom')) { const newState = setAsOrigin ? (component.ballState === BallState.PASSED || component.ballState === BallState.PASSED_ORIGIN) ? BallState.PASSED_ORIGIN : BallState.HOLDS_ORIGIN : BallState.HOLDS_BY_PASS content = changePlayerBallState(component, newState, content) } return removeBall(content) } export function removeBall(content: TacticContent): TacticContent { const ballObjIdx = content.components.findIndex((o) => o.type == "ball") if (ballObjIdx == -1) { return content } return { ...content, components: content.components.toSpliced(ballObjIdx, 1), } } export function placeBallAt( refBounds: DOMRect, courtBounds: DOMRect, content: TacticContent, ): TacticContent { if (!overlaps(courtBounds, refBounds)) { return removeBall(content) } const playerCollidedIdx = getComponentCollided( refBounds, content.components, BALL_ID, ) if (playerCollidedIdx != -1) { return dropBallOnComponent(playerCollidedIdx, content, true) } const ballIdx = content.components.findIndex((o) => o.type == "ball") const {x, y} = ratioWithinBase(refBounds, courtBounds) const ball: Ball = { type: BALL_TYPE, id: BALL_ID, rightRatio: x, bottomRatio: y, actions: [], } let components = content.components if (ballIdx != -1) { components = components.toSpliced(ballIdx, 1, ball) } else { components = components.concat(ball) } return { ...content, components, } } export function moveComponent( newPos: Pos, component: TacticComponent, info: PlayerInfo, courtBounds: DOMRect, content: TacticContent, removed: (content: TacticContent) => TacticContent, ): TacticContent { const playerBounds = document .getElementById(info.id)! .getBoundingClientRect() // if the piece is no longer on the court, remove it if (!overlaps(playerBounds, courtBounds)) { return removed(content) } return updateComponent( { ...component, rightRatio: newPos.x, bottomRatio: newPos.y, }, content, ) } export function removeComponent( componentId: ComponentId, content: TacticContent, ): TacticContent { const componentIdx = content.components.findIndex( (c) => c.id == componentId, ) return { ...content, components: content.components.toSpliced(componentIdx, 1), } } export function updateComponent( component: TacticComponent, content: TacticContent, ): TacticContent { const componentIdx = content.components.findIndex( (c) => c.id == component.id, ) return { ...content, components: content.components.toSpliced(componentIdx, 1, component), } } export function getComponentCollided( bounds: DOMRect, components: TacticComponent[], ignore?: ComponentId, ): number | -1 { for (let i = 0; i < components.length; i++) { const component = components[i] if (component.id == ignore) continue const playerBounds = document .getElementById(component.id)! .getBoundingClientRect() if (overlaps(playerBounds, bounds)) { return i } } return -1 } export function getRackPlayers( team: PlayerTeam, components: TacticComponent[], ): RackedPlayer[] { return ["1", "2", "3", "4", "5"] .filter( (role) => components.findIndex( (c) => c.type == "player" && c.team == team && c.role == role, ) == -1, ) .map((key) => ({team, key})) }