浏览代码

All objects that can be owned by player now implement IOwnableObject

Ivan Savenko 1 年之前
父节点
当前提交
d49a61645c

+ 2 - 24
lib/CGameInfoCallback.cpp

@@ -822,34 +822,12 @@ int3 CPlayerSpecificInfoCallback::getGrailPos( double *outKnownRatio )
 
 std::vector < const CGObjectInstance * > CPlayerSpecificInfoCallback::getMyObjects() const
 {
-	std::vector < const CGObjectInstance * > ret;
-	for(const CGObjectInstance * obj : gs->map->objects)
-	{
-		if(obj && obj->tempOwner == getPlayerID())
-			ret.push_back(obj);
-	}
-	return ret;
-}
-
-std::vector < const CGDwelling * > CPlayerSpecificInfoCallback::getMyDwellings() const
-{
-	ASSERT_IF_CALLED_WITH_PLAYER
-	std::vector < const CGDwelling * > ret;
-	for(const CGDwelling * dw : gs->getPlayerState(*getPlayerID())->getDwellings())
-	{
-		ret.push_back(dw);
-	}
-	return ret;
+	return gs->getPlayerState(*getPlayerID())->getOwnedObjects();
 }
 
 std::vector <QuestInfo> CPlayerSpecificInfoCallback::getMyQuests() const
 {
-	std::vector <QuestInfo> ret;
-	for(const auto & quest : gs->getPlayerState(*getPlayerID())->quests)
-	{
-		ret.push_back (quest);
-	}
-	return ret;
+	return gs->getPlayerState(*getPlayerID())->quests;
 }
 
 int CPlayerSpecificInfoCallback::howManyHeroes(bool includeGarrisoned) const

+ 0 - 1
lib/CGameInfoCallback.h

@@ -247,7 +247,6 @@ public:
 	virtual const CGTownInstance* getTownBySerial(int serialId) const; // serial id is [0, number of towns)
 	virtual const CGHeroInstance* getHeroBySerial(int serialId, bool includeGarrisoned=true) const; // serial id is [0, number of heroes)
 	virtual std::vector <const CGHeroInstance *> getHeroesInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible
-	virtual std::vector <const CGDwelling *> getMyDwellings() const; //returns all dwellings that belong to player
 	virtual std::vector <const CGObjectInstance * > getMyObjects() const; //returns all objects flagged by belonging player
 	virtual std::vector <QuestInfo> getMyQuests() const;
 

+ 1 - 13
lib/CPlayerState.cpp

@@ -93,19 +93,6 @@ int PlayerState::getResourceAmount(int type) const
 	return vstd::atOrDefault(resources, static_cast<size_t>(type), 0);
 }
 
