浏览代码

Battle timer

nordsoft 2 年之前
父节点
当前提交
d26fdaefe4
共有 5 个文件被更改,包括 122 次插入12 次删除
  1. 24 6
      client/adventureMap/TurnTimerWidget.cpp
  2. 1 1
      lib/TurnTimerInfo.cpp
  3. 10 0
      server/CGameHandler.cpp
  4. 81 5
      server/TurnTimerHandler.cpp
  5. 6 0
      server/TurnTimerHandler.h

+ 24 - 6
client/adventureMap/TurnTimerWidget.cpp

@@ -72,17 +72,35 @@ void TurnTimerWidget::setTime(int time)
 
 void TurnTimerWidget::tick(uint32_t msPassed)
 {
-	if(LOCPLINT && LOCPLINT->cb && !LOCPLINT->battleInt)
+	if(LOCPLINT && LOCPLINT->cb)
 	{
 		auto player = LOCPLINT->cb->getCurrentPlayer();
 		auto time = LOCPLINT->cb->getPlayerTurnTime(player);
 		cachedTurnTime -= msPassed;
-		if(time.turnTimer / 1000 != lastTurnTime / 1000)
+		if(cachedTurnTime < 0) cachedTurnTime = 0; //do not go below zero
+		
+		if(LOCPLINT->battleInt)
 		{
-			//do not update timer on this tick
-			lastTurnTime = time.turnTimer;
-			cachedTurnTime = time.turnTimer;
+			if(time.isBattleEnabled())
+			{
+				if(time.creatureTimer / 1000 != lastTurnTime / 1000)
+				{
+					//do not update timer on this tick
+					lastTurnTime = time.creatureTimer;
+					cachedTurnTime = time.creatureTimer;
+				}
+				else setTime(cachedTurnTime);
+			}
+		}
+		else
+		{
+			if(time.turnTimer / 1000 != lastTurnTime / 1000)
+			{
+				//do not update timer on this tick
+				lastTurnTime = time.turnTimer;
+				cachedTurnTime = time.turnTimer;
+			}
+			else setTime(cachedTurnTime);
 		}
-		else setTime(cachedTurnTime);
 	}
 }

+ 1 - 1
lib/TurnTimerInfo.cpp

@@ -19,7 +19,7 @@ bool TurnTimerInfo::isEnabled() const
 
 bool TurnTimerInfo::isBattleEnabled() const
 {
-	return battleTimer > 0;
+	return creatureTimer > 0;
 }
 
 VCMI_LIB_NAMESPACE_END

+ 10 - 0
server/CGameHandler.cpp

@@ -2091,6 +2091,11 @@ void CGameHandler::run(bool resume)
 				while(states.players.at(playerColor).makingTurn && lobby->state == EServerState::GAMEPLAY)
 				{
 					turnTimerHandler.onPlayerMakingTurn(gs->players[playerColor], waitTime);
+					if(gs->curB)
+					{
+						turnTimerHandler.onBattleLoop(gs->players[gs->curB->getSidePlayer(BattleSide::ATTACKER)], waitTime);
+						turnTimerHandler.onBattleLoop(gs->players[gs->curB->getSidePlayer(BattleSide::DEFENDER)], waitTime);
+					}
 					static time_duration p = milliseconds(waitTime);
 					states.cv.timed_wait(lock, p);
 				}
@@ -6085,6 +6090,9 @@ void CGameHandler::runBattle()
 	setBattle(gs->curB);
 	assert(gs->curB);
 	//TODO: pre-tactic stuff, call scripts etc.
+	
+	turnTimerHandler.onBattleStart(gs->players[gs->curB->getSidePlayer(BattleSide::ATTACKER)]);
+	turnTimerHandler.onBattleStart(gs->players[gs->curB->getSidePlayer(BattleSide::DEFENDER)]);
 
 	//Moat should be initialized here, because only here we can use spellcasting
 	if (gs->curB->town && gs->curB->town->fortLevel() >= CGTownInstance::CITADEL)
@@ -6247,6 +6255,8 @@ void CGameHandler::runBattle()
 		const CStack * next = nullptr;
 		while((lobby->state != EServerState::SHUTDOWN) && (next = getNextStack()))
 		{
+			turnTimerHandler.onBattleNextStack(gs->players[next->getOwner()]);
+			
 			BattleUnitsChanged removeGhosts;
 			for(auto stack : curB.stacks)
 			{

+ 81 - 5
server/TurnTimerHandler.cpp

@@ -10,8 +10,10 @@
 #include "StdInc.h"
 #include "TurnTimerHandler.h"
 #include "CGameHandler.h"
-#include "../lib/CPlayerState.h"
+#include "../lib/battle/BattleInfo.h"
 #include "../lib/gameState/CGameState.h"
+#include "../lib/CPlayerState.h"
+#include "../lib/CStack.h"
 #include "../lib/StartInfo.h"
 
 TurnTimerHandler::TurnTimerHandler(CGameHandler & gh):
@@ -30,7 +32,7 @@ void TurnTimerHandler::onGameplayStart(PlayerState & state)
 			ttu.player = state.color;
 			ttu.turnTimer = si->turnTimerInfo;
 			ttu.turnTimer.turnTimer = 0;
-			gameHandler.applyAndSend(&ttu);
+			gameHandler.sendAndApply(&ttu);
 		}
 	}
 }
