fix(turn): block cross-pointer reorder (BUG-13)
reorderParticipants allowed dragging across current pointer mid-round. nextTurn walks turnOrderIds forward from pointer, so cross-pointer drag = ambiguous who-acts-next: upcoming dragged ahead of pointer = skipped (walk wraps past), acted dragged behind pointer = double-act. Full fix needs actedThisRound tracking. Pragmatic now: block both directions during active encounter. Pre-combat: free reorder (no pointer). reorderParticipants: added pointer check (currentTurn index). If drag crosses pointer, return null patch (no-op). Same-side reorder allowed. syncTurnOrder now always mirrors (was started-only — pre-combat reorder left turnOrderIds stale). Tests: - turn.bug13.test.js: cross-pointer blocked (both dirs), same-side allowed, pre-combat free. - turn.reorder.test.js: 3 tests updated to pre-combat (cross-pointer now blocked post-start). - turn.invariant.test.js: reorder test uses same-side upcoming pair. 214 tests green.
This commit is contained in:
@@ -90,12 +90,15 @@ describe('1-list model: turnOrderIds === participants.map(id), no re-sort', () =
|
||||
expect(e.turnOrderIds).toEqual(['a','b','c']); // unchanged
|
||||
});
|
||||
|
||||
test('reorder same-init: rotation follows new list order', () => {
|
||||
let e = enc([p('a',10),p('b',10),p('c',3)]); // a,b tie
|
||||
e = apply(e, startEncounter(e)); // [a,b,c], cur=a
|
||||
e = apply(e, reorderParticipants(e, 'b', 'a')); // [b,a,c], cur still a
|
||||
const rot = walkRotation(e); // start a, next c (wrap), next b, back a
|
||||
expect(rot).toEqual(['a','c','b']);
|
||||
test('reorder same-init: within upcoming side of pointer follows new order', () => {
|
||||
let e = enc([p('a',10),p('b',10),p('c',10),p('d',3)]); // a,b,c tie
|
||||
e = apply(e, startEncounter(e)); // [a,b,c,d], cur=a (idx0)
|
||||
// Reorder c before b (both upcoming idx1,2). Within same side = allowed.
|
||||
e = apply(e, reorderParticipants(e, 'c', 'b')); // [a,c,b,d], cur=a
|
||||
expect(e.turnOrderIds).toEqual(['a','c','b','d']);
|
||||
// walk: a current, next c, next b, next d, wrap a
|
||||
e = apply(e, nextTurn(e));
|
||||
expect(e.currentTurnParticipantId).toBe('c');
|
||||
});
|
||||
|
||||
test('toggle inactive: list unchanged (stays in rotation slot)', () => {
|
||||
|
||||
Reference in New Issue
Block a user