import { BallState, Player, PlayerPhantom } from "../model/tactic/Player" import { middlePos, ratioWithinBase } from "../geo/Pos" import { ComponentId, TacticComponent, TacticContent, } from "../model/tactic/Tactic" import { overlaps } from "../geo/Box" import { Action, ActionKind } from "../model/tactic/Action" import { removeBall, updateComponent } from "./TacticContentDomains" import { getOrigin } from "./PlayerDomains" // export function refreshAllActions( // actions: Action[], // components: TacticComponent[], // ) { // return actions.map((action) => ({ // ...action, // type: getActionKindFrom(action.fromId, action.toId, components), // })) // } export function getActionKindFrom( originId: ComponentId, targetId: ComponentId | null, components: TacticComponent[], ): ActionKind { const origin = components.find((p) => p.id == originId)! const target = components.find((p) => p.id == targetId) let ballState = BallState.NONE if (origin.type == "player" || origin.type == "phantom") { ballState = origin.ballState } let hasTarget = target ? target.type != "phantom" || target.originPlayerId != origin.id : false return getActionKind(hasTarget, ballState) } export function getActionKind( hasTarget: boolean, ballState: BallState, ): ActionKind { switch (ballState) { case BallState.HOLDS: return hasTarget ? ActionKind.SHOOT : ActionKind.DRIBBLE case BallState.SHOOTED: return ActionKind.MOVE case BallState.NONE: return hasTarget ? ActionKind.SCREEN : ActionKind.MOVE } } export function placeArrow( origin: Player | PlayerPhantom, courtBounds: DOMRect, arrowHead: DOMRect, content: TacticContent, ): { createdAction: Action; newContent: TacticContent } { /** * Creates a new phantom component. * Be aware that this function will reassign the `content` parameter. * @param receivesBall */ function createPhantom(receivesBall: boolean): ComponentId { const { x, y } = ratioWithinBase(arrowHead, courtBounds) let itemIndex: number let originPlayer: Player if (origin.type == "phantom") { // if we create a phantom from another phantom, // simply add it to the phantom's path const originPlr = getOrigin(origin, content.components)! itemIndex = originPlr.path!.items.length originPlayer = originPlr } else { // if we create a phantom directly from a player // create a new path and add it into itemIndex = 0 originPlayer = origin } const path = originPlayer.path const phantomId = "phantom-" + itemIndex + "-" + originPlayer.id content = updateComponent( { ...originPlayer, path: { items: path ? [...path.items, phantomId] : [phantomId], }, }, content, ) const ballState = receivesBall ? BallState.HOLDS : origin.ballState == BallState.HOLDS ? BallState.HOLDS : BallState.NONE const phantom: PlayerPhantom = { actions: [], type: "phantom", id: phantomId, rightRatio: x, bottomRatio: y, originPlayerId: originPlayer.id, ballState, } content = { ...content, components: [...content.components, phantom], } return phantom.id } for (const component of content.components) { if (component.id == origin.id) { continue } const componentBounds = document .getElementById(component.id)! .getBoundingClientRect() if (overlaps(componentBounds, arrowHead)) { let toId = component.id if (component.type == "ball") { toId = createPhantom(true) content = removeBall(content) } const action: Action = { target: toId, type: getActionKind(true, origin.ballState), segments: [{ next: component.id }], } return { newContent: updateComponent( { ...origin, actions: [...origin.actions, action], }, content, ), createdAction: action, } } } const phantomId = createPhantom(origin.ballState == BallState.HOLDS) const action: Action = { target: phantomId, type: getActionKind(false, origin.ballState), segments: [{ next: phantomId }], } return { newContent: updateComponent( { ...content.components.find((c) => c.id == origin.id)!, actions: [...origin.actions, action], }, content, ), createdAction: action, } } export function removeAllActionsTargeting( componentId: ComponentId, content: TacticContent, ): TacticContent { let components = [] for (let i = 0; i < content.components.length; i++) { const component = content.components[i] components.push({ ...component, actions: component.actions.filter((a) => a.target != componentId), }) } return { ...content, components, } }