contra-renderer/www/js/moves/downTheHall.ts

96 lines
4.5 KiB
TypeScript

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<DownTheHall, typeof moveName> {
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, ShortLinesPosition>([
[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, HandConnection>([
[Hand.Left, { hand: Hand.Left, to: HandTo.DancerLeft }],
[Hand.Right, { hand: Hand.Right, to: HandTo.DancerRight }],
]) : new Map<Hand, HandConnection>([
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<typeof moveName> {
buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter {
return new DownTheHallSingleVariant(this, startingPos);
}
}
moveInterpreters.set(moveName, DownTheHall);