mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
Added cache for common hero-based bonuses
This commit is contained in:
@@ -528,14 +528,14 @@ bool CUnitState::isCaster() const
|
||||
|
||||
bool CUnitState::canShootBlocked() const
|
||||
{
|
||||
return bonusCache.cache.getBonusValue(UnitBonusValuesProxy::HAS_FREE_SHOOTING);
|
||||
return bonusCache.getBonusValue(UnitBonusValuesProxy::HAS_FREE_SHOOTING);
|
||||
}
|
||||
|
||||
bool CUnitState::canShoot() const
|
||||
{
|
||||
return
|
||||
shots.canUse(1) &&
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::FORGETFULL) <= 1; //advanced+ level
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::FORGETFULL) <= 1; //advanced+ level
|
||||
}
|
||||
|
||||
bool CUnitState::isShooter() const
|
||||
@@ -570,9 +570,9 @@ int64_t CUnitState::getTotalHealth() const
|
||||
return health.total();
|
||||
}
|
||||
|
||||
int64_t CUnitState::getMaxHealth() const
|
||||
uint32_t CUnitState::getMaxHealth() const
|
||||
{
|
||||
return std::max(1, bonusCache.cache.getBonusValue(UnitBonusValuesProxy::STACK_HEALTH));
|
||||
return std::max(1, bonusCache.getBonusValue(UnitBonusValuesProxy::STACK_HEALTH));
|
||||
}
|
||||
|
||||
BattleHex CUnitState::getPosition() const
|
||||
@@ -700,43 +700,43 @@ BattlePhases::Type CUnitState::battleQueuePhase(int turn) const
|
||||
|
||||
bool CUnitState::isHypnotized() const
|
||||
{
|
||||
return bonusCache.cache.getBonusValue(UnitBonusValuesProxy::HYPNOTIZED);
|
||||
return bonusCache.getBonusValue(UnitBonusValuesProxy::HYPNOTIZED);
|
||||
}
|
||||
|
||||
int CUnitState::getTotalAttacks(bool ranged) const
|
||||
{
|
||||
return 1 + (ranged ?
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::TOTAL_ATTACKS_RANGED):
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::TOTAL_ATTACKS_MELEE));
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::TOTAL_ATTACKS_RANGED):
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::TOTAL_ATTACKS_MELEE));
|
||||
}
|
||||
|
||||
int CUnitState::getMinDamage(bool ranged) const
|
||||
{
|
||||
return ranged ?
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MIN_DAMAGE_RANGED):
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MIN_DAMAGE_MELEE);
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::MIN_DAMAGE_RANGED):
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::MIN_DAMAGE_MELEE);
|
||||
|
||||
}
|
||||
|
||||
int CUnitState::getMaxDamage(bool ranged) const
|
||||
{
|
||||
return ranged ?
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MAX_DAMAGE_RANGED):
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MAX_DAMAGE_MELEE);
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::MAX_DAMAGE_RANGED):
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::MAX_DAMAGE_MELEE);
|
||||
}
|
||||
|
||||
int CUnitState::getAttack(bool ranged) const
|
||||
{
|
||||
int attack = ranged ?
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::ATTACK_RANGED):
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::ATTACK_MELEE);
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::ATTACK_RANGED):
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::ATTACK_MELEE);
|
||||
|
||||
int frenzy = bonusCache.cache.getBonusValue(UnitBonusValuesProxy::IN_FRENZY);
|
||||
int frenzy = bonusCache.getBonusValue(UnitBonusValuesProxy::IN_FRENZY);
|
||||
if(frenzy != 0)
|
||||
{
|
||||
int defence = ranged ?
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_RANGED):
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_MELEE);
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::DEFENCE_RANGED):
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::DEFENCE_MELEE);
|
||||
|
||||
int frenzyBonus = frenzy * defence / 100;
|
||||
attack += frenzyBonus;
|
||||
@@ -748,7 +748,7 @@ int CUnitState::getAttack(bool ranged) const
|
||||
|
||||
int CUnitState::getDefense(bool ranged) const
|
||||
{
|
||||
int frenzy = bonusCache.cache.getBonusValue(UnitBonusValuesProxy::IN_FRENZY);
|
||||
int frenzy = bonusCache.getBonusValue(UnitBonusValuesProxy::IN_FRENZY);
|
||||
|
||||
if(frenzy != 0)
|
||||
{
|
||||
@@ -757,8 +757,8 @@ int CUnitState::getDefense(bool ranged) const
|
||||
else
|
||||
{
|
||||
int defence = ranged ?
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_RANGED):
|
||||
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_MELEE);
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::DEFENCE_RANGED):
|
||||
bonusCache.getBonusValue(UnitBonusValuesProxy::DEFENCE_MELEE);
|
||||
vstd::amax(defence, 0);
|
||||
return defence;
|
||||
}
|
||||
|
@@ -125,45 +125,6 @@ private:
|
||||
int32_t resurrected;
|
||||
};
|
||||
|
||||
class UnitBonusValuesProxy
|
||||
{
|
||||
public:
|
||||
enum ECacheKeys : uint8_t
|
||||
{
|
||||
TOTAL_ATTACKS_MELEE,
|
||||
TOTAL_ATTACKS_RANGED,
|
||||
|
||||
MIN_DAMAGE_MELEE,
|
||||
MIN_DAMAGE_RANGED,
|
||||
MAX_DAMAGE_MELEE,
|
||||
MAX_DAMAGE_RANGED,
|
||||
|
||||
ATTACK_MELEE,
|
||||
ATTACK_RANGED,
|
||||
|
||||
DEFENCE_MELEE,
|
||||
DEFENCE_RANGED,
|
||||
|
||||
IN_FRENZY,
|
||||
HYPNOTIZED,
|
||||
FORGETFULL,
|
||||
HAS_FREE_SHOOTING,
|
||||
STACK_HEALTH,
|
||||
|
||||
TOTAL_KEYS,
|
||||
};
|
||||
|
||||
static constexpr size_t KEYS_COUNT = static_cast<size_t>(ECacheKeys::TOTAL_KEYS);
|
||||
|
||||
BonusValuesArrayCache<ECacheKeys, KEYS_COUNT> cache;
|
||||
|
||||
using SelectorsArray = BonusValuesArrayCache<ECacheKeys, KEYS_COUNT>::SelectorsArray;
|
||||
|
||||
UnitBonusValuesProxy(const IBonusBearer * Target, const SelectorsArray * selectors):
|
||||
cache(Target, selectors)
|
||||
{}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CUnitState : public Unit
|
||||
{
|
||||
public:
|
||||
@@ -248,7 +209,7 @@ public:
|
||||
int32_t getFirstHPleft() const override;
|
||||
int64_t getAvailableHealth() const override;
|
||||
int64_t getTotalHealth() const override;
|
||||
int64_t getMaxHealth() const override;
|
||||
uint32_t getMaxHealth() const override;
|
||||
|
||||
BattleHex getPosition() const override;
|
||||
void setPosition(BattleHex hex) override;
|
||||
|
@@ -50,6 +50,35 @@ int BonusValueCache::getValue() const
|
||||
return getBonusValueImpl(value, selector, BonusCacheMode::VALUE);
|
||||
}
|
||||
|
||||
MagicSchoolMasteryCache::MagicSchoolMasteryCache(const IBonusBearer * target)
|
||||
:target(target)
|
||||
{}
|
||||
|
||||
void MagicSchoolMasteryCache::update() const
|
||||
{
|
||||
static const CSelector allBonusesSelector = Selector::type()(BonusType::MAGIC_SCHOOL_SKILL);
|
||||
static const std::array schoolsSelector = {
|
||||
Selector::subtype()(SpellSchool::ANY),
|
||||
Selector::subtype()(SpellSchool::AIR),
|
||||
Selector::subtype()(SpellSchool::FIRE),
|
||||
Selector::subtype()(SpellSchool::WATER),
|
||||
Selector::subtype()(SpellSchool::EARTH),
|
||||
};
|
||||
|
||||
auto list = target->getBonuses(allBonusesSelector);
|
||||
for (int i = 0; i < schoolsSelector.size(); ++i)
|
||||
schools[i] = list->valOfBonuses(schoolsSelector[i]);
|
||||
|
||||
version = target->getTreeVersion();
|
||||
}
|
||||
|
||||
int32_t MagicSchoolMasteryCache::getMastery(const SpellSchool & school) const
|
||||
{
|
||||
if (target->getTreeVersion() != version)
|
||||
update();
|
||||
return schools[school.num + 1];
|
||||
}
|
||||
|
||||
PrimarySkillsCache::PrimarySkillsCache(const IBonusBearer * target)
|
||||
:target(target)
|
||||
{}
|
||||
|
@@ -48,7 +48,7 @@ public:
|
||||
};
|
||||
|
||||
/// Cache that can track a list of queries to bonus system
|
||||
template<typename EnumType, size_t SIZE>
|
||||
template<size_t SIZE>
|
||||
class BonusValuesArrayCache : public BonusCacheBase
|
||||
{
|
||||
public:
|
||||
@@ -59,15 +59,13 @@ public:
|
||||
, selectors(selectors)
|
||||
{}
|
||||
|
||||
int getBonusValue(EnumType which) const
|
||||
int getBonusValue(int index) const
|
||||
{
|
||||
auto index = static_cast<size_t>(which);
|
||||
return getBonusValueImpl(cache[index], (*selectors)[index], BonusCacheMode::VALUE);
|
||||
}
|
||||
|
||||
int hasBonus(EnumType which) const
|
||||
int hasBonus(int index) const
|
||||
{
|
||||
auto index = static_cast<size_t>(which);
|
||||
return getBonusValueImpl(cache[index], (*selectors)[index], BonusCacheMode::PRESENCE);
|
||||
}
|
||||
|
||||
@@ -78,6 +76,57 @@ private:
|
||||
mutable CacheArray cache;
|
||||
};
|
||||
|
||||
class UnitBonusValuesProxy
|
||||
{
|
||||
public:
|
||||
enum ECacheKeys : int8_t
|
||||
{
|
||||
TOTAL_ATTACKS_MELEE,
|
||||
TOTAL_ATTACKS_RANGED,
|
||||
|
||||
MIN_DAMAGE_MELEE,
|
||||
MIN_DAMAGE_RANGED,
|
||||
MAX_DAMAGE_MELEE,
|
||||
MAX_DAMAGE_RANGED,
|
||||
|
||||
ATTACK_MELEE,
|
||||
ATTACK_RANGED,
|
||||
|
||||
DEFENCE_MELEE,
|
||||
DEFENCE_RANGED,
|
||||
|
||||
IN_FRENZY,
|
||||
HYPNOTIZED,
|
||||
FORGETFULL,
|
||||
HAS_FREE_SHOOTING,
|
||||
STACK_HEALTH,
|
||||
|
||||
TOTAL_KEYS,
|
||||
};
|
||||
static constexpr size_t KEYS_COUNT = static_cast<size_t>(ECacheKeys::TOTAL_KEYS);
|
||||
|
||||
using SelectorsArray = BonusValuesArrayCache<KEYS_COUNT>::SelectorsArray;
|
||||
|
||||
UnitBonusValuesProxy(const IBonusBearer * Target, const SelectorsArray * selectors):
|
||||
cache(Target, selectors)
|
||||
{}
|
||||
|
||||
int getBonusValue(ECacheKeys which) const
|
||||
{
|
||||
auto index = static_cast<size_t>(which);
|
||||
return cache.getBonusValue(index);
|
||||
}
|
||||
|
||||
int hasBonus(ECacheKeys which) const
|
||||
{
|
||||
auto index = static_cast<size_t>(which);
|
||||
return cache.hasBonus(index);
|
||||
}
|
||||
|
||||
private:
|
||||
BonusValuesArrayCache<KEYS_COUNT> cache;
|
||||
};
|
||||
|
||||
/// Cache that tracks values of primary skill values in bonus system
|
||||
class PrimarySkillsCache
|
||||
{
|
||||
@@ -92,6 +141,20 @@ public:
|
||||
const std::array<std::atomic<int32_t>, 4> & getSkills() const;
|
||||
};
|
||||
|
||||
/// Cache that tracks values of spell school mastery in bonus system
|
||||
class MagicSchoolMasteryCache
|
||||
{
|
||||
const IBonusBearer * target;
|
||||
mutable std::atomic<int64_t> version = 0;
|
||||
mutable std::array<std::atomic<int32_t>, 4+1> schools;
|
||||
|
||||
void update() const;
|
||||
public:
|
||||
MagicSchoolMasteryCache(const IBonusBearer * target);
|
||||
|
||||
int32_t getMastery(const SpellSchool & school) const;
|
||||
};
|
||||
|
||||
/// Cache that tracks values for different values of bonus duration
|
||||
class BonusCachePerTurn : public BonusCacheBase
|
||||
{
|
||||
|
@@ -294,6 +294,8 @@ CGHeroInstance::CGHeroInstance(IGameCallback * cb)
|
||||
exp(UNINITIALIZED_EXPERIENCE),
|
||||
gender(EHeroGender::DEFAULT),
|
||||
primarySkills(this),
|
||||
magicSchoolMastery(this),
|
||||
manaPerKnowledgeCached(this, Selector::type()(BonusType::MANA_PER_KNOWLEDGE_PERCENTAGE)),
|
||||
lowestCreatureSpeed(0)
|
||||
{
|
||||
setNodeType(HERO);
|
||||
@@ -789,7 +791,7 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, SpellSc
|
||||
|
||||
spell->forEachSchool([&, this](const SpellSchool & cnf, bool & stop)
|
||||
{
|
||||
int32_t thisSchool = valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, BonusSubtypeID(cnf)); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
||||
int32_t thisSchool = magicSchoolMastery.getMastery(cnf); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies)
|
||||
if(thisSchool > skill)
|
||||
{
|
||||
skill = thisSchool;
|
||||
@@ -798,7 +800,7 @@ int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, SpellSc
|
||||
}
|
||||
});
|
||||
|
||||
vstd::amax(skill, valOfBonuses(BonusType::MAGIC_SCHOOL_SKILL, BonusSubtypeID(SpellSchool::ANY))); //any school bonus
|
||||
vstd::amax(skill, magicSchoolMastery.getMastery(SpellSchool::ANY)); //any school bonus
|
||||
vstd::amax(skill, valOfBonuses(BonusType::SPELL, BonusSubtypeID(spell->getId()))); //given by artifact or other effect
|
||||
|
||||
vstd::amax(skill, 0); //in case we don't know any school
|
||||
@@ -1187,8 +1189,7 @@ std::string CGHeroInstance::nodeName() const
|
||||
|
||||
si32 CGHeroInstance::manaLimit() const
|
||||
{
|
||||
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE)
|
||||
* (valOfBonuses(BonusType::MANA_PER_KNOWLEDGE_PERCENTAGE))) / 100;
|
||||
return getPrimSkillLevel(PrimarySkill::KNOWLEDGE) * manaPerKnowledgeCached.getValue() / 100;
|
||||
}
|
||||
|
||||
HeroTypeID CGHeroInstance::getPortraitSource() const
|
||||
|
@@ -60,6 +60,8 @@ class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator,
|
||||
|
||||
private:
|
||||
PrimarySkillsCache primarySkills;
|
||||
MagicSchoolMasteryCache magicSchoolMastery;
|
||||
BonusValueCache manaPerKnowledgeCached;
|
||||
|
||||
std::set<SpellID> spells; //known spells (spell IDs)
|
||||
mutable int lowestCreatureSpeed;
|
||||
|
Reference in New Issue
Block a user