@bct-app/game-engine 0.1.17 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +61 -83
- package/dist/index.mjs +61 -83
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -572,11 +572,6 @@ var resolveDynamicValue = (value, payloads, isExpected) => {
|
|
|
572
572
|
var getSortedPlayers = (playerSeatMap) => {
|
|
573
573
|
return [...playerSeatMap.values()].sort((left, right) => left.seat - right.seat);
|
|
574
574
|
};
|
|
575
|
-
var getCircularDistance = (anchorIdx, targetIdx, total) => {
|
|
576
|
-
const clockwise = (targetIdx - anchorIdx + total) % total;
|
|
577
|
-
const anticlockwise = (anchorIdx - targetIdx + total) % total;
|
|
578
|
-
return Math.min(clockwise, anticlockwise);
|
|
579
|
-
};
|
|
580
575
|
var getAnchorSeat = (dynamicTarget, payloads, effector) => {
|
|
581
576
|
const anchor = dynamicTarget.anchor;
|
|
582
577
|
if (!anchor || anchor.from === "EFFECTOR") {
|
|
@@ -595,42 +590,6 @@ var resolveSelectorScope = (dynamicTarget, payloads) => {
|
|
|
595
590
|
(value) => value === "BOTH_SIDES" || value === "LEFT_SIDE" || value === "RIGHT_SIDE"
|
|
596
591
|
) ?? "BOTH_SIDES";
|
|
597
592
|
};
|
|
598
|
-
var getCandidatesBySelector = (dynamicTarget, sortedPlayers, anchorSeat, payloads) => {
|
|
599
|
-
const selector = dynamicTarget.selector;
|
|
600
|
-
if (!selector) {
|
|
601
|
-
return sortedPlayers;
|
|
602
|
-
}
|
|
603
|
-
const scope = resolveSelectorScope(dynamicTarget, payloads);
|
|
604
|
-
if (!anchorSeat) {
|
|
605
|
-
return [];
|
|
606
|
-
}
|
|
607
|
-
const anchorIdx = sortedPlayers.findIndex((player) => player.seat === anchorSeat);
|
|
608
|
-
if (anchorIdx < 0) {
|
|
609
|
-
return [];
|
|
610
|
-
}
|
|
611
|
-
const total = sortedPlayers.length;
|
|
612
|
-
if (scope === "LEFT_SIDE") {
|
|
613
|
-
const left2 = [];
|
|
614
|
-
for (let step = 1; step < total; step += 1) {
|
|
615
|
-
left2.push(sortedPlayers[(anchorIdx + step) % total]);
|
|
616
|
-
}
|
|
617
|
-
return left2;
|
|
618
|
-
}
|
|
619
|
-
if (scope === "RIGHT_SIDE") {
|
|
620
|
-
const right2 = [];
|
|
621
|
-
for (let step = 1; step < total; step += 1) {
|
|
622
|
-
right2.push(sortedPlayers[(anchorIdx - step + total) % total]);
|
|
623
|
-
}
|
|
624
|
-
return right2;
|
|
625
|
-
}
|
|
626
|
-
const left = [];
|
|
627
|
-
const right = [];
|
|
628
|
-
for (let step = 1; step < total; step += 1) {
|
|
629
|
-
left.push(sortedPlayers[(anchorIdx + step) % total]);
|
|
630
|
-
right.push(sortedPlayers[(anchorIdx - step + total) % total]);
|
|
631
|
-
}
|
|
632
|
-
return [...left, ...right];
|
|
633
|
-
};
|
|
634
593
|
var matchesCondition = (player, condition, payloads, characterMap) => {
|
|
635
594
|
if (condition.field === "IS_DEAD") {
|
|
636
595
|
const expected = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "boolean");
|
|
@@ -659,55 +618,72 @@ var matchesCondition = (player, condition, payloads, characterMap) => {
|
|
|
659
618
|
const expectedKind = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "string");
|
|
660
619
|
return typeof expectedKind === "string" && kind === expectedKind;
|
|
661
620
|
};
|
|
662
|
-
var
|
|
621
|
+
var passesWhere = (player, dynamicTarget, payloads, characterMap) => {
|
|
663
622
|
const where = dynamicTarget.where;
|
|
664
623
|
const conditions = where?.conditions ?? [];
|
|
665
|
-
if (conditions.length === 0)
|
|
666
|
-
return candidates;
|
|
667
|
-
}
|
|
624
|
+
if (conditions.length === 0) return true;
|
|
668
625
|
const isAllMode = where?.mode !== "ANY";
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
return isAllMode ? results.every(Boolean) : results.some(Boolean);
|
|
672
|
-
});
|
|
626
|
+
const results = conditions.map((condition) => matchesCondition(player, condition, payloads, characterMap));
|
|
627
|
+
return isAllMode ? results.every(Boolean) : results.some(Boolean);
|
|
673
628
|
};
|
|
674
|
-
var
|
|
629
|
+
var walkSidesWithFilter = (dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap) => {
|
|
675
630
|
const scope = resolveSelectorScope(dynamicTarget, payloads);
|
|
676
|
-
if (
|
|
677
|
-
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
}
|
|
687
|
-
return [...candidates].sort((left, right) => {
|
|
688
|
-
const leftIdx = seatIndexMap.get(left.seat);
|
|
689
|
-
const rightIdx = seatIndexMap.get(right.seat);
|
|
690
|
-
if (typeof leftIdx !== "number" || typeof rightIdx !== "number") {
|
|
691
|
-
return left.seat - right.seat;
|
|
631
|
+
if (!anchorSeat) return { left: [], right: [] };
|
|
632
|
+
const anchorIdx = sortedPlayers.findIndex((player) => player.seat === anchorSeat);
|
|
633
|
+
if (anchorIdx < 0) return { left: [], right: [] };
|
|
634
|
+
const total = sortedPlayers.length;
|
|
635
|
+
const left = [];
|
|
636
|
+
const right = [];
|
|
637
|
+
if (scope === "LEFT_SIDE" || scope === "BOTH_SIDES") {
|
|
638
|
+
for (let step = 1; step < total; step += 1) {
|
|
639
|
+
const player = sortedPlayers[(anchorIdx + step) % total];
|
|
640
|
+
if (passesWhere(player, dynamicTarget, payloads, characterMap)) left.push(player);
|
|
692
641
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
642
|
+
}
|
|
643
|
+
if (scope === "RIGHT_SIDE" || scope === "BOTH_SIDES") {
|
|
644
|
+
for (let step = 1; step < total; step += 1) {
|
|
645
|
+
const player = sortedPlayers[(anchorIdx - step + total) % total];
|
|
646
|
+
if (passesWhere(player, dynamicTarget, payloads, characterMap)) right.push(player);
|
|
697
647
|
}
|
|
698
|
-
|
|
699
|
-
}
|
|
648
|
+
}
|
|
649
|
+
return { left, right };
|
|
700
650
|
};
|
|
701
|
-
var
|
|
702
|
-
const dedupedCandidates = [...new Map(sortedCandidates.map((player) => [player.seat, player])).values()];
|
|
651
|
+
var pickBalanced = (sides, dynamicTarget, payloads) => {
|
|
703
652
|
const configuredLimit = resolveDynamicValue(dynamicTarget.limit, payloads, (value) => typeof value === "number");
|
|
653
|
+
const seen = /* @__PURE__ */ new Set();
|
|
654
|
+
const out = [];
|
|
655
|
+
const pushUnique = (player) => {
|
|
656
|
+
if (!player || seen.has(player.seat)) return false;
|
|
657
|
+
seen.add(player.seat);
|
|
658
|
+
out.push(player);
|
|
659
|
+
return true;
|
|
660
|
+
};
|
|
704
661
|
if (typeof configuredLimit === "undefined") {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
662
|
+
sides.left.forEach(pushUnique);
|
|
663
|
+
sides.right.forEach(pushUnique);
|
|
664
|
+
return out;
|
|
665
|
+
}
|
|
666
|
+
if (configuredLimit <= 0) return [];
|
|
667
|
+
let li = 0;
|
|
668
|
+
let ri = 0;
|
|
669
|
+
let preferLeft = true;
|
|
670
|
+
while (out.length < configuredLimit && (li < sides.left.length || ri < sides.right.length)) {
|
|
671
|
+
if (preferLeft && li < sides.left.length) {
|
|
672
|
+
if (pushUnique(sides.left[li])) li += 1;
|
|
673
|
+
else li += 1;
|
|
674
|
+
} else if (!preferLeft && ri < sides.right.length) {
|
|
675
|
+
if (pushUnique(sides.right[ri])) ri += 1;
|
|
676
|
+
else ri += 1;
|
|
677
|
+
} else if (li < sides.left.length) {
|
|
678
|
+
if (pushUnique(sides.left[li])) li += 1;
|
|
679
|
+
else li += 1;
|
|
680
|
+
} else if (ri < sides.right.length) {
|
|
681
|
+
if (pushUnique(sides.right[ri])) ri += 1;
|
|
682
|
+
else ri += 1;
|
|
683
|
+
}
|
|
684
|
+
preferLeft = !preferLeft;
|
|
709
685
|
}
|
|
710
|
-
return
|
|
686
|
+
return out;
|
|
711
687
|
};
|
|
712
688
|
var resolveEffectTargets = ({
|
|
713
689
|
effect,
|
|
@@ -740,10 +716,12 @@ var resolveEffectTargets = ({
|
|
|
740
716
|
const dynamicTarget = effect.target;
|
|
741
717
|
const sortedPlayers = getSortedPlayers(playerSeatMap);
|
|
742
718
|
const anchorSeat = getAnchorSeat(dynamicTarget, payloads, effector);
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
719
|
+
if (!dynamicTarget.selector) {
|
|
720
|
+
const matches = sortedPlayers.filter((player) => passesWhere(player, dynamicTarget, payloads, characterMap));
|
|
721
|
+
return pickBalanced({ left: matches, right: [] }, dynamicTarget, payloads);
|
|
722
|
+
}
|
|
723
|
+
const sides = walkSidesWithFilter(dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap);
|
|
724
|
+
return pickBalanced(sides, dynamicTarget, payloads);
|
|
747
725
|
}
|
|
748
726
|
return [];
|
|
749
727
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -532,11 +532,6 @@ var resolveDynamicValue = (value, payloads, isExpected) => {
|
|
|
532
532
|
var getSortedPlayers = (playerSeatMap) => {
|
|
533
533
|
return [...playerSeatMap.values()].sort((left, right) => left.seat - right.seat);
|
|
534
534
|
};
|
|
535
|
-
var getCircularDistance = (anchorIdx, targetIdx, total) => {
|
|
536
|
-
const clockwise = (targetIdx - anchorIdx + total) % total;
|
|
537
|
-
const anticlockwise = (anchorIdx - targetIdx + total) % total;
|
|
538
|
-
return Math.min(clockwise, anticlockwise);
|
|
539
|
-
};
|
|
540
535
|
var getAnchorSeat = (dynamicTarget, payloads, effector) => {
|
|
541
536
|
const anchor = dynamicTarget.anchor;
|
|
542
537
|
if (!anchor || anchor.from === "EFFECTOR") {
|
|
@@ -555,42 +550,6 @@ var resolveSelectorScope = (dynamicTarget, payloads) => {
|
|
|
555
550
|
(value) => value === "BOTH_SIDES" || value === "LEFT_SIDE" || value === "RIGHT_SIDE"
|
|
556
551
|
) ?? "BOTH_SIDES";
|
|
557
552
|
};
|
|
558
|
-
var getCandidatesBySelector = (dynamicTarget, sortedPlayers, anchorSeat, payloads) => {
|
|
559
|
-
const selector = dynamicTarget.selector;
|
|
560
|
-
if (!selector) {
|
|
561
|
-
return sortedPlayers;
|
|
562
|
-
}
|
|
563
|
-
const scope = resolveSelectorScope(dynamicTarget, payloads);
|
|
564
|
-
if (!anchorSeat) {
|
|
565
|
-
return [];
|
|
566
|
-
}
|
|
567
|
-
const anchorIdx = sortedPlayers.findIndex((player) => player.seat === anchorSeat);
|
|
568
|
-
if (anchorIdx < 0) {
|
|
569
|
-
return [];
|
|
570
|
-
}
|
|
571
|
-
const total = sortedPlayers.length;
|
|
572
|
-
if (scope === "LEFT_SIDE") {
|
|
573
|
-
const left2 = [];
|
|
574
|
-
for (let step = 1; step < total; step += 1) {
|
|
575
|
-
left2.push(sortedPlayers[(anchorIdx + step) % total]);
|
|
576
|
-
}
|
|
577
|
-
return left2;
|
|
578
|
-
}
|
|
579
|
-
if (scope === "RIGHT_SIDE") {
|
|
580
|
-
const right2 = [];
|
|
581
|
-
for (let step = 1; step < total; step += 1) {
|
|
582
|
-
right2.push(sortedPlayers[(anchorIdx - step + total) % total]);
|
|
583
|
-
}
|
|
584
|
-
return right2;
|
|
585
|
-
}
|
|
586
|
-
const left = [];
|
|
587
|
-
const right = [];
|
|
588
|
-
for (let step = 1; step < total; step += 1) {
|
|
589
|
-
left.push(sortedPlayers[(anchorIdx + step) % total]);
|
|
590
|
-
right.push(sortedPlayers[(anchorIdx - step + total) % total]);
|
|
591
|
-
}
|
|
592
|
-
return [...left, ...right];
|
|
593
|
-
};
|
|
594
553
|
var matchesCondition = (player, condition, payloads, characterMap) => {
|
|
595
554
|
if (condition.field === "IS_DEAD") {
|
|
596
555
|
const expected = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "boolean");
|
|
@@ -619,55 +578,72 @@ var matchesCondition = (player, condition, payloads, characterMap) => {
|
|
|
619
578
|
const expectedKind = resolveDynamicValue(condition.value, payloads, (value) => typeof value === "string");
|
|
620
579
|
return typeof expectedKind === "string" && kind === expectedKind;
|
|
621
580
|
};
|
|
622
|
-
var
|
|
581
|
+
var passesWhere = (player, dynamicTarget, payloads, characterMap) => {
|
|
623
582
|
const where = dynamicTarget.where;
|
|
624
583
|
const conditions = where?.conditions ?? [];
|
|
625
|
-
if (conditions.length === 0)
|
|
626
|
-
return candidates;
|
|
627
|
-
}
|
|
584
|
+
if (conditions.length === 0) return true;
|
|
628
585
|
const isAllMode = where?.mode !== "ANY";
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
return isAllMode ? results.every(Boolean) : results.some(Boolean);
|
|
632
|
-
});
|
|
586
|
+
const results = conditions.map((condition) => matchesCondition(player, condition, payloads, characterMap));
|
|
587
|
+
return isAllMode ? results.every(Boolean) : results.some(Boolean);
|
|
633
588
|
};
|
|
634
|
-
var
|
|
589
|
+
var walkSidesWithFilter = (dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap) => {
|
|
635
590
|
const scope = resolveSelectorScope(dynamicTarget, payloads);
|
|
636
|
-
if (
|
|
637
|
-
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
return [...candidates].sort((left, right) => {
|
|
648
|
-
const leftIdx = seatIndexMap.get(left.seat);
|
|
649
|
-
const rightIdx = seatIndexMap.get(right.seat);
|
|
650
|
-
if (typeof leftIdx !== "number" || typeof rightIdx !== "number") {
|
|
651
|
-
return left.seat - right.seat;
|
|
591
|
+
if (!anchorSeat) return { left: [], right: [] };
|
|
592
|
+
const anchorIdx = sortedPlayers.findIndex((player) => player.seat === anchorSeat);
|
|
593
|
+
if (anchorIdx < 0) return { left: [], right: [] };
|
|
594
|
+
const total = sortedPlayers.length;
|
|
595
|
+
const left = [];
|
|
596
|
+
const right = [];
|
|
597
|
+
if (scope === "LEFT_SIDE" || scope === "BOTH_SIDES") {
|
|
598
|
+
for (let step = 1; step < total; step += 1) {
|
|
599
|
+
const player = sortedPlayers[(anchorIdx + step) % total];
|
|
600
|
+
if (passesWhere(player, dynamicTarget, payloads, characterMap)) left.push(player);
|
|
652
601
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
602
|
+
}
|
|
603
|
+
if (scope === "RIGHT_SIDE" || scope === "BOTH_SIDES") {
|
|
604
|
+
for (let step = 1; step < total; step += 1) {
|
|
605
|
+
const player = sortedPlayers[(anchorIdx - step + total) % total];
|
|
606
|
+
if (passesWhere(player, dynamicTarget, payloads, characterMap)) right.push(player);
|
|
657
607
|
}
|
|
658
|
-
|
|
659
|
-
}
|
|
608
|
+
}
|
|
609
|
+
return { left, right };
|
|
660
610
|
};
|
|
661
|
-
var
|
|
662
|
-
const dedupedCandidates = [...new Map(sortedCandidates.map((player) => [player.seat, player])).values()];
|
|
611
|
+
var pickBalanced = (sides, dynamicTarget, payloads) => {
|
|
663
612
|
const configuredLimit = resolveDynamicValue(dynamicTarget.limit, payloads, (value) => typeof value === "number");
|
|
613
|
+
const seen = /* @__PURE__ */ new Set();
|
|
614
|
+
const out = [];
|
|
615
|
+
const pushUnique = (player) => {
|
|
616
|
+
if (!player || seen.has(player.seat)) return false;
|
|
617
|
+
seen.add(player.seat);
|
|
618
|
+
out.push(player);
|
|
619
|
+
return true;
|
|
620
|
+
};
|
|
664
621
|
if (typeof configuredLimit === "undefined") {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
622
|
+
sides.left.forEach(pushUnique);
|
|
623
|
+
sides.right.forEach(pushUnique);
|
|
624
|
+
return out;
|
|
625
|
+
}
|
|
626
|
+
if (configuredLimit <= 0) return [];
|
|
627
|
+
let li = 0;
|
|
628
|
+
let ri = 0;
|
|
629
|
+
let preferLeft = true;
|
|
630
|
+
while (out.length < configuredLimit && (li < sides.left.length || ri < sides.right.length)) {
|
|
631
|
+
if (preferLeft && li < sides.left.length) {
|
|
632
|
+
if (pushUnique(sides.left[li])) li += 1;
|
|
633
|
+
else li += 1;
|
|
634
|
+
} else if (!preferLeft && ri < sides.right.length) {
|
|
635
|
+
if (pushUnique(sides.right[ri])) ri += 1;
|
|
636
|
+
else ri += 1;
|
|
637
|
+
} else if (li < sides.left.length) {
|
|
638
|
+
if (pushUnique(sides.left[li])) li += 1;
|
|
639
|
+
else li += 1;
|
|
640
|
+
} else if (ri < sides.right.length) {
|
|
641
|
+
if (pushUnique(sides.right[ri])) ri += 1;
|
|
642
|
+
else ri += 1;
|
|
643
|
+
}
|
|
644
|
+
preferLeft = !preferLeft;
|
|
669
645
|
}
|
|
670
|
-
return
|
|
646
|
+
return out;
|
|
671
647
|
};
|
|
672
648
|
var resolveEffectTargets = ({
|
|
673
649
|
effect,
|
|
@@ -700,10 +676,12 @@ var resolveEffectTargets = ({
|
|
|
700
676
|
const dynamicTarget = effect.target;
|
|
701
677
|
const sortedPlayers = getSortedPlayers(playerSeatMap);
|
|
702
678
|
const anchorSeat = getAnchorSeat(dynamicTarget, payloads, effector);
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
679
|
+
if (!dynamicTarget.selector) {
|
|
680
|
+
const matches = sortedPlayers.filter((player) => passesWhere(player, dynamicTarget, payloads, characterMap));
|
|
681
|
+
return pickBalanced({ left: matches, right: [] }, dynamicTarget, payloads);
|
|
682
|
+
}
|
|
683
|
+
const sides = walkSidesWithFilter(dynamicTarget, sortedPlayers, anchorSeat, payloads, characterMap);
|
|
684
|
+
return pickBalanced(sides, dynamicTarget, payloads);
|
|
707
685
|
}
|
|
708
686
|
return [];
|
|
709
687
|
};
|