import { Facing, ShortLinesPosition, PositionKind, CirclePosition, SemanticPosition, HandConnection, HandTo, oppositeFacing } from "../interpreterCommon.js"; import { Move } from "../libfigureMapper.js"; import { SemanticAnimationKind } from "../lowLevelMove.js"; import { Hand } from "../rendererConstants.js"; import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, moveInterpreters } from "./_moveInterpreter.js"; const moveName: Move["move"] = "down the hall"; class DownTheHallSingleVariant extends SingleVariantMoveInterpreter { moveAsLowLevelMoves(): LowLevelMovesForAllDancers { if (this.move.parameters.who !== "everyone") { throw new Error("Don't know what it means for not everyone to go down the hall."); } if (this.move.parameters.moving !== "all") { throw new Error("Not sure what it means for not all to be moving in down the hall."); } if (this.move.parameters.ender !== "turn-alone" && this.move.parameters.ender !== "turn-couple") { throw new Error("Unsupported down the hall ender: " + this.move.parameters.ender); } if (this.move.parameters.facing === "forward then backward") { throw new Error("Not sure what " + this.move.parameters.facing + " means for down the hall."); } return this.handleMove(({ startPos }) => { const startFacing = this.move.parameters.facing === "backward" ? Facing.Up : Facing.Down; if (startPos.facing !== startFacing && (startPos.facing === Facing.Up || startPos.facing === Facing.Down)) { throw new Error("Started facing the wrong direction."); } const startWhich: ShortLinesPosition = startPos.kind === PositionKind.ShortLines ? startPos.which // TODO Is this always the right way to convert circle to short lines? // (Does it even matter except for dance starting formations?) : new Map([ [CirclePosition.TopLeft, ShortLinesPosition.FarLeft], [CirclePosition.BottomLeft, ShortLinesPosition.MiddleLeft], [CirclePosition.BottomRight, ShortLinesPosition.MiddleRight], [CirclePosition.TopRight, ShortLinesPosition.FarRight], ]).get(startPos.which)!; const startingPos: SemanticPosition & { kind: PositionKind.ShortLines, setOffset: number } = { kind: PositionKind.ShortLines, facing: startFacing, which: startWhich, hands: startWhich.isMiddle() ? new Map([ [Hand.Left, { hand: Hand.Left, to: HandTo.DancerLeft }], [Hand.Right, { hand: Hand.Right, to: HandTo.DancerRight }], ]) : new Map([ startWhich.isLeft() === (this.move.parameters.facing === "backward") ? [Hand.Left, { hand: Hand.Left, to: HandTo.DancerLeft }] : [Hand.Right, { hand: Hand.Right, to: HandTo.DancerRight }] ]), setOffset: startPos.setOffset ?? 0, lineOffset: startPos.lineOffset, }; return this.combine([ { beats: 4, endPosition: { ...startingPos, setOffset: startingPos.setOffset + 1 }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, { beats: this.move.beats - 4, endPosition: { ...startingPos, setOffset: startingPos.setOffset + 1, facing: oppositeFacing(startFacing), which: this.move.parameters.ender === "turn-alone" ? startWhich : startWhich.swapOnSide(), }, movementPattern: this.move.parameters.ender === "turn-couple" ? { kind: SemanticAnimationKind.TwirlSwap, around: startWhich.leftRightSide(), // !== is NXOR, each of these booleans being flipped flips which hand to use. hand: startWhich.isMiddle() !== (startWhich.isLeft() !== (this.move.parameters.facing === "forward")) ? Hand.Left : Hand.Right } : { kind: SemanticAnimationKind.Linear, minRotation: startWhich.isMiddle() === startWhich.isLeft() ? -180 : +180, }, }, ], startingPos); }); } } class DownTheHall extends MoveInterpreter { buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter { return new DownTheHallSingleVariant(this, startingPos); } } moveInterpreters.set(moveName, DownTheHall);