|
|
@ -1,34 +1,13 @@
|
|
|
|
import { equals, Pos, ratioWithinBase } from "../geo/Pos"
|
|
|
|
import { equals, Pos, ratioWithinBase } from "../geo/Pos"
|
|
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
import { BallState, Player, PlayerInfo, PlayerLike, PlayerPhantom, PlayerTeam } from "../model/tactic/Player"
|
|
|
|
BallState,
|
|
|
|
import { Ball, BALL_ID, BALL_TYPE, CourtObject } from "../model/tactic/CourtObjects"
|
|
|
|
Player,
|
|
|
|
import { ComponentId, StepContent, TacticComponent } from "../model/tactic/Tactic"
|
|
|
|
PlayerInfo,
|
|
|
|
|
|
|
|
PlayerLike,
|
|
|
|
|
|
|
|
PlayerPhantom,
|
|
|
|
|
|
|
|
PlayerTeam,
|
|
|
|
|
|
|
|
} from "../model/tactic/Player"
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
|
|
Ball,
|
|
|
|
|
|
|
|
BALL_ID,
|
|
|
|
|
|
|
|
BALL_TYPE,
|
|
|
|
|
|
|
|
CourtObject,
|
|
|
|
|
|
|
|
} from "../model/tactic/CourtObjects"
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
|
|
ComponentId,
|
|
|
|
|
|
|
|
StepContent,
|
|
|
|
|
|
|
|
TacticComponent,
|
|
|
|
|
|
|
|
} from "../model/tactic/Tactic"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import { overlaps } from "../geo/Box"
|
|
|
|
import { overlaps } from "../geo/Box"
|
|
|
|
import { RackedCourtObject, RackedPlayer } from "./RackedItems"
|
|
|
|
import { RackedCourtObject, RackedPlayer } from "./RackedItems"
|
|
|
|
import {
|
|
|
|
import { getComponent, getOrigin, getPrecomputedPosition, removePlayer, tryGetComponent } from "./PlayerDomains"
|
|
|
|
getComponent,
|
|
|
|
import { Action, ActionKind } from "../model/tactic/Action.ts"
|
|
|
|
getOrigin,
|
|
|
|
|
|
|
|
getPrecomputedPosition,
|
|
|
|
|
|
|
|
tryGetComponent,
|
|
|
|
|
|
|
|
} from "./PlayerDomains"
|
|
|
|
|
|
|
|
import { ActionKind } from "../model/tactic/Action.ts"
|
|
|
|
|
|
|
|
import { spreadNewStateFromOriginStateChange } from "./ActionsDomains.ts"
|
|
|
|
import { spreadNewStateFromOriginStateChange } from "./ActionsDomains.ts"
|
|
|
|
|
|
|
|
|
|
|
|
export function placePlayerAt(
|
|
|
|
export function placePlayerAt(
|
|
|
@ -200,9 +179,9 @@ export function moveComponent(
|
|
|
|
phantomIdx == 0
|
|
|
|
phantomIdx == 0
|
|
|
|
? origin
|
|
|
|
? origin
|
|
|
|
: getComponent(
|
|
|
|
: getComponent(
|
|
|
|
originPathItems[phantomIdx - 1],
|
|
|
|
originPathItems[phantomIdx - 1],
|
|
|
|
content.components,
|
|
|
|
content.components,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
// detach the action from the screen target and transform it to a regular move action to the phantom.
|
|
|
|
// detach the action from the screen target and transform it to a regular move action to the phantom.
|
|
|
|
content = updateComponent(
|
|
|
|
content = updateComponent(
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -210,18 +189,18 @@ export function moveComponent(
|
|
|
|
actions: playerBeforePhantom.actions.map((a) =>
|
|
|
|
actions: playerBeforePhantom.actions.map((a) =>
|
|
|
|
a.target === referent
|
|
|
|
a.target === referent
|
|
|
|
? {
|
|
|
|
? {
|
|
|
|
...a,
|
|
|
|
...a,
|
|
|
|
segments: a.segments.toSpliced(
|
|
|
|
segments: a.segments.toSpliced(
|
|
|
|
a.segments.length - 2,
|
|
|
|
a.segments.length - 2,
|
|
|
|
1,
|
|
|
|
1,
|
|
|
|
{
|
|
|
|
{
|
|
|
|
...a.segments[a.segments.length - 1],
|
|
|
|
...a.segments[a.segments.length - 1],
|
|
|
|
next: component.id,
|
|
|
|
next: component.id,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
target: component.id,
|
|
|
|
target: component.id,
|
|
|
|
type: ActionKind.MOVE,
|
|
|
|
type: ActionKind.MOVE,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
: a,
|
|
|
|
: a,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
},
|
|
|
@ -234,9 +213,9 @@ export function moveComponent(
|
|
|
|
...component,
|
|
|
|
...component,
|
|
|
|
pos: isPhantom
|
|
|
|
pos: isPhantom
|
|
|
|
? {
|
|
|
|
? {
|
|
|
|
type: "fixed",
|
|
|
|
type: "fixed",
|
|
|
|
...newPos,
|
|
|
|
...newPos,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
: newPos,
|
|
|
|
: newPos,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
content,
|
|
|
|
content,
|
|
|
@ -321,9 +300,9 @@ export function computeTerminalState(
|
|
|
|
comp.type === "player"
|
|
|
|
comp.type === "player"
|
|
|
|
? getPlayerTerminalState(comp, content, computedPositions)
|
|
|
|
? getPlayerTerminalState(comp, content, computedPositions)
|
|
|
|
: {
|
|
|
|
: {
|
|
|
|
...comp,
|
|
|
|
...comp,
|
|
|
|
frozen: true,
|
|
|
|
frozen: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
@ -458,14 +437,12 @@ export function drainTerminalStateOnChildContent(
|
|
|
|
|
|
|
|
|
|
|
|
const initialChildCompsCount = childContent.components.length
|
|
|
|
const initialChildCompsCount = childContent.components.length
|
|
|
|
|
|
|
|
|
|
|
|
//filter out all frozen components that are not present on the parent's terminal state anymore
|
|
|
|
for (const component of childContent.components) {
|
|
|
|
childContent = {
|
|
|
|
if (component.type !== "phantom" && component.frozen && !tryGetComponent(component.id, parentTerminalState.components)) {
|
|
|
|
components: childContent.components.filter(
|
|
|
|
if (component.type === "player")
|
|
|
|
(comp) =>
|
|
|
|
childContent = removePlayer(component, childContent)
|
|
|
|
comp.type === "phantom" ||
|
|
|
|
else childContent = {...childContent, components: childContent.components.filter(c => c.id !== component.id)}
|
|
|
|
!comp.frozen ||
|
|
|
|
}
|
|
|
|
tryGetComponent(comp.id, parentTerminalState.components),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gotUpdated ||= childContent.components.length !== initialChildCompsCount
|
|
|
|
gotUpdated ||= childContent.components.length !== initialChildCompsCount
|
|
|
@ -474,25 +451,45 @@ export function drainTerminalStateOnChildContent(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function mapToParentContent(content: StepContent): StepContent {
|
|
|
|
export function mapToParentContent(content: StepContent): StepContent {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function mapToParentActions(actions: Action[]): Action[] {
|
|
|
|
|
|
|
|
return actions.map((a) => ({
|
|
|
|
|
|
|
|
...a,
|
|
|
|
|
|
|
|
target: a.target + "-parent",
|
|
|
|
|
|
|
|
segments: a.segments.map((s) => ({
|
|
|
|
|
|
|
|
...s,
|
|
|
|
|
|
|
|
next:
|
|
|
|
|
|
|
|
typeof s.next === "string"
|
|
|
|
|
|
|
|
? s.next + "-parent"
|
|
|
|
|
|
|
|
: s.next,
|
|
|
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
...content,
|
|
|
|
...content,
|
|
|
|
components: content.components.map((p) => {
|
|
|
|
components: content.components.map((p) => {
|
|
|
|
if (p.type == "ball") return p
|
|
|
|
if (p.type == "ball") return p
|
|
|
|
|
|
|
|
if (p.type == "player") {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
...p,
|
|
|
|
|
|
|
|
id: p.id + "-parent",
|
|
|
|
|
|
|
|
actions: mapToParentActions(p.actions),
|
|
|
|
|
|
|
|
path: p.path && { items: p.path.items.map(p => p + "-parent") },
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
...p,
|
|
|
|
...p,
|
|
|
|
|
|
|
|
pos: p.pos.type == "follows" ? { ...p.pos, attach: p.pos.attach + "-parent" } : p.pos,
|
|
|
|
id: p.id + "-parent",
|
|
|
|
id: p.id + "-parent",
|
|
|
|
actions: p.actions.map((a) => ({
|
|
|
|
originPlayerId: p.originPlayerId + "-parent",
|
|
|
|
...a,
|
|
|
|
actions: mapToParentActions(p.actions),
|
|
|
|
target: a.target + "-parent",
|
|
|
|
|
|
|
|
segments: a.segments.map((s) => ({
|
|
|
|
|
|
|
|
...s,
|
|
|
|
|
|
|
|
next:
|
|
|
|
|
|
|
|
typeof s.next === "string"
|
|
|
|
|
|
|
|
? s.next + "-parent"
|
|
|
|
|
|
|
|
: s.next,
|
|
|
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function selectContent(id: string, content: StepContent, parentContent: StepContent | null): StepContent {
|
|
|
|
|
|
|
|
return parentContent && id.endsWith("-parent") ? parentContent : content
|
|
|
|
|
|
|
|
}
|