1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Remove ConstTransitivePtr from hero and town instances

This commit is contained in:
Ivan Savenko
2025-03-09 21:51:33 +00:00
parent 62234fcf92
commit 417ea6451a
57 changed files with 436 additions and 390 deletions

View File

@ -308,6 +308,47 @@ void CGHeroInstance::setHeroType(HeroTypeID heroType)
subID = heroType;
}
bool CGHeroInstance::isGarrisoned() const
{
return inTownGarrison;
}
const CGTownInstance * CGHeroInstance::getVisitedTown() const
{
if (!visitedTown.hasValue())
return nullptr;
return cb->getTown(visitedTown);
}
CGTownInstance * CGHeroInstance::getVisitedTown()
{
if (!visitedTown.hasValue())
return nullptr;
return dynamic_cast<CGTownInstance*>(cb->gameState()->getObjInstance(visitedTown));
}
void CGHeroInstance::setVisitedTown(const CGTownInstance * town, bool garrisoned)
{
if (town)
visitedTown = town->id;
else
visitedTown = {};
inTownGarrison = garrisoned;
}
const CCommanderInstance * CGHeroInstance::getCommander() const
{
return commander.get();
}
CCommanderInstance * CGHeroInstance::getCommander()
{
return commander.get();
}
void CGHeroInstance::initObj(vstd::RNG & rand)
{
if (ID == Obj::HERO)
@ -423,7 +464,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
if (cb->getSettings().getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander && getHeroClass()->commander.hasValue())
{
commander = new CCommanderInstance(getHeroClass()->commander);
commander = std::make_unique<CCommanderInstance>(getHeroClass()->commander);
commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
commander->giveStackExp (exp); //after our exp is set
}
@ -504,10 +545,7 @@ void CGHeroInstance::initArmy(vstd::RNG & rand, IArmyDescriptor * dst)
}
}
CGHeroInstance::~CGHeroInstance()
{
commander.dellNull();
}
CGHeroInstance::~CGHeroInstance() = default;
bool CGHeroInstance::needsLastStack() const
{
@ -527,8 +565,8 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
}
else //battle
{
if(visitedTown) //we're in town
visitedTown->onHeroVisit(h); //town will handle attacking
if(getVisitedTown()) //we're in town
getVisitedTown()->onHeroVisit(h); //town will handle attacking
else
cb->startBattle(h, this);
}
@ -1060,7 +1098,7 @@ si32 CGHeroInstance::manaRegain() const
si32 CGHeroInstance::getManaNewTurn() const
{
if(visitedTown && visitedTown->hasBuilt(BuildingID::MAGES_GUILD_1))
if(getVisitedTown() && getVisitedTown()->hasBuilt(BuildingID::MAGES_GUILD_1))
{
//if hero starts turn in town with mage guild - restore all mana
return std::max(mana, manaLimit());
@ -1280,30 +1318,30 @@ void CGHeroInstance::boatDeserializationFix()
CBonusSystemNode * CGHeroInstance::whereShouldBeAttachedOnSiege(const bool isBattleOutsideTown) const
{
if(!visitedTown)
if(!getVisitedTown())
return nullptr;
return isBattleOutsideTown ? (CBonusSystemNode *)(& visitedTown->townAndVis)
: (CBonusSystemNode *)(visitedTown.get());
return isBattleOutsideTown ? (CBonusSystemNode *)(& getVisitedTown()->townAndVis)
: (CBonusSystemNode *)(getVisitedTown());
}
CBonusSystemNode * CGHeroInstance::whereShouldBeAttachedOnSiege(CGameState * gs)
{
if(visitedTown)
return whereShouldBeAttachedOnSiege(visitedTown->isBattleOutsideTown(this));
if(getVisitedTown())
return whereShouldBeAttachedOnSiege(getVisitedTown()->isBattleOutsideTown(this));
return &CArmedInstance::whereShouldBeAttached(gs);
}
CBonusSystemNode & CGHeroInstance::whereShouldBeAttached(CGameState * gs)
{
if(visitedTown)
if(getVisitedTown())
{
if(inTownGarrison)
return *visitedTown;
if(isGarrisoned())
return *getVisitedTown();
else
return visitedTown->townAndVis;
return getVisitedTown()->townAndVis;
}
else
return CArmedInstance::whereShouldBeAttached(gs);

View File

@ -17,7 +17,6 @@
#include "../bonuses/BonusCache.h"
#include "../entities/hero/EHeroGender.h"
#include "../CArtHandler.h" // For CArtifactSet
#include "../ConstTransitivePtr.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -66,12 +65,14 @@ private:
MagicSchoolMasteryCache magicSchoolMastery;
BonusValueCache manaPerKnowledgeCached;
std::unique_ptr<TurnInfoCache> turnInfoCache;
std::unique_ptr<CCommanderInstance> commander;
std::set<SpellID> spells; //known spells (spell IDs)
ObjectInstanceID visitedTown; //set if hero is visiting town or in the town garrison
ui32 movement; //remaining movement points
bool inTownGarrison; // if hero is in town garrison
public:
//////////////////////////////////////////////////////////////////////////
//format: 123
// 8 4
@ -93,9 +94,6 @@ public:
std::string nameCustomTextId;
std::string biographyCustomTextId;
bool inTownGarrison; // if hero is in town garrison
ConstTransitivePtr<CGTownInstance> visitedTown; //set if hero is visiting town or in the town garrison
ConstTransitivePtr<CCommanderInstance> commander;
const CGBoat * boat = nullptr; //set to CGBoat when sailing
static constexpr si32 UNINITIALIZED_MANA = -1;
@ -103,8 +101,6 @@ public:
static constexpr auto UNINITIALIZED_EXPERIENCE = std::numeric_limits<TExpType>::max();
static const ui32 NO_PATROLLING;
//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
std::set<ObjectInstanceID> visitedObjects;
struct DLL_LINKAGE Patrol
@ -252,6 +248,14 @@ public:
HeroTypeID getHeroTypeID() const;
void setHeroType(HeroTypeID type);
bool isGarrisoned() const;
const CGTownInstance * getVisitedTown() const;
CGTownInstance * getVisitedTown();
void setVisitedTown(const CGTownInstance * town, bool garrisoned);
const CCommanderInstance * getCommander() const;
CCommanderInstance * getCommander();
void initObj(vstd::RNG & rand) override;
void initHero(vstd::RNG & rand);
void initHero(vstd::RNG & rand, const HeroTypeID & SUBID);

View File

@ -59,13 +59,13 @@ void CGTownInstance::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
switch (what)
{
case ObjProperty::STRUCTURE_ADD_VISITING_HERO:
rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, visitingHero->id);
rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, getVisitingHero()->id);
break;
case ObjProperty::STRUCTURE_CLEAR_VISITORS:
rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::STRUCTURE_CLEAR_VISITORS, NumericID(0));
break;
case ObjProperty::STRUCTURE_ADD_GARRISONED_HERO: //add garrisoned hero to visitors
rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, garrisonHero->id);
rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, getGarrisonHero()->id);
break;
case ObjProperty::BONUS_VALUE_FIRST:
bonusValue.first = identifier.getNum();
@ -296,7 +296,7 @@ int CGTownInstance::spellsAtLevel(int level, bool checkGuild) const
bool CGTownInstance::needsLastStack() const
{
return garrisonHero != nullptr;
return getGarrisonHero() != nullptr;
}
void CGTownInstance::setOwner(const PlayerColor & player) const
@ -309,13 +309,13 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
{
if(cb->gameState()->getPlayerRelations( getOwner(), h->getOwner() ) == PlayerRelations::ENEMIES)
{
if(armedGarrison() || visitingHero)
if(armedGarrison() || getVisitingHero())
{
const CGHeroInstance * defendingHero = visitingHero ? visitingHero : garrisonHero;
const CGHeroInstance * defendingHero = getVisitingHero() ? getVisitingHero() : getGarrisonHero();
const CArmedInstance * defendingArmy = defendingHero ? (CArmedInstance *)defendingHero : this;
const bool isBattleOutside = isBattleOutsideTown(defendingHero);
if(!isBattleOutside && visitingHero && defendingHero == visitingHero)
if(!isBattleOutside && getVisitingHero() && defendingHero == getVisitingHero())
{
//we have two approaches to merge armies: mergeGarrisonOnSiege() and used in the CGameHandler::garrisonSwap(ObjectInstanceID tid)
auto * nodeSiege = defendingHero->whereShouldBeAttachedOnSiege(isBattleOutside);
@ -323,7 +323,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
if(nodeSiege == (CBonusSystemNode *)this)
cb->swapGarrisonOnSiege(this->id);
const_cast<CGHeroInstance *>(defendingHero)->inTownGarrison = false; //hack to return visitor from garrison after battle
const_cast<CGHeroInstance *>(defendingHero)->setVisitedTown(this, false); //hack to return visitor from garrison after battle
}
cb->startBattle(h, defendingArmy, getSightCenter(), h, defendingHero, BattleLayout::createDefaultLayout(cb, h, defendingArmy), (isBattleOutside ? nullptr : this));
}
@ -343,7 +343,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
else
{
assert(h->visitablePos() == this->visitablePos());
bool commander_recover = h->commander && !h->commander->alive;
bool commander_recover = h->getCommander() && !h->getCommander()->alive;
if (commander_recover) // rise commander from dead
{
SetCommanderProperty scp;
@ -358,8 +358,8 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
{
InfoWindow iw;
iw.player = h->tempOwner;
iw.text.appendRawString(h->commander->getName());
iw.components.emplace_back(ComponentType::CREATURE, h->commander->getId(), h->commander->getCount());
iw.text.appendRawString(h->getCommander()->getName());
iw.components.emplace_back(ComponentType::CREATURE, h->getCommander()->getId(), h->getCommander()->getCount());
cb->showInfoDialog(&iw);
}
}
@ -368,7 +368,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
{
//FIXME: find out why this issue appears on random maps
if(visitingHero == h)
if(getVisitingHero() == h)
{
cb->stopHeroVisitCastle(this, h);
logGlobal->trace("%s correctly left town %s", h->getNameTranslated(), getNameTranslated());
@ -584,13 +584,13 @@ void CGTownInstance::mergeGarrisonOnSiege() const
auto getWeakestStackSlot = [&](ui64 powerLimit)
{
std::vector<SlotID> weakSlots;
auto stacksList = visitingHero->stacks;
auto stacksList = getVisitingHero()->stacks;
std::pair<SlotID, CStackInstance *> pair;
while(!stacksList.empty())
{
pair = *vstd::minElementByFun(stacksList, [&](const std::pair<SlotID, CStackInstance *> & elem) { return elem.second->getPower(); });
if(powerLimit > pair.second->getPower() &&
(weakSlots.empty() || pair.second->getPower() == visitingHero->getStack(weakSlots.front()).getPower()))
(weakSlots.empty() || pair.second->getPower() == getVisitingHero()->getStack(weakSlots.front()).getPower()))
{
weakSlots.push_back(pair.first);
stacksList.erase(pair.first);
@ -612,20 +612,20 @@ void CGTownInstance::mergeGarrisonOnSiege() const
auto pair = *vstd::maxElementByFun(stacks, [&](const std::pair<SlotID, CStackInstance *> & elem)
{
ui64 power = elem.second->getPower();
auto dst = visitingHero->getSlotFor(elem.second->getCreatureID());
if(dst.validSlot() && visitingHero->hasStackAtSlot(dst))
power += visitingHero->getStack(dst).getPower();
auto dst = getVisitingHero()->getSlotFor(elem.second->getCreatureID());
if(dst.validSlot() && getVisitingHero()->hasStackAtSlot(dst))
power += getVisitingHero()->getStack(dst).getPower();
return power;
});
auto dst = visitingHero->getSlotFor(pair.second->getCreatureID());
auto dst = getVisitingHero()->getSlotFor(pair.second->getCreatureID());
if(dst.validSlot())
cb->moveStack(StackLocation(id, pair.first), StackLocation(visitingHero->id, dst), -1);
cb->moveStack(StackLocation(id, pair.first), StackLocation(getVisitingHero()->id, dst), -1);
else
{
dst = getWeakestStackSlot(static_cast<int>(pair.second->getPower()));
if(dst.validSlot())
cb->swapStacks(StackLocation(id, pair.first), StackLocation(visitingHero->id, dst));
cb->swapStacks(StackLocation(id, pair.first), StackLocation(getVisitingHero()->id, dst));
}
}
}
@ -722,10 +722,10 @@ void CGTownInstance::deserializationFix()
//Hero is already handled by CGameState::attachArmedObjects
// if(visitingHero)
// visitingHero->attachTo(&townAndVis);
// if(garrisonHero)
// garrisonHero->attachTo(this);
// if(getVisitingHero())
// getVisitingHero()->attachTo(&townAndVis);
// if(getGarrisonHero())
// getGarrisonHero()->attachTo(this);
}
void CGTownInstance::updateMoraleBonusFromArmy()
@ -737,7 +737,7 @@ void CGTownInstance::updateMoraleBonusFromArmy()
addNewBonus(b);
}
if (garrisonHero)
if (getGarrisonHero())
{
b->val = 0;
nodeHasChanged();
@ -786,7 +786,7 @@ void CGTownInstance::recreateBuildingsBonuses()
void CGTownInstance::setVisitingHero(CGHeroInstance *h)
{
if(visitingHero.get() == h)
if(getVisitingHero() == h)
return;
if(h)
@ -795,23 +795,23 @@ void CGTownInstance::setVisitingHero(CGHeroInstance *h)
assert(p);
h->detachFrom(*p);
h->attachTo(townAndVis);
visitingHero = h;
h->visitedTown = this;
h->inTownGarrison = false;
h->setVisitedTown(this, false);
visitingHero = h->id;
}
else
{
PlayerState *p = cb->gameState()->getPlayerState(visitingHero->tempOwner);
visitingHero->visitedTown = nullptr;
visitingHero->detachFrom(townAndVis);
visitingHero->attachTo(*p);
visitingHero = nullptr;
auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(visitingHero));
PlayerState *p = cb->gameState()->getPlayerState(getVisitingHero()->tempOwner);
oldVisitor->setVisitedTown(nullptr, false);
oldVisitor->detachFrom(townAndVis);
oldVisitor->attachTo(*p);
visitingHero = {};
}
}
void CGTownInstance::setGarrisonedHero(CGHeroInstance *h)
{
if(garrisonHero.get() == h)
if(getGarrisonHero() == h)
return;
if(h)
@ -820,25 +820,40 @@ void CGTownInstance::setGarrisonedHero(CGHeroInstance *h)
assert(p);
h->detachFrom(*p);
h->attachTo(*this);
garrisonHero = h;
h->visitedTown = this;
h->inTownGarrison = true;
h->setVisitedTown(this, true);
garrisonHero = h->id;
}
else
{
PlayerState *p = cb->gameState()->getPlayerState(garrisonHero->tempOwner);
garrisonHero->visitedTown = nullptr;
garrisonHero->inTownGarrison = false;
garrisonHero->detachFrom(*this);
garrisonHero->attachTo(*p);
garrisonHero = nullptr;
PlayerState *p = cb->gameState()->getPlayerState(getGarrisonHero()->tempOwner);
auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(visitingHero));
oldVisitor->setVisitedTown(nullptr, false);
oldVisitor->detachFrom(*this);
oldVisitor->attachTo(*p);
garrisonHero = {};
}
updateMoraleBonusFromArmy(); //avoid giving morale bonus for same army twice
}
const CGHeroInstance * CGTownInstance::getVisitingHero() const
{
if (!visitingHero.hasValue())
return nullptr;
return cb->getHero(visitingHero);
}
const CGHeroInstance * CGTownInstance::getGarrisonHero() const
{
if (!garrisonHero.hasValue())
return nullptr;
return cb->getHero(garrisonHero);
}
bool CGTownInstance::armedGarrison() const
{
return !stacks.empty() || garrisonHero;
return !stacks.empty() || getGarrisonHero();
}
int CGTownInstance::getTownLevel() const
@ -876,8 +891,8 @@ void CGTownInstance::setNameTextId( const std::string & newName )
const CArmedInstance * CGTownInstance::getUpperArmy() const
{
if(garrisonHero)
return garrisonHero;
if(getGarrisonHero())
return getGarrisonHero();
return this;
}
@ -1014,9 +1029,9 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID &
void CGTownInstance::addHeroToStructureVisitors(const CGHeroInstance *h, si64 structureInstanceID ) const
{
if(visitingHero == h)
if(getVisitingHero() == h)
cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_ADD_VISITING_HERO, structureInstanceID); //add to visitors
else if(garrisonHero == h)
else if(getGarrisonHero() == h)
cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_ADD_GARRISONED_HERO, structureInstanceID); //then it must be garrisoned hero
else
{

View File

@ -11,7 +11,6 @@
#include "IMarket.h"
#include "CGDwelling.h"
#include "../ConstTransitivePtr.h"
#include "../entities/faction/CFaction.h" // TODO: remove
#include "../entities/faction/CTown.h" // TODO: remove
@ -57,13 +56,14 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I
std::map<BuildingID, TownRewardableBuildingInstance*> convertOldBuildings(std::vector<TownRewardableBuildingInstance*> oldVector);
std::set<BuildingID> builtBuildings;
ObjectInstanceID garrisonHero;
ObjectInstanceID visitingHero;
public:
enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
CTownAndVisitingHero townAndVis;
si32 built; //how many buildings has been built this turn
si32 destroyed; //how many buildings has been destroyed this turn
ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero;
ui32 identifier; //special identifier from h3m (only > RoE maps)
PlayerColor alignmentToPlayer; // if set to non-neutral, random town will have same faction as specified player
std::set<BuildingID> forbiddenBuildings;
@ -115,6 +115,8 @@ public:
void setVisitingHero(CGHeroInstance *h);
void setGarrisonedHero(CGHeroInstance *h);
const CArmedInstance *getUpperArmy() const; //garrisoned hero if present or the town itself
const CGHeroInstance * getVisitingHero() const;
const CGHeroInstance * getGarrisonHero() const;
std::string getNameTranslated() const;
std::string getNameTextID() const;
@ -211,7 +213,7 @@ public:
inline bool isBattleOutsideTown(const CGHeroInstance * defendingHero) const
{
return defendingHero && garrisonHero && defendingHero != garrisonHero;
return defendingHero && getGarrisonHero() && defendingHero != getGarrisonHero();
}
protected:
void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override;

View File

@ -616,7 +616,7 @@ bool CGWhirlpool::isProtected(const CGHeroInstance * h)
{
return h->hasBonusOfType(BonusType::WHIRLPOOL_PROTECTION)
|| (h->stacksCount() == 1 && h->Slots().begin()->second->count == 1)
|| (h->stacksCount() == 0 && h->commander && h->commander->alive);
|| (h->stacksCount() == 0 && h->getCommander() && h->getCommander()->alive);
}
ArtifactID CGArtifact::getArtifact() const