mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Unified income handling, added IOwnableObject interface
This commit is contained in:
		| @@ -314,9 +314,7 @@ void BuildAnalyzer::updateDailyIncome() | ||||
| 		const CGMine* mine = dynamic_cast<const CGMine*>(obj); | ||||
|  | ||||
| 		if(mine) | ||||
| 		{ | ||||
| 			dailyIncome[mine->producedResource.getNum()] += mine->getProducedQuantity(); | ||||
| 		} | ||||
| 			dailyIncome += mine->dailyIncome(); | ||||
| 	} | ||||
|  | ||||
| 	for(const CGTownInstance* town : towns) | ||||
|   | ||||
| @@ -585,9 +585,7 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan | ||||
| 			const CGMine * mine = dynamic_cast<const CGMine *>(object); | ||||
| 			assert(mine); | ||||
| 			minesCount[mine->producedResource]++; | ||||
|  | ||||
| 			if (mine->producedResource == EGameResID::GOLD) | ||||
| 				totalIncome += mine->getProducedQuantity(); | ||||
| 			totalIncome += mine->dailyIncome()[EGameResID::GOLD]; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -596,7 +594,7 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan | ||||
| 	auto * playerSettings = LOCPLINT->cb->getPlayerSettings(LOCPLINT->playerID); | ||||
| 	for(auto & hero : heroes) | ||||
| 	{ | ||||
| 		totalIncome += hero->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, BonusSubtypeID(GameResID(EGameResID::GOLD)))) * playerSettings->handicap.percentIncome / 100; | ||||
| 		totalIncome += hero->dailyIncome()[EGameResID::GOLD]; | ||||
| 	} | ||||
|  | ||||
| 	//Add town income of all towns | ||||
|   | ||||
| @@ -504,6 +504,7 @@ set(lib_MAIN_HEADERS | ||||
| 	mapObjects/CRewardableObject.h | ||||
| 	mapObjects/IMarket.h | ||||
| 	mapObjects/IObjectInterface.h | ||||
| 	mapObjects/IOwnableObject.h | ||||
| 	mapObjects/MapObjects.h | ||||
| 	mapObjects/MiscObjects.h | ||||
| 	mapObjects/ObjectTemplate.h | ||||
|   | ||||
| @@ -64,6 +64,12 @@ void ResourceSet::positive() | ||||
| 		vstd::amax(elem, 0); | ||||
| } | ||||
|  | ||||
| void ResourceSet::applyHandicap(int percentage) | ||||
| { | ||||
| 	for(auto & elem : *this) | ||||
| 		elem = vstd::divideAndCeil(elem * percentage, 100); | ||||
| } | ||||
|  | ||||
| static bool canAfford(const ResourceSet &res, const ResourceSet &price) | ||||
| { | ||||
| 	assert(res.size() == price.size() && price.size() == GameConstants::RESOURCE_QUANTITY); | ||||
|   | ||||
| @@ -190,6 +190,7 @@ public: | ||||
| 	DLL_LINKAGE void amax(const TResourceCap &val); //performs vstd::amax on each element | ||||
| 	DLL_LINKAGE void amin(const TResourceCap &val); //performs vstd::amin on each element | ||||
| 	DLL_LINKAGE void positive(); //values below 0 are set to 0 - upgrade cost can't be negative, for example | ||||
| 	DLL_LINKAGE void applyHandicap(int percentage); | ||||
| 	DLL_LINKAGE bool nonZero() const; //returns true if at least one value is non-zero; | ||||
| 	DLL_LINKAGE bool canAfford(const ResourceSet &price) const; | ||||
| 	DLL_LINKAGE bool canBeAfforded(const ResourceSet &res) const; | ||||
|   | ||||
| @@ -255,20 +255,18 @@ si64 Statistic::getTotalExperience(const PlayerState * ps) | ||||
| // get total gold income | ||||
| int Statistic::getIncome(const CGameState * gs, const PlayerState * ps) | ||||
| { | ||||
| 	int percentIncome = gs->getStartInfo()->getIthPlayersSettings(ps->color).handicap.percentIncome; | ||||
| 	int totalIncome = 0; | ||||
|  | ||||
| 	//Heroes can produce gold as well - skill, specialty or arts | ||||
| 	for(const auto & h : ps->heroes) | ||||
| 		totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, BonusSubtypeID(GameResID(GameResID::GOLD)))) * percentIncome / 100; | ||||
| 		totalIncome += h->dailyIncome()[EGameResID::GOLD]; | ||||
|  | ||||
| 	//Add town income of all towns | ||||
| 	for(const auto & t : ps->towns) | ||||
| 		totalIncome += t->dailyIncome()[EGameResID::GOLD]; | ||||
|  | ||||
| 	for(const CGMine * mine : getMines(gs, ps)) | ||||
| 		if(mine->producedResource == EGameResID::GOLD) | ||||
| 			totalIncome += mine->getProducedQuantity(); | ||||
| 			totalIncome += mine->dailyIncome()[EGameResID::GOLD]; | ||||
|  | ||||
| 	return totalIncome; | ||||
| } | ||||
|   | ||||
| @@ -1822,4 +1822,22 @@ bool CGHeroInstance::isCampaignGem() const | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| ResourceSet CGHeroInstance::dailyIncome() const | ||||
| { | ||||
| 	ResourceSet income; | ||||
|  | ||||
| 	for (GameResID k : GameResID::ALL_RESOURCES()) | ||||
| 		income[k] += valOfBonuses(BonusType::GENERATE_RESOURCE, BonusSubtypeID(k)); | ||||
|  | ||||
| 	const auto & playerSettings = cb->getPlayerSettings(getOwner()); | ||||
| 	income.applyHandicap(playerSettings->handicap.percentIncome); | ||||
| 	return income; | ||||
| } | ||||
|  | ||||
| const IOwnableObject * CGHeroInstance::asOwnable() const | ||||
| { | ||||
| 	return this; | ||||
| } | ||||
|  | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -12,6 +12,7 @@ | ||||
| #include <vcmi/spells/Caster.h> | ||||
|  | ||||
| #include "CArmedInstance.h" | ||||
| #include "IOwnableObject.h" | ||||
|  | ||||
| #include "../CArtHandler.h" // For CArtifactSet | ||||
|  | ||||
| @@ -48,7 +49,7 @@ protected: | ||||
| }; | ||||
|  | ||||
|  | ||||
| class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet, public spells::Caster, public AFactionMember, public ICreatureUpgrader | ||||
| class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet, public spells::Caster, public AFactionMember, public ICreatureUpgrader, public IOwnableObject | ||||
| { | ||||
| 	// We serialize heroes into JSON for crossover | ||||
| 	friend class CampaignState; | ||||
| @@ -165,6 +166,9 @@ public: | ||||
| 	EAlignment getAlignment() const; | ||||
| 	bool needsLastStack()const override; | ||||
|  | ||||
| 	ResourceSet dailyIncome() const override; | ||||
| 	const IOwnableObject * asOwnable() const final; | ||||
|  | ||||
| 	//INativeTerrainProvider | ||||
| 	FactionID getFaction() const override; | ||||
| 	TerrainId getNativeTerrain() const override; | ||||
|   | ||||
| @@ -395,4 +395,9 @@ BattleField CGObjectInstance::getBattlefield() const | ||||
| 	return VLC->objtypeh->getHandlerFor(ID, subID)->getBattlefield(); | ||||
| } | ||||
|  | ||||
| const IOwnableObject * CGObjectInstance::asOwnable() const | ||||
| { | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -126,6 +126,8 @@ public: | ||||
| 	virtual std::vector<Component> getPopupComponents(PlayerColor player) const; | ||||
| 	virtual std::vector<Component> getPopupComponents(const CGHeroInstance * hero) const; | ||||
|  | ||||
| 	const IOwnableObject * asOwnable() const override; | ||||
|  | ||||
| 	/** OVERRIDES OF IObjectInterface **/ | ||||
|  | ||||
| 	void initObj(vstd::RNG & rand) override; | ||||
|   | ||||
| @@ -225,13 +225,16 @@ TResources CGTownInstance::dailyIncome() const | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	auto playerSettings = cb->gameState()->scenarioOps->getIthPlayersSettings(getOwner()); | ||||
| 	for(TResources::nziterator it(ret); it.valid(); it++) | ||||
| 		// always round up income - we don't want to always produce zero if handicap in use | ||||
| 		ret[it->resType] = vstd::divideAndCeil(ret[it->resType] * playerSettings.handicap.percentIncome, 100); | ||||
| 	const auto & playerSettings = cb->getPlayerSettings(getOwner()); | ||||
| 	ret.applyHandicap(playerSettings->handicap.percentIncome); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| const IOwnableObject * CGTownInstance::asOwnable() const | ||||
| { | ||||
| 	return this; | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::hasFort() const | ||||
| { | ||||
| 	return hasBuilt(BuildingID::FORT); | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
|  | ||||
| #include "IMarket.h" | ||||
| #include "CGDwelling.h" | ||||
| #include "IOwnableObject.h" | ||||
| #include "../entities/faction/CFaction.h" // TODO: remove | ||||
| #include "../entities/faction/CTown.h" // TODO: remove | ||||
|  | ||||
| @@ -47,7 +48,7 @@ struct DLL_LINKAGE GrowthInfo | ||||
| 	int handicapPercentage; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider, public ICreatureUpgrader | ||||
| class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider, public ICreatureUpgrader, public IOwnableObject | ||||
| { | ||||
| 	std::string nameTextId; // name of town | ||||
|  | ||||
| @@ -181,7 +182,9 @@ public: | ||||
| 	std::set<BuildingID> getBuildings() const; | ||||
|  | ||||
| 	TResources getBuildingCost(const BuildingID & buildingID) const; | ||||
| 	TResources dailyIncome() const; //calculates daily income of this town | ||||
| 	ResourceSet dailyIncome() const override; | ||||
| 	const IOwnableObject * asOwnable() const final; | ||||
|  | ||||
| 	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 | ||||
| 	int getTownLevel() const; | ||||
|   | ||||
| @@ -33,6 +33,7 @@ class ResourceSet; | ||||
| class int3; | ||||
| class MetaString; | ||||
| class PlayerColor; | ||||
| class IOwnableObject; | ||||
|  | ||||
| class DLL_LINKAGE IObjectInterface : public GameCallbackHolder, public virtual Serializeable | ||||
| { | ||||
| @@ -68,6 +69,8 @@ public: | ||||
| 	//unified helper to show info dialog for object owner | ||||
| 	virtual void showInfoDialog(const ui32 txtID, const ui16 soundID = 0, EInfoWindowMode mode = EInfoWindowMode::AUTO) const; | ||||
|  | ||||
| 	virtual const IOwnableObject * asOwnable() const = 0; | ||||
|  | ||||
| 	//unified interface, AI helpers | ||||
| 	virtual bool wasVisited (PlayerColor player) const; | ||||
| 	virtual bool wasVisited (const CGHeroInstance * h) const; | ||||
|   | ||||
							
								
								
									
										23
									
								
								lib/mapObjects/IOwnableObject.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/mapObjects/IOwnableObject.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
| * IOwnableObject.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 | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| class ResourceSet; | ||||
|  | ||||
| class DLL_LINKAGE IOwnableObject | ||||
| { | ||||
| public: | ||||
| 	virtual ResourceSet dailyIncome() const = 0; | ||||
| 	virtual ~IOwnableObject() = default; | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
| @@ -93,18 +93,6 @@ void CGMine::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 	} | ||||
|  | ||||
| 	flagMine(h->tempOwner); | ||||
|  | ||||
| } | ||||
|  | ||||
| void CGMine::newTurn(vstd::RNG & rand) const | ||||
| { | ||||
| 	if(cb->getDate() == 1) | ||||
| 		return; | ||||
|  | ||||
| 	if (tempOwner == PlayerColor::NEUTRAL) | ||||
| 		return; | ||||
|  | ||||
| 	cb->giveResource(tempOwner, producedResource, getProducedQuantity()); | ||||
| } | ||||
|  | ||||
| void CGMine::initObj(vstd::RNG & rand) | ||||
| @@ -139,11 +127,19 @@ bool CGMine::isAbandoned() const | ||||
| 	return subID.getNum() >= 7; | ||||
| } | ||||
|  | ||||
| const IOwnableObject * CGMine::asOwnable() const | ||||
| { | ||||
| 	return this; | ||||
| } | ||||
|  | ||||
| ResourceSet CGMine::dailyIncome() const | ||||
| { | ||||
| 	ResourceSet result; | ||||
| 	result[producedResource] += defaultResProduction(); | ||||
|  | ||||
| 	const auto & playerSettings = cb->getPlayerSettings(getOwner()); | ||||
| 	result.applyHandicap(playerSettings->handicap.percentIncome); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CArmedInstance.h" | ||||
| #include "IOwnableObject.h" | ||||
| #include "../texts/MetaString.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
| @@ -148,16 +149,13 @@ protected: | ||||
| 	void serializeJsonOptions(JsonSerializeFormat & handler) override; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CGMine : public CArmedInstance | ||||
| class DLL_LINKAGE CGMine : public CArmedInstance, public IOwnableObject | ||||
| { | ||||
| public: | ||||
| 	GameResID producedResource; | ||||
| 	ui32 producedQuantity; | ||||
| 	std::set<GameResID> abandonedMineResources; | ||||
| 	 | ||||
| 	bool isAbandoned() const; | ||||
| 	ResourceSet dailyIncome() const; | ||||
|  | ||||
| private: | ||||
| 	using CArmedInstance::CArmedInstance; | ||||
|  | ||||
| @@ -166,7 +164,6 @@ private: | ||||
| 	void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override; | ||||
|  | ||||
| 	void flagMine(const PlayerColor & player) const; | ||||
| 	void newTurn(vstd::RNG & rand) const override; | ||||
| 	void initObj(vstd::RNG & rand) override; | ||||
|  | ||||
| 	std::string getObjectName() const override; | ||||
| @@ -183,6 +180,9 @@ public: | ||||
| 	ui32 defaultResProduction() const; | ||||
| 	ui32 getProducedQuantity() const; | ||||
|  | ||||
| 	ResourceSet dailyIncome() const override; | ||||
| 	const IOwnableObject * asOwnable() const final; | ||||
|  | ||||
| protected: | ||||
| 	void serializeJsonOptions(JsonSerializeFormat & handler) override; | ||||
| }; | ||||
|   | ||||
| @@ -50,6 +50,11 @@ MapObjectSubID TownBuildingInstance::getObjTypeIndex() const | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| const IOwnableObject * TownBuildingInstance::asOwnable() const | ||||
| { | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| int3 TownBuildingInstance::visitablePos() const | ||||
| { | ||||
| 	return town->visitablePos(); | ||||
|   | ||||
| @@ -35,6 +35,7 @@ public: | ||||
| 	PlayerColor getOwner() const override; | ||||
| 	MapObjectID getObjGroupIndex() const override; | ||||
| 	MapObjectSubID getObjTypeIndex() const override; | ||||
| 	const IOwnableObject * asOwnable() const override; | ||||
|  | ||||
| 	int3 visitablePos() const override; | ||||
| 	int3 getPosition() const override; | ||||
|   | ||||
| @@ -643,8 +643,11 @@ 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 (!firstTurn) | ||||
| 	{ | ||||
| 		for (const auto & player : gs->players) | ||||
| 			n.playerIncome[player.first] = newTurnProcessor->generatePlayerIncome(player.first, newWeek); | ||||
| 	} | ||||
|  | ||||
| 	if (newWeek && !firstTurn) | ||||
| 	{ | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| #include "../../lib/gameState/CGameState.h" | ||||
| #include "../../lib/mapObjects/CGHeroInstance.h" | ||||
| #include "../../lib/mapObjects/CGTownInstance.h" | ||||
| #include "../../lib/mapObjects/IOwnableObject.h" | ||||
| #include "../../lib/mapping/CMap.h" | ||||
| #include "../../lib/networkPacks/PacksForClient.h" | ||||
| #include "../../lib/pathfinder/TurnInfo.h" | ||||
| @@ -87,20 +88,12 @@ void NewTurnProcessor::onPlayerTurnEnded(PlayerColor which) | ||||
|  | ||||
| ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool newWeek) | ||||
| { | ||||
| 	const auto & playerSettings = gameHandler->gameState()->scenarioOps->getIthPlayersSettings(playerID); | ||||
| 	const auto & playerSettings = gameHandler->getPlayerSettings(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 | ||||
| @@ -150,7 +143,15 @@ ResourceSet NewTurnProcessor::generatePlayerIncome(PlayerColor playerID, bool ne | ||||
| 			income[EGameResID::CRYSTAL] += 3; | ||||
| 	} | ||||
|  | ||||
| 	TResources incomeHandicapped = income * playerSettings.handicap.percentIncome / 100; | ||||
| 	TResources incomeHandicapped = income; | ||||
| 	incomeHandicapped.applyHandicap(playerSettings->handicap.percentIncome); | ||||
|  | ||||
| 	// FIXME: store pre-filtered, all owned objects in PlayerState | ||||
| 	for (auto obj : gameHandler->gameState()->map->objects) | ||||
| 	{ | ||||
| 		if (obj && obj->asOwnable() && obj->getOwner() == playerID) | ||||
| 			incomeHandicapped += obj->asOwnable()->dailyIncome(); | ||||
| 	} | ||||
|  | ||||
| 	return incomeHandicapped; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user