|
|
|
@ -201,7 +201,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getPosFor(id: common.ExtendedDancerIdentity) {
|
|
|
|
|
function getPosFor(id: common.ExtendedDancerIdentity): SemanticPosition & { setOffset: number, lineOffset: number } {
|
|
|
|
|
const basePos = startingPos.get(id.setIdentity)!;
|
|
|
|
|
return {...basePos,
|
|
|
|
|
setOffset: (basePos.setOffset ?? 0) + id.relativeSet,
|
|
|
|
@ -231,19 +231,92 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const res = new Map<DancerIdentity, LowLevelMove[]>();
|
|
|
|
|
function handleMove(dancerFunc: ((arg: { id: DancerIdentity, startPos: SemanticPosition }) => LowLevelMove[])): Map<DancerIdentity, LowLevelMove[]> {
|
|
|
|
|
const res = new Map<DancerIdentity, LowLevelMove[]>();
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
res.set(id, dancerFunc({ id, startPos }));
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleCircleMove(dancerFunc: ((arg: { id: DancerIdentity, startPos: SemanticPosition & { kind: PositionKind.Circle } }) => LowLevelMove[])): Map<DancerIdentity, LowLevelMove[]> {
|
|
|
|
|
return handleMove(({ id, startPos }) => {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dancerFunc({ id, startPos });
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handlePairedMove(who: chooser_pairz, dancerFunc: ((arg: {
|
|
|
|
|
id: DancerIdentity,
|
|
|
|
|
startPos: SemanticPosition,
|
|
|
|
|
withPos: SemanticPosition & { setOffset: number, lineOffset: number },
|
|
|
|
|
withId: common.ExtendedDancerIdentity,
|
|
|
|
|
around: CircleSideOrCenter,
|
|
|
|
|
}) => LowLevelMove[])): Map<DancerIdentity, LowLevelMove[]> {
|
|
|
|
|
return handleMove(({ id, startPos }) => {
|
|
|
|
|
const withId = findPairOpposite(who, id);
|
|
|
|
|
if (!withId) {
|
|
|
|
|
return combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]);
|
|
|
|
|
}
|
|
|
|
|
const withPos = getPosFor(withId);
|
|
|
|
|
const setDifference = withPos.setOffset - (startPos.setOffset ?? 0);
|
|
|
|
|
let startPosAdjusted = startPos;
|
|
|
|
|
if (setDifference !== 0) {
|
|
|
|
|
// TODO Can move be with a different short line or just a different circle?
|
|
|
|
|
// PassBy can probably be with the next short line...
|
|
|
|
|
if (startPos.kind === PositionKind.Circle && (setDifference === 1 || setDifference === -1)) {
|
|
|
|
|
startPosAdjusted = {
|
|
|
|
|
...startPos,
|
|
|
|
|
setOffset: (startPos.setOffset ?? 0) + setDifference / 2,
|
|
|
|
|
which: startPos.which.swapUpAndDown(),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throw "Not near dancer to " + move.move + " with.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const startWhich = startPosAdjusted.which;
|
|
|
|
|
// TODO Can swing be across the set (top or bottom)?
|
|
|
|
|
const around = withPos.kind === PositionKind.Circle
|
|
|
|
|
? (withPos.which.leftRightSide() === startWhich.leftRightSide()
|
|
|
|
|
? startWhich.leftRightSide()
|
|
|
|
|
: startWhich instanceof CirclePosition && withPos.which.topBottomSide() === startWhich.topBottomSide()
|
|
|
|
|
? startWhich.topBottomSide()
|
|
|
|
|
: "Center")
|
|
|
|
|
: "Center";
|
|
|
|
|
|
|
|
|
|
return dancerFunc({ id, startPos: startPosAdjusted, withId, withPos, around });
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleCirclePairedMove(who: chooser_pairz, dancerFunc: ((arg: {
|
|
|
|
|
id: DancerIdentity,
|
|
|
|
|
startPos: SemanticPosition & { kind: PositionKind.Circle },
|
|
|
|
|
withPos: SemanticPosition & { setOffset: number, lineOffset: number },
|
|
|
|
|
withId: common.ExtendedDancerIdentity,
|
|
|
|
|
around: CircleSideOrCenter,
|
|
|
|
|
}) => LowLevelMove[])): Map<DancerIdentity, LowLevelMove[]> {
|
|
|
|
|
return handlePairedMove(who, ({ id, startPos, withId, withPos, around }) => {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dancerFunc({ id, startPos, withId, withPos, around });
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (move.move) {
|
|
|
|
|
case "balance the ring":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
res.set(id, balanceCircleInAndOut(move, startPos));
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
return handleCircleMove(({ startPos }) => balanceCircleInAndOut(move, startPos));
|
|
|
|
|
case "petronella":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handleCircleMove(({ startPos }) => {
|
|
|
|
|
// TODO These should be actual parameters, not parsing the notes...
|
|
|
|
|
const rightShoulder: boolean = !(move.note?.includes('left') ?? false);
|
|
|
|
|
const newCircle: boolean = move.note?.includes('end facing') ?? false;
|
|
|
|
@ -262,52 +335,37 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const spin: ((prevEnd: SemanticPosition) => PartialLowLevelMove) = prevEnd => ({
|
|
|
|
|
beats: move.beats - (move.parameters.bal ? 4 : 0),
|
|
|
|
|
startPosition: {
|
|
|
|
|
...prevEnd,
|
|
|
|
|
facing: Facing.CenterOfCircle,
|
|
|
|
|
hands: undefined,
|
|
|
|
|
},
|
|
|
|
|
endPosition: finalPosition,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.Linear,
|
|
|
|
|
minRotation: rightShoulder ? 180 : -180,
|
|
|
|
|
handsDuring: "None",
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (move.parameters.bal) {
|
|
|
|
|
const balance: LowLevelMove[] = balanceCircleInAndOut(move, startPos);
|
|
|
|
|
res.set(id, append([...balance], prevEnd => ({
|
|
|
|
|
beats: move.beats - 4,
|
|
|
|
|
startPosition: {
|
|
|
|
|
...prevEnd,
|
|
|
|
|
hands: undefined,
|
|
|
|
|
},
|
|
|
|
|
endPosition: finalPosition,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.Linear,
|
|
|
|
|
minRotation: rightShoulder ? 180 : -180,
|
|
|
|
|
handsDuring: "None",
|
|
|
|
|
},
|
|
|
|
|
})));
|
|
|
|
|
return append([...balance], spin);
|
|
|
|
|
} else {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: {
|
|
|
|
|
...startPos,
|
|
|
|
|
facing: Facing.CenterOfCircle,
|
|
|
|
|
hands: undefined,
|
|
|
|
|
},
|
|
|
|
|
endPosition: finalPosition,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.Linear,
|
|
|
|
|
minRotation: rightShoulder ? 180 : -180,
|
|
|
|
|
handsDuring: "None",
|
|
|
|
|
},
|
|
|
|
|
}]));
|
|
|
|
|
return combine([spin]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
});
|
|
|
|
|
case "mad robin":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handleCircleMove(({ startPos }) => {
|
|
|
|
|
// TODO Read who of mad robin to decide direction?
|
|
|
|
|
const startAndEndPos = {
|
|
|
|
|
...startPos,
|
|
|
|
|
facing: startPos.which.isLeft() ? Facing.Right : Facing.Left,
|
|
|
|
|
hands: undefined,
|
|
|
|
|
};
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
return combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: startAndEndPos,
|
|
|
|
|
endPosition: startAndEndPos,
|
|
|
|
@ -316,27 +374,10 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
amount: move.parameters.circling,
|
|
|
|
|
around: startPos.which.leftRightSide(),
|
|
|
|
|
},
|
|
|
|
|
}]));
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}]);
|
|
|
|
|
});
|
|
|
|
|
case "do si do":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const withId = findPairOpposite(move.parameters.who, id);
|
|
|
|
|
if (!withId) {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const around = findCenterBetween(id, withId);
|
|
|
|
|
|
|
|
|
|
return handleCirclePairedMove(move.parameters.who, ({ startPos, around }) => {
|
|
|
|
|
// TODO Use other parameters?
|
|
|
|
|
const startAndEndPos = {
|
|
|
|
|
...startPos,
|
|
|
|
@ -347,7 +388,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
? (startPos.which.isTop() ? Facing.Down : Facing.Up)
|
|
|
|
|
: (startPos.which.isLeft() ? Facing.Right : Facing.Left),
|
|
|
|
|
};
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
return combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: startAndEndPos,
|
|
|
|
|
endPosition: startAndEndPos,
|
|
|
|
@ -356,112 +397,66 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
amount: move.parameters.circling,
|
|
|
|
|
around,
|
|
|
|
|
},
|
|
|
|
|
}]));
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}]);
|
|
|
|
|
});
|
|
|
|
|
case "swing":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (excludedByWho(move.parameters.who, id)) {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO swing can start from other positions.
|
|
|
|
|
return handleCirclePairedMove(move.parameters.who, ({ id, startPos, around, withId }) => {
|
|
|
|
|
// TODO swing can start from non-circle positions.
|
|
|
|
|
// TODO swing end is only in notes / looking at next move.
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (move.parameters.who) {
|
|
|
|
|
case "ladles":
|
|
|
|
|
case "gentlespoons":
|
|
|
|
|
case "ones":
|
|
|
|
|
case "twos":
|
|
|
|
|
throw "Swing in middle is currently unsupported.";
|
|
|
|
|
case "first corners":
|
|
|
|
|
case "second corners":
|
|
|
|
|
throw "contra corners currently unsupported.";
|
|
|
|
|
case "same roles":
|
|
|
|
|
throw "same role swing currently unsupported."
|
|
|
|
|
case "neighbors":
|
|
|
|
|
case "partners":
|
|
|
|
|
case "shadows":
|
|
|
|
|
// TODO Make sure referenced dancer is using same center.
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const withId = findPairOpposite(move.parameters.who, id);
|
|
|
|
|
if (!withId) {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const withPos = getPosFor(withId);
|
|
|
|
|
const setDifference = withPos.setOffset - (startPos.setOffset ?? 0);
|
|
|
|
|
let startPosAdjusted = startPos;
|
|
|
|
|
if (setDifference !== 0) {
|
|
|
|
|
if (setDifference === 1 || setDifference === -1) {
|
|
|
|
|
startPosAdjusted = {...startPos,
|
|
|
|
|
setOffset: (startPos.setOffset ?? 0) + setDifference / 2,
|
|
|
|
|
which: startPos.which.swapUpAndDown(),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throw "Not near dancer to swing with.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const startWhich = startPosAdjusted.which;
|
|
|
|
|
// TODO Can swing be across the set (top or bottom)?
|
|
|
|
|
const around = withPos.kind === PositionKind.Circle
|
|
|
|
|
? (withPos.which.leftRightSide() === startWhich.leftRightSide()
|
|
|
|
|
? startWhich.leftRightSide()
|
|
|
|
|
: "Center")
|
|
|
|
|
: "Center";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const startWhich = startPos.which;
|
|
|
|
|
const startPosition: SemanticPosition = {
|
|
|
|
|
...startPosAdjusted,
|
|
|
|
|
...startPos,
|
|
|
|
|
facing: startWhich.topBottomSide() === CircleSide.Bottom ? Facing.Up : Facing.Down,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const swingRole = id.danceRole != withId.setIdentity.danceRole
|
|
|
|
|
? id.danceRole
|
|
|
|
|
// Make some arbitrary choice for same-role swings
|
|
|
|
|
: id.coupleRole !== withId.setIdentity.coupleRole
|
|
|
|
|
? (id.coupleRole === CoupleRole.Ones ? DanceRole.Lark : DanceRole.Robin)
|
|
|
|
|
: withId.relativeSet !== 0
|
|
|
|
|
? (withId.relativeSet > 0 ? DanceRole.Lark : DanceRole.Robin)
|
|
|
|
|
: withId.relativeLine !== 0
|
|
|
|
|
? (withId.relativeLine > 0 ? DanceRole.Lark : DanceRole.Robin)
|
|
|
|
|
: /* should be unreachable as this means withId is equal to id */ DanceRole.Lark;
|
|
|
|
|
|
|
|
|
|
// TODO This assumes swing around right/left, not center or top/bottom.
|
|
|
|
|
const endPosition: SemanticPosition = {
|
|
|
|
|
...startPosAdjusted,
|
|
|
|
|
which: startWhich.isOnLeftLookingAcross() === (id.danceRole === DanceRole.Lark)
|
|
|
|
|
...startPos,
|
|
|
|
|
which: startWhich.isOnLeftLookingAcross() === (swingRole === DanceRole.Lark)
|
|
|
|
|
? startWhich
|
|
|
|
|
: startWhich.swapUpAndDown(),
|
|
|
|
|
facing: startWhich.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
|
|
|
|
balance: undefined,
|
|
|
|
|
dancerDistance: undefined,
|
|
|
|
|
hands: new Map<Hand, HandConnection>([id.danceRole === DanceRole.Lark
|
|
|
|
|
hands: new Map<Hand, HandConnection>([swingRole === DanceRole.Lark
|
|
|
|
|
? [Hand.Right, { to: HandTo.DancerRight, hand: Hand.Left }]
|
|
|
|
|
: [Hand.Left, { to: HandTo.DancerLeft, hand: Hand.Right }]]),
|
|
|
|
|
};
|
|
|
|
|
// TODO same role swing currently unsupported.
|
|
|
|
|
const swingRole = id.danceRole === DanceRole.Lark ? DancerDistance.SwingLark : DancerDistance.SwingRobin;
|
|
|
|
|
|
|
|
|
|
const swingBeats = move.parameters.prefix === "none" ? move.beats
|
|
|
|
|
: move.parameters.prefix === "balance"
|
|
|
|
|
? move.beats > 8 ? 8 : move.beats - 4
|
|
|
|
|
: move.parameters.prefix === "meltdown"
|
|
|
|
|
? move.beats - 4
|
|
|
|
|
: (() => { throw "Unknown swing prefix: " + move.parameters.prefix })();
|
|
|
|
|
|
|
|
|
|
const swing: PartialLowLevelMove = {
|
|
|
|
|
beats: swingBeats,
|
|
|
|
|
endPosition: endPosition,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.Swing,
|
|
|
|
|
minAmount: 360,
|
|
|
|
|
around,
|
|
|
|
|
endFacing: startWhich.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
|
|
|
|
swingRole,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (move.parameters.prefix) {
|
|
|
|
|
case "none":
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
endPosition: endPosition,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.Swing,
|
|
|
|
|
minAmount: 360,
|
|
|
|
|
around,
|
|
|
|
|
endFacing: startWhich.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
|
|
|
|
swingRole: id.danceRole,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
], startPosition));
|
|
|
|
|
break;
|
|
|
|
|
return combine([swing,], startPosition);
|
|
|
|
|
case "balance":
|
|
|
|
|
// TODO Right length for balance?
|
|
|
|
|
const balancePartBeats = move.beats > 8 ? (move.beats - 8) / 2 : 2;
|
|
|
|
@ -472,7 +467,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
[Hand.Right, { to: HandTo.DancerForward, hand: Hand.Left }],
|
|
|
|
|
]),
|
|
|
|
|
};
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: balancePartBeats,
|
|
|
|
|
startPosition: startWithBalHands,
|
|
|
|
@ -491,22 +486,11 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
},
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
|
|
|
|
}),
|
|
|
|
|
{
|
|
|
|
|
beats: move.beats - 2 * balancePartBeats,
|
|
|
|
|
endPosition: endPosition,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.Swing,
|
|
|
|
|
minAmount: 360,
|
|
|
|
|
around,
|
|
|
|
|
endFacing: startWhich.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
|
|
|
|
swingRole: id.danceRole,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
], startPosition));
|
|
|
|
|
break;
|
|
|
|
|
swing,
|
|
|
|
|
], startPosition);
|
|
|
|
|
case "meltdown":
|
|
|
|
|
const meltdownBeats = 4; // TODO right number here?
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
prevEnd => ({
|
|
|
|
|
beats: meltdownBeats,
|
|
|
|
|
endPosition: prevEnd,
|
|
|
|
@ -517,52 +501,19 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
byHand: undefined,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
{
|
|
|
|
|
beats: move.beats - meltdownBeats,
|
|
|
|
|
endPosition: endPosition,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.Swing,
|
|
|
|
|
minAmount: 360,
|
|
|
|
|
around,
|
|
|
|
|
endFacing: startWhich.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
|
|
|
|
swingRole: id.danceRole,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
], startPosition));
|
|
|
|
|
break;
|
|
|
|
|
swing,
|
|
|
|
|
], startPosition);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "allemande":
|
|
|
|
|
case "gyre":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (excludedByWho(move.parameters.who, id)) {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO allemande can start from other positions.
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const withId = findPairOpposite(move.parameters.who, id);
|
|
|
|
|
// findPairOpposite of null means this dancer doesn't participate in this move.
|
|
|
|
|
if (!withId) {
|
|
|
|
|
throw "fairPairOpposite and excludedByWho disagree on who does not act: who=" + move.parameters.who + ", id=" + id;
|
|
|
|
|
}
|
|
|
|
|
const around = findCenterBetween(id, withId);
|
|
|
|
|
|
|
|
|
|
return handlePairedMove(move.parameters.who, ({ startPos, around, withId }) => {
|
|
|
|
|
// TODO Not sure if this is right.
|
|
|
|
|
const byHandOrShoulder = (move.move === "allemande" ? move.parameters.hand : move.parameters.shoulder) ? Hand.Right : Hand.Left;
|
|
|
|
|
const swap = move.parameters.circling % 360 === 180;
|
|
|
|
|
if (!swap && move.parameters.circling % 360 !== 0) {
|
|
|
|
|
// TODO Support allemande that's not a swap or no-op.
|
|
|
|
|
throw "Unsupported allemande circle amount: " + move.parameters.circling;
|
|
|
|
|
}
|
|
|
|
|
let endPosition : SemanticPosition = startPos;
|
|
|
|
@ -572,7 +523,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
endPosition.lineOffset = (endPosition.lineOffset ?? 0) + withId.relativeLine;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
endPosition,
|
|
|
|
@ -583,20 +534,14 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
byHand: move.move === "allemande" ? byHandOrShoulder : undefined,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
], startPos));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
], startPos);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "circle":
|
|
|
|
|
const places = move.parameters.places/90 * (move.parameters.turn ? 1 : -1);
|
|
|
|
|
return handleCircleMove(({ startPos }) => {
|
|
|
|
|
const places = move.parameters.places / 90 * (move.parameters.turn ? 1 : -1);
|
|
|
|
|
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
endPosition: {
|
|
|
|
@ -610,32 +555,16 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
places,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
], { ...startPos, facing: Facing.CenterOfCircle }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
], { ...startPos, facing: Facing.CenterOfCircle });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "California twirl":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (excludedByWho(move.parameters.who, id)) {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handleCirclePairedMove(move.parameters.who, ({ startPos }) => {
|
|
|
|
|
// TODO does "who" matter here or is it entirely positional? At least need to know who to omit.
|
|
|
|
|
|
|
|
|
|
const onLeft : boolean = startPos.which.isOnLeftLookingUpAndDown();
|
|
|
|
|
// TODO get rid of this 1 beat set up and make it part of TwirlSwap?
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: 1,
|
|
|
|
|
endPosition: {
|
|
|
|
@ -661,23 +590,11 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
around: startPos.which.topBottomSide(),
|
|
|
|
|
hand: onLeft ? Hand.Right : Hand.Left,
|
|
|
|
|
}
|
|
|
|
|
}], startPos));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}], startPos);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "box the gnat":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (excludedByWho(move.parameters.who, id)) {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handlePairedMove(move.parameters.who, ({ startPos, around, withPos }) => {
|
|
|
|
|
const hand = move.parameters.hand ? Hand.Right : Hand.Left;
|
|
|
|
|
const balanceBeats = move.parameters.bal
|
|
|
|
|
? move.beats > 4
|
|
|
|
@ -690,18 +607,22 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
// TODO Adjust facing?
|
|
|
|
|
const startPosition = { ...startPos, hands: new Map<Hand, HandConnection>([[hand, { hand, to: HandTo.DancerForward }]]) };
|
|
|
|
|
|
|
|
|
|
const withId = findPairOpposite(move.parameters.who, id);
|
|
|
|
|
// findPairOpposite of null means this dancer doesn't participate in this move.
|
|
|
|
|
if (!withId) {
|
|
|
|
|
throw "fairPairOpposite and excludedByWho disagree on who does not act: who=" + move.parameters.who + ", id=" + id;
|
|
|
|
|
}
|
|
|
|
|
const around = findCenterBetween(id, withId);
|
|
|
|
|
if (around === "Center") {
|
|
|
|
|
throw "TwirlSwap around center is unsupported.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const twirl: PartialLowLevelMove = {
|
|
|
|
|
beats: twirlBeats,
|
|
|
|
|
endPosition: withPos,
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.TwirlSwap,
|
|
|
|
|
around,
|
|
|
|
|
hand,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (move.parameters.bal) {
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: balancePartBeats,
|
|
|
|
|
endPosition: {
|
|
|
|
@ -722,43 +643,14 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
kind: SemanticAnimationKind.Linear,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
beats: twirlBeats,
|
|
|
|
|
endPosition: getPosFor(withId),
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.TwirlSwap,
|
|
|
|
|
around,
|
|
|
|
|
hand,
|
|
|
|
|
}
|
|
|
|
|
}], startPosition));
|
|
|
|
|
twirl], startPosition);
|
|
|
|
|
} else {
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
{
|
|
|
|
|
beats: twirlBeats,
|
|
|
|
|
endPosition: getPosFor(withId),
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.TwirlSwap,
|
|
|
|
|
around,
|
|
|
|
|
hand,
|
|
|
|
|
}
|
|
|
|
|
}], startPosition));
|
|
|
|
|
return combine([twirl], startPosition);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "pull by dancers":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (excludedByWho(move.parameters.who, id)) {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
startPosition: { ...startPos, hands: undefined },
|
|
|
|
|
endPosition: { ...startPos, hands: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.StandStill },
|
|
|
|
|
}]));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handlePairedMove(move.parameters.who, ({ startPos, around, withPos }) => {
|
|
|
|
|
const hand = move.parameters.hand ? Hand.Right : Hand.Left;
|
|
|
|
|
const balanceBeats = move.parameters.bal
|
|
|
|
|
? move.beats > 4
|
|
|
|
@ -768,13 +660,6 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
const balancePartBeats = balanceBeats / 2;
|
|
|
|
|
const pullBeats = move.beats - balanceBeats;
|
|
|
|
|
|
|
|
|
|
const withId = findPairOpposite(move.parameters.who, id);
|
|
|
|
|
// findPairOpposite of null means this dancer doesn't participate in this move.
|
|
|
|
|
if (!withId) {
|
|
|
|
|
throw "fairPairOpposite and excludedByWho disagree on who does not act: who=" + move.parameters.who + ", id=" + id;
|
|
|
|
|
}
|
|
|
|
|
const around = findCenterBetween(id, withId);
|
|
|
|
|
|
|
|
|
|
// TODO Adjust facing?
|
|
|
|
|
const startPosition = {
|
|
|
|
|
...startPos,
|
|
|
|
@ -785,9 +670,19 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
]])
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const passBy: PartialLowLevelMove = {
|
|
|
|
|
beats: pullBeats,
|
|
|
|
|
endPosition: { ...withPos, facing: startPos.facing },
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.PassBy,
|
|
|
|
|
around,
|
|
|
|
|
side: hand,
|
|
|
|
|
withHands: true,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (move.parameters.bal) {
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: balancePartBeats,
|
|
|
|
|
endPosition: {
|
|
|
|
@ -808,43 +703,18 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
kind: SemanticAnimationKind.Linear,
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
beats: pullBeats,
|
|
|
|
|
endPosition: getPosFor(withId),
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.PassBy,
|
|
|
|
|
around,
|
|
|
|
|
side: hand,
|
|
|
|
|
withHands: true,
|
|
|
|
|
}
|
|
|
|
|
}], startPosition));
|
|
|
|
|
passBy], startPosition);
|
|
|
|
|
} else {
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
{
|
|
|
|
|
beats: pullBeats,
|
|
|
|
|
endPosition: getPosFor(withId),
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.PassBy,
|
|
|
|
|
around,
|
|
|
|
|
side: hand,
|
|
|
|
|
withHands: true,
|
|
|
|
|
}
|
|
|
|
|
}], startPosition));
|
|
|
|
|
return combine([passBy], startPosition);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "chain":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const mainRole = move.parameters.who === "gentlespoons" ? DanceRole.Lark : DanceRole.Robin;
|
|
|
|
|
const pullBeats = move.beats / 2;
|
|
|
|
|
const turnBeats = move.beats - pullBeats;
|
|
|
|
|
const mainRole = move.parameters.who === "gentlespoons" ? DanceRole.Lark : DanceRole.Robin;
|
|
|
|
|
const pullBeats = move.beats / 2;
|
|
|
|
|
const turnBeats = move.beats - pullBeats;
|
|
|
|
|
|
|
|
|
|
return handleCircleMove(({ id, startPos }) => {
|
|
|
|
|
if (id.danceRole === mainRole) {
|
|
|
|
|
const hand = move.parameters.hand ? Hand.Right : Hand.Left;
|
|
|
|
|
const endWhich = startPos.which.swapDiagonal();
|
|
|
|
@ -869,7 +739,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
|
|
|
|
|
const turnTo = hand === Hand.Right ? HandTo.DancerRight : HandTo.DancerLeft;
|
|
|
|
|
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: pullBeats,
|
|
|
|
|
endPosition: {
|
|
|
|
@ -902,9 +772,9 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
kind: SemanticAnimationKind.CourtesyTurn,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
], startPosition));
|
|
|
|
|
], startPosition);
|
|
|
|
|
} else {
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: pullBeats,
|
|
|
|
|
endPosition: startPos,
|
|
|
|
@ -923,18 +793,12 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
kind: SemanticAnimationKind.CourtesyTurn,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
], startPos));
|
|
|
|
|
], startPos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "long lines":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handleCircleMove(({ startPos }) => {
|
|
|
|
|
const startPosition: SemanticPosition = {
|
|
|
|
|
...startPos,
|
|
|
|
|
longLines: undefined,
|
|
|
|
@ -949,7 +813,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
if (move.parameters.go) {
|
|
|
|
|
const forwardBeats = move.beats / 2;
|
|
|
|
|
const backwardBeats = move.beats - forwardBeats;
|
|
|
|
|
res.set(id, combine([
|
|
|
|
|
return combine([
|
|
|
|
|
{
|
|
|
|
|
beats: forwardBeats,
|
|
|
|
|
endPosition: { ...startPosition, longLines: LongLines.Forward },
|
|
|
|
@ -960,24 +824,19 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
endPosition: startPosition,
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
|
|
|
|
},
|
|
|
|
|
], startPosition));
|
|
|
|
|
], startPosition);
|
|
|
|
|
} else {
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
return combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
endPosition: { ...startPosition, longLines: LongLines.Forward },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
|
|
|
|
}], startPosition));
|
|
|
|
|
}], startPosition);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
case "roll away":
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
if (startPos.kind !== PositionKind.Circle) {
|
|
|
|
|
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO maybe can roll away in short lines?
|
|
|
|
|
return handleCirclePairedMove(move.parameters.who, ({ id, startPos, withPos }) => {
|
|
|
|
|
let isRoller: boolean;
|
|
|
|
|
switch (move.parameters.who) {
|
|
|
|
|
case "gentlespoons":
|
|
|
|
@ -997,15 +856,8 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
throw "Roll away in contra corners is unsupported.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let oppositeId = findPairOpposite(move.parameters.whom, id);
|
|
|
|
|
if (!oppositeId) {
|
|
|
|
|
// TODO
|
|
|
|
|
throw "Failed to identify dancer to roll away with.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO This isn't quite right if there's no 1/2 sash?
|
|
|
|
|
const oppositePos = getPosFor(oppositeId);
|
|
|
|
|
let swapPos = oppositePos;
|
|
|
|
|
let swapPos = withPos;
|
|
|
|
|
if (swapPos.kind === PositionKind.Circle && swapPos.longLines) {
|
|
|
|
|
swapPos = { ...swapPos, longLines: undefined };
|
|
|
|
|
}
|
|
|
|
@ -1014,37 +866,35 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
if (isRoller) {
|
|
|
|
|
if (move.parameters["½sash"]) {
|
|
|
|
|
// swap positions by sliding
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
return combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
endPosition: swapPos,
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
|
|
|
|
}], startPos));
|
|
|
|
|
}], startPos);
|
|
|
|
|
} else {
|
|
|
|
|
// just stand still
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
return combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
endPosition: { ...startPos, longLines: undefined },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
|
|
|
|
}], startPos));
|
|
|
|
|
}], startPos);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// being rolled away, so do a spin
|
|
|
|
|
res.set(id, combine([{
|
|
|
|
|
return combine([{
|
|
|
|
|
beats: move.beats,
|
|
|
|
|
// TODO Is this the right end position logic?
|
|
|
|
|
endPosition: move.parameters["½sash"] ? swapPos : { ...startPos, which: startPos.which.swapDiagonal() },
|
|
|
|
|
movementPattern: { kind: SemanticAnimationKind.RollAway },
|
|
|
|
|
}], startPos));
|
|
|
|
|
}], startPos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX DEBUG Just leave out unsupported moves for now to allow viewing the known moves.
|
|
|
|
|
//throw "Unknown move: " + move.move + ": " + JSON.stringify(move);
|
|
|
|
|
for (const [id, startPos] of startingPos.entries()) {
|
|
|
|
|
res.set(id, [{
|
|
|
|
|
return handleMove(({ startPos }) => {
|
|
|
|
|
return [{
|
|
|
|
|
interpreterError: "UNKNOWN MOVE '" + move.move + "': standing still",
|
|
|
|
|
move,
|
|
|
|
|
startBeat: 0,
|
|
|
|
@ -1054,9 +904,8 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
|
|
|
|
movementPattern: {
|
|
|
|
|
kind: SemanticAnimationKind.StandStill,
|
|
|
|
|
},
|
|
|
|
|
}]);
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function danceAsLowLevelMoves(moves: Move[], startingPos: Map<DancerIdentity, SemanticPosition>): Map<DancerIdentity, LowLevelMove[]> {
|
|
|
|
|