import { BalanceWeight, Facing, HandConnection, HandTo, PositionKind, facingAdjacent, facingRequireAdjacent } from "../interpreterCommon.js"; import { SemanticAnimationKind } from "../lowLevelMove.js"; import { Hand } from "../rendererConstants.js"; import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, MoveInterpreterCtorArgs, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, Variant, VariantCollection, moveInterpreters } from "./_moveInterpreter.js"; const moveName = "balance"; class BalanceSingleVariant extends SingleVariantMoveInterpreter { private static readonly balanceOptions : [BalanceWeight, BalanceWeight | undefined, Hand | undefined][]= [ // TODO Any others? [BalanceWeight.Forward, undefined, undefined], [BalanceWeight.Forward, BalanceWeight.Backward, undefined], // TODO Should be left/right/inside/outside hands? [BalanceWeight.Forward, BalanceWeight.Backward, Hand.Left], [BalanceWeight.Forward, BalanceWeight.Backward, Hand.Right], [BalanceWeight.Right, BalanceWeight.Backward, undefined], [BalanceWeight.Right, BalanceWeight.Left, undefined], [BalanceWeight.Left, BalanceWeight.Right, undefined], ]; moveAsVariants(previousMoveVariant: string): VariantCollection { const res = new Map(); for (const [firstWeight, secondWeight, hand] of BalanceSingleVariant.balanceOptions) { // If balancing someone, need to know by which hand. if ((hand === undefined) !== (this.move.parameters.who === "everyone")) continue; try { res.set((firstWeight?.toString() ?? "") + (secondWeight?.toString() ?? "") + (hand === undefined ? "" : hand.toString() + "Hand"), { lowLevelMoves: this.moveAsLowLevelMovesWeights(firstWeight, secondWeight, hand), previousMoveVariant }); } catch { } } return res; } moveAsLowLevelMovesWeights(firstWeight?: BalanceWeight, secondWeight?: BalanceWeight, hand?: Hand): LowLevelMovesForAllDancers { if (this.move.parameters.who !== "everyone") { return this.handlePairedMove(this.move.parameters.who, ({ startPos, withPos }) => { // TODO Does this need to support balancing inside/outside hands? If so how to identify them? const hands = hand === undefined ? startPos.hands : new Map([[hand, {hand, to: HandTo.DancerForward}]]); const facing = facingRequireAdjacent(startPos, withPos, this.move.move); const startingPos = {...startPos, facing, hands}; return this.combine([ { beats: this.moveInterpreter.balancePartBeats, endPosition: { ...startingPos, balance: firstWeight, hands }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, { beats: this.moveInterpreter.balancePartBeats, endPosition: { ...startingPos, balance: secondWeight, hands }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, ], startingPos); }); } else { return this.handleMove(({ startPos }) => { // TODO Use who to determine facing? // TODO Could be left to right, not back and forth? // TODO How to determine hand... by next move, I guess? if (startPos.kind === PositionKind.Circle && startPos.facing === Facing.CenterOfCircle) { if (firstWeight === BalanceWeight.Left || firstWeight === BalanceWeight.Right || firstWeight === BalanceWeight.Backward || secondWeight === BalanceWeight.Left || secondWeight === BalanceWeight.Right || secondWeight === BalanceWeight.Backward) { throw new Error("Balancing left or right in a circle is unsupported."); } } return this.combine([ { beats: this.moveInterpreter.balancePartBeats, endPosition: { ...startPos, balance: firstWeight }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, { beats: this.moveInterpreter.balancePartBeats, endPosition: { ...startPos, balance: secondWeight }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, ], startPos); }); } } } class Balance extends MoveInterpreter { public readonly balancePartBeats: number; constructor(args: MoveInterpreterCtorArgs) { super(args); this.balancePartBeats = this.move.beats / 2; } buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter { return new BalanceSingleVariant(this, startingPos); } } moveInterpreters.set(moveName, Balance);