You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Application-Web/front/editor/ActionsDomains.ts

197 lines
5.5 KiB

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,
}
}