-std::vector<const CGDwelling* > PlayerState::getDwellings() const
-{
-	std::vector<const CGDwelling* > result;
-	for (auto const & object : ownedObjects)
-	{
-		auto dwelling = dynamic_cast<const CGDwelling *>(object);
-		auto town = dynamic_cast<const CGTownInstance *>(object);
-		if (dwelling && !town)
-			result.push_back(dwelling);
-	}
-	return result;
-}
-
 template<typename T>
 std::vector<T> PlayerState::getObjectsOfType() const
 {
@@ -146,6 +133,7 @@ std::vector<const CGObjectInstance *> PlayerState::getOwnedObjects() const
 
 void PlayerState::addOwnedObject(CGObjectInstance * object)
 {
+	assert(object->asOwnable() != nullptr);
 	ownedObjects.push_back(object);
 }
 

+ 0 - 1
lib/CPlayerState.h

@@ -97,7 +97,6 @@ public:
 	std::vector<CGHeroInstance* > getHeroes();
 	std::vector<CGTownInstance* > getTowns();
 
-	std::vector<const CGDwelling* > getDwellings() const;
 	std::vector<const CGObjectInstance* > getOwnedObjects() const;
 
 	void addOwnedObject(CGObjectInstance * object);

+ 11 - 1
lib/gameState/GameStatistics.cpp

@@ -53,7 +53,7 @@ StatisticDataSetEntry StatisticDataSet::createEntry(const PlayerState * ps, cons
 	data.numberHeroes = ps->getHeroes().size();
 	data.numberTowns = gs->howManyTowns(ps->color);
 	data.numberArtifacts = Statistic::getNumberOfArts(ps);
-	data.numberDwellings = gs->getPlayerState(ps->color)->getDwellings().size();
+	data.numberDwellings = Statistic::getNumberOfDwellings(ps);
 	data.armyStrength = Statistic::getArmyStrength(ps, true);
 	data.totalExperience = Statistic::getTotalExperience(ps);
 	data.income = Statistic::getIncome(gs, ps);
@@ -228,6 +228,16 @@ int Statistic::getNumberOfArts(const PlayerState * ps)
 	return ret;
 }
 
+int Statistic::getNumberOfDwellings(const PlayerState * ps)
+{
+	int ret = 0;
+	for(const auto * obj : ps->getOwnedObjects())
+		if (!obj->asOwnable()->providedCreatures().empty())
+			ret	+= 1;
+
+	return ret;
+}
+
 // get total strength of player army
 si64 Statistic::getArmyStrength(const PlayerState * ps, bool withTownGarrison)
 {

+ 1 - 0
lib/gameState/GameStatistics.h

@@ -158,6 +158,7 @@ class DLL_LINKAGE Statistic
 	static std::vector<const CGMine *> getMines(const CGameState * gs, const PlayerState * ps);
 public:
 	static int getNumberOfArts(const PlayerState * ps);
+	static int getNumberOfDwellings(const PlayerState * ps);
 	static si64 getArmyStrength(const PlayerState * ps, bool withTownGarrison = false);
 	static si64 getTotalExperience(const PlayerState * ps);
 	static int getIncome(const CGameState * gs, const PlayerState * ps);

+ 22 - 0
lib/mapObjects/CGDwelling.cpp

@@ -534,4 +534,26 @@ void CGDwelling::serializeJsonOptions(JsonSerializeFormat & handler)
 	}
 }
 
+const IOwnableObject * CGDwelling::asOwnable() const
+{
+	return this;
+}
+
+ResourceSet CGDwelling::dailyIncome() const
+{
+	return {};
+}
+
+std::vector<CreatureID> CGDwelling::providedCreatures() const
+{
+	if (ID == Obj::WAR_MACHINE_FACTORY || ID == Obj::REFUGEE_CAMP)
+		return {};
+
+	std::vector<CreatureID> result;
+	for (const auto & level : creatures)
+		result.insert(result.end(), level.second.begin(), level.second.end());
+
+	return result;
+}
+
 VCMI_LIB_NAMESPACE_END

+ 6 - 1
lib/mapObjects/CGDwelling.h

@@ -11,6 +11,7 @@
 #pragma once
 
 #include "CArmedInstance.h"
+#include "IOwnableObject.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -30,7 +31,7 @@ public:
 	void serializeJson(JsonSerializeFormat & handler);
 };
 
-class DLL_LINKAGE CGDwelling : public CArmedInstance
+class DLL_LINKAGE CGDwelling : public CArmedInstance, public IOwnableObject
 {
 public:
 	using TCreaturesSet = std::vector<std::pair<ui32, std::vector<CreatureID> > >;
@@ -41,6 +42,10 @@ public:
 	CGDwelling(IGameCallback *cb);
 	~CGDwelling() override;
 
+	const IOwnableObject * asOwnable() const final;
+	ResourceSet dailyIncome() const override;
+	std::vector<CreatureID> providedCreatures() const override;
+
 protected:
 	void serializeJsonOptions(JsonSerializeFormat & handler) override;
 

+ 5 - 0
lib/mapObjects/CGHeroInstance.cpp

@@ -1834,6 +1834,11 @@ ResourceSet CGHeroInstance::dailyIncome() const
 	return income;
 }
 
