mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
commit
c45ab07d0b
@ -193,6 +193,15 @@
|
|||||||
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Team Alignments",
|
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Team Alignments",
|
||||||
"vcmi.randomMapTab.widgets.roadTypesLabel" : "Road Types",
|
"vcmi.randomMapTab.widgets.roadTypesLabel" : "Road Types",
|
||||||
|
|
||||||
|
"vcmi.optionsTab.widgets.chessFieldBase.help" : "{Extra timer}\n\nStarts counting down when the {turn timer} reaches zero. It is set only once at the beginning of the game. When this timer reaches zero, the player's turn ends.",
|
||||||
|
"vcmi.optionsTab.widgets.chessFieldTurn.help" : "{Turn timer}\n\nStarts counting down when the player starts their turn on the adventure map. It is reset to its initial value at the start of each turn. Any unused turn time will be added to the {Extra timer} if it is in use.",
|
||||||
|
"vcmi.optionsTab.widgets.chessFieldBattle.help" : "{Battle timer}\n\nCounts down during battles when the {stack timer} reaches zero. It is reset to its initial value at the start of each battle. If the timer reaches zero, the currently active stack will defend.",
|
||||||
|
"vcmi.optionsTab.widgets.chessFieldCreature.help" : "{Stack timer}\n\nStarts counting down when the player is selecting an action for the current stack during battle. It resets to its initial value after the stack's action is completed.",
|
||||||
|
"vcmi.optionsTab.widgets.labelTimer" : "Timer",
|
||||||
|
"vcmi.optionsTab.widgets.timerModeSwitch.classic" : "Classic timer",
|
||||||
|
"vcmi.optionsTab.widgets.timerModeSwitch.chess" : "Chess timer",
|
||||||
|
|
||||||
|
|
||||||
// Custom victory conditions for H3 campaigns and HotA maps
|
// Custom victory conditions for H3 campaigns and HotA maps
|
||||||
"vcmi.map.victoryCondition.daysPassed.toOthers" : "The enemy has managed to survive till this day. Victory is theirs!",
|
"vcmi.map.victoryCondition.daysPassed.toOthers" : "The enemy has managed to survive till this day. Victory is theirs!",
|
||||||
"vcmi.map.victoryCondition.daysPassed.toSelf" : "Congratulations! You have managed to survive. Victory is yours!",
|
"vcmi.map.victoryCondition.daysPassed.toSelf" : "Congratulations! You have managed to survive. Victory is yours!",
|
||||||
|
@ -140,7 +140,6 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
|
|||||||
firstCall = 1; //if loading will be overwritten in serialize
|
firstCall = 1; //if loading will be overwritten in serialize
|
||||||
autosaveCount = 0;
|
autosaveCount = 0;
|
||||||
isAutoFightOn = false;
|
isAutoFightOn = false;
|
||||||
|
|
||||||
duringMovement = false;
|
duringMovement = false;
|
||||||
ignoreEvents = false;
|
ignoreEvents = false;
|
||||||
numOfMovedArts = 0;
|
numOfMovedArts = 0;
|
||||||
|
@ -63,7 +63,7 @@ AdventureMapInterface::AdventureMapInterface():
|
|||||||
shortcuts->setState(EAdventureState::MAKING_TURN);
|
shortcuts->setState(EAdventureState::MAKING_TURN);
|
||||||
widget->getMapView()->onViewMapActivated();
|
widget->getMapView()->onViewMapActivated();
|
||||||
|
|
||||||
if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.isEnabled())
|
if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.isEnabled() || LOCPLINT->cb->getStartInfo()->turnTimerInfo.isBattleEnabled())
|
||||||
watches = std::make_shared<TurnTimerWidget>();
|
watches = std::make_shared<TurnTimerWidget>();
|
||||||
|
|
||||||
addUsedEvents(KEYBOARD | TIME);
|
addUsedEvents(KEYBOARD | TIME);
|
||||||
|
@ -97,25 +97,14 @@ void TurnTimerWidget::setTime(PlayerColor player, int time)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TurnTimerWidget::tick(uint32_t msPassed)
|
void TurnTimerWidget::updateTimer(PlayerColor player, uint32_t msPassed)
|
||||||
{
|
{
|
||||||
if(!LOCPLINT || !LOCPLINT->cb)
|
const auto & time = LOCPLINT->cb->getPlayerTurnTime(player);
|
||||||
return;
|
if(time.isActive)
|
||||||
|
|
||||||
for (PlayerColor p(0); p < PlayerColor::PLAYER_LIMIT; ++p)
|
|
||||||
{
|
|
||||||
auto player = p;
|
|
||||||
if(LOCPLINT->battleInt)
|
|
||||||
{
|
|
||||||
if(auto * stack = LOCPLINT->battleInt->stacksController->getActiveStack())
|
|
||||||
player = stack->getOwner();
|
|
||||||
}
|
|
||||||
else if (!LOCPLINT->cb->isPlayerMakingTurn(player))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto time = LOCPLINT->cb->getPlayerTurnTime(player);
|
|
||||||
cachedTurnTime -= msPassed;
|
cachedTurnTime -= msPassed;
|
||||||
if(cachedTurnTime < 0) cachedTurnTime = 0; //do not go below zero
|
|
||||||
|
if(cachedTurnTime < 0)
|
||||||
|
cachedTurnTime = 0; //do not go below zero
|
||||||
|
|
||||||
if(lastPlayer != player)
|
if(lastPlayer != player)
|
||||||
{
|
{
|
||||||
@ -138,17 +127,33 @@ void TurnTimerWidget::tick(uint32_t msPassed)
|
|||||||
auto * playerInfo = LOCPLINT->cb->getPlayer(player);
|
auto * playerInfo = LOCPLINT->cb->getPlayer(player);
|
||||||
if(player.isValidPlayer() || (playerInfo && playerInfo->isHuman()))
|
if(player.isValidPlayer() || (playerInfo && playerInfo->isHuman()))
|
||||||
{
|
{
|
||||||
if(LOCPLINT->battleInt)
|
if(time.isBattle)
|
||||||
{
|
|
||||||
if(time.isBattleEnabled())
|
|
||||||
timeCheckAndUpdate(time.creatureTimer);
|
timeCheckAndUpdate(time.creatureTimer);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
timeCheckAndUpdate(time.turnTimer);
|
timeCheckAndUpdate(time.turnTimer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
timeCheckAndUpdate(0);
|
timeCheckAndUpdate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TurnTimerWidget::tick(uint32_t msPassed)
|
||||||
|
{
|
||||||
|
if(!LOCPLINT || !LOCPLINT->cb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(LOCPLINT->battleInt)
|
||||||
|
{
|
||||||
|
if(auto * stack = LOCPLINT->battleInt->stacksController->getActiveStack())
|
||||||
|
updateTimer(stack->getOwner(), msPassed);
|
||||||
|
else
|
||||||
|
updateTimer(PlayerColor::NEUTRAL, msPassed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(PlayerColor p(0); p < PlayerColor::PLAYER_LIMIT; ++p)
|
||||||
|
{
|
||||||
|
if(LOCPLINT->cb->isPlayerMakingTurn(p))
|
||||||
|
updateTimer(p, msPassed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ private:
|
|||||||
|
|
||||||
std::shared_ptr<DrawRect> buildDrawRect(const JsonNode & config) const;
|
std::shared_ptr<DrawRect> buildDrawRect(const JsonNode & config) const;
|
||||||
|
|
||||||
|
void updateTimer(PlayerColor player, uint32_t msPassed);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void show(Canvas & to) override;
|
void show(Canvas & to) override;
|
||||||
|
@ -184,11 +184,11 @@ Point CGuiHandler::screenDimensions() const
|
|||||||
|
|
||||||
void CGuiHandler::drawFPSCounter()
|
void CGuiHandler::drawFPSCounter()
|
||||||
{
|
{
|
||||||
static SDL_Rect overlay = { 0, 0, 64, 32};
|
static SDL_Rect overlay = { 0, 0, 24, 24};
|
||||||
uint32_t black = SDL_MapRGB(screen->format, 10, 10, 10);
|
uint32_t black = SDL_MapRGB(screen->format, 10, 10, 10);
|
||||||
SDL_FillRect(screen, &overlay, black);
|
SDL_FillRect(screen, &overlay, black);
|
||||||
std::string fps = std::to_string(framerate().getFramerate());
|
std::string fps = std::to_string(framerate().getFramerate());
|
||||||
graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, Colors::YELLOW, Point(10, 10));
|
graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, Colors::YELLOW, Point(4, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGuiHandler::amIGuiThread()
|
bool CGuiHandler::amIGuiThread()
|
||||||
|
@ -158,6 +158,8 @@ std::string InterfaceObjectConfigurable::readText(const JsonNode & config) const
|
|||||||
return "";
|
return "";
|
||||||
|
|
||||||
std::string s = config.String();
|
std::string s = config.String();
|
||||||
|
if(s.empty())
|
||||||
|
return s;
|
||||||
logGlobal->debug("Reading text from translations by key: %s", s);
|
logGlobal->debug("Reading text from translations by key: %s", s);
|
||||||
return CGI->generaltexth->translate(s);
|
return CGI->generaltexth->translate(s);
|
||||||
}
|
}
|
||||||
@ -579,8 +581,8 @@ std::shared_ptr<CTextInput> InterfaceObjectConfigurable::buildTextInput(const Js
|
|||||||
result->font = readFont(config["font"]);
|
result->font = readFont(config["font"]);
|
||||||
if(!config["color"].isNull())
|
if(!config["color"].isNull())
|
||||||
result->setColor(readColor(config["color"]));
|
result->setColor(readColor(config["color"]));
|
||||||
if(!config["text"].isNull())
|
if(!config["text"].isNull() && config["text"].isString())
|
||||||
result->setText(readText(config["text"]));
|
result->setText(config["text"].String()); //for input field raw string is taken
|
||||||
if(!config["callback"].isNull())
|
if(!config["callback"].isNull())
|
||||||
result->cb += callbacks_string.at(config["callback"].String());
|
result->cb += callbacks_string.at(config["callback"].String());
|
||||||
if(!config["help"].isNull())
|
if(!config["help"].isNull())
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
[
|
[
|
||||||
{ //backgound color
|
{ //backgound color
|
||||||
"type": "drawRect",
|
"type": "drawRect",
|
||||||
"rect": {"x": 4, "y": 4, "w": 68, "h": 24},
|
"rect": {"x": 4, "y": 4, "w": 72, "h": 24},
|
||||||
"color": [10, 10, 10, 255]
|
"color": [10, 10, 10, 255]
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"alignment": "left",
|
"alignment": "left",
|
||||||
"color": "yellow",
|
"color": "yellow",
|
||||||
"text": "",
|
"text": "",
|
||||||
"position": {"x": 24, "y": 2}
|
"position": {"x": 26, "y": 2}
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -14,12 +14,12 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
bool TurnTimerInfo::isEnabled() const
|
bool TurnTimerInfo::isEnabled() const
|
||||||
{
|
{
|
||||||
return turnTimer > 0;
|
return turnTimer > 0 || baseTimer > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TurnTimerInfo::isBattleEnabled() const
|
bool TurnTimerInfo::isBattleEnabled() const
|
||||||
{
|
{
|
||||||
return creatureTimer > 0;
|
return creatureTimer > 0 || battleTimer > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -19,6 +19,9 @@ struct DLL_LINKAGE TurnTimerInfo
|
|||||||
int battleTimer = 0; //in ms, counts down during battles when creature timer runs out
|
int battleTimer = 0; //in ms, counts down during battles when creature timer runs out
|
||||||
int creatureTimer = 0; //in ms, counts down when player is choosing action in battle
|
int creatureTimer = 0; //in ms, counts down when player is choosing action in battle
|
||||||
|
|
||||||
|
bool isActive = false; //is being counting down
|
||||||
|
bool isBattle = false; //indicator for current timer mode
|
||||||
|
|
||||||
bool isEnabled() const;
|
bool isEnabled() const;
|
||||||
bool isBattleEnabled() const;
|
bool isBattleEnabled() const;
|
||||||
|
|
||||||
@ -29,6 +32,8 @@ struct DLL_LINKAGE TurnTimerInfo
|
|||||||
h & baseTimer;
|
h & baseTimer;
|
||||||
h & battleTimer;
|
h & battleTimer;
|
||||||
h & creatureTimer;
|
h & creatureTimer;
|
||||||
|
h & isActive;
|
||||||
|
h & isBattle;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -999,18 +999,14 @@ void CGameHandler::run(bool resume)
|
|||||||
turnOrder->onGameStarted();
|
turnOrder->onGameStarted();
|
||||||
|
|
||||||
//wait till game is done
|
//wait till game is done
|
||||||
|
auto clockLast = std::chrono::steady_clock::now();
|
||||||
while(lobby->getState() == EServerState::GAMEPLAY)
|
while(lobby->getState() == EServerState::GAMEPLAY)
|
||||||
{
|
{
|
||||||
const int waitTime = 100; //ms
|
const auto clockDuration = std::chrono::steady_clock::now() - clockLast;
|
||||||
|
const int timePassed = std::chrono::duration_cast<std::chrono::milliseconds>(clockDuration).count();
|
||||||
for(PlayerColor player(0); player < PlayerColor::PLAYER_LIMIT; ++player)
|
clockLast += clockDuration;
|
||||||
if(gs->isPlayerMakingTurn(player))
|
turnTimerHandler.update(timePassed);
|
||||||
turnTimerHandler.onPlayerMakingTurn(player, waitTime);
|
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||||
|
|
||||||
if(gs->curB)
|
|
||||||
turnTimerHandler.onBattleLoop(waitTime);
|
|
||||||
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(waitTime));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1182,11 +1178,10 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
for(auto topQuery = queries->topQuery(h->tempOwner); true; topQuery = queries->topQuery(h->tempOwner))
|
for(auto topQuery = queries->topQuery(h->tempOwner); true; topQuery = queries->topQuery(h->tempOwner))
|
||||||
{
|
{
|
||||||
moveQuery = std::dynamic_pointer_cast<CHeroMovementQuery>(topQuery);
|
moveQuery = std::dynamic_pointer_cast<CHeroMovementQuery>(topQuery);
|
||||||
if(moveQuery
|
if(!moveQuery || (transit && result == TryMoveHero::SUCCESS))
|
||||||
&& (!transit || result != TryMoveHero::SUCCESS))
|
|
||||||
queries->popIfTop(moveQuery);
|
|
||||||
else
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
queries->popIfTop(moveQuery);
|
||||||
}
|
}
|
||||||
logGlobal->trace("Hero %s ends movement", h->getNameTranslated());
|
logGlobal->trace("Hero %s ends movement", h->getNameTranslated());
|
||||||
return result != TryMoveHero::FAILED;
|
return result != TryMoveHero::FAILED;
|
||||||
|
@ -28,71 +28,127 @@ TurnTimerHandler::TurnTimerHandler(CGameHandler & gh):
|
|||||||
|
|
||||||
void TurnTimerHandler::onGameplayStart(PlayerColor player)
|
void TurnTimerHandler::onGameplayStart(PlayerColor player)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
if(const auto * si = gameHandler.getStartInfo())
|
if(const auto * si = gameHandler.getStartInfo())
|
||||||
{
|
|
||||||
if(si->turnTimerInfo.isEnabled())
|
|
||||||
{
|
{
|
||||||
timers[player] = si->turnTimerInfo;
|
timers[player] = si->turnTimerInfo;
|
||||||
timers[player].turnTimer = 0;
|
timers[player].turnTimer = 0;
|
||||||
}
|
timers[player].isActive = true;
|
||||||
|
timers[player].isBattle = false;
|
||||||
|
lastUpdate[player] = std::numeric_limits<int>::max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TurnTimerHandler::onPlayerGetTurn(PlayerColor player)
|
void TurnTimerHandler::setTimerEnabled(PlayerColor player, bool enabled)
|
||||||
{
|
{
|
||||||
if(const auto * si = gameHandler.getStartInfo())
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
{
|
assert(player.isValidPlayer());
|
||||||
if(si->turnTimerInfo.isEnabled())
|
timers[player].isActive = enabled;
|
||||||
{
|
sendTimerUpdate(player);
|
||||||
timers[player].baseTimer += timers[player].turnTimer;
|
}
|
||||||
timers[player].turnTimer = si->turnTimerInfo.turnTimer;
|
|
||||||
|
|
||||||
|
void TurnTimerHandler::sendTimerUpdate(PlayerColor player)
|
||||||
|
{
|
||||||
TurnTimeUpdate ttu;
|
TurnTimeUpdate ttu;
|
||||||
ttu.player = player;
|
ttu.player = player;
|
||||||
ttu.turnTimer = timers[player];
|
ttu.turnTimer = timers[player];
|
||||||
gameHandler.sendAndApply(&ttu);
|
gameHandler.sendAndApply(&ttu);
|
||||||
|
lastUpdate[player] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TurnTimerHandler::onPlayerGetTurn(PlayerColor player)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
|
if(const auto * si = gameHandler.getStartInfo())
|
||||||
|
{
|
||||||
|
if(si->turnTimerInfo.isEnabled())
|
||||||
|
{
|
||||||
|
auto & timer = timers[player];
|
||||||
|
if(si->turnTimerInfo.baseTimer > 0)
|
||||||
|
timer.baseTimer += timer.turnTimer;
|
||||||
|
timer.turnTimer = si->turnTimerInfo.turnTimer;
|
||||||
|
|
||||||
|
sendTimerUpdate(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TurnTimerHandler::update(int waitTime)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
|
if(const auto * gs = gameHandler.gameState())
|
||||||
|
{
|
||||||
|
for(PlayerColor player(0); player < PlayerColor::PLAYER_LIMIT; ++player)
|
||||||
|
if(gs->isPlayerMakingTurn(player))
|
||||||
|
onPlayerMakingTurn(player, waitTime);
|
||||||
|
|
||||||
|
if(gs->curB)
|
||||||
|
onBattleLoop(waitTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TurnTimerHandler::timerCountDown(int & timer, int initialTimer, PlayerColor player, int waitTime)
|
||||||
|
{
|
||||||
|
if(timer > 0)
|
||||||
|
{
|
||||||
|
timer -= waitTime;
|
||||||
|
lastUpdate[player] += waitTime;
|
||||||
|
int frequency = (timer > turnTimePropagateThreshold
|
||||||
|
&& initialTimer - timer > turnTimePropagateThreshold)
|
||||||
|
? turnTimePropagateFrequency : turnTimePropagateFrequencyCrit;
|
||||||
|
|
||||||
|
if(lastUpdate[player] >= frequency)
|
||||||
|
sendTimerUpdate(player);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void TurnTimerHandler::onPlayerMakingTurn(PlayerColor player, int waitTime)
|
void TurnTimerHandler::onPlayerMakingTurn(PlayerColor player, int waitTime)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
const auto * gs = gameHandler.gameState();
|
const auto * gs = gameHandler.gameState();
|
||||||
const auto * si = gameHandler.getStartInfo();
|
const auto * si = gameHandler.getStartInfo();
|
||||||
if(!si || !gs)
|
if(!si || !gs || !si->turnTimerInfo.isEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto & state = gs->players.at(player);
|
auto & timer = timers[player];
|
||||||
|
const auto * state = gameHandler.getPlayerState(player);
|
||||||
if(state.human && si->turnTimerInfo.isEnabled() && !gs->curB)
|
if(state && state->human && timer.isActive && !timer.isBattle && state->status == EPlayerStatus::INGAME)
|
||||||
{
|
{
|
||||||
if(timers[player].turnTimer > 0)
|
if(!timerCountDown(timer.turnTimer, si->turnTimerInfo.turnTimer, player, waitTime))
|
||||||
{
|
{
|
||||||
timers[player].turnTimer -= waitTime;
|
if(timer.baseTimer > 0)
|
||||||
int frequency = (timers[player].turnTimer > turnTimePropagateThreshold ? turnTimePropagateFrequency : turnTimePropagateFrequencyCrit);
|
|
||||||
|
|
||||||
if(state.status == EPlayerStatus::INGAME //do not send message if player is not active already
|
|
||||||
&& timers[player].turnTimer % frequency == 0)
|
|
||||||
{
|
{
|
||||||
TurnTimeUpdate ttu;
|
timer.turnTimer = timer.baseTimer;
|
||||||
ttu.player = state.color;
|
timer.baseTimer = 0;
|
||||||
ttu.turnTimer = timers[player];
|
|
||||||
gameHandler.sendAndApply(&ttu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(timers[player].baseTimer > 0)
|
|
||||||
{
|
|
||||||
timers[player].turnTimer = timers[player].baseTimer;
|
|
||||||
timers[player].baseTimer = 0;
|
|
||||||
onPlayerMakingTurn(player, 0);
|
onPlayerMakingTurn(player, 0);
|
||||||
}
|
}
|
||||||
else if(!gameHandler.queries->topQuery(state.color)) //wait for replies to avoid pending queries
|
else if(!gameHandler.queries->topQuery(state->color)) //wait for replies to avoid pending queries
|
||||||
gameHandler.turnOrder->onPlayerEndsTurn(state.color);
|
gameHandler.turnOrder->onPlayerEndsTurn(state->color);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TurnTimerHandler::isPvpBattle() const
|
||||||
|
{
|
||||||
|
const auto * gs = gameHandler.gameState();
|
||||||
|
auto attacker = gs->curB->getSidePlayer(BattleSide::ATTACKER);
|
||||||
|
auto defender = gs->curB->getSidePlayer(BattleSide::DEFENDER);
|
||||||
|
if(attacker.isValidPlayer() && defender.isValidPlayer())
|
||||||
|
{
|
||||||
|
const auto * attackerState = gameHandler.getPlayerState(attacker);
|
||||||
|
const auto * defenderState = gameHandler.getPlayerState(defender);
|
||||||
|
if(attackerState && defenderState && attackerState->human && defenderState->human)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TurnTimerHandler::onBattleStart()
|
void TurnTimerHandler::onBattleStart()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
const auto * gs = gameHandler.gameState();
|
const auto * gs = gameHandler.gameState();
|
||||||
const auto * si = gameHandler.getStartInfo();
|
const auto * si = gameHandler.getStartInfo();
|
||||||
if(!si || !gs || !gs->curB || !si->turnTimerInfo.isBattleEnabled())
|
if(!si || !gs || !gs->curB || !si->turnTimerInfo.isBattleEnabled())
|
||||||
@ -101,95 +157,151 @@ void TurnTimerHandler::onBattleStart()
|
|||||||
auto attacker = gs->curB->getSidePlayer(BattleSide::ATTACKER);
|
auto attacker = gs->curB->getSidePlayer(BattleSide::ATTACKER);
|
||||||
auto defender = gs->curB->getSidePlayer(BattleSide::DEFENDER);
|
auto defender = gs->curB->getSidePlayer(BattleSide::DEFENDER);
|
||||||
|
|
||||||
|
bool pvpBattle = isPvpBattle();
|
||||||
|
|
||||||
for(auto i : {attacker, defender})
|
for(auto i : {attacker, defender})
|
||||||
{
|
{
|
||||||
if(i.isValidPlayer())
|
if(i.isValidPlayer())
|
||||||
{
|
{
|
||||||
timers[i].battleTimer = si->turnTimerInfo.battleTimer;
|
auto & timer = timers[i];
|
||||||
timers[i].creatureTimer = si->turnTimerInfo.creatureTimer;
|
timer.isBattle = true;
|
||||||
|
timer.battleTimer = (pvpBattle ? si->turnTimerInfo.battleTimer : 0);
|
||||||
|
timer.creatureTimer = (pvpBattle ? si->turnTimerInfo.creatureTimer : si->turnTimerInfo.battleTimer);
|
||||||
|
|
||||||
TurnTimeUpdate ttu;
|
sendTimerUpdate(i);
|
||||||
ttu.player = i;
|
}
|
||||||
ttu.turnTimer = timers[i];
|
}
|
||||||
gameHandler.sendAndApply(&ttu);
|
}
|
||||||
|
|
||||||
|
void TurnTimerHandler::onBattleEnd()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
|
const auto * gs = gameHandler.gameState();
|
||||||
|
const auto * si = gameHandler.getStartInfo();
|
||||||
|
if(!si || !gs || !gs->curB || !si->turnTimerInfo.isBattleEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto attacker = gs->curB->getSidePlayer(BattleSide::ATTACKER);
|
||||||
|
auto defender = gs->curB->getSidePlayer(BattleSide::DEFENDER);
|
||||||
|
|
||||||
|
bool pvpBattle = isPvpBattle();
|
||||||
|
|
||||||
|
for(auto i : {attacker, defender})
|
||||||
|
{
|
||||||
|
if(i.isValidPlayer())
|
||||||
|
{
|
||||||
|
auto & timer = timers[i];
|
||||||
|
timer.isBattle = false;
|
||||||
|
|
||||||
|
if(!pvpBattle)
|
||||||
|
{
|
||||||
|
if(si->turnTimerInfo.baseTimer && timer.baseTimer == 0)
|
||||||
|
timer.baseTimer = timer.creatureTimer;
|
||||||
|
else if(si->turnTimerInfo.turnTimer && timer.turnTimer == 0)
|
||||||
|
timer.turnTimer = timer.creatureTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTimerUpdate(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TurnTimerHandler::onBattleNextStack(const CStack & stack)
|
void TurnTimerHandler::onBattleNextStack(const CStack & stack)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
const auto * gs = gameHandler.gameState();
|
const auto * gs = gameHandler.gameState();
|
||||||
const auto * si = gameHandler.getStartInfo();
|
const auto * si = gameHandler.getStartInfo();
|
||||||
if(!si || !gs || !gs->curB || !si->turnTimerInfo.isBattleEnabled())
|
if(!si || !gs || !gs->curB || !si->turnTimerInfo.isBattleEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(isPvpBattle())
|
||||||
|
{
|
||||||
auto player = stack.getOwner();
|
auto player = stack.getOwner();
|
||||||
|
|
||||||
if(!player.isValidPlayer())
|
auto & timer = timers[player];
|
||||||
return;
|
if(timer.battleTimer == 0)
|
||||||
|
timer.battleTimer = timer.creatureTimer;
|
||||||
|
timer.creatureTimer = si->turnTimerInfo.creatureTimer;
|
||||||
|
|
||||||
if(timers[player].battleTimer < si->turnTimerInfo.battleTimer)
|
sendTimerUpdate(player);
|
||||||
timers[player].battleTimer = timers[player].creatureTimer;
|
}
|
||||||
timers[player].creatureTimer = si->turnTimerInfo.creatureTimer;
|
|
||||||
|
|
||||||
TurnTimeUpdate ttu;
|
|
||||||
ttu.player = player;
|
|
||||||
ttu.turnTimer = timers[player];
|
|
||||||
gameHandler.sendAndApply(&ttu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TurnTimerHandler::onBattleLoop(int waitTime)
|
void TurnTimerHandler::onBattleLoop(int waitTime)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mx);
|
||||||
const auto * gs = gameHandler.gameState();
|
const auto * gs = gameHandler.gameState();
|
||||||
const auto * si = gameHandler.getStartInfo();
|
const auto * si = gameHandler.getStartInfo();
|
||||||
if(!si || !gs || !gs->curB)
|
if(!si || !gs || !gs->curB || !si->turnTimerInfo.isBattleEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto * stack = gs->curB.get()->battleGetStackByID(gs->curB->getActiveStackID());
|
ui8 side = 0;
|
||||||
|
const CStack * stack = nullptr;
|
||||||
|
bool isTactisPhase = gs->curB->battleTacticDist() > 0;
|
||||||
|
|
||||||
|
if(isTactisPhase)
|
||||||
|
side = gs->curB->battleGetTacticsSide();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack = gs->curB->battleGetStackByID(gs->curB->getActiveStackID());
|
||||||
if(!stack || !stack->getOwner().isValidPlayer())
|
if(!stack || !stack->getOwner().isValidPlayer())
|
||||||
return;
|
return;
|
||||||
|
side = stack->unitSide();
|
||||||
auto & state = gs->players.at(gs->curB->getSidePlayer(stack->unitSide()));
|
|
||||||
|
|
||||||
auto turnTimerUpdateApplier = [&](TurnTimerInfo & tTimer, int waitTime)
|
|
||||||
{
|
|
||||||
if(tTimer.creatureTimer > 0)
|
|
||||||
{
|
|
||||||
tTimer.creatureTimer -= waitTime;
|
|
||||||
int frequency = (tTimer.creatureTimer > turnTimePropagateThreshold
|
|
||||||
&& si->turnTimerInfo.creatureTimer - tTimer.creatureTimer > turnTimePropagateThreshold)
|
|
||||||
? turnTimePropagateFrequency : turnTimePropagateFrequencyCrit;
|
|
||||||
|
|
||||||
if(state.status == EPlayerStatus::INGAME //do not send message if player is not active already
|
|
||||||
&& tTimer.creatureTimer % frequency == 0)
|
|
||||||
{
|
|
||||||
TurnTimeUpdate ttu;
|
|
||||||
ttu.player = state.color;
|
|
||||||
ttu.turnTimer = tTimer;
|
|
||||||
gameHandler.sendAndApply(&ttu);
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if(state.human && si->turnTimerInfo.isBattleEnabled())
|
auto player = gs->curB->getSidePlayer(side);
|
||||||
|
if(!player.isValidPlayer())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto * state = gameHandler.getPlayerState(player);
|
||||||
|
if(!state || state->status != EPlayerStatus::INGAME || !state->human)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto & timer = timers[player];
|
||||||
|
if(timer.isActive && timer.isBattle && !timerCountDown(timer.creatureTimer, si->turnTimerInfo.creatureTimer, player, waitTime))
|
||||||
{
|
{
|
||||||
if(!turnTimerUpdateApplier(timers[state.color], waitTime))
|
if(isPvpBattle())
|
||||||
{
|
{
|
||||||
if(timers[state.color].battleTimer > 0)
|
if(timer.battleTimer > 0)
|
||||||
{
|
{
|
||||||
timers[state.color].creatureTimer = timers[state.color].battleTimer;
|
timer.creatureTimer = timer.battleTimer;
|
||||||
timers[state.color].battleTimer = 0;
|
timerCountDown(timer.creatureTimer, timer.battleTimer, player, 0);
|
||||||
turnTimerUpdateApplier(timers[state.color], 0);
|
timer.battleTimer = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BattleAction doNothing;
|
BattleAction doNothing;
|
||||||
|
doNothing.side = side;
|
||||||
|
if(isTactisPhase)
|
||||||
|
doNothing.actionType = EActionType::END_TACTIC_PHASE;
|
||||||
|
else
|
||||||
|
{
|
||||||
doNothing.actionType = EActionType::DEFEND;
|
doNothing.actionType = EActionType::DEFEND;
|
||||||
doNothing.side = stack->unitSide();
|
|
||||||
doNothing.stackNumber = stack->unitId();
|
doNothing.stackNumber = stack->unitId();
|
||||||
gameHandler.battles->makePlayerBattleAction(state.color, doNothing);
|
}
|
||||||
|
gameHandler.battles->makePlayerBattleAction(player, doNothing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(timer.turnTimer > 0)
|
||||||
|
{
|
||||||
|
timer.creatureTimer = timer.turnTimer;
|
||||||
|
timerCountDown(timer.creatureTimer, timer.turnTimer, player, 0);
|
||||||
|
timer.turnTimer = 0;
|
||||||
|
}
|
||||||
|
else if(timer.baseTimer > 0)
|
||||||
|
{
|
||||||
|
timer.creatureTimer = timer.baseTimer;
|
||||||
|
timerCountDown(timer.creatureTimer, timer.baseTimer, player, 0);
|
||||||
|
timer.baseTimer = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BattleAction retreat;
|
||||||
|
retreat.side = side;
|
||||||
|
retreat.actionType = EActionType::RETREAT; //harsh punishment
|
||||||
|
gameHandler.battles->makePlayerBattleAction(player, retreat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../lib/TurnTimerInfo.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class CStack;
|
class CStack;
|
||||||
class PlayerColor;
|
class PlayerColor;
|
||||||
struct TurnTimerInfo;
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
@ -27,14 +28,24 @@ class TurnTimerHandler
|
|||||||
const int turnTimePropagateFrequencyCrit = 1000;
|
const int turnTimePropagateFrequencyCrit = 1000;
|
||||||
const int turnTimePropagateThreshold = 3000;
|
const int turnTimePropagateThreshold = 3000;
|
||||||
std::map<PlayerColor, TurnTimerInfo> timers;
|
std::map<PlayerColor, TurnTimerInfo> timers;
|
||||||
|
std::map<PlayerColor, int> lastUpdate;
|
||||||
|
std::recursive_mutex mx;
|
||||||
|
|
||||||
|
void onPlayerMakingTurn(PlayerColor player, int waitTime);
|
||||||
|
void onBattleLoop(int waitTime);
|
||||||
|
|
||||||
|
bool timerCountDown(int & timerToApply, int initialTimer, PlayerColor player, int waitTime);
|
||||||
|
bool isPvpBattle() const;
|
||||||
|
void sendTimerUpdate(PlayerColor player);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TurnTimerHandler(CGameHandler &);
|
TurnTimerHandler(CGameHandler &);
|
||||||
|
|
||||||
void onGameplayStart(PlayerColor player);
|
void onGameplayStart(PlayerColor player);
|
||||||
void onPlayerGetTurn(PlayerColor player);
|
void onPlayerGetTurn(PlayerColor player);
|
||||||
void onPlayerMakingTurn(PlayerColor player, int waitTime);
|
|
||||||
void onBattleStart();
|
void onBattleStart();
|
||||||
void onBattleNextStack(const CStack & stack);
|
void onBattleNextStack(const CStack & stack);
|
||||||
void onBattleLoop(int waitTime);
|
void onBattleEnd();
|
||||||
|
void update(int waitTime);
|
||||||
|
void setTimerEnabled(PlayerColor player, bool enabled);
|
||||||
};
|
};
|
||||||
|
@ -263,6 +263,7 @@ void BattleResultProcessor::endBattle(int3 tile, const CGHeroInstance * heroAtta
|
|||||||
otherBattleQuery->result = battleQuery->result;
|
otherBattleQuery->result = battleQuery->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameHandler->turnTimerHandler.onBattleEnd();
|
||||||
gameHandler->sendAndApply(battleResult.get()); //after this point casualties objects are destroyed
|
gameHandler->sendAndApply(battleResult.get()); //after this point casualties objects are destroyed
|
||||||
|
|
||||||
if (battleResult->queryID == QueryID::NONE)
|
if (battleResult->queryID == QueryID::NONE)
|
||||||
|
@ -28,12 +28,12 @@ bool PlayerStartsTurnQuery::blocksPack(const CPack *pack) const
|
|||||||
|
|
||||||
void PlayerStartsTurnQuery::onAdding(PlayerColor color)
|
void PlayerStartsTurnQuery::onAdding(PlayerColor color)
|
||||||
{
|
{
|
||||||
//gh->turnTimerHandler.setTimerEnabled(color, false);
|
gh->turnTimerHandler.setTimerEnabled(color, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerStartsTurnQuery::onRemoval(PlayerColor color)
|
void PlayerStartsTurnQuery::onRemoval(PlayerColor color)
|
||||||
{
|
{
|
||||||
//gh->turnTimerHandler.setTimerEnabled(color, true);
|
gh->turnTimerHandler.setTimerEnabled(color, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerStartsTurnQuery::endsByPlayerAnswer() const
|
bool PlayerStartsTurnQuery::endsByPlayerAnswer() const
|
||||||
|
Loading…
Reference in New Issue
Block a user