Просмотр исходного кода

Moved most of daily income handling to a separate method

Ivan Savenko 1 год назад
Родитель
Сommit
189cb1c762

+ 0 - 14
lib/mapObjects/CGTownInstance.cpp

@@ -478,20 +478,6 @@ void CGTownInstance::newTurn(vstd::RNG & rand) const
 {
 	if (cb->getDate(Date::DAY_OF_WEEK) == 1) //reset on new week
 	{
-		//give resources if there's a Mystic Pond
-		if (hasBuilt(BuildingSubID::MYSTIC_POND)
-			&& cb->getDate(Date::DAY) != 1
-			&& (tempOwner.isValidPlayer())
-			)
-		{
-			int resID = rand.nextInt(2, 5); //bonus to random rare resource
-			resID = (resID==2)?1:resID;
-			int resVal = rand.nextInt(1, 4);//with size 1..4
-			cb->giveResource(tempOwner, static_cast<EGameResID>(resID), resVal);
-			cb->setObjPropertyValue(id, ObjProperty::BONUS_VALUE_FIRST, resID);
-			cb->setObjPropertyValue(id, ObjProperty::BONUS_VALUE_SECOND, resVal);
-		}
-
 		if (tempOwner == PlayerColor::NEUTRAL) //garrison growth for neutral towns
 		{
 			std::vector<SlotID> nativeCrits; //slots

+ 3 - 4
lib/networkPacks/NetPacksLib.cpp

@@ -1916,11 +1916,10 @@ void NewTurn::applyGs(CGameState *gs)
 
 	gs->heroesPool->onNewDay();
 
-	for(const auto & re : res)
+	for(const auto & entry : playerIncome)
 	{
-		assert(re.first.isValidPlayer());
-		gs->getPlayerState(re.first)->resources = re.second;
-		gs->getPlayerState(re.first)->resources.amin(GameConstants::PLAYER_RESOURCES_CAP);
+		gs->getPlayerState(entry.first)->resources += entry.second;
+		gs->getPlayerState(entry.first)->resources.amin(GameConstants::PLAYER_RESOURCES_CAP);
 	}
 
 	for(auto & creatureSet : cres) //set available creatures in towns

+ 2 - 2
lib/networkPacks/PacksForClient.h

@@ -1136,8 +1136,8 @@ struct DLL_LINKAGE NewTurn : public CPackForClient
 	};
 
 	std::set<Hero> heroes; //updates movement and mana points
-	std::map<PlayerColor, ResourceSet> res; //player ID => resource value[res_id]
 	std::map<ObjectInstanceID, SetAvailableCreatures> cres;//creatures to be placed in towns
+	std::map<PlayerColor, ResourceSet> playerIncome; //player ID => resource value[res_id]
 	ui32 day = 0;
 	ui8 specialWeek = 0; //weekType
 	CreatureID creatureid; //for creature weeks
@@ -1149,7 +1149,7 @@ struct DLL_LINKAGE NewTurn : public CPackForClient
 	{
 		h & heroes;
 		h & cres;
-		h & res;
+		h & playerIncome;
 		h & day;
 		h & specialWeek;
 		h & creatureid;

+ 8 - 103
server/CGameHandler.cpp

@@ -16,6 +16,7 @@
 #include "ServerSpellCastEnvironment.h"
 #include "battles/BattleProcessor.h"
 #include "processors/HeroPoolProcessor.h"
+#include "processors/NewTurnProcessor.h"
 #include "processors/PlayerMessageProcessor.h"
 #include "processors/TurnOrderProcessor.h"
 #include "queries/QueriesProcessor.h"
@@ -489,6 +490,7 @@ CGameHandler::CGameHandler(CVCMIServer * lobby)
 	, complainNotEnoughCreatures("Cannot split that stack, not enough creatures!")
 	, complainInvalidSlot("Invalid slot accessed!")
 	, turnTimerHandler(std::make_unique<TurnTimerHandler>(*this))
+	, newTurnProcessor(std::make_unique<NewTurnProcessor>(this))
 {
 	QID = 1;
 
@@ -582,54 +584,12 @@ void CGameHandler::onPlayerTurnStarted(PlayerColor which)
 {
 	events::PlayerGotTurn::defaultExecute(serverEventBus.get(), which);
 	turnTimerHandler->onPlayerGetTurn(which);
-
-	const auto * playerState = gs->getPlayerState(which);
-
-	handleTimeEvents(which);
-	for (auto t : playerState->towns)
-		handleTownEvents(t);
-
-	for (auto t : playerState->towns)
-	{
-		//garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
-		if (t->garrisonHero != nullptr)
-			objectVisited(t, t->garrisonHero);
-
-		if (t->visitingHero != nullptr)
-			objectVisited(t, t->visitingHero);
-	}
+	newTurnProcessor->onPlayerTurnStarted(which);
 }
 
 void CGameHandler::onPlayerTurnEnded(PlayerColor which)
 {
-	const auto * playerState = gs->getPlayerState(which);
-	assert(playerState->status == EPlayerStatus::INGAME);
-
-	if (playerState->towns.empty())
-	{
-		DaysWithoutTown pack;
-		pack.player = which;
-		pack.daysWithoutCastle = playerState->daysWithoutCastle.value_or(0) + 1;
-		sendAndApply(&pack);
-	}
-	else
-	{
-		if (playerState->daysWithoutCastle.has_value())
-		{
-			DaysWithoutTown pack;
-			pack.player = which;
-			pack.daysWithoutCastle = std::nullopt;
-			sendAndApply(&pack);
-		}
-	}
-
-	// check for 7 days without castle
-	checkVictoryLossConditionsForPlayer(which);
-
-	bool newWeek = getDate(Date::DAY_OF_WEEK) == 7; // end of 7th day
-
-	if (newWeek) //new heroes in tavern
-		heroPool->onNewWeek(which);
+	newTurnProcessor->onPlayerTurnEnded(which);
 }
 
 void CGameHandler::addStatistics(StatisticDataSet &stat) const
@@ -683,6 +643,9 @@ void CGameHandler::onNewTurn()
 			throw std::runtime_error("Invalid player in player state! Player " + std::to_string(player.first.getNum()) + ", map name: " + gs->map->name.toString() + ", map description: " + gs->map->description.toString());
 	}
 
+	for (const auto & player : gs->players)
+		n.playerIncome[player.first] = newTurnProcessor->generatePlayerIncome(player.first, newWeek && !firstTurn);
+
 	if (newWeek && !firstTurn)
 	{
 		n.specialWeek = NewTurn::NORMAL;
@@ -758,49 +721,6 @@ void CGameHandler::onNewTurn()
 		if (firstTurn)
 			heroPool->onNewWeek(elem.first);
 
-		n.res[elem.first] = elem.second.resources;
-
-		if(!firstTurn)
-		{
-			for (GameResID k = GameResID::WOOD; k < GameResID::COUNT; k++)
-			{
-				n.res[elem.first][k] += elem.second.valOfBonuses(BonusType::RESOURCES_CONSTANT_BOOST, BonusSubtypeID(k)) * playerSettings.handicap.percentIncome / 100;
-				n.res[elem.first][k] += elem.second.valOfBonuses(BonusType::RESOURCES_TOWN_MULTIPLYING_BOOST, BonusSubtypeID(k)) * elem.second.towns.size() * playerSettings.handicap.percentIncome / 100;
-			}
-
-			if(newWeek) //weekly crystal generation if 1 or more crystal dragons in any hero army or town garrison
-			{
-				bool hasCrystalGenCreature = false;
-				for(CGHeroInstance * hero : elem.second.heroes)
-				{
-					for(auto stack : hero->stacks)
-					{
-						if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
-						{
-							hasCrystalGenCreature = true;
-							break;
-						}
-					}
-				}
-				if(!hasCrystalGenCreature) //not found in armies, check towns
-				{
-					for(CGTownInstance * town : elem.second.towns)
-					{
-						for(auto stack : town->stacks)
-						{
-							if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
-							{
-								hasCrystalGenCreature = true;
-								break;
-							}
-						}
-					}
-				}
-				if(hasCrystalGenCreature)
-					n.res[elem.first][EGameResID::CRYSTAL] += 3 * playerSettings.handicap.percentIncome / 100;
-			}
-		}
-
 		for (CGHeroInstance *h : (elem).second.heroes)
 		{
 			if (h->visitedTown)
@@ -814,14 +734,6 @@ void CGameHandler::onNewTurn()
 			hth.mana = h->getManaNewTurn();
 
 			n.heroes.insert(hth);
-
-			if (!firstTurn) //not first day
-			{
-				for (GameResID k = GameResID::WOOD; k < GameResID::COUNT; k++)
-				{
-					n.res[elem.first][k] += h->valOfBonuses(BonusType::GENERATE_RESOURCE, BonusSubtypeID(k)) * playerSettings.handicap.percentIncome / 100;
-				}
-			}
 		}
 	}
 	for (CGTownInstance *t : gs->map->towns)
@@ -832,10 +744,6 @@ void CGameHandler::onNewTurn()
 			if (t->hasBuilt(BuildingSubID::PORTAL_OF_SUMMONING))
 				setPortalDwelling(t, true, (n.specialWeek == NewTurn::PLAGUE ? true : false)); //set creatures for Portal of Summoning
 
-			if (!firstTurn)
-				if (t->hasBuilt(BuildingSubID::TREASURY) && player.isValidPlayer())
-						n.res[player][EGameResID::GOLD] += hadGold.at(player)/10; //give 10% of starting gold
-
 			if (!vstd::contains(n.cres, t->id))
 			{
 				n.cres[t->id].tid = t->id;
@@ -874,10 +782,7 @@ void CGameHandler::onNewTurn()
 				}
 			}
 		}
-		if (!firstTurn  &&  player.isValidPlayer())//not the first day and town not neutral
-		{
-			n.res[player] = n.res[player] + t->dailyIncome();
-		}
+
 		if(t->hasBuilt(BuildingID::GRAIL)
 			&& t->town->buildings.at(BuildingID::GRAIL)->height == CBuilding::HEIGHT_SKYSHIP)
 		{

+ 2 - 0
server/CGameHandler.h

@@ -51,6 +51,7 @@ class TurnOrderProcessor;
 class TurnTimerHandler;
 class QueriesProcessor;
 class CObjectVisitQuery;
+class NewTurnProcessor;
 
 class CGameHandler : public IGameCallback, public Environment
 {
@@ -62,6 +63,7 @@ public:
 	std::unique_ptr<QueriesProcessor> queries;
 	std::unique_ptr<TurnOrderProcessor> turnOrder;
 	std::unique_ptr<TurnTimerHandler> turnTimerHandler;
+	std::unique_ptr<NewTurnProcessor> newTurnProcessor;
 	std::unique_ptr<CRandomGenerator> randomNumberGenerator;
 
 	//use enums as parameters, because doMove(sth, true, false, true) is not readable

+ 2 - 0
server/CMakeLists.txt

@@ -12,6 +12,7 @@ set(vcmiservercommon_SRCS
 		queries/QueriesProcessor.cpp
 
 		processors/HeroPoolProcessor.cpp
+		processors/NewTurnProcessor.cpp
 		processors/PlayerMessageProcessor.cpp
 		processors/TurnOrderProcessor.cpp
 
@@ -38,6 +39,7 @@ set(vcmiservercommon_HEADERS
 		queries/QueriesProcessor.h
 
 		processors/HeroPoolProcessor.h
+		processors/NewTurnProcessor.h
 		processors/PlayerMessageProcessor.h
 		processors/TurnOrderProcessor.h
 

+ 156 - 0
server/processors/NewTurnProcessor.cpp

@@ -0,0 +1,156 @@
+/*
+ * NewTurnProcessor.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "NewTurnProcessor.h"
+
+#include "HeroPoolProcessor.h"
+
+#include "../CGameHandler.h"
+
+#include "../../lib/CPlayerState.h"
+#include "../../lib/GameSettings.h"
+#include "../../lib/StartInfo.h"
+#include "../../lib/TerrainHandler.h"
+#include "../../lib/entities/building/CBuilding.h"
+#include "../../lib/entities/faction/CTownHandler.h"
+#include "../../lib/gameState/CGameState.h"
+#include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
+#include "../../lib/mapping/CMap.h"
+#include "../../lib/networkPacks/PacksForClient.h"
+#include "../../lib/pathfinder/TurnInfo.h"
+
+#include <vstd/RNG.h>
+
+NewTurnProcessor::NewTurnProcessor(CGameHandler * gameHandler)
+	:gameHandler(gameHandler)
+{
+}
+
+void NewTurnProcessor::onPlayerTurnStarted(PlayerColor which)
+{
+	const auto * playerState = gameHandler->gameState()->getPlayerState(which);
+
+	gameHandler->handleTimeEvents(which);
+	for (auto t : playerState->towns)
+		gameHandler->handleTownEvents(t);
+
+	for (auto t : playerState->towns)
+	{
+		//garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
+		if (t->garrisonHero != nullptr)
+			gameHandler->objectVisited(t, t->garrisonHero);
+
+		if (t->visitingHero != nullptr)
+			gameHandler->objectVisited(t, t->visitingHero);
+	}
+}
+
+void NewTurnProcessor::onPlayerTurnEnded(PlayerColor which)
+{
+	const auto * playerState = gameHandler->gameState()->getPlayerState(which);
+	assert(playerState->status == EPlayerStatus::INGAME);
+
+	if (playerState->towns.empty())
+	{
+		DaysWithoutTown pack;
+		pack.player = which;
+		pack.daysWithoutCastle = playerState->daysWithoutCastle.value_or(0) + 1;
+		gameHandler->sendAndApply(&pack);
+	}
+	else
+	{
+		if (playerState->daysWithoutCastle.has_value())
+		{
+			DaysWithoutTown pack;
+			pack.player = which;
+			pack.daysWithoutCastle = std::nullopt;
+			gameHandler->sendAndApply(&pack);
+		}
+	}
+
+	// check for 7 days without castle
+	gameHandler->checkVictoryLossConditionsForPlayer(which);
+
+	bool newWeek = gameHandler->getDate(Date::DAY_OF_WEEK) == 7; // end of 7th day
+
+	if (newWeek) //new heroes in tavern
+		gameHandler->heroPool->onNewWeek(which);
+}
+
+ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool newWeek)
+{
+	const auto & playerSettings = gameHandler->gameState()->scenarioOps->getIthPlayersSettings(playerID);
+	const PlayerState & state = gameHandler->gameState()->players.at(playerID);
+	ResourceSet income;
+
+	for (const auto & hero : state.heroes)
+	{
+		for (GameResID k : GameResID::ALL_RESOURCES())
+			income[k] += hero->valOfBonuses(BonusType::GENERATE_RESOURCE, BonusSubtypeID(k));
+	}
+
+	for (const auto & town : state.towns)
+	{
+		income += town->dailyIncome();
+
+		if (newWeek && town->hasBuilt(BuildingSubID::TREASURY))
+		{
+			//give 10% of starting gold
+			income[EGameResID::GOLD] += state.resources[EGameResID::GOLD] / 10;
+		}
+
+		//give resources if there's a Mystic Pond
+		if (newWeek && town->hasBuilt(BuildingSubID::MYSTIC_POND))
+		{
+			static constexpr std::array rareResources = {
+				GameResID::MERCURY,
+				GameResID::SULFUR,
+				GameResID::CRYSTAL,
+				GameResID::GEMS
+			};
+
+			auto resID = *RandomGeneratorUtil::nextItem(rareResources, gameHandler->getRandomGenerator());
+			int resVal = gameHandler->getRandomGenerator().nextInt(1, 4);
+
+			income[resID] += resVal;
+
+			gameHandler->setObjPropertyValue(town->id, ObjProperty::BONUS_VALUE_FIRST, resID);
+			gameHandler->setObjPropertyValue(town->id, ObjProperty::BONUS_VALUE_SECOND, resVal);
+		}
+	}
+
+	for (GameResID k = GameResID::WOOD; k < GameResID::COUNT; k++)
+	{
+		income += state.valOfBonuses(BonusType::RESOURCES_CONSTANT_BOOST, BonusSubtypeID(k));
+		income += state.valOfBonuses(BonusType::RESOURCES_TOWN_MULTIPLYING_BOOST, BonusSubtypeID(k)) * state.towns.size();
+	}
+
+	if(newWeek) //weekly crystal generation if 1 or more crystal dragons in any hero army or town garrison
+	{
+		bool hasCrystalGenCreature = false;
+		for (const auto & hero : state.heroes)
+			for(auto stack : hero->stacks)
+				if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
+					hasCrystalGenCreature = true;
+
+		for(const auto & town : state.towns)
+			for(auto stack : town->stacks)
+				if(stack.second->hasBonusOfType(BonusType::SPECIAL_CRYSTAL_GENERATION))
+					hasCrystalGenCreature = true;
+
+		if(hasCrystalGenCreature)
+			income[EGameResID::CRYSTAL] += 3;
+	}
+
+	TResources incomeHandicapped = income * playerSettings.handicap.percentIncome / 100;
+
+	return incomeHandicapped;
+}

+ 31 - 0
server/processors/NewTurnProcessor.h

@@ -0,0 +1,31 @@
+/*
+ * NewTurnProcessor.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../../lib/constants/EntityIdentifiers.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+class CGTownInstance;
+class ResourceSet;
+VCMI_LIB_NAMESPACE_END
+
+class CGameHandler;
+
+class NewTurnProcessor : boost::noncopyable
+{
+	CGameHandler * gameHandler;
+public:
+	NewTurnProcessor(CGameHandler * gameHandler);
+
+	ResourceSet generatePlayerIncome(PlayerColor playerID, bool newWeek);
+
+	void onPlayerTurnStarted(PlayerColor color);
+	void onPlayerTurnEnded(PlayerColor color);
+};