+std::vector<CreatureID> CGHeroInstance::providedCreatures() const
+{
+	return {};
+}
+
 const IOwnableObject * CGHeroInstance::asOwnable() const
 {
 	return this;

+ 1 - 0
lib/mapObjects/CGHeroInstance.h

@@ -167,6 +167,7 @@ public:
 	bool needsLastStack()const override;
 
 	ResourceSet dailyIncome() const override;
+	std::vector<CreatureID> providedCreatures() const override;
 	const IOwnableObject * asOwnable() const final;
 
 	//INativeTerrainProvider

+ 11 - 8
lib/mapObjects/CGTownInstance.cpp

@@ -181,7 +181,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
 	int dwellingBonus = 0;
 	if(const PlayerState *p = cb->getPlayerState(tempOwner, false))
 	{
-		dwellingBonus = getDwellingBonus(creatures[level].second, p->getDwellings());
+		dwellingBonus = getDwellingBonus(creatures[level].second, p->getOwnedObjects());
 	}
 	if(dwellingBonus)
 		ret.entries.emplace_back(VLC->generaltexth->allTexts[591], dwellingBonus); // \nExternal dwellings %+d
@@ -192,15 +192,18 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
 	return ret;
 }
 
-int CGTownInstance::getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<const CGDwelling * >& dwellings) const
+int CGTownInstance::getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<const CGObjectInstance * >& dwellings) const
 {
 	int totalBonus = 0;
 	for (const auto& dwelling : dwellings)
 	{
-		for (const auto& creature : dwelling->creatures)
-		{
-			totalBonus += vstd::contains(creatureIds, creature.second[0]) ? 1 : 0;
-		}
+		const auto & dwellingCreatures = dwelling->asOwnable()->providedCreatures();
+		bool hasMatch = false;
+		for (const auto& creature : dwellingCreatures)
+			hasMatch = vstd::contains(creatureIds, creature);
+
+		if (hasMatch)
+			totalBonus += 1;
 	}
 	return totalBonus;
 }
@@ -230,9 +233,9 @@ TResources CGTownInstance::dailyIncome() const
 	return ret;
 }
 
-const IOwnableObject * CGTownInstance::asOwnable() const
+std::vector<CreatureID> CGTownInstance::providedCreatures() const
 {
-	return this;
+	return {};
 }
 
 bool CGTownInstance::hasFort() const

+ 3 - 4
lib/mapObjects/CGTownInstance.h

@@ -11,7 +11,6 @@
 
 #include "IMarket.h"
 #include "CGDwelling.h"
-#include "IOwnableObject.h"
 #include "../entities/faction/CFaction.h" // TODO: remove
 #include "../entities/faction/CTown.h" // TODO: remove
 
@@ -48,7 +47,7 @@ struct DLL_LINKAGE GrowthInfo
 	int handicapPercentage;
 };
 
-class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider, public ICreatureUpgrader, public IOwnableObject
+class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider, public ICreatureUpgrader
 {
 	std::string nameTextId; // name of town
 
@@ -183,7 +182,7 @@ public:
 
 	TResources getBuildingCost(const BuildingID & buildingID) const;
 	ResourceSet dailyIncome() const override;
-	const IOwnableObject * asOwnable() const final;
+	std::vector<CreatureID> providedCreatures() const override;
 
 	int spellsAtLevel(int level, bool checkGuild) const; //levels are counted from 1 (1 - 5)
 	bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero
@@ -239,7 +238,7 @@ private:
 	FactionID randomizeFaction(vstd::RNG & rand);
 	void setOwner(const PlayerColor & owner) const;
 	void onTownCaptured(const PlayerColor & winner) const;
-	int getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<const CGDwelling* >& dwellings) const;
+	int getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<const CGObjectInstance* >& dwellings) const;
 	bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const;
 	void initializeConfigurableBuildings(vstd::RNG & rand);
 };

+ 8 - 0
lib/mapObjects/IOwnableObject.h

