valtech-components 4.0.573 → 4.0.576
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/esm2022/lib/components/organisms/mini-games/chessimals-engine.mjs +376 -67
- package/esm2022/lib/components/organisms/mini-games/chessimals-game.component.mjs +415 -262
- package/esm2022/lib/components/organisms/mini-games/mini-games.i18n.mjs +3 -1
- package/esm2022/lib/components/organisms/mini-games/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +792 -328
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/mini-games/chessimals-game.component.d.ts +2 -1
- package/lib/components/organisms/mini-games/types.d.ts +1 -1
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -59,7 +59,7 @@ import fixWebmDuration from 'fix-webm-duration';
|
|
|
59
59
|
* Current version of valtech-components.
|
|
60
60
|
* This is automatically updated during the publish process.
|
|
61
61
|
*/
|
|
62
|
-
const VERSION = '4.0.
|
|
62
|
+
const VERSION = '4.0.576';
|
|
63
63
|
|
|
64
64
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
65
65
|
let isRefreshing = false;
|
|
@@ -61711,28 +61711,250 @@ const CHESSIMALS_BOT_PROFILES = [
|
|
|
61711
61711
|
},
|
|
61712
61712
|
];
|
|
61713
61713
|
const BOT_STYLES = {
|
|
61714
|
-
explorer: {
|
|
61715
|
-
|
|
61716
|
-
|
|
61717
|
-
|
|
61718
|
-
|
|
61719
|
-
|
|
61720
|
-
|
|
61721
|
-
|
|
61722
|
-
|
|
61723
|
-
|
|
61724
|
-
|
|
61725
|
-
|
|
61726
|
-
|
|
61727
|
-
|
|
61728
|
-
|
|
61729
|
-
|
|
61730
|
-
|
|
61714
|
+
explorer: {
|
|
61715
|
+
advancement: 1.05,
|
|
61716
|
+
capture: 0.82,
|
|
61717
|
+
safety: 0.62,
|
|
61718
|
+
power: 0.8,
|
|
61719
|
+
center: 1.15,
|
|
61720
|
+
unlock: 1.05,
|
|
61721
|
+
reply: 0.7,
|
|
61722
|
+
randomness: 260,
|
|
61723
|
+
spread: 0.68,
|
|
61724
|
+
mobility: 0.75,
|
|
61725
|
+
trap: 0.5,
|
|
61726
|
+
endgame: 0.55,
|
|
61727
|
+
},
|
|
61728
|
+
impulsive: {
|
|
61729
|
+
advancement: 0.9,
|
|
61730
|
+
capture: 1.45,
|
|
61731
|
+
safety: 0.48,
|
|
61732
|
+
power: 1.15,
|
|
61733
|
+
center: 0.8,
|
|
61734
|
+
unlock: 0.9,
|
|
61735
|
+
reply: 0.55,
|
|
61736
|
+
randomness: 290,
|
|
61737
|
+
spread: 0.62,
|
|
61738
|
+
mobility: 0.85,
|
|
61739
|
+
trap: 0.62,
|
|
61740
|
+
endgame: 0.5,
|
|
61741
|
+
},
|
|
61742
|
+
runner: {
|
|
61743
|
+
advancement: 1.55,
|
|
61744
|
+
capture: 0.78,
|
|
61745
|
+
safety: 0.5,
|
|
61746
|
+
power: 0.95,
|
|
61747
|
+
center: 0.7,
|
|
61748
|
+
unlock: 1.1,
|
|
61749
|
+
reply: 0.55,
|
|
61750
|
+
randomness: 250,
|
|
61751
|
+
spread: 0.6,
|
|
61752
|
+
mobility: 0.72,
|
|
61753
|
+
trap: 0.45,
|
|
61754
|
+
endgame: 1.1,
|
|
61755
|
+
},
|
|
61756
|
+
hunter: {
|
|
61757
|
+
advancement: 0.95,
|
|
61758
|
+
capture: 1.45,
|
|
61759
|
+
safety: 0.9,
|
|
61760
|
+
power: 1.05,
|
|
61761
|
+
center: 0.95,
|
|
61762
|
+
unlock: 0.95,
|
|
61763
|
+
reply: 1,
|
|
61764
|
+
randomness: 90,
|
|
61765
|
+
spread: 0.3,
|
|
61766
|
+
mobility: 0.95,
|
|
61767
|
+
trap: 0.82,
|
|
61768
|
+
endgame: 0.76,
|
|
61769
|
+
},
|
|
61770
|
+
guardian: {
|
|
61771
|
+
advancement: 0.88,
|
|
61772
|
+
capture: 1,
|
|
61773
|
+
safety: 1.45,
|
|
61774
|
+
power: 0.85,
|
|
61775
|
+
center: 1.05,
|
|
61776
|
+
unlock: 1,
|
|
61777
|
+
reply: 1.15,
|
|
61778
|
+
randomness: 70,
|
|
61779
|
+
spread: 0.26,
|
|
61780
|
+
mobility: 0.82,
|
|
61781
|
+
trap: 0.72,
|
|
61782
|
+
endgame: 0.72,
|
|
61783
|
+
},
|
|
61784
|
+
jumper: {
|
|
61785
|
+
advancement: 1.12,
|
|
61786
|
+
capture: 1,
|
|
61787
|
+
safety: 0.92,
|
|
61788
|
+
power: 1.42,
|
|
61789
|
+
center: 1.18,
|
|
61790
|
+
unlock: 1.08,
|
|
61791
|
+
reply: 0.95,
|
|
61792
|
+
randomness: 95,
|
|
61793
|
+
spread: 0.32,
|
|
61794
|
+
mobility: 1.15,
|
|
61795
|
+
trap: 0.9,
|
|
61796
|
+
endgame: 0.82,
|
|
61797
|
+
},
|
|
61798
|
+
strategist: {
|
|
61799
|
+
advancement: 1.05,
|
|
61800
|
+
capture: 1.08,
|
|
61801
|
+
safety: 1.22,
|
|
61802
|
+
power: 1.08,
|
|
61803
|
+
center: 1.16,
|
|
61804
|
+
unlock: 1.1,
|
|
61805
|
+
reply: 1.25,
|
|
61806
|
+
randomness: 22,
|
|
61807
|
+
spread: 0.14,
|
|
61808
|
+
mobility: 1.08,
|
|
61809
|
+
trap: 1.06,
|
|
61810
|
+
endgame: 1,
|
|
61811
|
+
},
|
|
61812
|
+
predator: {
|
|
61813
|
+
advancement: 0.98,
|
|
61814
|
+
capture: 1.68,
|
|
61815
|
+
safety: 1.02,
|
|
61816
|
+
power: 1.34,
|
|
61817
|
+
center: 1,
|
|
61818
|
+
unlock: 1,
|
|
61819
|
+
reply: 1.12,
|
|
61820
|
+
randomness: 28,
|
|
61821
|
+
spread: 0.16,
|
|
61822
|
+
mobility: 1.02,
|
|
61823
|
+
trap: 1.18,
|
|
61824
|
+
endgame: 0.82,
|
|
61825
|
+
},
|
|
61826
|
+
sprinter: {
|
|
61827
|
+
advancement: 1.72,
|
|
61828
|
+
capture: 0.9,
|
|
61829
|
+
safety: 0.95,
|
|
61830
|
+
power: 1.08,
|
|
61831
|
+
center: 0.86,
|
|
61832
|
+
unlock: 1.18,
|
|
61833
|
+
reply: 1,
|
|
61834
|
+
randomness: 26,
|
|
61835
|
+
spread: 0.15,
|
|
61836
|
+
mobility: 0.95,
|
|
61837
|
+
trap: 0.78,
|
|
61838
|
+
endgame: 1.42,
|
|
61839
|
+
},
|
|
61840
|
+
sentinel: {
|
|
61841
|
+
advancement: 0.9,
|
|
61842
|
+
capture: 1.12,
|
|
61843
|
+
safety: 1.72,
|
|
61844
|
+
power: 0.95,
|
|
61845
|
+
center: 1.28,
|
|
61846
|
+
unlock: 1.05,
|
|
61847
|
+
reply: 1.38,
|
|
61848
|
+
randomness: 18,
|
|
61849
|
+
spread: 0.12,
|
|
61850
|
+
mobility: 0.86,
|
|
61851
|
+
trap: 1.04,
|
|
61852
|
+
endgame: 0.84,
|
|
61853
|
+
},
|
|
61854
|
+
oracle: {
|
|
61855
|
+
advancement: 1,
|
|
61856
|
+
capture: 1.12,
|
|
61857
|
+
safety: 1.42,
|
|
61858
|
+
power: 1.1,
|
|
61859
|
+
center: 1.18,
|
|
61860
|
+
unlock: 1.08,
|
|
61861
|
+
reply: 1.8,
|
|
61862
|
+
randomness: 8,
|
|
61863
|
+
spread: 0.08,
|
|
61864
|
+
mobility: 1.06,
|
|
61865
|
+
trap: 1.22,
|
|
61866
|
+
endgame: 1.08,
|
|
61867
|
+
},
|
|
61868
|
+
ambusher: {
|
|
61869
|
+
advancement: 0.9,
|
|
61870
|
+
capture: 1.48,
|
|
61871
|
+
safety: 1.08,
|
|
61872
|
+
power: 1.46,
|
|
61873
|
+
center: 1.05,
|
|
61874
|
+
unlock: 1.02,
|
|
61875
|
+
reply: 1.32,
|
|
61876
|
+
randomness: 14,
|
|
61877
|
+
spread: 0.1,
|
|
61878
|
+
mobility: 1.12,
|
|
61879
|
+
trap: 1.72,
|
|
61880
|
+
endgame: 0.92,
|
|
61881
|
+
},
|
|
61882
|
+
locksmith: {
|
|
61883
|
+
advancement: 0.88,
|
|
61884
|
+
capture: 1.04,
|
|
61885
|
+
safety: 1.55,
|
|
61886
|
+
power: 1.02,
|
|
61887
|
+
center: 1.48,
|
|
61888
|
+
unlock: 1.12,
|
|
61889
|
+
reply: 1.52,
|
|
61890
|
+
randomness: 12,
|
|
61891
|
+
spread: 0.1,
|
|
61892
|
+
mobility: 1.58,
|
|
61893
|
+
trap: 1.24,
|
|
61894
|
+
endgame: 0.86,
|
|
61895
|
+
},
|
|
61896
|
+
storm: {
|
|
61897
|
+
advancement: 1.18,
|
|
61898
|
+
capture: 1.38,
|
|
61899
|
+
safety: 0.98,
|
|
61900
|
+
power: 1.62,
|
|
61901
|
+
center: 1.08,
|
|
61902
|
+
unlock: 1.18,
|
|
61903
|
+
reply: 1.22,
|
|
61904
|
+
randomness: 18,
|
|
61905
|
+
spread: 0.13,
|
|
61906
|
+
mobility: 1.36,
|
|
61907
|
+
trap: 1.28,
|
|
61908
|
+
endgame: 1.02,
|
|
61909
|
+
},
|
|
61910
|
+
matriarch: {
|
|
61911
|
+
advancement: 0.96,
|
|
61912
|
+
capture: 1.18,
|
|
61913
|
+
safety: 1.64,
|
|
61914
|
+
power: 1.18,
|
|
61915
|
+
center: 1.22,
|
|
61916
|
+
unlock: 1.08,
|
|
61917
|
+
reply: 1.66,
|
|
61918
|
+
randomness: 10,
|
|
61919
|
+
spread: 0.08,
|
|
61920
|
+
mobility: 1.02,
|
|
61921
|
+
trap: 1.36,
|
|
61922
|
+
endgame: 1,
|
|
61923
|
+
},
|
|
61924
|
+
endgame: {
|
|
61925
|
+
advancement: 1.46,
|
|
61926
|
+
capture: 1,
|
|
61927
|
+
safety: 1.28,
|
|
61928
|
+
power: 1.04,
|
|
61929
|
+
center: 0.94,
|
|
61930
|
+
unlock: 1.08,
|
|
61931
|
+
reply: 1.44,
|
|
61932
|
+
randomness: 10,
|
|
61933
|
+
spread: 0.09,
|
|
61934
|
+
mobility: 0.98,
|
|
61935
|
+
trap: 1.02,
|
|
61936
|
+
endgame: 1.86,
|
|
61937
|
+
},
|
|
61938
|
+
magnus: {
|
|
61939
|
+
advancement: 1.04,
|
|
61940
|
+
capture: 1.22,
|
|
61941
|
+
safety: 1.9,
|
|
61942
|
+
power: 0.9,
|
|
61943
|
+
center: 1.42,
|
|
61944
|
+
unlock: 1.08,
|
|
61945
|
+
reply: 2.08,
|
|
61946
|
+
randomness: 3,
|
|
61947
|
+
spread: 0.04,
|
|
61948
|
+
mobility: 1.08,
|
|
61949
|
+
trap: 1.42,
|
|
61950
|
+
endgame: 1.86,
|
|
61951
|
+
},
|
|
61731
61952
|
};
|
|
61732
61953
|
const DEFAULT_BOT_PROFILE_BY_DIFFICULTY = {
|
|
61733
61954
|
easy: 'explorer',
|
|
61734
61955
|
normal: 'hunter',
|
|
61735
61956
|
hard: 'strategist',
|
|
61957
|
+
master: 'magnus',
|
|
61736
61958
|
};
|
|
61737
61959
|
function createChessimalsGame(boardSize = 6, options = {}) {
|
|
61738
61960
|
const pieces = [];
|
|
@@ -61772,12 +61994,12 @@ function createChessimalsGame(boardSize = 6, options = {}) {
|
|
|
61772
61994
|
};
|
|
61773
61995
|
}
|
|
61774
61996
|
function getChessimalsPieceAt(state, position) {
|
|
61775
|
-
return activePieces(state).find(
|
|
61997
|
+
return activePieces(state).find(piece => !piece.captured && piece.position.row === position.row && piece.position.col === position.col);
|
|
61776
61998
|
}
|
|
61777
61999
|
function getChessimalsLegalMoves(state, pieceId, animal) {
|
|
61778
62000
|
if (state.status !== 'in_progress')
|
|
61779
62001
|
return [];
|
|
61780
|
-
const piece = activePieces(state).find(
|
|
62002
|
+
const piece = activePieces(state).find(item => item.id === pieceId && !item.captured);
|
|
61781
62003
|
if (!piece || piece.color !== state.currentTurn)
|
|
61782
62004
|
return [];
|
|
61783
62005
|
if (animal) {
|
|
@@ -61816,9 +62038,18 @@ function chooseChessimalsBotMove(state, difficulty = 'normal', profileId = DEFAU
|
|
|
61816
62038
|
const challengePressure = getChallengePressure(options.challengeRound);
|
|
61817
62039
|
const style = tuneBotStyle(baseStyle, difficulty, challengePressure, options.nightmareMode);
|
|
61818
62040
|
const quickScored = moves
|
|
61819
|
-
.map(
|
|
62041
|
+
.map(move => ({
|
|
62042
|
+
move,
|
|
62043
|
+
score: scoreBotMove(state, move, difficulty, style, challengePressure, false, options.nightmareMode),
|
|
62044
|
+
}))
|
|
61820
62045
|
.sort((a, b) => b.score - a.score);
|
|
61821
|
-
const lookaheadLimit = options.nightmareMode === 'magnus'
|
|
62046
|
+
const lookaheadLimit = options.nightmareMode === 'magnus' || difficulty === 'master'
|
|
62047
|
+
? 48
|
|
62048
|
+
: difficulty === 'hard'
|
|
62049
|
+
? 32
|
|
62050
|
+
: difficulty === 'normal'
|
|
62051
|
+
? 24
|
|
62052
|
+
: 0;
|
|
61822
62053
|
const scored = quickScored
|
|
61823
62054
|
.map((item, index) => ({
|
|
61824
62055
|
move: item.move,
|
|
@@ -61828,18 +62059,18 @@ function chooseChessimalsBotMove(state, difficulty = 'normal', profileId = DEFAU
|
|
|
61828
62059
|
}))
|
|
61829
62060
|
.sort((a, b) => b.score - a.score);
|
|
61830
62061
|
if (difficulty === 'easy') {
|
|
61831
|
-
const playable = scored.filter(
|
|
62062
|
+
const playable = scored.filter(item => item.score > -3000);
|
|
61832
62063
|
return pickNoisyBotMove(playable.length ? playable : scored, 0.55);
|
|
61833
62064
|
}
|
|
61834
62065
|
if (difficulty === 'normal') {
|
|
61835
62066
|
return scored[0]?.move;
|
|
61836
62067
|
}
|
|
61837
|
-
const winningMove = scored.find(
|
|
62068
|
+
const winningMove = scored.find(item => item.score >= 10000);
|
|
61838
62069
|
if (winningMove)
|
|
61839
62070
|
return winningMove.move;
|
|
61840
|
-
const opponentWinningTargets = new Set(getImmediateWinningMoves(state, otherColor(state.currentTurn)).map(
|
|
62071
|
+
const opponentWinningTargets = new Set(getImmediateWinningMoves(state, otherColor(state.currentTurn)).map(move => positionKey(move.to)));
|
|
61841
62072
|
if (opponentWinningTargets.size > 0) {
|
|
61842
|
-
const blockingMove = scored.find(
|
|
62073
|
+
const blockingMove = scored.find(item => item.move.capturesPieceId || opponentWinningTargets.has(positionKey(item.move.to)));
|
|
61843
62074
|
if (blockingMove)
|
|
61844
62075
|
return blockingMove.move;
|
|
61845
62076
|
}
|
|
@@ -61855,15 +62086,15 @@ function chooseChessimalsBotMove(state, difficulty = 'normal', profileId = DEFAU
|
|
|
61855
62086
|
return scored[0]?.move;
|
|
61856
62087
|
}
|
|
61857
62088
|
function applyChessimalsMove(state, candidate) {
|
|
61858
|
-
const legalMove = getChessimalsLegalMoves(state, candidate.pieceId, candidate.animal).find(
|
|
62089
|
+
const legalMove = getChessimalsLegalMoves(state, candidate.pieceId, candidate.animal).find(move => samePosition(move.from, candidate.from) && samePosition(move.to, candidate.to));
|
|
61859
62090
|
if (!legalMove) {
|
|
61860
62091
|
throw new Error('CHESSIMALS_ILLEGAL_MOVE');
|
|
61861
62092
|
}
|
|
61862
|
-
const movedPiece = activePieces(state).find(
|
|
62093
|
+
const movedPiece = activePieces(state).find(piece => piece.id === legalMove.pieceId);
|
|
61863
62094
|
if (!movedPiece) {
|
|
61864
62095
|
throw new Error('CHESSIMALS_PIECE_NOT_FOUND');
|
|
61865
62096
|
}
|
|
61866
|
-
const pieces = activePieces(state).map(
|
|
62097
|
+
const pieces = activePieces(state).map(piece => {
|
|
61867
62098
|
if (piece.id === legalMove.pieceId) {
|
|
61868
62099
|
return { ...piece, position: { ...legalMove.to } };
|
|
61869
62100
|
}
|
|
@@ -61893,7 +62124,7 @@ function applyChessimalsMove(state, candidate) {
|
|
|
61893
62124
|
lastMove: legalMove,
|
|
61894
62125
|
});
|
|
61895
62126
|
const promoted = isPromotionRow(nextState.boardSize, movedPiece.color, legalMove.to);
|
|
61896
|
-
const enemyPieces = activePieces(nextState).filter(
|
|
62127
|
+
const enemyPieces = activePieces(nextState).filter(piece => piece.color !== movedPiece.color && !piece.captured);
|
|
61897
62128
|
const enemyHasLegalMoves = getChessimalsAllLegalMoves(nextState, nextState.currentTurn).length > 0;
|
|
61898
62129
|
const resolvedState = promoted || enemyPieces.length === 0 || !enemyHasLegalMoves
|
|
61899
62130
|
? {
|
|
@@ -61909,10 +62140,7 @@ function applyChessimalsMove(state, candidate) {
|
|
|
61909
62140
|
: nextState;
|
|
61910
62141
|
return {
|
|
61911
62142
|
...resolvedState,
|
|
61912
|
-
moveHistory: [
|
|
61913
|
-
...ensureMoveHistory(state),
|
|
61914
|
-
createMoveHistoryEntry(resolvedState, legalMove),
|
|
61915
|
-
],
|
|
62143
|
+
moveHistory: [...ensureMoveHistory(state), createMoveHistoryEntry(resolvedState, legalMove)],
|
|
61916
62144
|
};
|
|
61917
62145
|
}
|
|
61918
62146
|
function createChessimalsReviewState(state, entry) {
|
|
@@ -61955,7 +62183,7 @@ function cloneMoveHistoryEntry(entry) {
|
|
|
61955
62183
|
};
|
|
61956
62184
|
}
|
|
61957
62185
|
function clonePieces(pieces) {
|
|
61958
|
-
return pieces.map(
|
|
62186
|
+
return pieces.map(piece => ({
|
|
61959
62187
|
...piece,
|
|
61960
62188
|
position: { ...piece.position },
|
|
61961
62189
|
}));
|
|
@@ -61979,10 +62207,7 @@ function resignChessimalsGame(state, color) {
|
|
|
61979
62207
|
};
|
|
61980
62208
|
return {
|
|
61981
62209
|
...resignedState,
|
|
61982
|
-
moveHistory: [
|
|
61983
|
-
...ensureMoveHistory(state),
|
|
61984
|
-
createMoveHistoryEntry(resignedState),
|
|
61985
|
-
],
|
|
62210
|
+
moveHistory: [...ensureMoveHistory(state), createMoveHistoryEntry(resignedState)],
|
|
61986
62211
|
};
|
|
61987
62212
|
}
|
|
61988
62213
|
function positionKey(position) {
|
|
@@ -62109,12 +62334,16 @@ function getKangarooMoves(state, piece) {
|
|
|
62109
62334
|
function scoreBotMove(state, move, difficulty, style, challengePressure = 0, includeTacticalPressure = true, nightmareMode = 'none') {
|
|
62110
62335
|
const color = state.currentTurn;
|
|
62111
62336
|
const targetPiece = move.capturesPieceId
|
|
62112
|
-
? activePieces(state).find(
|
|
62337
|
+
? activePieces(state).find(piece => piece.id === move.capturesPieceId)
|
|
62113
62338
|
: undefined;
|
|
62114
62339
|
const advancement = color === 'white' ? state.boardSize - 1 - move.to.row : move.to.row;
|
|
62115
62340
|
let score = advancement * 24 * style.advancement;
|
|
62116
62341
|
const stepsToPromotion = color === 'white' ? move.to.row : state.boardSize - 1 - move.to.row;
|
|
62117
|
-
score +=
|
|
62342
|
+
score +=
|
|
62343
|
+
Math.max(0, state.boardSize - 1 - stepsToPromotion) *
|
|
62344
|
+
10 *
|
|
62345
|
+
challengePressure *
|
|
62346
|
+
style.advancement;
|
|
62118
62347
|
if (move.kind === 'basic' && isPromotionRow(state.boardSize, color, move.to)) {
|
|
62119
62348
|
score += 10000 + 2500 * challengePressure;
|
|
62120
62349
|
}
|
|
@@ -62131,7 +62360,9 @@ function scoreBotMove(state, move, difficulty, style, challengePressure = 0, inc
|
|
|
62131
62360
|
score += targetAdvancement * (16 + 8 * challengePressure) * style.capture;
|
|
62132
62361
|
}
|
|
62133
62362
|
if (move.kind === 'power') {
|
|
62134
|
-
score +=
|
|
62363
|
+
score +=
|
|
62364
|
+
(targetPiece ? 120 : difficulty === 'hard' ? -60 - 170 * challengePressure : -30) *
|
|
62365
|
+
style.power;
|
|
62135
62366
|
}
|
|
62136
62367
|
if (nightmareMode === 'magnus' && move.kind === 'power') {
|
|
62137
62368
|
score += scoreMagnusPowerPatience(state, move, targetPiece, style);
|
|
@@ -62143,8 +62374,14 @@ function scoreBotMove(state, move, difficulty, style, challengePressure = 0, inc
|
|
|
62143
62374
|
if (wouldUnlockPower(state, color, move.to))
|
|
62144
62375
|
score += 90 * style.unlock;
|
|
62145
62376
|
if (includeTacticalPressure && state.boardSize <= 6) {
|
|
62146
|
-
score +=
|
|
62147
|
-
|
|
62377
|
+
score +=
|
|
62378
|
+
countPowerReachAfterMove(state, move, color) *
|
|
62379
|
+
(difficulty === 'hard' ? 8 : 4) *
|
|
62380
|
+
style.mobility;
|
|
62381
|
+
score +=
|
|
62382
|
+
countProtectedThreatsAfterMove(state, move, color) *
|
|
62383
|
+
(difficulty === 'hard' ? 36 : 18) *
|
|
62384
|
+
style.trap;
|
|
62148
62385
|
score += scoreEndgamePressure(state, move, color) * style.endgame;
|
|
62149
62386
|
}
|
|
62150
62387
|
else {
|
|
@@ -62163,30 +62400,83 @@ function scoreBotMoveWithLookahead(state, move, difficulty, style, challengePres
|
|
|
62163
62400
|
if (afterMove.status === 'finished')
|
|
62164
62401
|
return score + 5000;
|
|
62165
62402
|
const opponentMoves = getChessimalsAllLegalMoves(afterMove);
|
|
62166
|
-
const opponentImmediateWin = opponentMoves.some(
|
|
62403
|
+
const opponentImmediateWin = opponentMoves.some(opponentMove => opponentMove.kind === 'basic' &&
|
|
62167
62404
|
isPromotionRow(afterMove.boardSize, afterMove.currentTurn, opponentMove.to));
|
|
62168
62405
|
if (opponentImmediateWin) {
|
|
62169
|
-
score -=
|
|
62170
|
-
|
|
62171
|
-
|
|
62406
|
+
score -=
|
|
62407
|
+
(difficulty === 'easy'
|
|
62408
|
+
? 1800
|
|
62409
|
+
: difficulty === 'normal'
|
|
62410
|
+
? 5200
|
|
62411
|
+
: 8000 + 4200 * challengePressure) * style.safety;
|
|
62412
|
+
}
|
|
62413
|
+
const movedPiece = afterMove.pieces.find(piece => piece.id === move.pieceId && !piece.captured);
|
|
62172
62414
|
if (movedPiece) {
|
|
62173
|
-
const canCaptureMovedPiece = opponentMoves.some(
|
|
62415
|
+
const canCaptureMovedPiece = opponentMoves.some(opponentMove => opponentMove.capturesPieceId === move.pieceId);
|
|
62174
62416
|
if (canCaptureMovedPiece) {
|
|
62175
|
-
score -=
|
|
62176
|
-
|
|
62177
|
-
|
|
62417
|
+
score -=
|
|
62418
|
+
(move.capturesPieceId
|
|
62419
|
+
? 180
|
|
62420
|
+
: difficulty === 'easy'
|
|
62421
|
+
? 120
|
|
62422
|
+
: difficulty === 'normal'
|
|
62423
|
+
? 360
|
|
62424
|
+
: 560) *
|
|
62425
|
+
style.safety *
|
|
62426
|
+
(1 + challengePressure);
|
|
62178
62427
|
}
|
|
62179
62428
|
const center = (afterMove.boardSize - 1) / 2;
|
|
62180
62429
|
const centerControl = Math.max(0, afterMove.boardSize / 2 - Math.abs(movedPiece.position.col - center));
|
|
62181
62430
|
score += centerControl * (difficulty === 'hard' ? 18 : 10) * style.center;
|
|
62182
62431
|
}
|
|
62183
62432
|
const opponentBestReply = opponentMoves
|
|
62184
|
-
.map(
|
|
62433
|
+
.map(opponentMove => scoreBotMove(afterMove, opponentMove, difficulty, style, challengePressure, false, nightmareMode))
|
|
62185
62434
|
.sort((a, b) => b - a)[0];
|
|
62186
62435
|
if (opponentBestReply) {
|
|
62187
|
-
const replyWeight = difficulty === 'easy'
|
|
62436
|
+
const replyWeight = difficulty === 'easy'
|
|
62437
|
+
? 0.12
|
|
62438
|
+
: difficulty === 'normal'
|
|
62439
|
+
? 0.4 + 0.1 * challengePressure
|
|
62440
|
+
: difficulty === 'master'
|
|
62441
|
+
? 0.72 + 0.22 * challengePressure
|
|
62442
|
+
: nightmareMode && nightmareMode !== 'none'
|
|
62443
|
+
? 0.82 + 0.18 * challengePressure
|
|
62444
|
+
: 0.48 + 0.16 * challengePressure;
|
|
62188
62445
|
score -= opponentBestReply * replyWeight * style.reply;
|
|
62189
62446
|
}
|
|
62447
|
+
if (difficulty === 'hard' || difficulty === 'master') {
|
|
62448
|
+
const topOppMoves = opponentMoves
|
|
62449
|
+
.map(m => ({
|
|
62450
|
+
move: m,
|
|
62451
|
+
score: scoreBotMove(afterMove, m, difficulty, style, challengePressure, false, nightmareMode),
|
|
62452
|
+
}))
|
|
62453
|
+
.sort((a, b) => b.score - a.score)
|
|
62454
|
+
.slice(0, 4);
|
|
62455
|
+
for (const { move: oppMove } of topOppMoves) {
|
|
62456
|
+
try {
|
|
62457
|
+
const s2 = applyChessimalsMove(afterMove, oppMove);
|
|
62458
|
+
if (s2.status === 'finished')
|
|
62459
|
+
continue;
|
|
62460
|
+
const myCounters = getChessimalsAllLegalMoves(s2);
|
|
62461
|
+
if (myCounters.length === 0)
|
|
62462
|
+
continue;
|
|
62463
|
+
const myBest = myCounters
|
|
62464
|
+
.map(m => scoreBotMove(s2, m, difficulty, style, challengePressure, false, nightmareMode))
|
|
62465
|
+
.sort((a, b) => b - a)[0] ?? 0;
|
|
62466
|
+
score +=
|
|
62467
|
+
myBest *
|
|
62468
|
+
(difficulty === 'master'
|
|
62469
|
+
? 0.22
|
|
62470
|
+
: nightmareMode && nightmareMode !== 'none'
|
|
62471
|
+
? 0.2
|
|
62472
|
+
: 0.14) *
|
|
62473
|
+
style.reply;
|
|
62474
|
+
}
|
|
62475
|
+
catch {
|
|
62476
|
+
// skip
|
|
62477
|
+
}
|
|
62478
|
+
}
|
|
62479
|
+
}
|
|
62190
62480
|
}
|
|
62191
62481
|
catch {
|
|
62192
62482
|
score -= 1000;
|
|
@@ -62194,9 +62484,9 @@ function scoreBotMoveWithLookahead(state, move, difficulty, style, challengePres
|
|
|
62194
62484
|
return score;
|
|
62195
62485
|
}
|
|
62196
62486
|
function getChallengePressure(round) {
|
|
62197
|
-
if (!round
|
|
62487
|
+
if (!round)
|
|
62198
62488
|
return 0;
|
|
62199
|
-
return Math.min(1, Math.max(0,
|
|
62489
|
+
return Math.min(1, Math.max(0, round / 8));
|
|
62200
62490
|
}
|
|
62201
62491
|
function tuneBotStyle(style, difficulty, challengePressure, nightmareMode = 'none') {
|
|
62202
62492
|
if (nightmareMode === 'hunt') {
|
|
@@ -62234,9 +62524,28 @@ function tuneBotStyle(style, difficulty, challengePressure, nightmareMode = 'non
|
|
|
62234
62524
|
endgame: style.endgame * 1.28,
|
|
62235
62525
|
};
|
|
62236
62526
|
}
|
|
62527
|
+
if (difficulty === 'master') {
|
|
62528
|
+
style = {
|
|
62529
|
+
...style,
|
|
62530
|
+
capture: style.capture * 1.08,
|
|
62531
|
+
safety: style.safety * 1.22,
|
|
62532
|
+
reply: style.reply * 1.32,
|
|
62533
|
+
center: style.center * 1.12,
|
|
62534
|
+
randomness: Math.min(style.randomness, 3),
|
|
62535
|
+
spread: style.spread * 0.5,
|
|
62536
|
+
trap: style.trap * 1.14,
|
|
62537
|
+
endgame: style.endgame * 1.18,
|
|
62538
|
+
};
|
|
62539
|
+
}
|
|
62237
62540
|
if (!challengePressure)
|
|
62238
62541
|
return style;
|
|
62239
|
-
const pressure = difficulty === 'easy'
|
|
62542
|
+
const pressure = difficulty === 'easy'
|
|
62543
|
+
? challengePressure * 0.45
|
|
62544
|
+
: difficulty === 'master'
|
|
62545
|
+
? challengePressure * 1.15
|
|
62546
|
+
: nightmareMode && nightmareMode !== 'none'
|
|
62547
|
+
? challengePressure * 1.25
|
|
62548
|
+
: challengePressure;
|
|
62240
62549
|
return {
|
|
62241
62550
|
...style,
|
|
62242
62551
|
capture: style.capture * (1 + pressure * 0.28),
|
|
@@ -62251,7 +62560,7 @@ function chooseChallengeBasicCapture(scored, challengePressure) {
|
|
|
62251
62560
|
if (challengePressure < 0.5)
|
|
62252
62561
|
return undefined;
|
|
62253
62562
|
const best = scored[0];
|
|
62254
|
-
const bestBasicCapture = scored.find(
|
|
62563
|
+
const bestBasicCapture = scored.find(item => item.move.kind === 'basic' && item.move.capturesPieceId);
|
|
62255
62564
|
if (!best || !bestBasicCapture)
|
|
62256
62565
|
return undefined;
|
|
62257
62566
|
if (best.move.kind === 'basic' && best.move.capturesPieceId)
|
|
@@ -62263,7 +62572,7 @@ function chooseNightmareCapture(scored, nightmareMode) {
|
|
|
62263
62572
|
if (nightmareMode !== 'hunt')
|
|
62264
62573
|
return undefined;
|
|
62265
62574
|
const best = scored[0];
|
|
62266
|
-
const capture = scored.find(
|
|
62575
|
+
const capture = scored.find(item => item.move.capturesPieceId);
|
|
62267
62576
|
if (!best || !capture)
|
|
62268
62577
|
return undefined;
|
|
62269
62578
|
return best.score - capture.score <= 1800 ? capture.move : undefined;
|
|
@@ -62288,7 +62597,7 @@ function countPowerReachAfterMove(state, move, color) {
|
|
|
62288
62597
|
try {
|
|
62289
62598
|
const afterMove = applyChessimalsMove(state, move);
|
|
62290
62599
|
const evaluationState = { ...afterMove, currentTurn: color };
|
|
62291
|
-
return getChessimalsAllLegalMoves(evaluationState, color).filter(
|
|
62600
|
+
return getChessimalsAllLegalMoves(evaluationState, color).filter(nextMove => nextMove.kind === 'power').length;
|
|
62292
62601
|
}
|
|
62293
62602
|
catch {
|
|
62294
62603
|
return 0;
|
|
@@ -62299,15 +62608,15 @@ function countProtectedThreatsAfterMove(state, move, color) {
|
|
|
62299
62608
|
const afterMove = applyChessimalsMove(state, move);
|
|
62300
62609
|
const evaluationState = { ...afterMove, currentTurn: color };
|
|
62301
62610
|
const ourMoves = getChessimalsAllLegalMoves(evaluationState, color);
|
|
62302
|
-
const enemyPieces = activePieces(afterMove).filter(
|
|
62303
|
-
return enemyPieces.filter(
|
|
62611
|
+
const enemyPieces = activePieces(afterMove).filter(piece => piece.color !== color && !piece.captured);
|
|
62612
|
+
return enemyPieces.filter(piece => ourMoves.some(nextMove => nextMove.capturesPieceId === piece.id)).length;
|
|
62304
62613
|
}
|
|
62305
62614
|
catch {
|
|
62306
62615
|
return 0;
|
|
62307
62616
|
}
|
|
62308
62617
|
}
|
|
62309
62618
|
function scoreEndgamePressure(state, move, color) {
|
|
62310
|
-
const remainingEnemyPieces = activePieces(state).filter(
|
|
62619
|
+
const remainingEnemyPieces = activePieces(state).filter(piece => piece.color !== color && !piece.captured).length;
|
|
62311
62620
|
const urgency = remainingEnemyPieces <= Math.max(2, Math.floor(state.boardSize / 2)) ? 1.6 : 1;
|
|
62312
62621
|
const distanceToPromotion = color === 'white' ? move.to.row : state.boardSize - 1 - move.to.row;
|
|
62313
62622
|
return Math.max(0, state.boardSize - distanceToPromotion) * 14 * urgency;
|
|
@@ -62319,7 +62628,7 @@ function chooseConservativeHardCapture(state, scored) {
|
|
|
62319
62628
|
if (!best || best.move.kind !== 'power' || !best.move.capturesPieceId || best.score >= 10000) {
|
|
62320
62629
|
return undefined;
|
|
62321
62630
|
}
|
|
62322
|
-
const bestBasicCapture = scored.find(
|
|
62631
|
+
const bestBasicCapture = scored.find(item => item.move.kind === 'basic' && item.move.capturesPieceId);
|
|
62323
62632
|
if (!bestBasicCapture)
|
|
62324
62633
|
return undefined;
|
|
62325
62634
|
return best.score - bestBasicCapture.score <= 650 ? bestBasicCapture.move : undefined;
|
|
@@ -62345,7 +62654,7 @@ function pickNoisyBotMove(scored, spread) {
|
|
|
62345
62654
|
return pool[0]?.move;
|
|
62346
62655
|
}
|
|
62347
62656
|
function getImmediateWinningMoves(state, color) {
|
|
62348
|
-
return getChessimalsAllLegalMoves(state, color).filter(
|
|
62657
|
+
return getChessimalsAllLegalMoves(state, color).filter(move => move.kind === 'basic' && isPromotionRow(state.boardSize, color, move.to));
|
|
62349
62658
|
}
|
|
62350
62659
|
function wouldUnlockPower(state, color, position) {
|
|
62351
62660
|
if (state.players[color].powerUnlocked)
|
|
@@ -62359,7 +62668,7 @@ function isSquareVulnerableAfterMove(state, move) {
|
|
|
62359
62668
|
const afterMove = applyChessimalsMove(state, move);
|
|
62360
62669
|
if (afterMove.status === 'finished')
|
|
62361
62670
|
return false;
|
|
62362
|
-
return getChessimalsAllLegalMoves(afterMove).some(
|
|
62671
|
+
return getChessimalsAllLegalMoves(afterMove).some(enemyMove => samePosition(enemyMove.to, move.to) && !!enemyMove.capturesPieceId);
|
|
62363
62672
|
}
|
|
62364
62673
|
catch {
|
|
62365
62674
|
return false;
|
|
@@ -62415,7 +62724,7 @@ function refreshChessimalsPowerUnlocks(state) {
|
|
|
62415
62724
|
function hasCrossedCenter(state, color) {
|
|
62416
62725
|
const centerTop = state.boardSize / 2 - 1;
|
|
62417
62726
|
const centerBottom = state.boardSize / 2;
|
|
62418
|
-
return activePieces(state).some(
|
|
62727
|
+
return activePieces(state).some(piece => {
|
|
62419
62728
|
if (piece.color !== color || piece.captured)
|
|
62420
62729
|
return false;
|
|
62421
62730
|
return color === 'white' ? piece.position.row <= centerTop : piece.position.row >= centerBottom;
|
|
@@ -62425,7 +62734,7 @@ function hasEnemyEnteredHome(state, color) {
|
|
|
62425
62734
|
const centerTop = state.boardSize / 2 - 1;
|
|
62426
62735
|
const centerBottom = state.boardSize / 2;
|
|
62427
62736
|
const enemy = otherColor(color);
|
|
62428
|
-
return activePieces(state).some(
|
|
62737
|
+
return activePieces(state).some(piece => {
|
|
62429
62738
|
if (piece.color !== enemy || piece.captured)
|
|
62430
62739
|
return false;
|
|
62431
62740
|
return color === 'white' ? piece.position.row >= centerBottom : piece.position.row <= centerTop;
|
|
@@ -64009,6 +64318,7 @@ const MINI_GAMES_I18N = {
|
|
|
64009
64318
|
chessimalsBotEasy: 'Suave',
|
|
64010
64319
|
chessimalsBotNormal: 'Normal',
|
|
64011
64320
|
chessimalsBotHard: 'Maestro',
|
|
64321
|
+
chessimalsBotMaster: 'Experto',
|
|
64012
64322
|
chessimalsBotNightmare: 'Pesadilla',
|
|
64013
64323
|
chessimalsNightmareRivals: 'Rivales pesadilla',
|
|
64014
64324
|
chessimalsNightmareMode: 'Modo pesadilla',
|
|
@@ -64803,6 +65113,7 @@ const MINI_GAMES_I18N = {
|
|
|
64803
65113
|
chessimalsBotEasy: 'Gentle',
|
|
64804
65114
|
chessimalsBotNormal: 'Normal',
|
|
64805
65115
|
chessimalsBotHard: 'Master',
|
|
65116
|
+
chessimalsBotMaster: 'Expert',
|
|
64806
65117
|
chessimalsBotNightmare: 'Nightmare',
|
|
64807
65118
|
chessimalsNightmareRivals: 'Nightmare rivals',
|
|
64808
65119
|
chessimalsNightmareMode: 'Nightmare mode',
|
|
@@ -66373,14 +66684,70 @@ const ANIMALS = [
|
|
|
66373
66684
|
{ type: 'lion', assetSrc: `${CHESSIMALS_POWER_ASSET_BASE}/lion-power.png`, tone: 392 },
|
|
66374
66685
|
];
|
|
66375
66686
|
const CHESSIMALS_CHALLENGE_LADDER = [
|
|
66376
|
-
{
|
|
66377
|
-
|
|
66378
|
-
|
|
66379
|
-
|
|
66380
|
-
|
|
66381
|
-
|
|
66382
|
-
|
|
66383
|
-
|
|
66687
|
+
{
|
|
66688
|
+
id: 'sprout',
|
|
66689
|
+
round: 1,
|
|
66690
|
+
profileId: 'explorer',
|
|
66691
|
+
difficulty: 'easy',
|
|
66692
|
+
boardSize: 6,
|
|
66693
|
+
introKey: 'chessimalsChallengeBotSproutIntro',
|
|
66694
|
+
},
|
|
66695
|
+
{
|
|
66696
|
+
id: 'sentinel',
|
|
66697
|
+
round: 2,
|
|
66698
|
+
profileId: 'guardian',
|
|
66699
|
+
difficulty: 'normal',
|
|
66700
|
+
boardSize: 6,
|
|
66701
|
+
introKey: 'chessimalsChallengeBotSentinelIntro',
|
|
66702
|
+
},
|
|
66703
|
+
{
|
|
66704
|
+
id: 'hunter',
|
|
66705
|
+
round: 3,
|
|
66706
|
+
profileId: 'hunter',
|
|
66707
|
+
difficulty: 'normal',
|
|
66708
|
+
boardSize: 6,
|
|
66709
|
+
introKey: 'chessimalsChallengeBotHunterIntro',
|
|
66710
|
+
},
|
|
66711
|
+
{
|
|
66712
|
+
id: 'jumper',
|
|
66713
|
+
round: 4,
|
|
66714
|
+
profileId: 'jumper',
|
|
66715
|
+
difficulty: 'normal',
|
|
66716
|
+
boardSize: 6,
|
|
66717
|
+
introKey: 'chessimalsChallengeBotJumperIntro',
|
|
66718
|
+
},
|
|
66719
|
+
{
|
|
66720
|
+
id: 'predator',
|
|
66721
|
+
round: 5,
|
|
66722
|
+
profileId: 'predator',
|
|
66723
|
+
difficulty: 'hard',
|
|
66724
|
+
boardSize: 8,
|
|
66725
|
+
introKey: 'chessimalsChallengeBotPredatorIntro',
|
|
66726
|
+
},
|
|
66727
|
+
{
|
|
66728
|
+
id: 'oracle',
|
|
66729
|
+
round: 6,
|
|
66730
|
+
profileId: 'strategist',
|
|
66731
|
+
difficulty: 'hard',
|
|
66732
|
+
boardSize: 8,
|
|
66733
|
+
introKey: 'chessimalsChallengeBotOracleIntro',
|
|
66734
|
+
},
|
|
66735
|
+
{
|
|
66736
|
+
id: 'sprinter',
|
|
66737
|
+
round: 7,
|
|
66738
|
+
profileId: 'sprinter',
|
|
66739
|
+
difficulty: 'master',
|
|
66740
|
+
boardSize: 8,
|
|
66741
|
+
introKey: 'chessimalsChallengeBotSprinterIntro',
|
|
66742
|
+
},
|
|
66743
|
+
{
|
|
66744
|
+
id: 'champion',
|
|
66745
|
+
round: 8,
|
|
66746
|
+
profileId: 'magnus',
|
|
66747
|
+
difficulty: 'master',
|
|
66748
|
+
boardSize: 8,
|
|
66749
|
+
introKey: 'chessimalsChallengeBotChampionIntro',
|
|
66750
|
+
},
|
|
66384
66751
|
];
|
|
66385
66752
|
class ChessimalsGameComponent {
|
|
66386
66753
|
set onlineGameId(value) {
|
|
@@ -66410,7 +66777,7 @@ class ChessimalsGameComponent {
|
|
|
66410
66777
|
this.turnTimerExpiredKey = '';
|
|
66411
66778
|
this.boardSizes = [6, 8];
|
|
66412
66779
|
this.localModes = ['one-device', 'bot'];
|
|
66413
|
-
this.botDifficulties = ['easy', 'normal', 'hard', 'nightmare'];
|
|
66780
|
+
this.botDifficulties = ['easy', 'normal', 'hard', 'master', 'nightmare'];
|
|
66414
66781
|
this.nightmareRivals = ['hunt', 'pride', 'magnus'];
|
|
66415
66782
|
this.botProfiles = CHESSIMALS_BOT_PROFILES;
|
|
66416
66783
|
this.challengeLadder = CHESSIMALS_CHALLENGE_LADDER;
|
|
@@ -66617,7 +66984,7 @@ class ChessimalsGameComponent {
|
|
|
66617
66984
|
color: 'primary',
|
|
66618
66985
|
startLabel: '0',
|
|
66619
66986
|
endLabel: '100',
|
|
66620
|
-
pinFormatter:
|
|
66987
|
+
pinFormatter: value => `${value}%`,
|
|
66621
66988
|
}));
|
|
66622
66989
|
this.sfxVolumeProps = computed(() => ({
|
|
66623
66990
|
control: this.sfxVolumeControl,
|
|
@@ -66629,30 +66996,39 @@ class ChessimalsGameComponent {
|
|
|
66629
66996
|
color: 'primary',
|
|
66630
66997
|
startLabel: '0',
|
|
66631
66998
|
endLabel: '100',
|
|
66632
|
-
pinFormatter:
|
|
66999
|
+
pinFormatter: value => `${value}%`,
|
|
66633
67000
|
}));
|
|
66634
67001
|
this.availableBotProfiles = computed(() => {
|
|
66635
67002
|
const difficulty = this.selectedBotDifficulty();
|
|
66636
67003
|
if (difficulty === 'nightmare')
|
|
66637
67004
|
return [];
|
|
66638
|
-
|
|
67005
|
+
if (difficulty === 'master')
|
|
67006
|
+
return this.botProfiles.filter(profile => profile.id === 'magnus');
|
|
67007
|
+
return this.botProfiles.filter(profile => profile.difficulty === difficulty && profile.id !== 'magnus');
|
|
66639
67008
|
});
|
|
66640
|
-
this.selectedBotProfile = computed(() => this.botProfiles.find(
|
|
67009
|
+
this.selectedBotProfile = computed(() => this.botProfiles.find(profile => profile.id === this.selectedBotProfileId()));
|
|
66641
67010
|
this.gameBotProfile = computed(() => {
|
|
66642
67011
|
const profileId = this.gameBotProfileId();
|
|
66643
|
-
return profileId ? this.botProfiles.find(
|
|
67012
|
+
return profileId ? this.botProfiles.find(profile => profile.id === profileId) : undefined;
|
|
67013
|
+
});
|
|
67014
|
+
this.challengeHeaderBot = computed(() => {
|
|
67015
|
+
if (!this.isChallengeActive())
|
|
67016
|
+
return undefined;
|
|
67017
|
+
if (this.challengePhase() === 'playing')
|
|
67018
|
+
return this.activeChallengeBot();
|
|
67019
|
+
return this.challengeLastBot() ?? this.activeChallengeBot();
|
|
66644
67020
|
});
|
|
66645
67021
|
this.botOpponentProfile = computed(() => {
|
|
66646
67022
|
const game = this.game();
|
|
66647
67023
|
if (game.mode !== 'local' || this.selectedLocalMode() !== 'bot')
|
|
66648
67024
|
return undefined;
|
|
66649
|
-
const challengeBot = this.
|
|
67025
|
+
const challengeBot = this.challengeHeaderBot();
|
|
66650
67026
|
if (challengeBot)
|
|
66651
67027
|
return this.challengeBotProfile(challengeBot);
|
|
66652
67028
|
return this.gameBotProfile() ?? this.selectedBotProfile();
|
|
66653
67029
|
});
|
|
66654
67030
|
this.botOpponentEyebrow = computed(() => {
|
|
66655
|
-
const challengeBot = this.
|
|
67031
|
+
const challengeBot = this.challengeHeaderBot();
|
|
66656
67032
|
if (challengeBot)
|
|
66657
67033
|
return this.challengeBotDifficultyLabel(challengeBot);
|
|
66658
67034
|
return this.botDifficultyLabel(this.selectedBotDifficulty());
|
|
@@ -66663,7 +67039,7 @@ class ChessimalsGameComponent {
|
|
|
66663
67039
|
return this.t('chessimalsBotReportVs').replace('{bot}', botName);
|
|
66664
67040
|
});
|
|
66665
67041
|
this.botOpponentDescription = computed(() => {
|
|
66666
|
-
const challengeBot = this.
|
|
67042
|
+
const challengeBot = this.challengeHeaderBot();
|
|
66667
67043
|
if (challengeBot)
|
|
66668
67044
|
return this.challengeBotStyleLine(challengeBot);
|
|
66669
67045
|
const profile = this.botOpponentProfile();
|
|
@@ -66673,7 +67049,7 @@ class ChessimalsGameComponent {
|
|
|
66673
67049
|
const game = this.game();
|
|
66674
67050
|
if (game.mode !== 'local' || this.selectedLocalMode() !== 'bot')
|
|
66675
67051
|
return undefined;
|
|
66676
|
-
const challengeBot = this.
|
|
67052
|
+
const challengeBot = this.challengeHeaderBot();
|
|
66677
67053
|
if (challengeBot) {
|
|
66678
67054
|
const profile = this.challengeBotProfile(challengeBot);
|
|
66679
67055
|
const botName = profile ? this.botProfileLabel(profile) : this.t('chessimalsBotName');
|
|
@@ -66763,25 +67139,29 @@ class ChessimalsGameComponent {
|
|
|
66763
67139
|
const expected = this.tutorialExpectedMove();
|
|
66764
67140
|
if (!expected)
|
|
66765
67141
|
return moves;
|
|
66766
|
-
return moves.filter(
|
|
67142
|
+
return moves.filter(move => move.pieceId === expected.pieceId &&
|
|
66767
67143
|
positionKey(move.to) === positionKey(expected.to) &&
|
|
66768
67144
|
(move.animal ?? undefined) === (expected.animal ?? undefined));
|
|
66769
67145
|
});
|
|
66770
|
-
this.legalMoveKeys = computed(() => new Set(this.legalMoves().map(
|
|
66771
|
-
this.captureMoveKeys = computed(() => new Set(this.legalMoves()
|
|
67146
|
+
this.legalMoveKeys = computed(() => new Set(this.legalMoves().map(move => positionKey(move.to))));
|
|
67147
|
+
this.captureMoveKeys = computed(() => new Set(this.legalMoves()
|
|
67148
|
+
.filter(move => !!move.capturesPieceId)
|
|
67149
|
+
.map(move => positionKey(move.to))));
|
|
66772
67150
|
this.winningMoveKeys = computed(() => {
|
|
66773
67151
|
const game = this.game();
|
|
66774
67152
|
if (game.status !== 'in_progress')
|
|
66775
67153
|
return new Set();
|
|
66776
67154
|
const promotionRow = game.currentTurn === 'white' ? 0 : game.boardSize - 1;
|
|
66777
|
-
return new Set(this.legalMoves()
|
|
67155
|
+
return new Set(this.legalMoves()
|
|
67156
|
+
.filter(move => move.to.row === promotionRow)
|
|
67157
|
+
.map(move => positionKey(move.to)));
|
|
66778
67158
|
});
|
|
66779
67159
|
this.captureReadyPieceIds = computed(() => {
|
|
66780
67160
|
const game = this.game();
|
|
66781
67161
|
if (this.activeReviewIndex() !== undefined || game.status !== 'in_progress')
|
|
66782
67162
|
return new Set();
|
|
66783
|
-
const moves = this.basicMovesForColor(game, game.currentTurn).filter(
|
|
66784
|
-
return new Set(moves.map(
|
|
67163
|
+
const moves = this.basicMovesForColor(game, game.currentTurn).filter(move => !!move.capturesPieceId);
|
|
67164
|
+
return new Set(moves.map(move => move.pieceId));
|
|
66785
67165
|
});
|
|
66786
67166
|
this.threatenedPieceIds = computed(() => {
|
|
66787
67167
|
const game = this.game();
|
|
@@ -66789,7 +67169,7 @@ class ChessimalsGameComponent {
|
|
|
66789
67169
|
return new Set();
|
|
66790
67170
|
const opponent = game.currentTurn === 'white' ? 'black' : 'white';
|
|
66791
67171
|
const threatened = this.basicMovesForColor(game, opponent)
|
|
66792
|
-
.map(
|
|
67172
|
+
.map(move => move.capturesPieceId)
|
|
66793
67173
|
.filter((pieceId) => !!pieceId);
|
|
66794
67174
|
return new Set(threatened);
|
|
66795
67175
|
});
|
|
@@ -66805,7 +67185,7 @@ class ChessimalsGameComponent {
|
|
|
66805
67185
|
if (this.tutorialMode())
|
|
66806
67186
|
return 'white';
|
|
66807
67187
|
if (game.mode === 'online')
|
|
66808
|
-
return uid ? this.online.participantSide(game, uid) ?? 'white' : 'white';
|
|
67188
|
+
return uid ? (this.online.participantSide(game, uid) ?? 'white') : 'white';
|
|
66809
67189
|
if (game.mode === 'local' && this.selectedLocalMode() === 'bot')
|
|
66810
67190
|
return 'white';
|
|
66811
67191
|
return game.currentTurn;
|
|
@@ -66953,15 +67333,15 @@ class ChessimalsGameComponent {
|
|
|
66953
67333
|
const move = entry.move;
|
|
66954
67334
|
if (!move?.capturesPieceId)
|
|
66955
67335
|
continue;
|
|
66956
|
-
const piece = entry.pieces.find(
|
|
67336
|
+
const piece = entry.pieces.find(item => item.id === move.pieceId);
|
|
66957
67337
|
if (piece?.color)
|
|
66958
67338
|
score[piece.color] += 1;
|
|
66959
67339
|
}
|
|
66960
67340
|
return score;
|
|
66961
67341
|
});
|
|
66962
|
-
this.resultCaptures = computed(() => this.replayEntries().filter(
|
|
67342
|
+
this.resultCaptures = computed(() => this.replayEntries().filter(entry => !!entry.move?.capturesPieceId).length);
|
|
66963
67343
|
this.resultPowers = computed(() => this.replayEntries()
|
|
66964
|
-
.map(
|
|
67344
|
+
.map(entry => entry.move?.animal)
|
|
66965
67345
|
.filter((animal) => !!animal));
|
|
66966
67346
|
this.liveScore = computed(() => this.isChallengeActive() ? this.createGameScore(this.game(), 'W').score : this.createGameScore(this.game()).score);
|
|
66967
67347
|
this.resultScore = computed(() => this.createGameScore(this.game()));
|
|
@@ -66991,7 +67371,7 @@ class ChessimalsGameComponent {
|
|
|
66991
67371
|
const powers = this.resultPowers();
|
|
66992
67372
|
if (!powers.length)
|
|
66993
67373
|
return this.t('chessimalsResultNoPowers');
|
|
66994
|
-
return powers.map(
|
|
67374
|
+
return powers.map(animal => this.animalLabel(animal)).join(' · ');
|
|
66995
67375
|
});
|
|
66996
67376
|
this.liveScoreLabel = computed(() => String(this.liveScore()));
|
|
66997
67377
|
this.resultBestMoveLabel = computed(() => {
|
|
@@ -67012,12 +67392,10 @@ class ChessimalsGameComponent {
|
|
|
67012
67392
|
});
|
|
67013
67393
|
this.botReportBody = computed(() => {
|
|
67014
67394
|
const profile = this.gameBotProfile();
|
|
67015
|
-
const botMoves = this.replayEntries().filter(
|
|
67016
|
-
const captures = botMoves.filter(
|
|
67017
|
-
const powers = botMoves.filter(
|
|
67018
|
-
const outcomeKey = this.game().winner === CHESSIMALS_BOT_COLOR
|
|
67019
|
-
? 'chessimalsBotReportOutcomeWon'
|
|
67020
|
-
: 'chessimalsBotReportOutcomeLost';
|
|
67395
|
+
const botMoves = this.replayEntries().filter(entry => entry.move?.pieceId.startsWith('B'));
|
|
67396
|
+
const captures = botMoves.filter(entry => !!entry.move?.capturesPieceId).length;
|
|
67397
|
+
const powers = botMoves.filter(entry => !!entry.move?.animal).length;
|
|
67398
|
+
const outcomeKey = this.game().winner === CHESSIMALS_BOT_COLOR ? 'chessimalsBotReportOutcomeWon' : 'chessimalsBotReportOutcomeLost';
|
|
67021
67399
|
return this.t('chessimalsBotReportBody')
|
|
67022
67400
|
.replace('{outcome}', this.t(outcomeKey))
|
|
67023
67401
|
.replace('{captures}', String(captures))
|
|
@@ -67028,15 +67406,15 @@ class ChessimalsGameComponent {
|
|
|
67028
67406
|
const opponentUid = this.currentOpponentUid();
|
|
67029
67407
|
if (!opponentUid)
|
|
67030
67408
|
return [];
|
|
67031
|
-
return this.onlineHistory().filter(
|
|
67409
|
+
return this.onlineHistory().filter(entry => entry.opponentUid === opponentUid && entry.status === 'finished');
|
|
67032
67410
|
});
|
|
67033
67411
|
this.seriesScore = computed(() => {
|
|
67034
67412
|
const games = this.seriesGames();
|
|
67035
67413
|
if (!games.length)
|
|
67036
67414
|
return undefined;
|
|
67037
67415
|
return {
|
|
67038
|
-
mine: games.filter(
|
|
67039
|
-
rival: games.filter(
|
|
67416
|
+
mine: games.filter(entry => entry.outcome === 'won').length,
|
|
67417
|
+
rival: games.filter(entry => entry.outcome === 'lost').length,
|
|
67040
67418
|
total: games.length,
|
|
67041
67419
|
};
|
|
67042
67420
|
});
|
|
@@ -67160,14 +67538,14 @@ class ChessimalsGameComponent {
|
|
|
67160
67538
|
this.audio.preloadChessimalsSamples();
|
|
67161
67539
|
this.audio.stopMusic();
|
|
67162
67540
|
this.startChessimalsMenuMusicSoon();
|
|
67163
|
-
this.routeSubscription.add(this.musicEnabledControl.valueChanges.subscribe(
|
|
67541
|
+
this.routeSubscription.add(this.musicEnabledControl.valueChanges.subscribe(enabled => {
|
|
67164
67542
|
this.audio.setMusicEnabled(enabled);
|
|
67165
67543
|
if (enabled)
|
|
67166
67544
|
this.syncChessimalsMusicAfterSettingsChange();
|
|
67167
67545
|
}));
|
|
67168
|
-
this.routeSubscription.add(this.sfxEnabledControl.valueChanges.subscribe(
|
|
67169
|
-
this.routeSubscription.add(this.musicVolumeControl.valueChanges.subscribe(
|
|
67170
|
-
this.routeSubscription.add(this.sfxVolumeControl.valueChanges.subscribe(
|
|
67546
|
+
this.routeSubscription.add(this.sfxEnabledControl.valueChanges.subscribe(enabled => this.audio.setSfxEnabled(enabled)));
|
|
67547
|
+
this.routeSubscription.add(this.musicVolumeControl.valueChanges.subscribe(volume => this.setMusicVolume(volume)));
|
|
67548
|
+
this.routeSubscription.add(this.sfxVolumeControl.valueChanges.subscribe(volume => this.setSfxVolume(volume)));
|
|
67171
67549
|
effect(() => {
|
|
67172
67550
|
const user = this.loggedInUser();
|
|
67173
67551
|
if (user) {
|
|
@@ -67210,7 +67588,7 @@ class ChessimalsGameComponent {
|
|
|
67210
67588
|
if (this.lastModeStatsHandledKey === key)
|
|
67211
67589
|
return;
|
|
67212
67590
|
this.lastModeStatsHandledKey = key;
|
|
67213
|
-
void this.challengeProgress.recordModeResult(result.mode, result.won, result.roundStats).catch(
|
|
67591
|
+
void this.challengeProgress.recordModeResult(result.mode, result.won, result.roundStats).catch(error => {
|
|
67214
67592
|
console.warn('[Chessimals] mode stats save failed', error);
|
|
67215
67593
|
});
|
|
67216
67594
|
}, { allowSignalWrites: true });
|
|
@@ -67248,7 +67626,7 @@ class ChessimalsGameComponent {
|
|
|
67248
67626
|
this.challengeActiveRunSubscription?.unsubscribe();
|
|
67249
67627
|
}
|
|
67250
67628
|
ngOnInit() {
|
|
67251
|
-
this.routeSubscription.add(this.router.events.subscribe(
|
|
67629
|
+
this.routeSubscription.add(this.router.events.subscribe(event => {
|
|
67252
67630
|
if (event instanceof NavigationStart) {
|
|
67253
67631
|
this.resetFinishedLocalGameForNextVisit(true);
|
|
67254
67632
|
}
|
|
@@ -67269,7 +67647,7 @@ class ChessimalsGameComponent {
|
|
|
67269
67647
|
return `${normalized.slice(0, 4)}…${normalized.slice(-4)}`;
|
|
67270
67648
|
}
|
|
67271
67649
|
rangeValueToNumber(value) {
|
|
67272
|
-
const raw = typeof value === 'number' ? value : value.upper ?? value.lower ?? 0;
|
|
67650
|
+
const raw = typeof value === 'number' ? value : (value.upper ?? value.lower ?? 0);
|
|
67273
67651
|
return Math.min(100, Math.max(0, Math.round(raw)));
|
|
67274
67652
|
}
|
|
67275
67653
|
startChallenge() {
|
|
@@ -67335,7 +67713,7 @@ class ChessimalsGameComponent {
|
|
|
67335
67713
|
losses: 0,
|
|
67336
67714
|
bestStreakInRun: 0,
|
|
67337
67715
|
currentStreak: 0,
|
|
67338
|
-
botLadder: this.challengeLadder.map(
|
|
67716
|
+
botLadder: this.challengeLadder.map(bot => bot.id),
|
|
67339
67717
|
roundResults: [],
|
|
67340
67718
|
startedAt: now,
|
|
67341
67719
|
lastEventAt: now,
|
|
@@ -67344,7 +67722,7 @@ class ChessimalsGameComponent {
|
|
|
67344
67722
|
this.challengeRun.set(run);
|
|
67345
67723
|
this.activeStoredChallengeRun.set(run);
|
|
67346
67724
|
this.startChallengeRound(run);
|
|
67347
|
-
void this.challengeProgress.recordChallengeStarted(this.challengeRun() ?? run).catch(
|
|
67725
|
+
void this.challengeProgress.recordChallengeStarted(this.challengeRun() ?? run).catch(error => {
|
|
67348
67726
|
console.warn('[Chessimals] challenge run save failed', error);
|
|
67349
67727
|
});
|
|
67350
67728
|
}
|
|
@@ -67599,16 +67977,18 @@ class ChessimalsGameComponent {
|
|
|
67599
67977
|
this.challengeLastWon.set(won);
|
|
67600
67978
|
this.challengeLastBot.set(bot);
|
|
67601
67979
|
this.challengeLastRoundStats.set(roundStats);
|
|
67602
|
-
this.challengeNewRecord.set(roundIndex > this.challengeStats().bestRoundReached
|
|
67603
|
-
|
|
67980
|
+
this.challengeNewRecord.set(roundIndex > this.challengeStats().bestRoundReached ||
|
|
67981
|
+
Math.max(run.bestStreakInRun, nextStreak) > this.challengeStats().bestWinStreak);
|
|
67604
67982
|
this.challengePhase.set(completed ? 'completed' : failed ? 'failed' : 'between');
|
|
67605
|
-
void this.challengeProgress
|
|
67983
|
+
void this.challengeProgress
|
|
67984
|
+
.applyRoundResult({
|
|
67606
67985
|
run: nextRun,
|
|
67607
67986
|
roundReached: roundIndex,
|
|
67608
67987
|
won,
|
|
67609
67988
|
completed,
|
|
67610
67989
|
roundStats,
|
|
67611
|
-
})
|
|
67990
|
+
})
|
|
67991
|
+
.catch(error => {
|
|
67612
67992
|
console.warn('[Chessimals] challenge stats save failed', error);
|
|
67613
67993
|
});
|
|
67614
67994
|
}
|
|
@@ -67629,7 +68009,7 @@ class ChessimalsGameComponent {
|
|
|
67629
68009
|
finishedAt: now,
|
|
67630
68010
|
};
|
|
67631
68011
|
this.activeStoredChallengeRun.set(undefined);
|
|
67632
|
-
void this.challengeProgress.saveRun(nextRun).catch(
|
|
68012
|
+
void this.challengeProgress.saveRun(nextRun).catch(error => {
|
|
67633
68013
|
console.warn('[Chessimals] challenge abandon save failed', error);
|
|
67634
68014
|
});
|
|
67635
68015
|
}
|
|
@@ -68066,7 +68446,7 @@ class ChessimalsGameComponent {
|
|
|
68066
68446
|
moveHistory: [
|
|
68067
68447
|
{
|
|
68068
68448
|
moveNumber: 0,
|
|
68069
|
-
pieces: pieces.map(
|
|
68449
|
+
pieces: pieces.map(piece => ({ ...piece, position: { ...piece.position } })),
|
|
68070
68450
|
currentTurn: 'white',
|
|
68071
68451
|
status: 'in_progress',
|
|
68072
68452
|
},
|
|
@@ -68076,19 +68456,23 @@ class ChessimalsGameComponent {
|
|
|
68076
68456
|
basicMovesForColor(game, color) {
|
|
68077
68457
|
const turnState = color === game.currentTurn ? game : { ...game, currentTurn: color };
|
|
68078
68458
|
return turnState.pieces
|
|
68079
|
-
.filter(
|
|
68080
|
-
.flatMap(
|
|
68459
|
+
.filter(piece => piece.color === color && !piece.captured)
|
|
68460
|
+
.flatMap(piece => getChessimalsLegalMoves(turnState, piece.id));
|
|
68081
68461
|
}
|
|
68082
68462
|
selectCell(position) {
|
|
68083
68463
|
const game = this.game();
|
|
68084
|
-
if (this.projectionMode ||
|
|
68464
|
+
if (this.projectionMode ||
|
|
68465
|
+
game.status !== 'in_progress' ||
|
|
68466
|
+
!this.canPlayCurrentTurn() ||
|
|
68467
|
+
this.movingPiece() ||
|
|
68468
|
+
this.moveSyncing())
|
|
68085
68469
|
return;
|
|
68086
68470
|
const piece = getChessimalsPieceAt(game, position);
|
|
68087
68471
|
if (piece?.color === game.currentTurn) {
|
|
68088
68472
|
this.selectedPieceId.set(piece.id);
|
|
68089
68473
|
return;
|
|
68090
68474
|
}
|
|
68091
|
-
const move = this.legalMoves().find(
|
|
68475
|
+
const move = this.legalMoves().find(item => positionKey(item.to) === positionKey(position));
|
|
68092
68476
|
if (!move)
|
|
68093
68477
|
return;
|
|
68094
68478
|
this.commitChessimalsMove(game, move);
|
|
@@ -68108,7 +68492,7 @@ class ChessimalsGameComponent {
|
|
|
68108
68492
|
.then(() => {
|
|
68109
68493
|
void this.haptics.impact(move.capturesPieceId ? 'medium' : 'light');
|
|
68110
68494
|
})
|
|
68111
|
-
.catch(
|
|
68495
|
+
.catch(error => {
|
|
68112
68496
|
console.warn('[Chessimals] online move failed', { gameId: game.id, move, error });
|
|
68113
68497
|
this.game.set(game);
|
|
68114
68498
|
this.onlineError.set(this.t('chessimalsOnlineError'));
|
|
@@ -68218,14 +68602,14 @@ class ChessimalsGameComponent {
|
|
|
68218
68602
|
}
|
|
68219
68603
|
chooseAutomaticTurnMove(game) {
|
|
68220
68604
|
const moves = game.pieces
|
|
68221
|
-
.filter(
|
|
68222
|
-
.flatMap(
|
|
68223
|
-
const basicMoves = moves.filter(
|
|
68224
|
-
return basicMoves.find(
|
|
68225
|
-
|
|
68226
|
-
|
|
68227
|
-
|
|
68228
|
-
|
|
68605
|
+
.filter(piece => piece.color === game.currentTurn && !piece.captured)
|
|
68606
|
+
.flatMap(piece => getChessimalsLegalMoves(game, piece.id));
|
|
68607
|
+
const basicMoves = moves.filter(move => move.kind === 'basic');
|
|
68608
|
+
return (basicMoves.find(move => this.isPromotionMove(game, move)) ??
|
|
68609
|
+
basicMoves.find(move => !!move.capturesPieceId) ??
|
|
68610
|
+
basicMoves[0] ??
|
|
68611
|
+
moves.find(move => !!move.capturesPieceId) ??
|
|
68612
|
+
moves[0]);
|
|
68229
68613
|
}
|
|
68230
68614
|
isPromotionMove(game, move) {
|
|
68231
68615
|
return move.kind === 'basic' && move.to.row === (game.currentTurn === 'white' ? 0 : game.boardSize - 1);
|
|
@@ -68234,7 +68618,7 @@ class ChessimalsGameComponent {
|
|
|
68234
68618
|
if (this.moveAnimationTimer)
|
|
68235
68619
|
clearTimeout(this.moveAnimationTimer);
|
|
68236
68620
|
this.queueMoveEffect(move);
|
|
68237
|
-
const movingPiece = game.pieces.find(
|
|
68621
|
+
const movingPiece = game.pieces.find(piece => piece.id === move.pieceId);
|
|
68238
68622
|
if (!movingPiece) {
|
|
68239
68623
|
this.applyAnimatedMove(game, updated);
|
|
68240
68624
|
return;
|
|
@@ -68292,7 +68676,7 @@ class ChessimalsGameComponent {
|
|
|
68292
68676
|
updatedAt: new Date().toISOString(),
|
|
68293
68677
|
};
|
|
68294
68678
|
this.challengeRun.set(nextRun);
|
|
68295
|
-
void this.challengeProgress.saveRun(nextRun).catch(
|
|
68679
|
+
void this.challengeProgress.saveRun(nextRun).catch(error => {
|
|
68296
68680
|
console.warn('[Chessimals] challenge snapshot save failed', error);
|
|
68297
68681
|
});
|
|
68298
68682
|
}
|
|
@@ -68566,7 +68950,7 @@ class ChessimalsGameComponent {
|
|
|
68566
68950
|
const next = current === animal.type ? undefined : animal.type;
|
|
68567
68951
|
this.selectedAnimal.set(next);
|
|
68568
68952
|
if (!this.selectedPieceId()) {
|
|
68569
|
-
const firstPiece = this.game().pieces.find(
|
|
68953
|
+
const firstPiece = this.game().pieces.find(piece => !piece.captured && piece.color === this.game().currentTurn);
|
|
68570
68954
|
this.selectedPieceId.set(firstPiece?.id);
|
|
68571
68955
|
}
|
|
68572
68956
|
if (next)
|
|
@@ -68710,7 +69094,7 @@ class ChessimalsGameComponent {
|
|
|
68710
69094
|
.split(/\s+/)
|
|
68711
69095
|
.filter(Boolean)
|
|
68712
69096
|
.slice(0, 2)
|
|
68713
|
-
.map(
|
|
69097
|
+
.map(part => part.charAt(0).toUpperCase())
|
|
68714
69098
|
.join('');
|
|
68715
69099
|
return initials || this.winnerSideLabel().charAt(0).toUpperCase();
|
|
68716
69100
|
}
|
|
@@ -68836,10 +69220,7 @@ class ChessimalsGameComponent {
|
|
|
68836
69220
|
canReviewPendingGuest() {
|
|
68837
69221
|
const game = this.game();
|
|
68838
69222
|
const uid = this.onlineUid();
|
|
68839
|
-
return !!uid
|
|
68840
|
-
&& game.mode === 'online'
|
|
68841
|
-
&& this.online.isHostWaiting(game, uid)
|
|
68842
|
-
&& !!game.online.pendingGuest;
|
|
69223
|
+
return !!uid && game.mode === 'online' && this.online.isHostWaiting(game, uid) && !!game.online.pendingGuest;
|
|
68843
69224
|
}
|
|
68844
69225
|
pendingGuestName() {
|
|
68845
69226
|
return this.game().online?.pendingGuest?.name ?? this.t('defaultPlayerName');
|
|
@@ -68857,7 +69238,7 @@ class ChessimalsGameComponent {
|
|
|
68857
69238
|
.split(/\s+/)
|
|
68858
69239
|
.filter(Boolean)
|
|
68859
69240
|
.slice(0, 2)
|
|
68860
|
-
.map(
|
|
69241
|
+
.map(part => part.charAt(0).toUpperCase())
|
|
68861
69242
|
.join('');
|
|
68862
69243
|
return initials || '?';
|
|
68863
69244
|
}
|
|
@@ -68889,7 +69270,7 @@ class ChessimalsGameComponent {
|
|
|
68889
69270
|
.split(/\s+/)
|
|
68890
69271
|
.filter(Boolean)
|
|
68891
69272
|
.slice(0, 2)
|
|
68892
|
-
.map(
|
|
69273
|
+
.map(part => part.charAt(0).toUpperCase())
|
|
68893
69274
|
.join('');
|
|
68894
69275
|
return initials || '?';
|
|
68895
69276
|
}
|
|
@@ -68972,7 +69353,7 @@ class ChessimalsGameComponent {
|
|
|
68972
69353
|
historyOutcomeLabel(entry) {
|
|
68973
69354
|
const outcomeKey = `chessimalsHistory${entry.outcome
|
|
68974
69355
|
.split('_')
|
|
68975
|
-
.map(
|
|
69356
|
+
.map(part => this.capitalize(part))
|
|
68976
69357
|
.join('')}`;
|
|
68977
69358
|
const opponent = entry.opponentName
|
|
68978
69359
|
? ` · ${this.t('chessimalsHistoryAgainst').replace('{player}', entry.opponentName)}`
|
|
@@ -69023,7 +69404,7 @@ class ChessimalsGameComponent {
|
|
|
69023
69404
|
this.historyUid = uid;
|
|
69024
69405
|
this.historySubscription?.unsubscribe();
|
|
69025
69406
|
this.historySubscription = this.online.watchHistory(24).subscribe({
|
|
69026
|
-
next:
|
|
69407
|
+
next: history => this.onlineHistory.set(history),
|
|
69027
69408
|
error: () => this.onlineHistory.set([]),
|
|
69028
69409
|
});
|
|
69029
69410
|
}
|
|
@@ -69031,15 +69412,15 @@ class ChessimalsGameComponent {
|
|
|
69031
69412
|
if (this.challengeStatsSubscription)
|
|
69032
69413
|
return;
|
|
69033
69414
|
this.challengeStatsSubscription = this.challengeProgress.watchStats().subscribe({
|
|
69034
|
-
next:
|
|
69415
|
+
next: stats => this.challengeStats.set(stats ?? this.challengeProgress.emptyStats()),
|
|
69035
69416
|
error: () => this.challengeStats.set(this.challengeProgress.emptyStats()),
|
|
69036
69417
|
});
|
|
69037
69418
|
this.challengeRunsSubscription = this.challengeProgress.watchRecentRuns(4).subscribe({
|
|
69038
|
-
next:
|
|
69419
|
+
next: runs => this.challengeHistory.set(runs),
|
|
69039
69420
|
error: () => this.challengeHistory.set([]),
|
|
69040
69421
|
});
|
|
69041
69422
|
this.challengeActiveRunSubscription = this.challengeProgress.watchActiveRun().subscribe({
|
|
69042
|
-
next:
|
|
69423
|
+
next: run => this.activeStoredChallengeRun.set(this.isResumableChallengeRun(run) ? run : undefined),
|
|
69043
69424
|
error: () => this.activeStoredChallengeRun.set(undefined),
|
|
69044
69425
|
});
|
|
69045
69426
|
}
|
|
@@ -69060,7 +69441,7 @@ class ChessimalsGameComponent {
|
|
|
69060
69441
|
return;
|
|
69061
69442
|
}
|
|
69062
69443
|
this.selectedNightmareMode.set('none');
|
|
69063
|
-
const profile = this.botProfiles.find(
|
|
69444
|
+
const profile = this.botProfiles.find(item => item.difficulty === difficulty);
|
|
69064
69445
|
if (profile)
|
|
69065
69446
|
this.selectedBotProfileId.set(profile.id);
|
|
69066
69447
|
}
|
|
@@ -69121,6 +69502,8 @@ class ChessimalsGameComponent {
|
|
|
69121
69502
|
return this.t('chessimalsBotEasy');
|
|
69122
69503
|
if (difficulty === 'hard')
|
|
69123
69504
|
return this.t('chessimalsBotHard');
|
|
69505
|
+
if (difficulty === 'master')
|
|
69506
|
+
return this.t('chessimalsBotMaster');
|
|
69124
69507
|
if (difficulty === 'nightmare')
|
|
69125
69508
|
return this.t('chessimalsBotNightmare');
|
|
69126
69509
|
return this.t('chessimalsBotNormal');
|
|
@@ -69135,13 +69518,13 @@ class ChessimalsGameComponent {
|
|
|
69135
69518
|
return this.t(`chessimalsBot${this.capitalize(profile.id)}Tendency`);
|
|
69136
69519
|
}
|
|
69137
69520
|
botProfileAvatar(profileId) {
|
|
69138
|
-
return this.botProfiles.find(
|
|
69521
|
+
return this.botProfiles.find(profile => profile.id === profileId)?.avatar ?? '♟';
|
|
69139
69522
|
}
|
|
69140
69523
|
botProfileAvatarSrc(profileId) {
|
|
69141
|
-
return this.botProfiles.find(
|
|
69524
|
+
return this.botProfiles.find(profile => profile.id === profileId)?.avatarSrc ?? '';
|
|
69142
69525
|
}
|
|
69143
69526
|
challengeBotProfile(bot) {
|
|
69144
|
-
return this.botProfiles.find(
|
|
69527
|
+
return this.botProfiles.find(profile => profile.id === bot.profileId);
|
|
69145
69528
|
}
|
|
69146
69529
|
challengeOpeningBot() {
|
|
69147
69530
|
return this.challengeLadder[0];
|
|
@@ -69217,7 +69600,7 @@ class ChessimalsGameComponent {
|
|
|
69217
69600
|
return this.challengePhase() !== 'idle' && !!this.challengeRun();
|
|
69218
69601
|
}
|
|
69219
69602
|
shouldShowChallengeInGamePanel() {
|
|
69220
|
-
return !this.projectionMode && this.screen() === 'game' && this.challengePhase() === 'playing' && !!this.challengeRun();
|
|
69603
|
+
return (!this.projectionMode && this.screen() === 'game' && this.challengePhase() === 'playing' && !!this.challengeRun());
|
|
69221
69604
|
}
|
|
69222
69605
|
showChallengeIntro() {
|
|
69223
69606
|
if (this.projectionMode || this.challengePhase() !== 'playing' || !this.activeChallengeBot())
|
|
@@ -69320,7 +69703,7 @@ class ChessimalsGameComponent {
|
|
|
69320
69703
|
challengeRoundStageLabel() {
|
|
69321
69704
|
const bot = this.challengePhase() === 'playing'
|
|
69322
69705
|
? this.activeChallengeBot()
|
|
69323
|
-
: this.challengeLastBot() ?? this.activeChallengeBot();
|
|
69706
|
+
: (this.challengeLastBot() ?? this.activeChallengeBot());
|
|
69324
69707
|
const run = this.challengeRun();
|
|
69325
69708
|
const round = bot?.round ?? (run ? this.challengeRunRoundIndex(run) : 1);
|
|
69326
69709
|
return this.t('chessimalsChallengeRoundStage')
|
|
@@ -69425,7 +69808,7 @@ class ChessimalsGameComponent {
|
|
|
69425
69808
|
pathHighlights() {
|
|
69426
69809
|
const stats = this.challengeStats();
|
|
69427
69810
|
const favoritePower = this.favoritePowerLabel();
|
|
69428
|
-
const nextAchievement = this.challengeAchievements().find(
|
|
69811
|
+
const nextAchievement = this.challengeAchievements().find(achievement => !achievement.unlocked);
|
|
69429
69812
|
return [
|
|
69430
69813
|
{
|
|
69431
69814
|
title: this.t('chessimalsPathWinsTitle'),
|
|
@@ -69548,8 +69931,8 @@ class ChessimalsGameComponent {
|
|
|
69548
69931
|
challengeFeaturedAchievements() {
|
|
69549
69932
|
const achievements = this.challengeAchievements();
|
|
69550
69933
|
return [
|
|
69551
|
-
...achievements.filter(
|
|
69552
|
-
...achievements.filter(
|
|
69934
|
+
...achievements.filter(achievement => achievement.unlocked),
|
|
69935
|
+
...achievements.filter(achievement => !achievement.unlocked),
|
|
69553
69936
|
].slice(0, 4);
|
|
69554
69937
|
}
|
|
69555
69938
|
challengeTensionMoment() {
|
|
@@ -69560,7 +69943,7 @@ class ChessimalsGameComponent {
|
|
|
69560
69943
|
if (!run)
|
|
69561
69944
|
return undefined;
|
|
69562
69945
|
const nextBot = this.activeChallengeBot();
|
|
69563
|
-
const lastBot = phase === 'playing' ? nextBot : this.challengeLastBot() ?? nextBot;
|
|
69946
|
+
const lastBot = phase === 'playing' ? nextBot : (this.challengeLastBot() ?? nextBot);
|
|
69564
69947
|
const botName = lastBot ? this.challengeBotName(lastBot) : this.t('chessimalsBotName');
|
|
69565
69948
|
if (run.livesRemaining <= 1) {
|
|
69566
69949
|
return {
|
|
@@ -69649,11 +70032,11 @@ class ChessimalsGameComponent {
|
|
|
69649
70032
|
scoreChessimalsMove(move, promotion, currentCombo) {
|
|
69650
70033
|
const capture = !!move.capturesPieceId;
|
|
69651
70034
|
const combo = capture ? currentCombo + 1 : 0;
|
|
69652
|
-
const score = 1
|
|
69653
|
-
|
|
69654
|
-
|
|
69655
|
-
|
|
69656
|
-
|
|
70035
|
+
const score = 1 +
|
|
70036
|
+
(capture ? (move.animal ? 5 : 3) : 0) +
|
|
70037
|
+
(move.animal && !capture ? 1 : 0) +
|
|
70038
|
+
(promotion ? 8 : 0) +
|
|
70039
|
+
(combo > 1 ? combo - 1 : 0);
|
|
69657
70040
|
const labelKey = promotion
|
|
69658
70041
|
? 'chessimalsScorePromotion'
|
|
69659
70042
|
: capture && move.animal
|
|
@@ -69740,7 +70123,7 @@ class ChessimalsGameComponent {
|
|
|
69740
70123
|
return glyphs[type];
|
|
69741
70124
|
}
|
|
69742
70125
|
animalAssetSrc(type) {
|
|
69743
|
-
return ANIMALS.find(
|
|
70126
|
+
return ANIMALS.find(animal => animal.type === type)?.assetSrc ?? '';
|
|
69744
70127
|
}
|
|
69745
70128
|
powerCalloutTone(type) {
|
|
69746
70129
|
const tones = {
|
|
@@ -69802,7 +70185,7 @@ class ChessimalsGameComponent {
|
|
|
69802
70185
|
watchOnlineGame(gameId) {
|
|
69803
70186
|
this.onlineSubscription?.unsubscribe();
|
|
69804
70187
|
this.onlineSubscription = this.online.watchGame(gameId).subscribe({
|
|
69805
|
-
next:
|
|
70188
|
+
next: state => {
|
|
69806
70189
|
this.ngZone.run(() => {
|
|
69807
70190
|
if (!state) {
|
|
69808
70191
|
this.onlineConnectionState.set('error');
|
|
@@ -69916,7 +70299,11 @@ class ChessimalsGameComponent {
|
|
|
69916
70299
|
|
|
69917
70300
|
<section class="chessimals-panel">
|
|
69918
70301
|
<section class="chessimals-home-actions" [attr.aria-label]="t('chessimalsHomeChoose')">
|
|
69919
|
-
<button
|
|
70302
|
+
<button
|
|
70303
|
+
class="chessimals-home-action chessimals-home-action--play"
|
|
70304
|
+
type="button"
|
|
70305
|
+
(click)="openPlayOptionsModal()"
|
|
70306
|
+
>
|
|
69920
70307
|
<img
|
|
69921
70308
|
class="chessimals-mode-icon"
|
|
69922
70309
|
src="assets/games/chessimals/mode-icons/solo-borderless.png"
|
|
@@ -69970,60 +70357,60 @@ class ChessimalsGameComponent {
|
|
|
69970
70357
|
</summary>
|
|
69971
70358
|
|
|
69972
70359
|
<article class="chessimals-online">
|
|
69973
|
-
|
|
69974
|
-
|
|
69975
|
-
|
|
69976
|
-
|
|
69977
|
-
|
|
69978
|
-
|
|
69979
|
-
|
|
69980
|
-
|
|
69981
|
-
|
|
69982
|
-
|
|
69983
|
-
|
|
70360
|
+
<div>
|
|
70361
|
+
<h2>{{ t('chessimalsOnlineTitle') }}</h2>
|
|
70362
|
+
<p>{{ t('chessimalsOnlineBody') }}</p>
|
|
70363
|
+
</div>
|
|
70364
|
+
@if (onlineError()) {
|
|
70365
|
+
<p class="chessimals-online__error">{{ onlineError() }}</p>
|
|
70366
|
+
}
|
|
70367
|
+
@if (onlineLoading()) {
|
|
70368
|
+
<div class="chessimals-online__loading" role="status" aria-live="polite">
|
|
70369
|
+
<span aria-hidden="true"></span>
|
|
70370
|
+
<strong>{{ t('chessimalsOnlineLoading') }}</strong>
|
|
70371
|
+
</div>
|
|
70372
|
+
}
|
|
70373
|
+
<div class="chessimals-online__create">
|
|
70374
|
+
<button
|
|
70375
|
+
class="chessimals-primary"
|
|
70376
|
+
type="button"
|
|
70377
|
+
[class.is-working]="onlineAction() === 'create'"
|
|
70378
|
+
[attr.aria-busy]="onlineAction() === 'create'"
|
|
70379
|
+
[disabled]="onlineLoading()"
|
|
70380
|
+
(click)="createOnlineGame()"
|
|
70381
|
+
>
|
|
70382
|
+
@if (onlineAction() === 'create') {
|
|
70383
|
+
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
70384
|
+
}
|
|
70385
|
+
{{ t('chessimalsCreateOnline') }}
|
|
70386
|
+
</button>
|
|
70387
|
+
<small>{{ t('chessimalsCreateOnlineHint') }}</small>
|
|
70388
|
+
</div>
|
|
70389
|
+
<div class="chessimals-online__join">
|
|
70390
|
+
<strong>{{ t('chessimalsJoinOnlineTitle') }}</strong>
|
|
70391
|
+
<label class="chessimals-online-code">
|
|
70392
|
+
<span>{{ t('chessimalsJoinCode') }}</span>
|
|
70393
|
+
<input
|
|
70394
|
+
type="text"
|
|
70395
|
+
[value]="onlineJoinCode()"
|
|
70396
|
+
[placeholder]="t('chessimalsJoinCodePlaceholder')"
|
|
70397
|
+
(input)="onlineJoinCode.set(normalizeGameId($any($event.target).value))"
|
|
70398
|
+
/>
|
|
70399
|
+
</label>
|
|
70400
|
+
<button
|
|
70401
|
+
class="chessimals-primary"
|
|
70402
|
+
type="button"
|
|
70403
|
+
[class.is-working]="onlineAction() === 'join'"
|
|
70404
|
+
[attr.aria-busy]="onlineAction() === 'join'"
|
|
70405
|
+
[disabled]="onlineLoading() || !onlineJoinCode()"
|
|
70406
|
+
(click)="joinOnlineGameByCode()"
|
|
70407
|
+
>
|
|
70408
|
+
@if (onlineAction() === 'join') {
|
|
70409
|
+
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
70410
|
+
}
|
|
70411
|
+
{{ t('chessimalsJoinOnline') }}
|
|
70412
|
+
</button>
|
|
69984
70413
|
</div>
|
|
69985
|
-
}
|
|
69986
|
-
<div class="chessimals-online__create">
|
|
69987
|
-
<button
|
|
69988
|
-
class="chessimals-primary"
|
|
69989
|
-
type="button"
|
|
69990
|
-
[class.is-working]="onlineAction() === 'create'"
|
|
69991
|
-
[attr.aria-busy]="onlineAction() === 'create'"
|
|
69992
|
-
[disabled]="onlineLoading()"
|
|
69993
|
-
(click)="createOnlineGame()"
|
|
69994
|
-
>
|
|
69995
|
-
@if (onlineAction() === 'create') {
|
|
69996
|
-
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
69997
|
-
}
|
|
69998
|
-
{{ t('chessimalsCreateOnline') }}
|
|
69999
|
-
</button>
|
|
70000
|
-
<small>{{ t('chessimalsCreateOnlineHint') }}</small>
|
|
70001
|
-
</div>
|
|
70002
|
-
<div class="chessimals-online__join">
|
|
70003
|
-
<strong>{{ t('chessimalsJoinOnlineTitle') }}</strong>
|
|
70004
|
-
<label class="chessimals-online-code">
|
|
70005
|
-
<span>{{ t('chessimalsJoinCode') }}</span>
|
|
70006
|
-
<input
|
|
70007
|
-
type="text"
|
|
70008
|
-
[value]="onlineJoinCode()"
|
|
70009
|
-
[placeholder]="t('chessimalsJoinCodePlaceholder')"
|
|
70010
|
-
(input)="onlineJoinCode.set(normalizeGameId($any($event.target).value))"
|
|
70011
|
-
/>
|
|
70012
|
-
</label>
|
|
70013
|
-
<button
|
|
70014
|
-
class="chessimals-primary"
|
|
70015
|
-
type="button"
|
|
70016
|
-
[class.is-working]="onlineAction() === 'join'"
|
|
70017
|
-
[attr.aria-busy]="onlineAction() === 'join'"
|
|
70018
|
-
[disabled]="onlineLoading() || !onlineJoinCode()"
|
|
70019
|
-
(click)="joinOnlineGameByCode()"
|
|
70020
|
-
>
|
|
70021
|
-
@if (onlineAction() === 'join') {
|
|
70022
|
-
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
70023
|
-
}
|
|
70024
|
-
{{ t('chessimalsJoinOnline') }}
|
|
70025
|
-
</button>
|
|
70026
|
-
</div>
|
|
70027
70414
|
</article>
|
|
70028
70415
|
</details>
|
|
70029
70416
|
|
|
@@ -70106,7 +70493,12 @@ class ChessimalsGameComponent {
|
|
|
70106
70493
|
<strong>{{ challengeBotName(challengeMenuBot()) }}</strong>
|
|
70107
70494
|
<p>{{ t(challengeMenuBot().introKey) }}</p>
|
|
70108
70495
|
<em>
|
|
70109
|
-
{{
|
|
70496
|
+
{{
|
|
70497
|
+
t('chessimalsChallengeBoardLabel').replace(
|
|
70498
|
+
'{size}',
|
|
70499
|
+
challengeMenuBot().boardSize + 'x' + challengeMenuBot().boardSize
|
|
70500
|
+
)
|
|
70501
|
+
}}
|
|
70110
70502
|
, {{ challengeBotDifficultyLabel(challengeMenuBot()) }}
|
|
70111
70503
|
</em>
|
|
70112
70504
|
</div>
|
|
@@ -70368,7 +70760,10 @@ class ChessimalsGameComponent {
|
|
|
70368
70760
|
@if (pendingGuestAvatarUrl()) {
|
|
70369
70761
|
<val-user-avatar [props]="pendingGuestAvatarProps()" />
|
|
70370
70762
|
} @else {
|
|
70371
|
-
<span
|
|
70763
|
+
<span
|
|
70764
|
+
class="chessimals-player-strip__avatar chessimals-player-strip__avatar--initials"
|
|
70765
|
+
aria-hidden="true"
|
|
70766
|
+
>
|
|
70372
70767
|
{{ pendingGuestInitials() }}
|
|
70373
70768
|
</span>
|
|
70374
70769
|
}
|
|
@@ -70428,26 +70823,26 @@ class ChessimalsGameComponent {
|
|
|
70428
70823
|
@if (isChallengeActive() || turnSecondsRemaining() !== undefined) {
|
|
70429
70824
|
<div class="chessimals-status chessimals-status--simple">
|
|
70430
70825
|
@if (isChallengeActive()) {
|
|
70431
|
-
|
|
70432
|
-
|
|
70433
|
-
|
|
70434
|
-
|
|
70435
|
-
|
|
70436
|
-
|
|
70437
|
-
|
|
70438
|
-
|
|
70826
|
+
<div>
|
|
70827
|
+
<small>{{ t('chessimalsChallengeRound') }}</small>
|
|
70828
|
+
<strong>{{ challengeRoundLabel() }}</strong>
|
|
70829
|
+
</div>
|
|
70830
|
+
<div>
|
|
70831
|
+
<small>{{ t('chessimalsChallengeLives') }}</small>
|
|
70832
|
+
<strong>{{ challengeLivesLabel() }}</strong>
|
|
70833
|
+
</div>
|
|
70439
70834
|
}
|
|
70440
70835
|
@if (turnSecondsRemaining() !== undefined) {
|
|
70441
|
-
|
|
70442
|
-
|
|
70443
|
-
|
|
70444
|
-
|
|
70445
|
-
|
|
70446
|
-
|
|
70447
|
-
|
|
70448
|
-
|
|
70449
|
-
|
|
70450
|
-
|
|
70836
|
+
<div
|
|
70837
|
+
class="chessimals-status__timer"
|
|
70838
|
+
[class.is-low]="isTurnTimerLow()"
|
|
70839
|
+
[style.--timer-progress]="turnTimerProgress()"
|
|
70840
|
+
role="timer"
|
|
70841
|
+
aria-live="polite"
|
|
70842
|
+
>
|
|
70843
|
+
<small>{{ t('chessimalsTurnTimer') }}</small>
|
|
70844
|
+
<strong>{{ turnTimerLabel() }}</strong>
|
|
70845
|
+
</div>
|
|
70451
70846
|
}
|
|
70452
70847
|
</div>
|
|
70453
70848
|
}
|
|
@@ -70545,7 +70940,14 @@ class ChessimalsGameComponent {
|
|
|
70545
70940
|
[class.effect-bull]="isMoveEffectCell(row, col, 'bull')"
|
|
70546
70941
|
[class.effect-kangaroo]="isMoveEffectCell(row, col, 'kangaroo')"
|
|
70547
70942
|
[class.effect-lion]="isMoveEffectCell(row, col, 'lion')"
|
|
70548
|
-
[disabled]="
|
|
70943
|
+
[disabled]="
|
|
70944
|
+
projectionMode ||
|
|
70945
|
+
game().status !== 'in_progress' ||
|
|
70946
|
+
!canPlayCurrentTurn() ||
|
|
70947
|
+
!!movingPiece() ||
|
|
70948
|
+
botThinking() ||
|
|
70949
|
+
moveSyncing()
|
|
70950
|
+
"
|
|
70549
70951
|
(click)="selectCell({ row, col })"
|
|
70550
70952
|
>
|
|
70551
70953
|
<span class="chessimals-cell-texture" aria-hidden="true"></span>
|
|
@@ -70698,7 +71100,11 @@ class ChessimalsGameComponent {
|
|
|
70698
71100
|
type="button"
|
|
70699
71101
|
[class.is-selected]="selectedAnimal() === animal.type"
|
|
70700
71102
|
[class.is-used]="powerPlayer().cards[animal.type].used"
|
|
70701
|
-
[disabled]="
|
|
71103
|
+
[disabled]="
|
|
71104
|
+
!canUsePowerCards() ||
|
|
71105
|
+
powerPlayer().cards[animal.type].used ||
|
|
71106
|
+
isPowerCardBlockedByTutorial(animal.type)
|
|
71107
|
+
"
|
|
70702
71108
|
(click)="toggleAnimal(animal)"
|
|
70703
71109
|
>
|
|
70704
71110
|
<span class="chessimals-animal-face" aria-hidden="true">
|
|
@@ -70793,11 +71199,19 @@ class ChessimalsGameComponent {
|
|
|
70793
71199
|
</div>
|
|
70794
71200
|
<div class="chessimals-challenge-summary__actions">
|
|
70795
71201
|
@if (challengePhase() === 'between') {
|
|
70796
|
-
<button
|
|
71202
|
+
<button
|
|
71203
|
+
class="chessimals-primary chessimals-challenge-summary__play"
|
|
71204
|
+
type="button"
|
|
71205
|
+
(click)="continueChallenge()"
|
|
71206
|
+
>
|
|
70797
71207
|
{{ challengeContinueLabel() }}
|
|
70798
71208
|
</button>
|
|
70799
71209
|
} @else {
|
|
70800
|
-
<button
|
|
71210
|
+
<button
|
|
71211
|
+
class="chessimals-primary chessimals-challenge-summary__play"
|
|
71212
|
+
type="button"
|
|
71213
|
+
(click)="startChallenge()"
|
|
71214
|
+
>
|
|
70801
71215
|
{{ t('chessimalsChallengePlayAgain') }}
|
|
70802
71216
|
</button>
|
|
70803
71217
|
}
|
|
@@ -70872,7 +71286,10 @@ class ChessimalsGameComponent {
|
|
|
70872
71286
|
@if (rematchOpponentAvatarUrl()) {
|
|
70873
71287
|
<val-user-avatar [props]="rematchOpponentAvatarProps()" />
|
|
70874
71288
|
} @else {
|
|
70875
|
-
<span
|
|
71289
|
+
<span
|
|
71290
|
+
class="chessimals-player-strip__avatar chessimals-player-strip__avatar--initials"
|
|
71291
|
+
aria-hidden="true"
|
|
71292
|
+
>
|
|
70876
71293
|
{{ rematchOpponentInitials() }}
|
|
70877
71294
|
</span>
|
|
70878
71295
|
}
|
|
@@ -70995,7 +71412,9 @@ class ChessimalsGameComponent {
|
|
|
70995
71412
|
|
|
70996
71413
|
<article class="chessimals-play-options__group">
|
|
70997
71414
|
<h3 id="chessimals-play-bot">
|
|
70998
|
-
{{
|
|
71415
|
+
{{
|
|
71416
|
+
selectedBotDifficulty() === 'nightmare' ? t('chessimalsNightmareRivals') : t('chessimalsBotStyle')
|
|
71417
|
+
}}
|
|
70999
71418
|
</h3>
|
|
71000
71419
|
<div class="chessimals-bots" role="radiogroup" aria-labelledby="chessimals-play-bot">
|
|
71001
71420
|
@if (selectedBotDifficulty() === 'nightmare') {
|
|
@@ -71275,7 +71694,16 @@ class ChessimalsGameComponent {
|
|
|
71275
71694
|
}
|
|
71276
71695
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChessimalsGameComponent, decorators: [{
|
|
71277
71696
|
type: Component,
|
|
71278
|
-
args: [{ selector: 'val-chessimals-game', standalone: true, imports: [
|
|
71697
|
+
args: [{ selector: 'val-chessimals-game', standalone: true, imports: [
|
|
71698
|
+
IonModal,
|
|
71699
|
+
MiniGameCalloutComponent,
|
|
71700
|
+
MiniGameScorePopComponent,
|
|
71701
|
+
ModalLayoutComponent,
|
|
71702
|
+
RangeInputComponent,
|
|
71703
|
+
ToggleInputComponent,
|
|
71704
|
+
ButtonComponent,
|
|
71705
|
+
UserAvatarComponent,
|
|
71706
|
+
], template: `
|
|
71279
71707
|
<main class="chessimals-shell" [class.chessimals-shell--projection]="projectionMode">
|
|
71280
71708
|
@if (screen() === 'home') {
|
|
71281
71709
|
<section class="chessimals-hero">
|
|
@@ -71298,7 +71726,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
71298
71726
|
|
|
71299
71727
|
<section class="chessimals-panel">
|
|
71300
71728
|
<section class="chessimals-home-actions" [attr.aria-label]="t('chessimalsHomeChoose')">
|
|
71301
|
-
<button
|
|
71729
|
+
<button
|
|
71730
|
+
class="chessimals-home-action chessimals-home-action--play"
|
|
71731
|
+
type="button"
|
|
71732
|
+
(click)="openPlayOptionsModal()"
|
|
71733
|
+
>
|
|
71302
71734
|
<img
|
|
71303
71735
|
class="chessimals-mode-icon"
|
|
71304
71736
|
src="assets/games/chessimals/mode-icons/solo-borderless.png"
|
|
@@ -71352,60 +71784,60 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
71352
71784
|
</summary>
|
|
71353
71785
|
|
|
71354
71786
|
<article class="chessimals-online">
|
|
71355
|
-
|
|
71356
|
-
|
|
71357
|
-
|
|
71358
|
-
|
|
71359
|
-
|
|
71360
|
-
|
|
71361
|
-
|
|
71362
|
-
|
|
71363
|
-
|
|
71364
|
-
|
|
71365
|
-
|
|
71787
|
+
<div>
|
|
71788
|
+
<h2>{{ t('chessimalsOnlineTitle') }}</h2>
|
|
71789
|
+
<p>{{ t('chessimalsOnlineBody') }}</p>
|
|
71790
|
+
</div>
|
|
71791
|
+
@if (onlineError()) {
|
|
71792
|
+
<p class="chessimals-online__error">{{ onlineError() }}</p>
|
|
71793
|
+
}
|
|
71794
|
+
@if (onlineLoading()) {
|
|
71795
|
+
<div class="chessimals-online__loading" role="status" aria-live="polite">
|
|
71796
|
+
<span aria-hidden="true"></span>
|
|
71797
|
+
<strong>{{ t('chessimalsOnlineLoading') }}</strong>
|
|
71798
|
+
</div>
|
|
71799
|
+
}
|
|
71800
|
+
<div class="chessimals-online__create">
|
|
71801
|
+
<button
|
|
71802
|
+
class="chessimals-primary"
|
|
71803
|
+
type="button"
|
|
71804
|
+
[class.is-working]="onlineAction() === 'create'"
|
|
71805
|
+
[attr.aria-busy]="onlineAction() === 'create'"
|
|
71806
|
+
[disabled]="onlineLoading()"
|
|
71807
|
+
(click)="createOnlineGame()"
|
|
71808
|
+
>
|
|
71809
|
+
@if (onlineAction() === 'create') {
|
|
71810
|
+
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
71811
|
+
}
|
|
71812
|
+
{{ t('chessimalsCreateOnline') }}
|
|
71813
|
+
</button>
|
|
71814
|
+
<small>{{ t('chessimalsCreateOnlineHint') }}</small>
|
|
71815
|
+
</div>
|
|
71816
|
+
<div class="chessimals-online__join">
|
|
71817
|
+
<strong>{{ t('chessimalsJoinOnlineTitle') }}</strong>
|
|
71818
|
+
<label class="chessimals-online-code">
|
|
71819
|
+
<span>{{ t('chessimalsJoinCode') }}</span>
|
|
71820
|
+
<input
|
|
71821
|
+
type="text"
|
|
71822
|
+
[value]="onlineJoinCode()"
|
|
71823
|
+
[placeholder]="t('chessimalsJoinCodePlaceholder')"
|
|
71824
|
+
(input)="onlineJoinCode.set(normalizeGameId($any($event.target).value))"
|
|
71825
|
+
/>
|
|
71826
|
+
</label>
|
|
71827
|
+
<button
|
|
71828
|
+
class="chessimals-primary"
|
|
71829
|
+
type="button"
|
|
71830
|
+
[class.is-working]="onlineAction() === 'join'"
|
|
71831
|
+
[attr.aria-busy]="onlineAction() === 'join'"
|
|
71832
|
+
[disabled]="onlineLoading() || !onlineJoinCode()"
|
|
71833
|
+
(click)="joinOnlineGameByCode()"
|
|
71834
|
+
>
|
|
71835
|
+
@if (onlineAction() === 'join') {
|
|
71836
|
+
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
71837
|
+
}
|
|
71838
|
+
{{ t('chessimalsJoinOnline') }}
|
|
71839
|
+
</button>
|
|
71366
71840
|
</div>
|
|
71367
|
-
}
|
|
71368
|
-
<div class="chessimals-online__create">
|
|
71369
|
-
<button
|
|
71370
|
-
class="chessimals-primary"
|
|
71371
|
-
type="button"
|
|
71372
|
-
[class.is-working]="onlineAction() === 'create'"
|
|
71373
|
-
[attr.aria-busy]="onlineAction() === 'create'"
|
|
71374
|
-
[disabled]="onlineLoading()"
|
|
71375
|
-
(click)="createOnlineGame()"
|
|
71376
|
-
>
|
|
71377
|
-
@if (onlineAction() === 'create') {
|
|
71378
|
-
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
71379
|
-
}
|
|
71380
|
-
{{ t('chessimalsCreateOnline') }}
|
|
71381
|
-
</button>
|
|
71382
|
-
<small>{{ t('chessimalsCreateOnlineHint') }}</small>
|
|
71383
|
-
</div>
|
|
71384
|
-
<div class="chessimals-online__join">
|
|
71385
|
-
<strong>{{ t('chessimalsJoinOnlineTitle') }}</strong>
|
|
71386
|
-
<label class="chessimals-online-code">
|
|
71387
|
-
<span>{{ t('chessimalsJoinCode') }}</span>
|
|
71388
|
-
<input
|
|
71389
|
-
type="text"
|
|
71390
|
-
[value]="onlineJoinCode()"
|
|
71391
|
-
[placeholder]="t('chessimalsJoinCodePlaceholder')"
|
|
71392
|
-
(input)="onlineJoinCode.set(normalizeGameId($any($event.target).value))"
|
|
71393
|
-
/>
|
|
71394
|
-
</label>
|
|
71395
|
-
<button
|
|
71396
|
-
class="chessimals-primary"
|
|
71397
|
-
type="button"
|
|
71398
|
-
[class.is-working]="onlineAction() === 'join'"
|
|
71399
|
-
[attr.aria-busy]="onlineAction() === 'join'"
|
|
71400
|
-
[disabled]="onlineLoading() || !onlineJoinCode()"
|
|
71401
|
-
(click)="joinOnlineGameByCode()"
|
|
71402
|
-
>
|
|
71403
|
-
@if (onlineAction() === 'join') {
|
|
71404
|
-
<span class="chessimals-button-spinner" aria-hidden="true"></span>
|
|
71405
|
-
}
|
|
71406
|
-
{{ t('chessimalsJoinOnline') }}
|
|
71407
|
-
</button>
|
|
71408
|
-
</div>
|
|
71409
71841
|
</article>
|
|
71410
71842
|
</details>
|
|
71411
71843
|
|
|
@@ -71488,7 +71920,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
71488
71920
|
<strong>{{ challengeBotName(challengeMenuBot()) }}</strong>
|
|
71489
71921
|
<p>{{ t(challengeMenuBot().introKey) }}</p>
|
|
71490
71922
|
<em>
|
|
71491
|
-
{{
|
|
71923
|
+
{{
|
|
71924
|
+
t('chessimalsChallengeBoardLabel').replace(
|
|
71925
|
+
'{size}',
|
|
71926
|
+
challengeMenuBot().boardSize + 'x' + challengeMenuBot().boardSize
|
|
71927
|
+
)
|
|
71928
|
+
}}
|
|
71492
71929
|
, {{ challengeBotDifficultyLabel(challengeMenuBot()) }}
|
|
71493
71930
|
</em>
|
|
71494
71931
|
</div>
|
|
@@ -71750,7 +72187,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
71750
72187
|
@if (pendingGuestAvatarUrl()) {
|
|
71751
72188
|
<val-user-avatar [props]="pendingGuestAvatarProps()" />
|
|
71752
72189
|
} @else {
|
|
71753
|
-
<span
|
|
72190
|
+
<span
|
|
72191
|
+
class="chessimals-player-strip__avatar chessimals-player-strip__avatar--initials"
|
|
72192
|
+
aria-hidden="true"
|
|
72193
|
+
>
|
|
71754
72194
|
{{ pendingGuestInitials() }}
|
|
71755
72195
|
</span>
|
|
71756
72196
|
}
|
|
@@ -71810,26 +72250,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
71810
72250
|
@if (isChallengeActive() || turnSecondsRemaining() !== undefined) {
|
|
71811
72251
|
<div class="chessimals-status chessimals-status--simple">
|
|
71812
72252
|
@if (isChallengeActive()) {
|
|
71813
|
-
|
|
71814
|
-
|
|
71815
|
-
|
|
71816
|
-
|
|
71817
|
-
|
|
71818
|
-
|
|
71819
|
-
|
|
71820
|
-
|
|
72253
|
+
<div>
|
|
72254
|
+
<small>{{ t('chessimalsChallengeRound') }}</small>
|
|
72255
|
+
<strong>{{ challengeRoundLabel() }}</strong>
|
|
72256
|
+
</div>
|
|
72257
|
+
<div>
|
|
72258
|
+
<small>{{ t('chessimalsChallengeLives') }}</small>
|
|
72259
|
+
<strong>{{ challengeLivesLabel() }}</strong>
|
|
72260
|
+
</div>
|
|
71821
72261
|
}
|
|
71822
72262
|
@if (turnSecondsRemaining() !== undefined) {
|
|
71823
|
-
|
|
71824
|
-
|
|
71825
|
-
|
|
71826
|
-
|
|
71827
|
-
|
|
71828
|
-
|
|
71829
|
-
|
|
71830
|
-
|
|
71831
|
-
|
|
71832
|
-
|
|
72263
|
+
<div
|
|
72264
|
+
class="chessimals-status__timer"
|
|
72265
|
+
[class.is-low]="isTurnTimerLow()"
|
|
72266
|
+
[style.--timer-progress]="turnTimerProgress()"
|
|
72267
|
+
role="timer"
|
|
72268
|
+
aria-live="polite"
|
|
72269
|
+
>
|
|
72270
|
+
<small>{{ t('chessimalsTurnTimer') }}</small>
|
|
72271
|
+
<strong>{{ turnTimerLabel() }}</strong>
|
|
72272
|
+
</div>
|
|
71833
72273
|
}
|
|
71834
72274
|
</div>
|
|
71835
72275
|
}
|
|
@@ -71927,7 +72367,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
71927
72367
|
[class.effect-bull]="isMoveEffectCell(row, col, 'bull')"
|
|
71928
72368
|
[class.effect-kangaroo]="isMoveEffectCell(row, col, 'kangaroo')"
|
|
71929
72369
|
[class.effect-lion]="isMoveEffectCell(row, col, 'lion')"
|
|
71930
|
-
[disabled]="
|
|
72370
|
+
[disabled]="
|
|
72371
|
+
projectionMode ||
|
|
72372
|
+
game().status !== 'in_progress' ||
|
|
72373
|
+
!canPlayCurrentTurn() ||
|
|
72374
|
+
!!movingPiece() ||
|
|
72375
|
+
botThinking() ||
|
|
72376
|
+
moveSyncing()
|
|
72377
|
+
"
|
|
71931
72378
|
(click)="selectCell({ row, col })"
|
|
71932
72379
|
>
|
|
71933
72380
|
<span class="chessimals-cell-texture" aria-hidden="true"></span>
|
|
@@ -72080,7 +72527,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72080
72527
|
type="button"
|
|
72081
72528
|
[class.is-selected]="selectedAnimal() === animal.type"
|
|
72082
72529
|
[class.is-used]="powerPlayer().cards[animal.type].used"
|
|
72083
|
-
[disabled]="
|
|
72530
|
+
[disabled]="
|
|
72531
|
+
!canUsePowerCards() ||
|
|
72532
|
+
powerPlayer().cards[animal.type].used ||
|
|
72533
|
+
isPowerCardBlockedByTutorial(animal.type)
|
|
72534
|
+
"
|
|
72084
72535
|
(click)="toggleAnimal(animal)"
|
|
72085
72536
|
>
|
|
72086
72537
|
<span class="chessimals-animal-face" aria-hidden="true">
|
|
@@ -72175,11 +72626,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72175
72626
|
</div>
|
|
72176
72627
|
<div class="chessimals-challenge-summary__actions">
|
|
72177
72628
|
@if (challengePhase() === 'between') {
|
|
72178
|
-
<button
|
|
72629
|
+
<button
|
|
72630
|
+
class="chessimals-primary chessimals-challenge-summary__play"
|
|
72631
|
+
type="button"
|
|
72632
|
+
(click)="continueChallenge()"
|
|
72633
|
+
>
|
|
72179
72634
|
{{ challengeContinueLabel() }}
|
|
72180
72635
|
</button>
|
|
72181
72636
|
} @else {
|
|
72182
|
-
<button
|
|
72637
|
+
<button
|
|
72638
|
+
class="chessimals-primary chessimals-challenge-summary__play"
|
|
72639
|
+
type="button"
|
|
72640
|
+
(click)="startChallenge()"
|
|
72641
|
+
>
|
|
72183
72642
|
{{ t('chessimalsChallengePlayAgain') }}
|
|
72184
72643
|
</button>
|
|
72185
72644
|
}
|
|
@@ -72254,7 +72713,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72254
72713
|
@if (rematchOpponentAvatarUrl()) {
|
|
72255
72714
|
<val-user-avatar [props]="rematchOpponentAvatarProps()" />
|
|
72256
72715
|
} @else {
|
|
72257
|
-
<span
|
|
72716
|
+
<span
|
|
72717
|
+
class="chessimals-player-strip__avatar chessimals-player-strip__avatar--initials"
|
|
72718
|
+
aria-hidden="true"
|
|
72719
|
+
>
|
|
72258
72720
|
{{ rematchOpponentInitials() }}
|
|
72259
72721
|
</span>
|
|
72260
72722
|
}
|
|
@@ -72377,7 +72839,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
72377
72839
|
|
|
72378
72840
|
<article class="chessimals-play-options__group">
|
|
72379
72841
|
<h3 id="chessimals-play-bot">
|
|
72380
|
-
{{
|
|
72842
|
+
{{
|
|
72843
|
+
selectedBotDifficulty() === 'nightmare' ? t('chessimalsNightmareRivals') : t('chessimalsBotStyle')
|
|
72844
|
+
}}
|
|
72381
72845
|
</h3>
|
|
72382
72846
|
<div class="chessimals-bots" role="radiogroup" aria-labelledby="chessimals-play-bot">
|
|
72383
72847
|
@if (selectedBotDifficulty() === 'nightmare') {
|