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

100 lines
4.0 KiB
TypeScript

import { DanceRole, CoupleRole } from "../danceCommon.js";
import { SemanticPosition, Facing, HandConnection, HandTo, BalanceWeight, handsInLine, LongLines } from "../interpreterCommon.js";
import { Move } from "../libfigureMapper.js";
import { SemanticAnimationKind } from "../lowLevelMove.js";
import { Hand } from "../rendererConstants.js";
import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, PartialLowLevelMove, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, Variant, VariantCollection, moveInterpreters } from "./_moveInterpreter.js";
const moveName: Move["move"] = "box circulate";
class BoxCirculateSingleVariant extends SingleVariantMoveInterpreter<BoxCirculate, typeof moveName> {
moveAsVariants(previousMoveVariant: string): VariantCollection {
const res = new Map<string, Variant>();
for (const crossPartway of (this.move.note?.includes("catch") ? [true] : [true, false])) {
try {
res.set(crossPartway ? "CrossPartway" : "Normal", {
lowLevelMoves: this.moveAsLowLevelMovesCross(crossPartway),
previousMoveVariant
});
}
catch { }
}
return res;
}
moveAsLowLevelMovesCross(crossPartway: boolean): LowLevelMovesForAllDancers {
const circulateRight: boolean = this.move.parameters.hand;
const whoCrosses = this.move.parameters.who;
return this.handleCircleMove(({ id, startPos }) => {
let isCrossing: boolean;
switch (whoCrosses) {
case "gentlespoons":
isCrossing = id.danceRole === DanceRole.Lark;
break;
case "ladles":
isCrossing = id.danceRole === DanceRole.Robin;
break;
case "ones":
isCrossing = id.coupleRole === CoupleRole.Ones;
break;
case "twos":
isCrossing = id.coupleRole === CoupleRole.Twos;
break;
case "first corners":
case "second corners":
throw "first/second corner leading box circulate doesn't make sense?";
}
// Starts in long wavy lines.
const startingPos: SemanticPosition = {
...startPos,
facing: isCrossing ? startPos.which.facingAcross() : startPos.which.facingOut(),
hands: new Map<Hand, HandConnection>([
[Hand.Left, { hand: Hand.Left, to: HandTo.DancerLeft }],
[Hand.Right, { hand: Hand.Right, to: HandTo.DancerRight }],
]),
balance: undefined,
longLines: undefined,
dancerDistance: undefined,
};
const balance: PartialLowLevelMove[] = this.move.parameters.bal ? [
{
beats: 2,
endPosition: { ...startingPos, balance: circulateRight ? BalanceWeight.Right : BalanceWeight.Left },
movementPattern: { kind: SemanticAnimationKind.Linear },
},
{
beats: 2,
endPosition: { ...startingPos, balance: BalanceWeight.Backward },
movementPattern: { kind: SemanticAnimationKind.Linear },
},
] : [];
const circulate: PartialLowLevelMove = {
beats: this.move.beats - (this.move.parameters.bal ? 4 : 0),
endPosition: {
...startingPos,
which: isCrossing ? startingPos.which.swapAcross() : startingPos.which.swapUpAndDown(),
facing: isCrossing ? startingPos.facing : startingPos.facing === Facing.Right ? Facing.Left : Facing.Right,
longLines: isCrossing && crossPartway ? LongLines.Center : undefined,
},
movementPattern: {
// TODO Not sure loop should really be linear...
kind: SemanticAnimationKind.Linear,
minRotation: isCrossing ? undefined : circulateRight ? 180 : -180,
handsDuring: "None",
}
};
return this.combine([...balance, circulate], startingPos);
});
}
}
class BoxCirculate extends MoveInterpreter<typeof moveName> {
buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter {
return new BoxCirculateSingleVariant(this, startingPos);
}
}
moveInterpreters.set(moveName, BoxCirculate);