@@ -12,11 +12,19 @@
 VCMI_LIB_NAMESPACE_BEGIN
 
 class ResourceSet;
+class CreatureID;
 
 class DLL_LINKAGE IOwnableObject
 {
 public:
+	/// Fixed daily income of this object
+	/// May not include random or periodical (e.g. weekly) income sources
 	virtual ResourceSet dailyIncome() const = 0;
+
+	/// List of creatures that are provided by this building
+	/// For use in town dwellings growth bonus and for portal of summoning
+	virtual std::vector<CreatureID> providedCreatures() const = 0;
+
 	virtual ~IOwnableObject() = default;
 };
 

+ 35 - 0
lib/mapObjects/MiscObjects.cpp

@@ -132,6 +132,11 @@ const IOwnableObject * CGMine::asOwnable() const
 	return this;
 }
 
+std::vector<CreatureID> CGMine::providedCreatures() const
+{
+	return {};
+}
+
 ResourceSet CGMine::dailyIncome() const
 {
 	ResourceSet result;
@@ -974,6 +979,21 @@ void CGSignBottle::serializeJsonOptions(JsonSerializeFormat& handler)
 	handler.serializeStruct("text", message);
 }
 
+const IOwnableObject * CGGarrison::asOwnable() const
+{
+	return this;
+}
+
+ResourceSet CGGarrison::dailyIncome() const
+{
+	return {};
+}
+
+std::vector<CreatureID> CGGarrison::providedCreatures() const
+{
+	return {};
+}
+
 void CGGarrison::onHeroVisit (const CGHeroInstance *h) const
 {
 	auto relations = cb->gameState()->getPlayerRelations(h->tempOwner, tempOwner);
@@ -1277,6 +1297,21 @@ void CGObelisk::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
 	}
 }
 
+const IOwnableObject * CGLighthouse::asOwnable() const
+{
+	return this;
+}
+
+ResourceSet CGLighthouse::dailyIncome() const
+{
+	return {};
+}
+
+std::vector<CreatureID> CGLighthouse::providedCreatures() const
+{
+	return {};
+}
+
 void CGLighthouse::onHeroVisit( const CGHeroInstance * h ) const
 {
 	if(h->tempOwner != tempOwner)

+ 13 - 3
lib/mapObjects/MiscObjects.h

@@ -60,7 +60,7 @@ protected:
 	void serializeJsonOptions(JsonSerializeFormat & handler) override;
 };
 
-class DLL_LINKAGE CGGarrison : public CArmedInstance
+class DLL_LINKAGE CGGarrison : public CArmedInstance, public IOwnableObject
 {
 public:
 	using CArmedInstance::CArmedInstance;
@@ -72,6 +72,10 @@ public:
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
 
+	const IOwnableObject * asOwnable() const final;
+	ResourceSet dailyIncome() const override;
+	std::vector<CreatureID> providedCreatures() const override;
+
 	template <typename Handler> void serialize(Handler &h)
 	{
 		h & static_cast<CArmedInstance&>(*this);
@@ -80,6 +84,7 @@ public:
 protected:
 	void serializeJsonOptions(JsonSerializeFormat & handler) override;
 	void addAntimagicGarrisonBonus();
+
 };
 
 class DLL_LINKAGE CGArtifact : public CArmedInstance
@@ -180,8 +185,9 @@ public:
 	ui32 defaultResProduction() const;
 	ui32 getProducedQuantity() const;
 
-	ResourceSet dailyIncome() const override;
 	const IOwnableObject * asOwnable() const final;
+	ResourceSet dailyIncome() const override;
+	std::vector<CreatureID> providedCreatures() const override;
 
 protected:
 	void serializeJsonOptions(JsonSerializeFormat & handler) override;
@@ -403,7 +409,7 @@ protected:
 	void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override;
 };
 
