1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-20 20:23:03 +02:00

All objects that can be owned by player now implement IOwnableObject

This commit is contained in:
Ivan Savenko 2024-08-25 15:04:44 +00:00
parent a481f07daf
commit d49a61645c
18 changed files with 131 additions and 73 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

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

View File

@ -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

View File

@ -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

View File

@ -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);
};

View File

@ -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;
};

View File

@ -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)

View File

@ -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);

View File

@ -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>();

View File

@ -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())
{

View File

@ -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();
}
return incomeHandicapped;
}