import { takeLatest , take , delay , put } from "@redux-saga/core/effects" ; import { select } from "typed-redux-saga" ; import { PieceModel , PIECES_TO_EVOLVE } from "@creature-chess/models" ; import { BoardSelectors } from "@shoki/board" ; import * as pieceSelectors from "../../../player/pieceSelectors" ; import { getDefinitionById } from "../../../definitions" ; import { isPlayerBoardLocked } from "../state/selectors" ; import { PlayerState } from "../state" ; import { getPlayerEntityDependencies } from "../dependencies" ; const pieceCanEvolve = ( piece ) => { const definition = getDefinitionById ( piece . definitionId ) ; if ( ! definition ) { return false ; } return piece . stage < definition . stages . length - 1 ; } ; export const evolutionSaga = function * ( ) { const { boardSlices : { boardSlice , benchSlice } } = yield * getPlayerEntityDependencies ( ) ; yield takeLatest < ReturnType < typeof boardSlice . commands . addBoardPieceCommand > | ReturnType < typeof benchSlice . commands . addBoardPieceCommand > > ( [ boardSlice . commands . addBoardPieceCommand , benchSlice . commands . addBoardPieceCommand ] , function * ( { payload : { piece } } ) { if ( ! pieceCanEvolve ( piece ) ) { return ; } const boardLocked = yield * select ( isPlayerBoardLocked ) ; if ( boardLocked ) { yield take ( boardSlice . commands . unlockBoardCommand ) ; yield delay ( 500 ) ; } const targetDefinitionId = piece . definitionId ; const targetStage = piece . stage ; const getCombinablePieces = ( pieces ) => pieces . filter ( p => p . stage === targetStage ) ; const matchingBoardPieces = yield * select ( ( state ) => getCombinablePieces ( pieceSelectors . getPiecesForDefinition ( state . board , targetDefinitionId ) ) ) ; const matchingBenchPieces = yield * select ( ( state ) => getCombinablePieces ( pieceSelectors . getPiecesForDefinition ( state . bench , targetDefinitionId ) ) ) ; const totalInstances = matchingBoardPieces . length + matchingBenchPieces . length ; if ( totalInstances < PIECES_TO_EVOLVE ) { return ; } if ( matchingBoardPieces . length > 0 ) { const pieceToReplace = matchingBoardPieces . pop ( ) ! ; const piecePosition = yield * select ( ( s ) => BoardSelectors . getPiecePosition ( s . board , pieceToReplace . id ) ) ; if ( ! piecePosition ) { return ; } const { x , y } = piecePosition ; const boardPieceIds = [ ... matchingBoardPieces , pieceToReplace ] . map ( p => p . id ) ; yield put ( boardSlice . commands . removeBoardPiecesCommand ( boardPieceIds ) ) ; const benchPieceIds = matchingBenchPieces . map ( p => p . id ) ; yield put ( benchSlice . commands . removeBoardPiecesCommand ( [ ... benchPieceIds , piece . id ] ) ) ; const newPiece = { ... pieceToReplace , stage : targetStage + 1 } ; yield put ( boardSlice . commands . addBoardPieceCommand ( { x , y , piece : newPiece } ) ) ; } else { const benchPieceIds = matchingBenchPieces . map ( p => p . id ) ; const newPiece = { ... piece , stage : targetStage + 1 } ; const piecePosition = yield * select ( ( s ) => BoardSelectors . getPiecePosition ( s . bench , piece . id ) ) ; if ( ! piecePosition ) { return ; } const { x , y } = piecePosition ; yield put ( benchSlice . commands . removeBoardPiecesCommand ( [ ... benchPieceIds , piece . id ] ) ) ; yield put ( benchSlice . commands . addBoardPieceCommand ( { x , y , piece : newPiece } ) ) ; } } ) ; } ;