@@ -47,7 +49,7 @@ void TurnTimerHandler::onPlayerGetTurn(PlayerState & state)
 			TurnTimeUpdate ttu;
 			ttu.player = state.color;
 			ttu.turnTimer = state.turnTimer;
-			gameHandler.applyAndSend(&ttu);
+			gameHandler.sendAndApply(&ttu);
 		}
 	}
 }
@@ -64,14 +66,15 @@ void TurnTimerHandler::onPlayerMakingTurn(PlayerState & state, int waitTime)
 		if(state.turnTimer.turnTimer > 0)
 		{
 			state.turnTimer.turnTimer -= waitTime;
+			int frequency = (state.turnTimer.creatureTimer > turnTimePropagateThreshold ? turnTimePropagateFrequency : turnTimePropagateFrequencyCrit);
 			
 			if(state.status == EPlayerStatus::INGAME //do not send message if player is not active already
-			   && state.turnTimer.turnTimer % turnTimePropagateFrequency == 0)
+			   && state.turnTimer.turnTimer % frequency == 0)
 			{
 				TurnTimeUpdate ttu;
 				ttu.player = state.color;
 				ttu.turnTimer = state.turnTimer;
-				gameHandler.applyAndSend(&ttu);
+				gameHandler.sendAndApply(&ttu);
 			}
 		}
 		else if(state.turnTimer.baseTimer > 0)
@@ -84,3 +87,76 @@ void TurnTimerHandler::onPlayerMakingTurn(PlayerState & state, int waitTime)
 			gameHandler.states.players.at(state.color).makingTurn = false; //force end turn
 	}
 }
+
+void TurnTimerHandler::onBattleStart(PlayerState & state)
+{
+	if(const auto * si = gameHandler.getStartInfo())
+	{
+		if(si->turnTimerInfo.isBattleEnabled())
+		{
+			TurnTimeUpdate ttu;
+			ttu.player = state.color;
+			ttu.turnTimer = state.turnTimer;
+			ttu.turnTimer.battleTimer = si->turnTimerInfo.battleTimer;
+			ttu.turnTimer.creatureTimer = si->turnTimerInfo.creatureTimer;
+			gameHandler.sendAndApply(&ttu);
+		}
+	}
+}
+
+void TurnTimerHandler::onBattleNextStack(PlayerState & state)
+{
+	if(const auto * si = gameHandler.getStartInfo())
+	{
+		if(si->turnTimerInfo.isBattleEnabled())
+		{
+			TurnTimeUpdate ttu;
+			ttu.player = state.color;
+			ttu.turnTimer = state.turnTimer;
+			if(state.turnTimer.battleTimer < si->turnTimerInfo.battleTimer)
+				ttu.turnTimer.battleTimer = ttu.turnTimer.creatureTimer;
+			ttu.turnTimer.creatureTimer = si->turnTimerInfo.creatureTimer;
+			gameHandler.sendAndApply(&ttu);
+		}
+	}
+}
+
+void TurnTimerHandler::onBattleLoop(PlayerState & state, int waitTime)
+{
+	const auto * gs = gameHandler.gameState();
+	const auto * si = gameHandler.getStartInfo();
+	if(!si || !gs || !gs->curB)
+		return;
+	
+	if(si->turnTimerInfo.isBattleEnabled())
+	{
+		if(state.turnTimer.creatureTimer > 0)
+		{
+			state.turnTimer.creatureTimer -= waitTime;
+			int frequency = (state.turnTimer.creatureTimer > turnTimePropagateThreshold ? turnTimePropagateFrequency : turnTimePropagateFrequencyCrit);
+			
+			if(state.status == EPlayerStatus::INGAME //do not send message if player is not active already
+			   && state.turnTimer.creatureTimer % frequency == 0)
+			{
+				TurnTimeUpdate ttu;
+				ttu.player = state.color;
+				ttu.turnTimer = state.turnTimer;
+				gameHandler.sendAndApply(&ttu);
+			}
+		}
+		else if(state.turnTimer.battleTimer > 0)
+		{
+			state.turnTimer.creatureTimer = state.turnTimer.battleTimer;
+			state.turnTimer.battleTimer = 0;
+			onBattleLoop(state, waitTime);
+		}
+		else if(auto * stack = const_cast<BattleInfo *>(gs->curB.get())->getStack(gs->curB->getActiveStackID()))
+		{
+			BattleAction doNothing;
+			doNothing.actionType = EActionType::DEFEND;
+			doNothing.side = stack->unitSide();
+			doNothing.stackNumber = stack->unitId();
+			gameHandler.makeAutomaticAction(stack, doNothing);
+		}
+	}
+}

+ 6 - 0
server/TurnTimerHandler.h

@@ -12,6 +12,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
+class CStack;
 class PlayerColor;
 struct PlayerState;
 
@@ -23,6 +24,8 @@ class TurnTimerHandler
 {
 	CGameHandler & gameHandler;
 	const int turnTimePropagateFrequency = 5000;
+	const int turnTimePropagateFrequencyCrit = 1000;
+	const int turnTimePropagateThreshold = 3000;
 	
 public:
 	TurnTimerHandler(CGameHandler &);
@@ -30,4 +33,7 @@ public:
 	void onGameplayStart(PlayerState & state);
 	void onPlayerGetTurn(PlayerState & state);
 	void onPlayerMakingTurn(PlayerState & state, int waitTime);
+	void onBattleStart(PlayerState & state);
+	void onBattleNextStack(PlayerState & state);
+	void onBattleLoop(PlayerState & state, int waitTime);
 };