2024-12-24 23:11:20 +00:00
|
|
|
/*
|
|
|
|
* BonusCache.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
|
|
|
|
|
|
|
|
#include "BonusSelector.h"
|
|
|
|
|
2024-12-26 16:58:04 +00:00
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
2024-12-25 21:25:06 +00:00
|
|
|
enum class BonusCacheMode : int8_t
|
2024-12-25 11:40:18 +00:00
|
|
|
{
|
|
|
|
VALUE, // total value of bonus will be cached
|
|
|
|
PRESENCE, // presence of bonus will be cached
|
|
|
|
};
|
|
|
|
|
2024-12-24 23:11:20 +00:00
|
|
|
/// Internal base class with no own cache
|
|
|
|
class BonusCacheBase
|
|
|
|
{
|
2024-12-25 11:40:18 +00:00
|
|
|
protected:
|
2024-12-24 23:11:20 +00:00
|
|
|
const IBonusBearer * target;
|
|
|
|
|
|
|
|
explicit BonusCacheBase(const IBonusBearer * target):
|
|
|
|
target(target)
|
|
|
|
{}
|
|
|
|
|
|
|
|
struct BonusCacheEntry
|
|
|
|
{
|
2025-01-10 23:45:02 +00:00
|
|
|
std::atomic<int32_t> version = 0;
|
|
|
|
std::atomic<int32_t> value = 0;
|
2025-01-08 16:06:31 +00:00
|
|
|
|
|
|
|
BonusCacheEntry() = default;
|
|
|
|
BonusCacheEntry(const BonusCacheEntry & other)
|
|
|
|
: version(other.version.load())
|
|
|
|
, value(other.value.load())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
BonusCacheEntry & operator =(const BonusCacheEntry & other)
|
|
|
|
{
|
|
|
|
version = other.version.load();
|
|
|
|
value = other.value.load();
|
|
|
|
return *this;
|
|
|
|
}
|
2024-12-24 23:11:20 +00:00
|
|
|
};
|
|
|
|
|
2024-12-25 21:25:06 +00:00
|
|
|
int getBonusValueImpl(BonusCacheEntry & currentValue, const CSelector & selector, BonusCacheMode) const;
|
2024-12-24 23:11:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Cache that tracks a single query to bonus system
|
|
|
|
class BonusValueCache : public BonusCacheBase
|
|
|
|
{
|
|
|
|
CSelector selector;
|
|
|
|
mutable BonusCacheEntry value;
|
|
|
|
public:
|
2025-01-05 15:41:42 +00:00
|
|
|
BonusValueCache(const IBonusBearer * target, const CSelector & selector);
|
2024-12-24 23:11:20 +00:00
|
|
|
int getValue() const;
|
2024-12-26 16:57:05 +00:00
|
|
|
bool hasBonus() const;
|
2024-12-24 23:11:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Cache that can track a list of queries to bonus system
|
2024-12-25 23:04:15 +00:00
|
|
|
template<size_t SIZE>
|
2024-12-24 23:11:20 +00:00
|
|
|
class BonusValuesArrayCache : public BonusCacheBase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
using SelectorsArray = std::array<const CSelector, SIZE>;
|
|
|
|
|
|
|
|
BonusValuesArrayCache(const IBonusBearer * target, const SelectorsArray * selectors)
|
|
|
|
: BonusCacheBase(target)
|
|
|
|
, selectors(selectors)
|
|
|
|
{}
|
|
|
|
|
2024-12-25 23:04:15 +00:00
|
|
|
int getBonusValue(int index) const
|
2024-12-24 23:11:20 +00:00
|
|
|
{
|
2024-12-25 21:25:06 +00:00
|
|
|
return getBonusValueImpl(cache[index], (*selectors)[index], BonusCacheMode::VALUE);
|
|
|
|
}
|
|
|
|
|
2024-12-25 23:04:15 +00:00
|
|
|
int hasBonus(int index) const
|
2024-12-25 21:25:06 +00:00
|
|
|
{
|
|
|
|
return getBonusValueImpl(cache[index], (*selectors)[index], BonusCacheMode::PRESENCE);
|
2024-12-24 23:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
using CacheArray = std::array<BonusCacheEntry, SIZE>;
|
|
|
|
|
|
|
|
const SelectorsArray * selectors;
|
|
|
|
mutable CacheArray cache;
|
|
|
|
};
|
|
|
|
|
2024-12-25 23:04:15 +00:00
|
|
|
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,
|
2025-01-10 21:15:37 +00:00
|
|
|
INVINCIBLE,
|
2024-12-25 23:04:15 +00:00
|
|
|
|
2024-12-26 16:57:05 +00:00
|
|
|
CLONE_MARKER,
|
|
|
|
|
2024-12-25 23:04:15 +00:00
|
|
|
TOTAL_KEYS,
|
|
|
|
};
|
|
|
|
static constexpr size_t KEYS_COUNT = static_cast<size_t>(ECacheKeys::TOTAL_KEYS);
|
|
|
|
|
|
|
|
using SelectorsArray = BonusValuesArrayCache<KEYS_COUNT>::SelectorsArray;
|
|
|
|
|
2025-01-05 15:41:42 +00:00
|
|
|
UnitBonusValuesProxy(const IBonusBearer * Target):
|
|
|
|
cache(Target, generateSelectors())
|
2024-12-25 23:04:15 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
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:
|
2025-01-05 15:41:42 +00:00
|
|
|
const SelectorsArray * generateSelectors();
|
|
|
|
|
2024-12-25 23:04:15 +00:00
|
|
|
BonusValuesArrayCache<KEYS_COUNT> cache;
|
|
|
|
};
|
|
|
|
|
2024-12-24 23:11:20 +00:00
|
|
|
/// Cache that tracks values of primary skill values in bonus system
|
|
|
|
class PrimarySkillsCache
|
|
|
|
{
|
|
|
|
const IBonusBearer * target;
|
2025-01-10 23:45:02 +00:00
|
|
|
mutable std::atomic<int32_t> version = 0;
|
2024-12-24 23:11:20 +00:00
|
|
|
mutable std::array<std::atomic<int32_t>, 4> skills;
|
|
|
|
|
|
|
|
void update() const;
|
|
|
|
public:
|
|
|
|
PrimarySkillsCache(const IBonusBearer * target);
|
|
|
|
|
|
|
|
const std::array<std::atomic<int32_t>, 4> & getSkills() const;
|
|
|
|
};
|
2024-12-25 11:40:18 +00:00
|
|
|
|
2024-12-25 23:04:15 +00:00
|
|
|
/// Cache that tracks values of spell school mastery in bonus system
|
|
|
|
class MagicSchoolMasteryCache
|
|
|
|
{
|
|
|
|
const IBonusBearer * target;
|
2025-01-10 23:45:02 +00:00
|
|
|
mutable std::atomic<int32_t> version = 0;
|
2024-12-25 23:04:15 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2024-12-25 11:40:18 +00:00
|
|
|
/// Cache that tracks values for different values of bonus duration
|
|
|
|
class BonusCachePerTurn : public BonusCacheBase
|
|
|
|
{
|
|
|
|
static constexpr int cachedTurns = 8;
|
|
|
|
|
|
|
|
const CSelector selector;
|
|
|
|
mutable TConstBonusListPtr bonusList;
|
|
|
|
mutable std::mutex bonusListMutex;
|
2025-01-10 23:45:02 +00:00
|
|
|
mutable std::atomic<int32_t> bonusListVersion = 0;
|
2024-12-25 11:40:18 +00:00
|
|
|
mutable std::array<BonusCacheEntry, cachedTurns> cache;
|
|
|
|
const BonusCacheMode mode;
|
|
|
|
|
|
|
|
int getValueUncached(int turns) const;
|
|
|
|
public:
|
|
|
|
BonusCachePerTurn(const IBonusBearer * target, const CSelector & selector, BonusCacheMode mode)
|
|
|
|
: BonusCacheBase(target)
|
|
|
|
, selector(selector)
|
|
|
|
, mode(mode)
|
|
|
|
{}
|
|
|
|
|
|
|
|
int getValue(int turns) const;
|
|
|
|
};
|
2024-12-26 16:58:04 +00:00
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|