-class DLL_LINKAGE CGLighthouse : public CGObjectInstance
+class DLL_LINKAGE CGLighthouse : public CGObjectInstance, public IOwnableObject
 {
 public:
 	using CGObjectInstance::CGObjectInstance;
@@ -411,6 +417,10 @@ public:
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void initObj(vstd::RNG & rand) override;
 
+	const IOwnableObject * asOwnable() const final;
+	ResourceSet dailyIncome() const override;
+	std::vector<CreatureID> providedCreatures() const override;
+
 	template <typename Handler> void serialize(Handler &h)
 	{
 		h & static_cast<CGObjectInstance&>(*this);

+ 1 - 1
lib/networkPacks/NetPacksLib.cpp

@@ -1943,7 +1943,7 @@ void SetObjectProperty::applyGs(CGameState *gs)
 
 	auto * cai = dynamic_cast<CArmedInstance *>(obj);
 
-	if(what == ObjProperty::OWNER)
+	if(what == ObjProperty::OWNER && obj->asOwnable())
 	{
 		PlayerColor oldOwner = obj->getOwner();
 		PlayerColor newOwner = identifier.as<PlayerColor>();

+ 10 - 12
server/CGameHandler.cpp

@@ -555,25 +555,25 @@ void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=fa
 			ssi.creatures = town->creatures;
 			ssi.creatures[town->town->creatures.size()].second.clear();//remove old one
 
-			const auto &dwellings = p->getDwellings();
-			if (dwellings.empty())//no dwellings - just remove
+			std::set<CreatureID> availableCreatures;
+			for (const auto & dwelling : p->getOwnedObjects())
 			{
-				sendAndApply(&ssi);
-				return;
+				const auto & dwellingCreatures = dwelling->asOwnable()->providedCreatures();
+				availableCreatures.insert(dwellingCreatures.begin(), dwellingCreatures.end());
 			}
 
-			auto dwelling = *RandomGeneratorUtil::nextItem(dwellings, getRandomGenerator());
+			if (availableCreatures.empty())
+				return;
 
-			// for multi-creature dwellings like Golem Factory
-			auto creatureId = RandomGeneratorUtil::nextItem(dwelling->creatures, getRandomGenerator())->second[0];
+			CreatureID creatureId = *RandomGeneratorUtil::nextItem(availableCreatures, getRandomGenerator());
 
 			if (clear)
 			{
-				ssi.creatures[town->town->creatures.size()].first = std::max(1, (VLC->creh->objects.at(creatureId)->getGrowth())/2);
+				ssi.creatures[town->town->creatures.size()].first = std::max(1, (creatureId.toEntity(VLC)->getGrowth())/2);
 			}
 			else
 			{
-				ssi.creatures[town->town->creatures.size()].first = VLC->creh->objects.at(creatureId)->getGrowth();
+				ssi.creatures[town->town->creatures.size()].first = creatureId.toEntity(VLC)->getGrowth();
 			}
 			ssi.creatures[town->town->creatures.size()].second.push_back(creatureId);
 			sendAndApply(&ssi);
@@ -1284,9 +1284,7 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, const PlayerColor owne
 		}
 	}
 
-	const PlayerState * p = getPlayerState(owner);
-
-	if ((obj->ID == Obj::CREATURE_GENERATOR1 || obj->ID == Obj::CREATURE_GENERATOR4) && p && p->getDwellings().size()==1)//first dwelling captured
+	if ((obj->ID == Obj::CREATURE_GENERATOR1 || obj->ID == Obj::CREATURE_GENERATOR4))
 	{
 		for (const CGTownInstance * t : getPlayerState(owner)->getTowns())
 		{

+ 1 - 4
server/processors/NewTurnProcessor.cpp

@@ -147,10 +147,7 @@ ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool ne
 	incomeHandicapped.applyHandicap(playerSettings->handicap.percentIncome);
 
 	for (auto obj :	state.getOwnedObjects())
-	{
-		if (obj->asOwnable())
-			incomeHandicapped += obj->asOwnable()->dailyIncome();
-	}
+		incomeHandicapped += obj->asOwnable()->dailyIncome();
 
 	return incomeHandicapped;
 }