playship_ludo_pseudo_quick
Version:
Server side neutrino plugin code for ludo game
258 lines (234 loc) • 9.69 kB
JavaScript
const enums = require('../utils/enums');
const logger = require('../utils/playshipUtils').getLogger();
const gameLogic = require('./logic');
const events = enums.NEW_EVENTS
const eventObjs = require('../utils/newGameEvent')
const {
_getGameProp, _setGameProp, _getMeta,
_setPlayerProp, _getPlayerProp,_gameOver,
_remainingTurnToEndGame,_aggregatePlayerTurnTime,
_offExtraTimeIfEnabled,_isPauseEnabled,_isGamePaused,
_getPlayerRemExtraTime
} = require('../utils/utils');
const {ALL_PLAYERS_EXHAUSTED_MOVED} = require('../utils/enums');
const PLAYER_PROPS = enums.PLAYER_PROPS;
const GAME_PROPS = enums.GAME_PROPS;
const step = function(game) {
const gk = {key: game.getId()};
if (game.getState() >= 30)
return logger.debug(gk, 'Game has ended, nothing to do');
let gameOverTs = _getGameProp(game, GAME_PROPS.GAME_OVER_TS);
if (!isNaN(gameOverTs)) {
if (Date.now() > gameOverTs)
_gameOver(game,_getGameProp(game, GAME_PROPS.GAME_OVER_REASON))
//game.endGame(_getGameProp(game, GAME_PROPS.GAME_OVER_REASON));
return;
}
let gameTimerEndTs = _getGameProp(game, GAME_PROPS.GAME_TIMER_END_TS);
let timeLeft = gameTimerEndTs - Date.now()
if(isNaN(timeLeft)) return;
if (timeLeft < 0 && !_getGameProp(game,GAME_PROPS.IS_FINAL_TURNS)
&& !_isGamePaused(game)){
_setGameProp(game, GAME_PROPS.IS_FINAL_TURNS, true);
let remPlayer = _remainingTurnToEndGame(game)
_setGameProp(game,GAME_PROPS.FINAL_REM_PLAYERS,remPlayer)
game.syncGameStateServVars();
}
checkAndSkipTurn(game);
checkAndHandleTurnExpiry(game);
checkMoveTurnAndEndGame(game);
checkTurnSkip(game)
checkForTip(game);
};
function checkForTip(game) {
const gk = {key: game.getId()};
const meta = _getMeta(game);
let lastTipTs = game.getTransient(GAME_PROPS.LAST_TIP_TS);
if (lastTipTs + meta.genericTipsCheckInterval > Date.now())
return;
let random = Math.random();
if (random > meta.probabilityOfTip) return;
let tipIdToSend = meta.genericTipIds[Math.floor(
Math.random() * meta.genericTipIds.length)];
logger.debug(gk, 'genric tip probability cleared, sending tip tipId',
tipIdToSend);
game.addTransient(GAME_PROPS.LAST_TIP_TS, Date.now());
game.sendTip(game.getAllPlayerIds()[0], tipIdToSend);
}
function checkMoveTurnAndEndGame(game) {
const gk = {key: game.getId()};
let nextTurnTs = _getGameProp(game, GAME_PROPS.NEXT_TURN_TS);
logger.trace(gk, 'Next turn move ts is', nextTurnTs);
if (Date.now() >= nextTurnTs) {
_setGameProp(game, GAME_PROPS.NEXT_TURN_TS, null);
let isTurnContinue = _getGameProp(game, GAME_PROPS.IS_CONTINUE);
_setGameProp(game, GAME_PROPS.IS_TURN_PROCESSED_SERVER, false);
_setGameProp(game, GAME_PROPS.IS_TURN_PROCESSED, false);
_setGameProp(game, GAME_PROPS.IS_TURN_COMPLETED, false);
game.addTransient(GAME_PROPS.IS_SKIP_CHECKED, false);
game.syncGameStateServVars();
gameLogic.destroyForfeitPlayerPawns(game).catch(e => {
logger.error(gk, 'forfeit players failed with exception', e);
});
if (isTurnContinue)
game.continueTurn();
else {
if (checkAndEndGame(game))
return; // if game ends nothing to do
game.nextTurn();
}
gameLogic.issueTurnStartSavePoint(game);
}
}
function checkAndEndGame(game) {
const gk = {key: game.getId()};
let isGameTimerEnded = _getGameProp(game, GAME_PROPS.IS_FINAL_TURNS);
if (!isGameTimerEnded) return false;
let prevMoveCount;
for (let p of game.getAllPlayerIds()) {
logger.debug(gk,"player %s state count %s",p,game.getPlayerState(p))
if (parseInt(game.getPlayerState(p)) < 20) {
let moveCount = _getPlayerProp(game, p, enums.PLAYER_PROPS.TURN_COUNT);
logger.debug(gk,"player %s move count %s",p,moveCount)
if (!prevMoveCount) prevMoveCount = moveCount;
if (prevMoveCount !== moveCount)
return false;
}
}
_gameOver(game,ALL_PLAYERS_EXHAUSTED_MOVED)
//game.endGame(ALL_PLAYERS_EXHAUSTED_MOVED);
return true;
}
function checkAndSkipTurn(game) {
const gk = {key: game.getId()};
if (_getGameProp(game, GAME_PROPS.IS_TURN_PROCESSED_SERVER))
return;
const meta = _getMeta(game);
let turnExpiry = game.getCurrentTurnExpiry();
let isTurnSkipChecked = game.getTransient(GAME_PROPS.IS_SKIP_CHECKED);
let TURN_COOL_OFF_SKIP = meta.turnSkipCoolOffDur || 1000
if (turnExpiry > -1 && (turnExpiry + TURN_COOL_OFF_SKIP> Date.now() || _isGamePaused(game)) &&
!isTurnSkipChecked) {
let playerId = game.getCurrentTurnPlayerId();
if(parseInt(game.getPlayerState(playerId)) === 30) return;
if(gameLogic.isTurnSkip(game, playerId)) {
if(_isGamePaused(game)) _offExtraTimeIfEnabled(game, playerId);
game.addTransient(GAME_PROPS.IS_SKIP_CHECKED, true);
game.addTransient(GAME_PROPS.IS_TURN_SKIPPED, true);
logger.info(gk, 'Skipping turn due to no possible moves for', playerId);
_setGameProp(game, GAME_PROPS.IS_TURN_PROCESSED, true);
_setGameProp(game, GAME_PROPS.IS_TURN_PROCESSED_SERVER, true);
game.syncGameStateServVars();
gameLogic.turnEndHandler(game, playerId, null, null,true,
null,meta.addOnTimeForSkip || 500);
}
}
}
function checkAndHandleTurnExpiry(game) {
const gk = {key: game.getId()};
if (_getGameProp(game, GAME_PROPS.IS_TURN_PROCESSED_SERVER))
return;
let turnExpiry = game.getCurrentTurnExpiry();
logger.trace('Current turn expiry is', turnExpiry);
const meta = _getMeta(game);
let TURN_COOL_OFF = 0
if (turnExpiry > -1 && turnExpiry + TURN_COOL_OFF < Date.now()) {
let playerId = game.getCurrentTurnPlayerId();
if(_isPauseEnabled(game)){
if(!_isGamePaused(game) ){
if(_getPlayerRemExtraTime(game,playerId) > 0) return pauseAndStartExtraTime(game,playerId);
} else {
if(canGameBePaused(game,playerId)) return;
}
}
let missMoveEventObj = new eventObjs.missMoveEvent()
if(parseInt(game.getPlayerState(playerId)) === 30) return;
let curMissMoves = _getPlayerProp(game, playerId, PLAYER_PROPS.MISS_MOVES) +
1;
_aggregatePlayerTurnTime(game,playerId)
logger.info(gk, 'Miss move, switching turn for player', playerId,
'curMissMoves', curMissMoves);
game.incrPluginStats('ludo.movemissed.count');
let isPlayerConnected = false
let connectedPlayers = game.getConnectedPlayers()
for(let i = 0 ; i < connectedPlayers.length;i++){
if(connectedPlayers[i] === playerId){
isPlayerConnected = true
break;
}
}
missMoveEventObj.class = isPlayerConnected ? 1 : 0
let curTurnCount = _getPlayerProp(game, playerId, PLAYER_PROPS.TURN_COUNT);
missMoveEventObj.kingdom = curTurnCount + 1
game.publishNewGameEvent(playerId,missMoveEventObj)
game.publishHHGameEvent(playerId,"miss_move",{
turn_id : game.getCurrentTurnId(),
update_time : Date.now()
})
game.publishExternalGameEvent('BE_GAME_MISSED_MOVE',playerId,{
turn_id : game.getCurrentTurnId(),
connected : isPlayerConnected ? 1 : 0,
missed_move_count : curMissMoves,
update_time : Date.now()
})
_setPlayerProp(game, playerId, PLAYER_PROPS.MISS_MOVES, curMissMoves);
if (curMissMoves === 1)
game.sendTip(playerId, 8);
else if (curMissMoves === 2)
game.sendTip(playerId, 9);
if (curMissMoves >= meta.maxMissMoves) {
game.syncPlayerServVars(playerId);
logger.debug(gk, 'Max miss moves reached', curMissMoves, 'by', playerId);
_setGameProp(game,GAME_PROPS.ABSOLUTE_WIN_TYPE,1)
game.forfeitGameForPlayer(playerId, enums.MAX_MISS_MOVES);
game.publishGameEvent(1609, [playerId]);
game.incrPluginStats('ludo.moves.allmiss');
return;
}
_setGameProp(game, GAME_PROPS.IS_TURN_PROCESSED, true);
_setGameProp(game, GAME_PROPS.IS_TURN_PROCESSED_SERVER, true);
if(_isPauseEnabled(game)){_offExtraTimeIfEnabled(game,playerId)}
game.syncGameStateServVars();
gameLogic.turnEndHandler(game, playerId,null,null,true,
null);
game.publishNewGameEvent(playerId,missMoveEventObj)
checkMoveTurnAndEndGame(game)
}
}
const canGameBePaused = function(game,playerId){
const gk = {key: game.getId()};
let remainingExtraTime = getRemainingExtraTime(game,playerId)
logger.debug(gk,"is game paused %s remaining time",
remainingExtraTime);
if(remainingExtraTime > 0) return true;
return false;
}
const getRemainingExtraTime = function(game,playerId){
let extraTimeCheckTime = _getGameProp(game,GAME_PROPS.EXTRA_TIME_CHECK_TIME);
let playerRemExtraTime = game.getPlayerRemainingExtraTime(playerId)
let now = Date.now()
return playerRemExtraTime + extraTimeCheckTime - now
}
const pauseAndStartExtraTime= function(game,playerId){
_setGameProp(game,GAME_PROPS.IS_GAME_PAUSED,true);
let now = Date.now();
let gameTimerEndTs = _getGameProp(game, enums.GAME_PROPS.GAME_TIMER_END_TS);
let timeLeft = gameTimerEndTs - now
_setGameProp(game, GAME_PROPS.GAME_TIMER_REMAINING,
timeLeft >= 0 ? timeLeft : 0);
_setGameProp(game,GAME_PROPS.EXTRA_TIME_START_TIME,now);
_setGameProp(game,GAME_PROPS.EXTRA_TIME_CHECK_TIME,now)
game.incrPluginStats('ludo.extratime.used');
game.syncGameStateServVars();
}
const checkTurnSkip = function (game) {
const gk = {key: game.getId()};
if (game.getTransient(GAME_PROPS.IS_TURN_SKIPPED)
&& Date.now() >= _getGameProp(game, GAME_PROPS.NEXT_TURN_TS)) {
logger.info(gk, 'Proceeding Skipping turn');
game.incrPluginStats('ludo.moveskip.count');
game.addTransient(GAME_PROPS.IS_TURN_SKIPPED, false);
checkMoveTurnAndEndGame(game)
}
}
module.exports = step;