1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-05 00:49:09 +02:00

Initial version of new bonus caching system

This commit is contained in:
Ivan Savenko
2024-12-24 23:11:20 +00:00
parent 873d916a41
commit 16cfb51f3e
12 changed files with 286 additions and 332 deletions

View File

@ -26,7 +26,7 @@ namespace battle
CAmmo::CAmmo(const battle::Unit * Owner, CSelector totalSelector):
used(0),
owner(Owner),
totalProxy(Owner, std::move(totalSelector))
totalProxy(Owner, totalSelector)
{
reset();
}
@ -34,7 +34,6 @@ CAmmo::CAmmo(const battle::Unit * Owner, CSelector totalSelector):
CAmmo & CAmmo::operator= (const CAmmo & other)
{
used = other.used;
totalProxy = other.totalProxy;
return *this;
}
@ -60,7 +59,7 @@ void CAmmo::reset()
int32_t CAmmo::total() const
{
return totalProxy->totalValue();
return totalProxy.getValue();
}
void CAmmo::use(int32_t amount)
@ -89,13 +88,6 @@ CShots::CShots(const battle::Unit * Owner)
{
}
CShots & CShots::operator=(const CShots & other)
{
CAmmo::operator=(other);
shooter = other.shooter;
return *this;
}
bool CShots::isLimited() const
{
return !shooter.getHasBonus() || !env->unitHasAmmoCart(owner);
@ -140,7 +132,7 @@ int32_t CRetaliations::total() const
return 0;
//after dispel bonus should remain during current round
int32_t val = 1 + totalProxy->totalValue();
int32_t val = 1 + totalProxy.getValue();
vstd::amax(totalCache, val);
return totalCache;
}
@ -341,12 +333,7 @@ CUnitState::CUnitState():
counterAttacks(this),
health(this),
shots(this),
totalAttacks(this, Selector::type()(BonusType::ADDITIONAL_ATTACK), 1),
minDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin)), 0),
maxDamage(this, Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMax)), 0),
attack(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::ATTACK)), 0),
defence(this, Selector::typeSubtype(BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::DEFENSE)), 0),
inFrenzy(this, Selector::type()(BonusType::IN_FRENZY)),
bonusCache(this, generateBonusSelectors()),
cloneLifetimeMarker(this, Selector::type()(BonusType::NONE).And(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(SpellID(SpellID::CLONE)))), "CUnitState::cloneLifetimeMarker"),
cloneID(-1)
{
@ -374,12 +361,7 @@ CUnitState & CUnitState::operator=(const CUnitState & other)
counterAttacks = other.counterAttacks;
health = other.health;
shots = other.shots;
totalAttacks = other.totalAttacks;
minDamage = other.minDamage;
maxDamage = other.maxDamage;
attack = other.attack;
defence = other.defence;
inFrenzy = other.inFrenzy;
// bonusCache = other.bonusCache;
cloneLifetimeMarker = other.cloneLifetimeMarker;
cloneID = other.cloneID;
position = other.position;
@ -695,45 +677,62 @@ BattlePhases::Type CUnitState::battleQueuePhase(int turn) const
int CUnitState::getTotalAttacks(bool ranged) const
{
return ranged ? totalAttacks.getRangedValue() : totalAttacks.getMeleeValue();
return 1 + (ranged ?
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::TOTAL_ATTACKS_RANGED):
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::TOTAL_ATTACKS_MELEE));
}
int CUnitState::getMinDamage(bool ranged) const
{
return ranged ? minDamage.getRangedValue() : minDamage.getMeleeValue();
return ranged ?
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MIN_DAMAGE_RANGED):
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MIN_DAMAGE_MELEE);
}
int CUnitState::getMaxDamage(bool ranged) const
{
return ranged ? maxDamage.getRangedValue() : maxDamage.getMeleeValue();
return ranged ?
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MAX_DAMAGE_RANGED):
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::MAX_DAMAGE_MELEE);
}
int CUnitState::getAttack(bool ranged) const
{
int ret = ranged ? attack.getRangedValue() : attack.getMeleeValue();
int attack = ranged ?
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::ATTACK_RANGED):
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::ATTACK_MELEE);
if(!inFrenzy->empty())
int frenzy = bonusCache.cache.getBonusValue(UnitBonusValuesProxy::IN_FRENZY);
if(frenzy != 0)
{
double frenzyPower = static_cast<double>(inFrenzy->totalValue()) / 100;
frenzyPower *= static_cast<double>(ranged ? defence.getRangedValue() : defence.getMeleeValue());
ret += static_cast<int>(frenzyPower);
int defence = ranged ?
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_RANGED):
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_MELEE);
int frenzyBonus = frenzy * defence / 100;
attack += frenzyBonus;
}
vstd::amax(ret, 0);
return ret;
vstd::amax(attack, 0);
return attack;
}
int CUnitState::getDefense(bool ranged) const
{
if(!inFrenzy->empty())
int frenzy = bonusCache.cache.getBonusValue(UnitBonusValuesProxy::IN_FRENZY);
if(frenzy != 0)
{
return 0;
}
else
{
int ret = ranged ? defence.getRangedValue() : defence.getMeleeValue();
vstd::amax(ret, 0);
return ret;
int defence = ranged ?
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_RANGED):
bonusCache.cache.getBonusValue(UnitBonusValuesProxy::DEFENCE_MELEE);
vstd::amax(defence, 0);
return defence;
}
}
@ -911,6 +910,33 @@ void CUnitState::onRemoved()
ghost = true;
}
const UnitBonusValuesProxy::SelectorsArray * CUnitState::generateBonusSelectors()
{
static const CSelector additionalAttack = Selector::type()(BonusType::ADDITIONAL_ATTACK);
static const CSelector selectorMelee = Selector::effectRange()(BonusLimitEffect::NO_LIMIT).Or(Selector::effectRange()(BonusLimitEffect::ONLY_MELEE_FIGHT));
static const CSelector selectorRanged = Selector::effectRange()(BonusLimitEffect::NO_LIMIT).Or(Selector::effectRange()(BonusLimitEffect::ONLY_DISTANCE_FIGHT));
static const CSelector minDamage = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin));
static const CSelector maxDamage = Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageBoth).Or(Selector::typeSubtype(BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin));
static const CSelector attack = Selector::typeSubtype(BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::ATTACK));
static const CSelector defence = Selector::typeSubtype(BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::ATTACK));
static const UnitBonusValuesProxy::SelectorsArray selectors = {
additionalAttack.And(selectorMelee), //TOTAL_ATTACKS_MELEE,
additionalAttack.And(selectorRanged), //TOTAL_ATTACKS_RANGED,
minDamage.And(selectorMelee), //MIN_DAMAGE_MELEE,
minDamage.And(selectorRanged), //MIN_DAMAGE_RANGED,
minDamage.And(selectorMelee), //MAX_DAMAGE_MELEE,
maxDamage.And(selectorRanged), //MAX_DAMAGE_RANGED,
attack.And(selectorRanged),//ATTACK_MELEE,
attack.And(selectorRanged),//ATTACK_RANGED,
defence.And(selectorRanged),//DEFENCE_MELEE,
defence.And(selectorRanged),//DEFENCE_RANGED,
Selector::type()(BonusType::IN_FRENZY),//IN_FRENZY,
};
return &selectors;
}
CUnitStateDetached::CUnitStateDetached(const IUnitInfo * unit_, const IBonusBearer * bonus_):
unit(unit_),
bonus(bonus_)