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

Fix: Morale bonus should be shown correctly

This commit is contained in:
Dmitry Orlov 2020-11-11 22:43:40 +03:00
parent 9ca9c809c6
commit 39de2f6435
27 changed files with 281 additions and 196 deletions

3
.gitignore vendored
View File

@ -42,11 +42,14 @@ VCMI_VS11.opensdf
*.suo
*.user
/AI/*/RD
/AI/BattleAI/*/RD
/client/RD
/launcher/RD
/lib/RD
/lib/minizip/RD
/lib/minizip/*/RD
/scripting/erm/RD
/scripting/erm/*/RD
/server/RD
/test/RD
/VCMI_VS11.VC.opendb

View File

@ -66,7 +66,7 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo & attackInf
auto attacker = attackInfo.attacker;
auto defender = attackInfo.defender;
const std::string cachingStringBlocksRetaliation = "type_BLOCKS_RETALIATION";
static const auto selectorBlocksRetaliation = Selector::type(Bonus::BLOCKS_RETALIATION);
static const auto selectorBlocksRetaliation = Selector::type()(Bonus::BLOCKS_RETALIATION);
const auto attackerSide = getCbc()->playerToSide(getCbc()->battleGetOwner(attacker));
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);

View File

@ -52,13 +52,13 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
double shootersStrength = 0;
ui32 maxSpeed = 0;
static const CSelector selectorSHOOTER = Selector::type(Bonus::SHOOTER);
static const CSelector selectorSHOOTER = Selector::type()(Bonus::SHOOTER);
static const std::string keySHOOTER = "type_"+std::to_string((int32_t)Bonus::SHOOTER);
static const CSelector selectorFLYING = Selector::type(Bonus::FLYING);
static const CSelector selectorFLYING = Selector::type()(Bonus::FLYING);
static const std::string keyFLYING = "type_"+std::to_string((int32_t)Bonus::FLYING);
static const CSelector selectorSTACKS_SPEED = Selector::type(Bonus::STACKS_SPEED);
static const CSelector selectorSTACKS_SPEED = Selector::type()(Bonus::STACKS_SPEED);
static const std::string keySTACKS_SPEED = "type_"+std::to_string((int32_t)Bonus::STACKS_SPEED);
for(auto s : army->Slots())

View File

@ -493,7 +493,7 @@ bool CMovementAnimation::init()
distanceX = endPosition.x - begPosition.x;
distanceY = endPosition.y - begPosition.y;
if (stack->hasBonus(Selector::type(Bonus::FLYING)))
if (stack->hasBonus(Selector::type()(Bonus::FLYING)))
{
float distance = static_cast<float>(sqrt(distanceX * distanceX + distanceY * distanceY));

View File

@ -904,7 +904,7 @@ void CBattleInterface::bSpellf()
{
//TODO: move to spell mechanics, add more information to spell cast problem
//Handle Orb of Inhibition-like effects -> we want to display dialog with info, why casting is impossible
auto blockingBonus = currentHero()->getBonusLocalFirst(Selector::type(Bonus::BLOCK_ALL_MAGIC));
auto blockingBonus = currentHero()->getBonusLocalFirst(Selector::type()(Bonus::BLOCK_ALL_MAGIC));
if (!blockingBonus)
return;
@ -1638,8 +1638,8 @@ void CBattleInterface::activateStack()
redrawBackgroundWithHexes(activeStack);
//set casting flag to true if creature can use it to not check it every time
const auto spellcaster = s->getBonusLocalFirst(Selector::type(Bonus::SPELLCASTER)),
randomSpellcaster = s->getBonusLocalFirst(Selector::type(Bonus::RANDOM_SPELLCASTER));
const auto spellcaster = s->getBonusLocalFirst(Selector::type()(Bonus::SPELLCASTER)),
randomSpellcaster = s->getBonusLocalFirst(Selector::type()(Bonus::RANDOM_SPELLCASTER));
if(s->canCast() && (spellcaster || randomSpellcaster))
{
stackCanCastSpell = true;

View File

@ -367,19 +367,11 @@ void MoraleLuckBox::set(const IBonusBearer * node)
const int neutralDescr[] = {60, 86}; //eg {Neutral Morale} \n\n Neutral morale means your armies will neither be blessed with extra attacks or freeze in combat.
const int componentType[] = {CComponent::luck, CComponent::morale};
const int hoverTextBase[] = {7, 4};
const Bonus::BonusType bonusType[] = {Bonus::LUCK, Bonus::MORALE};
int (IBonusBearer::*getValue[])() const = {&IBonusBearer::LuckVal, &IBonusBearer::MoraleVal};
TConstBonusListPtr modifierList(new BonusList());
TConstBonusListPtr modifierList = std::make_shared<const BonusList>();
bonusValue = 0;
if(node)
{
modifierList = node->getBonuses(Selector::type(bonusType[morale]));
bonusValue = (node->*getValue[morale])();
}
else
{
bonusValue = 0;
}
bonusValue = morale ? node->MoraleValAndBonusList(modifierList) : node->LuckValAndBonusList(modifierList);
int mrlt = (bonusValue>0)-(bonusValue<0); //signum: -1 - bad luck / morale, 0 - neutral, 1 - good
hoverText = CGI->generaltexth->heroscrn[hoverTextBase[morale] - mrlt];
@ -402,13 +394,13 @@ void MoraleLuckBox::set(const IBonusBearer * node)
}
else if(morale && node && node->hasBonusOfType(Bonus::NO_MORALE))
{
auto noMorale = node->getBonus(Selector::type(Bonus::NO_MORALE));
auto noMorale = node->getBonus(Selector::type()(Bonus::NO_MORALE));
text += "\n" + noMorale->Description();
bonusValue = 0;
}
else if (!morale && node && node->hasBonusOfType(Bonus::NO_LUCK))
{
auto noLuck = node->getBonus(Selector::type(Bonus::NO_LUCK));
auto noLuck = node->getBonus(Selector::type()(Bonus::NO_LUCK));
text += "\n" + noLuck->Description();
bonusValue = 0;
}

View File

@ -990,7 +990,7 @@ void CArtifactInstance::deserializationFix()
SpellID CArtifactInstance::getGivenSpellID() const
{
const auto b = getBonusLocalFirst(Selector::type(Bonus::SPELL));
const auto b = getBonusLocalFirst(Selector::type()(Bonus::SPELL));
if(!b)
{
logMod->warn("Warning: %s doesn't bear any spell!", nodeName());

View File

@ -595,7 +595,7 @@ int CStackInstance::getLevel() const
si32 CStackInstance::magicResistance() const
{
si32 val = valOfBonuses(Selector::type(Bonus::MAGIC_RESISTANCE));
si32 val = valOfBonuses(Selector::type()(Bonus::MAGIC_RESISTANCE));
if (const CGHeroInstance * hero = dynamic_cast<const CGHeroInstance *>(_armyObj))
{
//resistance skill

View File

@ -1172,9 +1172,9 @@ void CGameState::prepareCrossoverHeroes(std::vector<CGameState::CampaignHeroRepl
{
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
{
auto sel = Selector::type(Bonus::PRIMARY_SKILL)
.And(Selector::subtype(g))
.And(Selector::sourceType(Bonus::HERO_BASE_SKILL));
auto sel = Selector::type()(Bonus::PRIMARY_SKILL)
.And(Selector::subtype()(g))
.And(Selector::sourceType()(Bonus::HERO_BASE_SKILL));
cgh->getBonusLocalFirst(sel)->val = cgh->type->heroClass->primarySkillInitial[g];
}

View File

@ -1021,14 +1021,14 @@ TurnInfo::BonusCache::BonusCache(TConstBonusListPtr bl)
for(int i = 0; i < ETerrainType::ROCK; i++)
{
noTerrainPenalty.push_back(static_cast<bool>(
bl->getFirst(Selector::type(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype(i)))));
bl->getFirst(Selector::type()(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype()(i)))));
}
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type(Bonus::FREE_SHIP_BOARDING)));
flyingMovement = static_cast<bool>(bl->getFirst(Selector::type(Bonus::FLYING_MOVEMENT)));
flyingMovementVal = bl->valOfBonuses(Selector::type(Bonus::FLYING_MOVEMENT));
waterWalking = static_cast<bool>(bl->getFirst(Selector::type(Bonus::WATER_WALKING)));
waterWalkingVal = bl->valOfBonuses(Selector::type(Bonus::WATER_WALKING));
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::FREE_SHIP_BOARDING)));
flyingMovement = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::FLYING_MOVEMENT)));
flyingMovementVal = bl->valOfBonuses(Selector::type()(Bonus::FLYING_MOVEMENT));
waterWalking = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::WATER_WALKING)));
waterWalkingVal = bl->valOfBonuses(Selector::type()(Bonus::WATER_WALKING));
}
TurnInfo::TurnInfo(const CGHeroInstance * Hero, const int turn)
@ -1074,7 +1074,7 @@ bool TurnInfo::hasBonusOfType(Bonus::BonusType type, int subtype) const
}
return static_cast<bool>(
bonuses->getFirst(Selector::type(type).And(Selector::subtype(subtype))));
bonuses->getFirst(Selector::type()(type).And(Selector::subtype()(subtype))));
}
int TurnInfo::valOfBonuses(Bonus::BonusType type, int subtype) const
@ -1087,7 +1087,7 @@ int TurnInfo::valOfBonuses(Bonus::BonusType type, int subtype) const
return bonusCache->waterWalkingVal;
}
return bonuses->valOfBonuses(Selector::type(type).And(Selector::subtype(subtype)));
return bonuses->valOfBonuses(Selector::type()(type).And(Selector::subtype()(subtype)));
}
int TurnInfo::getMaxMovePoints(const EPathfindingLayer layer) const

View File

@ -135,7 +135,7 @@ std::vector<si32> CStack::activeSpells() const
std::stringstream cachingStr;
cachingStr << "!type_" << Bonus::NONE << "source_" << Bonus::SPELL_EFFECT;
CSelector selector = Selector::sourceType(Bonus::SPELL_EFFECT)
CSelector selector = Selector::sourceType()(Bonus::SPELL_EFFECT)
.And(CSelector([](const Bonus * b)->bool
{
return b->type != Bonus::NONE;

View File

@ -92,82 +92,80 @@ const std::map<std::string, TUpdaterPtr> bonusUpdaterMap =
///CBonusProxy
CBonusProxy::CBonusProxy(const IBonusBearer * Target, CSelector Selector)
: cachedLast(0),
: bonusListCachedLast(0),
target(Target),
selector(Selector),
data()
bonusList()
{
}
CBonusProxy::CBonusProxy(const CBonusProxy & other)
: cachedLast(other.cachedLast),
: bonusListCachedLast(other.bonusListCachedLast),
target(other.target),
selector(other.selector),
data(other.data)
bonusList(other.bonusList)
{
}
CBonusProxy::CBonusProxy(CBonusProxy && other)
: cachedLast(0),
: bonusListCachedLast(0),
target(other.target),
selector(),
data()
bonusList()
{
std::swap(cachedLast, other.cachedLast);
std::swap(bonusListCachedLast, other.bonusListCachedLast);
std::swap(selector, other.selector);
std::swap(data, other.data);
std::swap(bonusList, other.bonusList);
}
CBonusProxy & CBonusProxy::operator=(const CBonusProxy & other)
{
cachedLast = other.cachedLast;
bonusListCachedLast = other.bonusListCachedLast;
selector = other.selector;
data = other.data;
bonusList = other.bonusList;
return *this;
}
CBonusProxy & CBonusProxy::operator=(CBonusProxy && other)
{
std::swap(cachedLast, other.cachedLast);
std::swap(bonusListCachedLast, other.bonusListCachedLast);
std::swap(selector, other.selector);
std::swap(data, other.data);
std::swap(bonusList, other.bonusList);
return *this;
}
TConstBonusListPtr CBonusProxy::get() const
TConstBonusListPtr CBonusProxy::getBonusList() const
{
if(target->getTreeVersion() != cachedLast || !data)
if(target->getTreeVersion() != bonusListCachedLast || !bonusList)
{
//TODO: support limiters
data = target->getAllBonuses(selector, Selector::all);
cachedLast = target->getTreeVersion();
bonusList = target->getAllBonuses(selector, Selector::all);
bonusListCachedLast = target->getTreeVersion();
}
return data;
return bonusList;
}
const BonusList * CBonusProxy::operator->() const
{
return get().get();
return getBonusList().get();
}
CTotalsProxy::CTotalsProxy(const IBonusBearer * Target, CSelector Selector, int InitialValue)
: target(Target),
selector(Selector),
: CBonusProxy(Target, Selector),
initialValue(InitialValue),
meleeCachedLast(0),
meleeValue(0),
rangedCachedLast(0),
rangedValue(0),
value(0),
cachedLast(0)
valueCachedLast(0)
{
}
CTotalsProxy::CTotalsProxy(const CTotalsProxy & other)
: target(other.target),
selector(other.selector),
: CBonusProxy(other),
initialValue(other.initialValue),
meleeCachedLast(other.meleeCachedLast),
meleeValue(other.meleeValue),
@ -178,13 +176,14 @@ CTotalsProxy::CTotalsProxy(const CTotalsProxy & other)
CTotalsProxy & CTotalsProxy::operator=(const CTotalsProxy & other)
{
CBonusProxy::operator=(other);
initialValue = other.initialValue;
meleeCachedLast = other.meleeCachedLast;
meleeValue = other.meleeValue;
rangedCachedLast = other.rangedCachedLast;
rangedValue = other.rangedValue;
value = other.value;
cachedLast = other.cachedLast;
valueCachedLast = other.valueCachedLast;
return *this;
}
@ -193,20 +192,32 @@ int CTotalsProxy::getValue() const
{
const auto treeVersion = target->getTreeVersion();
if(treeVersion != cachedLast)
if(treeVersion != valueCachedLast)
{
auto bonuses = target->getBonuses(selector);
auto bonuses = getBonusList();
value = initialValue + bonuses->totalValue();
cachedLast = treeVersion;
valueCachedLast = treeVersion;
}
return value;
}
int CTotalsProxy::getValueAndList(TConstBonusListPtr & outBonusList) const
{
const auto treeVersion = target->getTreeVersion();
outBonusList = getBonusList();
if(treeVersion != valueCachedLast)
{
value = initialValue + outBonusList->totalValue();
valueCachedLast = treeVersion;
}
return value;
}
int CTotalsProxy::getMeleeValue() const
{
static const auto limit = Selector::effectRange(Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_MELEE_FIGHT));
static const auto limit = Selector::effectRange()(Bonus::NO_LIMIT).Or(Selector::effectRange()(Bonus::ONLY_MELEE_FIGHT));
const auto treeVersion = target->getTreeVersion();
@ -222,7 +233,7 @@ int CTotalsProxy::getMeleeValue() const
int CTotalsProxy::getRangedValue() const
{
static const auto limit = Selector::effectRange(Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT));
static const auto limit = Selector::effectRange()(Bonus::NO_LIMIT).Or(Selector::effectRange()(Bonus::ONLY_DISTANCE_FIGHT));
const auto treeVersion = target->getTreeVersion();
@ -582,24 +593,28 @@ void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusLi
}
CSelector IBonusBearer::anaffectedByMoraleSelector
= Selector::type(Bonus::NON_LIVING)
.Or(Selector::type(Bonus::UNDEAD))
.Or(Selector::type(Bonus::NO_MORALE))
.Or(Selector::type(Bonus::SIEGE_WEAPON));
= Selector::type()(Bonus::NON_LIVING)
.Or(Selector::type()(Bonus::UNDEAD))
.Or(Selector::type()(Bonus::NO_MORALE))
.Or(Selector::type()(Bonus::SIEGE_WEAPON));
CSelector IBonusBearer::moraleSelector = Selector::type(Bonus::MORALE);
CSelector IBonusBearer::selfMoraleSelector = Selector::type(Bonus::SELF_MORALE);
CSelector IBonusBearer::moraleSelector = Selector::type()(Bonus::MORALE);
CSelector IBonusBearer::luckSelector = Selector::type()(Bonus::LUCK);
CSelector IBonusBearer::selfMoraleSelector = Selector::type()(Bonus::SELF_MORALE);
CSelector IBonusBearer::selfLuckSelector = Selector::type()(Bonus::SELF_LUCK);
IBonusBearer::IBonusBearer()
:anaffectedByMorale(this, anaffectedByMoraleSelector),
moraleValue(this, moraleSelector, 0),
selfMorale(this, selfMoraleSelector)
luckValue(this, luckSelector, 0),
selfMorale(this, selfMoraleSelector),
selfLuck(this, selfLuckSelector)
{
}
int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
{
return valOfBonuses(Selector::type(type).And(selector));
return valOfBonuses(Selector::type()(type).And(selector));
}
int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype) const
@ -607,9 +622,9 @@ int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype) const
boost::format fmt("type_%ds_%d");
fmt % (int)type % subtype;
CSelector s = Selector::type(type);
CSelector s = Selector::type()(type);
if(subtype != -1)
s = s.And(Selector::subtype(subtype));
s = s.And(Selector::subtype()(subtype));
return valOfBonuses(s, fmt.str());
}
@ -635,9 +650,9 @@ bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype) const
boost::format fmt("type_%ds_%d");
fmt % (int)type % subtype;
CSelector s = Selector::type(type);
CSelector s = Selector::type()(type);
if(subtype != -1)
s = s.And(Selector::subtype(subtype));
s = s.And(Selector::subtype()(subtype));
return hasBonus(s, fmt.str());
}
@ -678,9 +693,41 @@ int IBonusBearer::LuckVal() const
if(hasBonusOfType(Bonus::NO_LUCK))
return 0;
int ret = valOfBonuses(Bonus::LUCK);
int ret = luckValue.getValue();
if(hasBonusOfType(Bonus::SELF_LUCK)) //eg. halfling
if(selfLuck.getHasBonus()) //eg. halfling
vstd::amax(ret, +1);
return vstd::abetween(ret, -3, +3);
}
int IBonusBearer::MoraleValAndBonusList(TConstBonusListPtr & bonusList) const
{
if(anaffectedByMorale.getHasBonus())
{
if(!bonusList->empty())
bonusList = std::make_shared<const BonusList>();
return 0;
}
int ret = moraleValue.getValueAndList(bonusList);
if(selfMorale.getHasBonus()) //eg. minotaur
vstd::amax(ret, +1);
return vstd::abetween(ret, -3, +3);
}
int IBonusBearer::LuckValAndBonusList(TConstBonusListPtr & bonusList) const
{
if(hasBonusOfType(Bonus::NO_LUCK))
{
if(!bonusList->empty())
bonusList = std::make_shared<const BonusList>();
return 0;
}
int ret = luckValue.getValueAndList(bonusList);
if(selfLuck.getHasBonus()) //eg. halfling
vstd::amax(ret, +1);
return vstd::abetween(ret, -3, +3);
@ -689,7 +736,7 @@ int IBonusBearer::LuckVal() const
ui32 IBonusBearer::MaxHealth() const
{
const std::string cachingStr = "type_STACK_HEALTH";
static const auto selector = Selector::type(Bonus::STACK_HEALTH);
static const auto selector = Selector::type()(Bonus::STACK_HEALTH);
auto value = valOfBonuses(selector, cachingStr);
return std::max(1, value); //never 0
}
@ -735,12 +782,12 @@ si32 IBonusBearer::manaLimit() const
int IBonusBearer::getPrimSkillLevel(PrimarySkill::PrimarySkill id) const
{
static const CSelector selectorAllSkills = Selector::type(Bonus::PRIMARY_SKILL);
static const CSelector selectorAllSkills = Selector::type()(Bonus::PRIMARY_SKILL);
static const std::string keyAllSkills = "type_PRIMARY_SKILL";
auto allSkills = getBonuses(selectorAllSkills, keyAllSkills);
int ret = allSkills->valOfBonuses(Selector::subtype(id));
int ret = allSkills->valOfBonuses(Selector::subtype()(id));
vstd::amax(ret, id/2); //minimal value is 0 for attack and defense and 1 for spell power and knowledge
return ret;
@ -754,26 +801,26 @@ si32 IBonusBearer::magicResistance() const
ui32 IBonusBearer::Speed(int turn, bool useBind) const
{
//war machines cannot move
if(hasBonus(Selector::type(Bonus::SIEGE_WEAPON).And(Selector::turns(turn))))
if(hasBonus(Selector::type()(Bonus::SIEGE_WEAPON).And(Selector::turns(turn))))
{
return 0;
}
//bind effect check - doesn't influence stack initiative
if(useBind && hasBonus(Selector::type(Bonus::BIND_EFFECT).And(Selector::turns(turn))))
if(useBind && hasBonus(Selector::type()(Bonus::BIND_EFFECT).And(Selector::turns(turn))))
{
return 0;
}
return valOfBonuses(Selector::type(Bonus::STACKS_SPEED).And(Selector::turns(turn)));
return valOfBonuses(Selector::type()(Bonus::STACKS_SPEED).And(Selector::turns(turn)));
}
bool IBonusBearer::isLiving() const //TODO: theoreticaly there exists "LIVING" bonus in stack experience documentation
{
static const std::string cachingStr = "IBonusBearer::isLiving";
static const CSelector selector = Selector::type(Bonus::UNDEAD)
.Or(Selector::type(Bonus::NON_LIVING))
.Or(Selector::type(Bonus::GARGOYLE))
.Or(Selector::type(Bonus::SIEGE_WEAPON));
static const CSelector selector = Selector::type()(Bonus::UNDEAD)
.Or(Selector::type()(Bonus::NON_LIVING))
.Or(Selector::type()(Bonus::GARGOYLE))
.Or(Selector::type()(Bonus::SIEGE_WEAPON));
return !hasBonus(selector, cachingStr);
}
@ -1561,17 +1608,42 @@ std::shared_ptr<Bonus> Bonus::addPropagator(TPropagatorPtr Propagator)
namespace Selector
{
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> type(&Bonus::type);
DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> subtype(&Bonus::subtype);
DLL_LINKAGE CSelectFieldEqual<CAddInfo> info(&Bonus::additionalInfo);
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> sourceType(&Bonus::source);
DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> effectRange(&Bonus::effectRange);
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> & type()
{
static CSelectFieldEqual<Bonus::BonusType> stype(&Bonus::type);
return stype;
}
DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> & subtype()
{
static CSelectFieldEqual<TBonusSubtype> ssubtype(&Bonus::subtype);
return ssubtype;
}
DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info()
{
static CSelectFieldEqual<CAddInfo> sinfo(&Bonus::additionalInfo);
return sinfo;
}
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & sourceType()
{
static CSelectFieldEqual<Bonus::BonusSource> ssourceType(&Bonus::source);
return ssourceType;
}
DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange()
{
static CSelectFieldEqual<Bonus::LimitEffect> seffectRange(&Bonus::effectRange);
return seffectRange;
}
DLL_LINKAGE CWillLastTurns turns;
DLL_LINKAGE CWillLastDays days;
CSelector DLL_LINKAGE typeSubtype(Bonus::BonusType Type, TBonusSubtype Subtype)
{
return type(Type).And(subtype(Subtype));
return type()(Type).And(subtype()(Subtype));
}
CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, CAddInfo info)
@ -1796,7 +1868,7 @@ int HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const
{
CSelector mySelector = isSubtypeRelevant
? Selector::typeSubtype(type, subtype)
: Selector::type(type);
: Selector::type()(type);
//if we have a bonus of required type accepted, limiter should accept also this bonus
if(context.alreadyAccepted.getFirst(mySelector))

View File

@ -77,18 +77,17 @@ public:
CBonusProxy & operator=(CBonusProxy && other);
CBonusProxy & operator=(const CBonusProxy & other);
TConstBonusListPtr get() const;
const BonusList * operator->() const;
private:
mutable int64_t cachedLast;
const IBonusBearer * target;
TConstBonusListPtr getBonusList() const;
protected:
CSelector selector;
mutable TConstBonusListPtr data;
const IBonusBearer * target;
mutable int64_t bonusListCachedLast;
mutable TConstBonusListPtr bonusList;
};
class DLL_LINKAGE CTotalsProxy
class DLL_LINKAGE CTotalsProxy : public CBonusProxy
{
public:
CTotalsProxy(const IBonusBearer * Target, CSelector Selector, int InitialValue);
@ -101,13 +100,17 @@ public:
int getMeleeValue() const;
int getRangedValue() const;
int getValue() const;
/**
Returns total value of all selected bonuses and sets bonusList as a pointer to the list of selected bonuses
@param bonusList is the out list of all selected bonuses
@return total value of all selected bonuses and 0 otherwise
*/
int getValueAndList(TConstBonusListPtr & bonusList) const;
private:
const IBonusBearer * target;
CSelector selector;
int initialValue;
mutable int64_t cachedLast;
mutable int64_t valueCachedLast;
mutable int value;
mutable int64_t meleeCachedLast;
@ -692,8 +695,12 @@ private:
CCheckProxy anaffectedByMorale;
static CSelector moraleSelector;
CTotalsProxy moraleValue;
static CSelector luckSelector;
CTotalsProxy luckValue;
static CSelector selfMoraleSelector;
CCheckProxy selfMorale;
static CSelector selfLuckSelector;
CCheckProxy selfLuck;
public:
//new bonusing node interface
@ -726,6 +733,14 @@ public:
int MoraleVal() const; //range [-3, +3]
int LuckVal() const; //range [-3, +3]
/**
Returns total value of all morale bonuses and sets bonusList as a pointer to the list of selected bonuses.
@param bonusList is the out param it's list of all selected bonuses
@return total value of all morale in the range [-3, +3] and 0 otherwise
*/
int MoraleValAndBonusList(TConstBonusListPtr & bonusList) const;
int LuckValAndBonusList(TConstBonusListPtr & bonusList) const;
ui32 MaxHealth() const; //get max HP of stack with all modifiers
bool isLiving() const; //non-undead, non-non living or alive
virtual si32 magicResistance() const;
@ -864,7 +879,10 @@ public:
CSelector operator()(const T &valueToCompareAgainst) const
{
auto ptr2 = ptr; //We need a COPY because we don't want to reference this (might be outlived by lambda)
return [ptr2, valueToCompareAgainst](const Bonus *bonus) { return bonus->*ptr2 == valueToCompareAgainst; };
return [ptr2, valueToCompareAgainst](const Bonus *bonus)
{
return bonus->*ptr2 == valueToCompareAgainst;
};
}
};
@ -1112,11 +1130,11 @@ public:
namespace Selector
{
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> type;
extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> subtype;
extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> info;
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> sourceType;
extern DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> effectRange;
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusType> & type();
extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> & subtype();
extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info();
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & sourceType();
extern DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange();
extern DLL_LINKAGE CWillLastTurns turns;
extern DLL_LINKAGE CWillLastDays days;

View File

@ -1310,7 +1310,7 @@ DLL_LINKAGE void BattleTriggerEffect::applyGs(CGameState *gs)
case Bonus::POISON:
{
auto b = st->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT, SpellID::POISON)
.And(Selector::type(Bonus::STACK_HEALTH)));
.And(Selector::type()(Bonus::STACK_HEALTH)));
if (b)
b->val = val;
break;
@ -1601,7 +1601,7 @@ DLL_LINKAGE void BattleSetStackProperty::applyGs(CGameState * gs)
}
case UNBIND:
{
stack->removeBonusesRecursive(Selector::type(Bonus::BIND_EFFECT));
stack->removeBonusesRecursive(Selector::type()(Bonus::BIND_EFFECT));
break;
}
case CLONED:

View File

@ -164,7 +164,7 @@ bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, Bat
return false;
const std::string cachingStrNoWallPenalty = "type_NO_WALL_PENALTY";
static const auto selectorNoWallPenalty = Selector::type(Bonus::NO_WALL_PENALTY);
static const auto selectorNoWallPenalty = Selector::type()(Bonus::NO_WALL_PENALTY);
if(shooter->hasBonus(selectorNoWallPenalty, cachingStrNoWallPenalty))
return false;
@ -680,10 +680,10 @@ bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker) const
return false;
//forgetfulness
TConstBonusListPtr forgetfulList = attacker->getBonuses(Selector::type(Bonus::FORGETFULL));
TConstBonusListPtr forgetfulList = attacker->getBonuses(Selector::type()(Bonus::FORGETFULL));
if (!forgetfulList->empty())
{
int forgetful = forgetfulList->valOfBonuses(Selector::type(Bonus::FORGETFULL));
int forgetful = forgetfulList->valOfBonuses(Selector::type()(Bonus::FORGETFULL));
//advanced+ level
if (forgetful > 1)
@ -712,10 +712,10 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
{
auto battleBonusValue = [&](const IBonusBearer * bearer, CSelector selector) -> int
{
auto noLimit = Selector::effectRange(Bonus::NO_LIMIT);
auto noLimit = Selector::effectRange()(Bonus::NO_LIMIT);
auto limitMatches = info.shooting
? Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT)
: Selector::effectRange(Bonus::ONLY_MELEE_FIGHT);
? Selector::effectRange()(Bonus::ONLY_DISTANCE_FIGHT)
: Selector::effectRange()(Bonus::ONLY_MELEE_FIGHT);
//any regular bonuses or just ones for melee/ranged
return bearer->getBonuses(selector, noLimit.Or(limitMatches))->totalValue();
@ -743,7 +743,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
}
const std::string cachingStrSiedgeWeapon = "type_SIEGE_WEAPON";
static const auto selectorSiedgeWeapon = Selector::type(Bonus::SIEGE_WEAPON);
static const auto selectorSiedgeWeapon = Selector::type()(Bonus::SIEGE_WEAPON);
if(attackerBonuses->hasBonus(selectorSiedgeWeapon, cachingStrSiedgeWeapon) && info.attacker->creatureIndex() != CreatureID::ARROW_TOWERS) //any siege weapon, but only ballista can attack (second condition - not arrow turret)
{ //minDmg and maxDmg are multiplied by hero attack + 1
@ -760,14 +760,14 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
double attackDefenceDifference = 0.0;
double multAttackReduction = 1.0 - battleBonusValue(attackerBonuses, Selector::type(Bonus::GENERAL_ATTACK_REDUCTION)) / 100.0;
double multAttackReduction = 1.0 - battleBonusValue(attackerBonuses, Selector::type()(Bonus::GENERAL_ATTACK_REDUCTION)) / 100.0;
attackDefenceDifference += info.attacker->getAttack(info.shooting) * multAttackReduction;
double multDefenceReduction = 1.0 - battleBonusValue(attackerBonuses, Selector::type(Bonus::ENEMY_DEFENCE_REDUCTION)) / 100.0;
double multDefenceReduction = 1.0 - battleBonusValue(attackerBonuses, Selector::type()(Bonus::ENEMY_DEFENCE_REDUCTION)) / 100.0;
attackDefenceDifference -= info.defender->getDefence(info.shooting) * multDefenceReduction;
const std::string cachingStrSlayer = "type_SLAYER";
static const auto selectorSlayer = Selector::type(Bonus::SLAYER);
static const auto selectorSlayer = Selector::type()(Bonus::SLAYER);
//slayer handling //TODO: apply only ONLY_MELEE_FIGHT / DISTANCE_FIGHT?
auto slayerEffects = attackerBonuses->getBonuses(selectorSlayer, cachingStrSlayer);
@ -807,10 +807,10 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
}
const std::string cachingStrJousting = "type_JOUSTING";
static const auto selectorJousting = Selector::type(Bonus::JOUSTING);
static const auto selectorJousting = Selector::type()(Bonus::JOUSTING);
const std::string cachingStrChargeImmunity = "type_CHARGE_IMMUNITY";
static const auto selectorChargeImmunity = Selector::type(Bonus::CHARGE_IMMUNITY);
static const auto selectorChargeImmunity = Selector::type()(Bonus::CHARGE_IMMUNITY);
//applying jousting bonus
if(info.chargedFields > 0 && attackerBonuses->hasBonus(selectorJousting, cachingStrJousting) && !defenderBonuses->hasBonus(selectorChargeImmunity, cachingStrChargeImmunity))
@ -836,11 +836,11 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
//handling hate effect
//assume that unit have only few HATE features and cache them all
const std::string cachingStrHate = "type_HATE";
static const auto selectorHate = Selector::type(Bonus::HATE);
static const auto selectorHate = Selector::type()(Bonus::HATE);
auto allHateEffects = attackerBonuses->getBonuses(selectorHate, cachingStrHate);
additiveBonus += allHateEffects->valOfBonuses(Selector::subtype(info.defender->creatureIndex())) / 100.0;
additiveBonus += allHateEffects->valOfBonuses(Selector::subtype()(info.defender->creatureIndex())) / 100.0;
const std::string cachingStrMeleeReduction = "type_GENERAL_DAMAGE_REDUCTIONs_0";
static const auto selectorMeleeReduction = Selector::typeSubtype(Bonus::GENERAL_DAMAGE_REDUCTION, 0);
@ -863,7 +863,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
//todo: set actual percentage in spell bonus configuration instead of just level; requires non trivial backward compatibility handling
//get list first, total value of 0 also counts
TConstBonusListPtr forgetfulList = attackerBonuses->getBonuses(Selector::type(Bonus::FORGETFULL),"type_FORGETFULL");
TConstBonusListPtr forgetfulList = attackerBonuses->getBonuses(Selector::type()(Bonus::FORGETFULL),"type_FORGETFULL");
if(!forgetfulList->empty())
{
@ -878,10 +878,10 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
}
const std::string cachingStrForcedMinDamage = "type_ALWAYS_MINIMUM_DAMAGE";
static const auto selectorForcedMinDamage = Selector::type(Bonus::ALWAYS_MINIMUM_DAMAGE);
static const auto selectorForcedMinDamage = Selector::type()(Bonus::ALWAYS_MINIMUM_DAMAGE);
const std::string cachingStrForcedMaxDamage = "type_ALWAYS_MAXIMUM_DAMAGE";
static const auto selectorForcedMaxDamage = Selector::type(Bonus::ALWAYS_MAXIMUM_DAMAGE);
static const auto selectorForcedMaxDamage = Selector::type()(Bonus::ALWAYS_MAXIMUM_DAMAGE);
TConstBonusListPtr curseEffects = attackerBonuses->getBonuses(selectorForcedMinDamage, cachingStrForcedMinDamage);
TConstBonusListPtr blessEffects = attackerBonuses->getBonuses(selectorForcedMaxDamage, cachingStrForcedMaxDamage);
@ -920,7 +920,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
else
{
const std::string cachingStrNoMeleePenalty = "type_NO_MELEE_PENALTY";
static const auto selectorNoMeleePenalty = Selector::type(Bonus::NO_MELEE_PENALTY);
static const auto selectorNoMeleePenalty = Selector::type()(Bonus::NO_MELEE_PENALTY);
if(info.attacker->isShooter() && !attackerBonuses->hasBonus(selectorNoMeleePenalty, cachingStrNoMeleePenalty))
multBonus *= 0.5;
@ -930,7 +930,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
if(info.attacker->creatureIndex() == CreatureID::PSYCHIC_ELEMENTAL)
{
const std::string cachingStrMindImmunity = "type_MIND_IMMUNITY";
static const auto selectorMindImmunity = Selector::type(Bonus::MIND_IMMUNITY);
static const auto selectorMindImmunity = Selector::type()(Bonus::MIND_IMMUNITY);
if(defenderBonuses->hasBonus(selectorMindImmunity, cachingStrMindImmunity))
multBonus *= 0.5;
@ -1596,7 +1596,7 @@ bool CBattleInfoCallback::battleHasDistancePenalty(const IBonusBearer * shooter,
RETURN_IF_NOT_BATTLE(false);
const std::string cachingStrNoDistancePenalty = "type_NO_DISTANCE_PENALTY";
static const auto selectorNoDistancePenalty = Selector::type(Bonus::NO_DISTANCE_PENALTY);
static const auto selectorNoDistancePenalty = Selector::type()(Bonus::NO_DISTANCE_PENALTY);
if(shooter->hasBonus(selectorNoDistancePenalty, cachingStrNoDistancePenalty))
return false;
@ -1831,9 +1831,9 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(CRandomGenerator & rand, c
{
auto kingMonster = getAliveEnemy([&](const CStack * stack) -> bool //look for enemy, non-shooting stack
{
const auto isKing = Selector::type(Bonus::KING1)
.Or(Selector::type(Bonus::KING2))
.Or(Selector::type(Bonus::KING3));
const auto isKing = Selector::type()(Bonus::KING1)
.Or(Selector::type()(Bonus::KING2))
.Or(Selector::type()(Bonus::KING3));
return stack->hasBonus(isKing);
});
@ -1860,7 +1860,7 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(CRandomGenerator & rand,const
{
RETURN_IF_NOT_BATTLE(SpellID::NONE);
TConstBonusListPtr bl = caster->getBonuses(Selector::type(Bonus::SPELLCASTER));
TConstBonusListPtr bl = caster->getBonuses(Selector::type()(Bonus::SPELLCASTER));
if (!bl->size())
return SpellID::NONE;
int totalWeight = 0;
@ -1917,7 +1917,7 @@ si8 CBattleInfoCallback::battleMinSpellLevel(ui8 side) const
if(!node)
return 0;
auto b = node->getBonuses(Selector::type(Bonus::BLOCK_MAGIC_BELOW));
auto b = node->getBonuses(Selector::type()(Bonus::BLOCK_MAGIC_BELOW));
if(b->size())
return b->totalValue();
@ -1936,7 +1936,7 @@ si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const
return GameConstants::SPELL_LEVELS;
//We can't "just get value" - it'd be 0 if there are bonuses (and all would be blocked)
auto b = node->getBonuses(Selector::type(Bonus::BLOCK_MAGIC_ABOVE));
auto b = node->getBonuses(Selector::type()(Bonus::BLOCK_MAGIC_ABOVE));
if(b->size())
return b->totalValue();

View File

@ -386,7 +386,7 @@ PlayerColor CBattleInfoEssentials::battleGetOwner(const battle::Unit * unit) con
PlayerColor initialOwner = getBattle()->getSidePlayer(unit->unitSide());
static CSelector selector = Selector::type(Bonus::HYPNOTIZED);
static CSelector selector = Selector::type()(Bonus::HYPNOTIZED);
static std::string cachingString = "type_103s-1";
if(unit->hasBonus(selector, cachingString))

View File

@ -89,8 +89,8 @@ void CAmmo::serializeJson(JsonSerializeFormat & handler)
///CShots
CShots::CShots(const battle::Unit * Owner)
: CAmmo(Owner, Selector::type(Bonus::SHOTS)),
shooter(Owner, Selector::type(Bonus::SHOOTER))
: CAmmo(Owner, Selector::type()(Bonus::SHOTS)),
shooter(Owner, Selector::type()(Bonus::SHOOTER))
{
}
@ -128,7 +128,7 @@ int32_t CShots::total() const
///CCasts
CCasts::CCasts(const battle::Unit * Owner):
CAmmo(Owner, Selector::type(Bonus::CASTS))
CAmmo(Owner, Selector::type()(Bonus::CASTS))
{
}
@ -145,10 +145,10 @@ CCasts & CCasts::operator=(const CCasts & other)
///CRetaliations
CRetaliations::CRetaliations(const battle::Unit * Owner)
: CAmmo(Owner, Selector::type(Bonus::ADDITIONAL_RETALIATION)),
: CAmmo(Owner, Selector::type()(Bonus::ADDITIONAL_RETALIATION)),
totalCache(0),
noRetaliation(Owner, Selector::type(Bonus::SIEGE_WEAPON).Or(Selector::type(Bonus::HYPNOTIZED)).Or(Selector::type(Bonus::NO_RETALIATION))),
unlimited(Owner, Selector::type(Bonus::UNLIMITED_RETALIATIONS))
noRetaliation(Owner, Selector::type()(Bonus::SIEGE_WEAPON).Or(Selector::type()(Bonus::HYPNOTIZED)).Or(Selector::type()(Bonus::NO_RETALIATION))),
unlimited(Owner, Selector::type()(Bonus::UNLIMITED_RETALIATIONS))
{
}
@ -388,13 +388,13 @@ CUnitState::CUnitState()
counterAttacks(this),
health(this),
shots(this),
totalAttacks(this, Selector::type(Bonus::ADDITIONAL_ATTACK), 1),
totalAttacks(this, Selector::type()(Bonus::ADDITIONAL_ATTACK), 1),
minDamage(this, Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1)), 0),
maxDamage(this, Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 0).Or(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2)), 0),
attack(this, Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), 0),
defence(this, Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), 0),
inFrenzy(this, Selector::type(Bonus::IN_FRENZY)),
cloneLifetimeMarker(this, Selector::type(Bonus::NONE).And(Selector::source(Bonus::SPELL_EFFECT, SpellID::CLONE))),
inFrenzy(this, Selector::type()(Bonus::IN_FRENZY)),
cloneLifetimeMarker(this, Selector::type()(Bonus::NONE).And(Selector::source(Bonus::SPELL_EFFECT, SpellID::CLONE))),
cloneID(-1),
position()
{
@ -618,12 +618,12 @@ void CUnitState::setPosition(BattleHex hex)
int32_t CUnitState::getInitiative(int turn) const
{
return valOfBonuses(Selector::type(Bonus::STACKS_SPEED).And(Selector::turns(turn)));
return valOfBonuses(Selector::type()(Bonus::STACKS_SPEED).And(Selector::turns(turn)));
}
bool CUnitState::canMove(int turn) const
{
return alive() && !hasBonus(Selector::type(Bonus::NOT_ACTIVE).And(Selector::turns(turn))); //eg. Ammo Cart or blinded creature
return alive() && !hasBonus(Selector::type()(Bonus::NOT_ACTIVE).And(Selector::turns(turn))); //eg. Ammo Cart or blinded creature
}
bool CUnitState::defended(int turn) const

View File

@ -37,7 +37,7 @@ void CArmedInstance::randomizeArmy(int type)
}
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type(Bonus::NONEVIL_ALIGNMENT_MIX);
CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type()(Bonus::NONEVIL_ALIGNMENT_MIX);
CArmedInstance::CArmedInstance()
:nonEvilAlignmentMix(this, nonEvilAlignmentMixSelector)
@ -50,7 +50,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
if(!validTypes(false)) //object not randomized, don't bother
return;
auto b = getExportedBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
auto b = getExportedBonusList().getFirst(Selector::sourceType()(Bonus::ARMY).And(Selector::type()(Bonus::MORALE)));
if(!b)
{
b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
@ -62,7 +62,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
bool hasUndead = false;
const std::string undeadCacheKey = "type_UNDEAD";
static const CSelector undeadSelector = Selector::type(Bonus::UNDEAD);
static const CSelector undeadSelector = Selector::type()(Bonus::UNDEAD);
for(auto slot : Slots())
{

View File

@ -56,7 +56,7 @@ static int lowestSpeed(const CGHeroInstance * chi)
auto i = chi->Slots().begin();
//TODO? should speed modifiers (eg from artifacts) affect hero movement?
static const CSelector selectorSTACKS_SPEED = Selector::type(Bonus::STACKS_SPEED);
static const CSelector selectorSTACKS_SPEED = Selector::type()(Bonus::STACKS_SPEED);
static const std::string keySTACKS_SPEED = "type_"+std::to_string((si32)Bonus::STACKS_SPEED);
int ret = (i++)->second->valOfBonuses(selectorSTACKS_SPEED, keySTACKS_SPEED);
@ -289,7 +289,7 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
if(portrait < 0 || portrait == 255)
portrait = type->imageIndex;
if(!hasBonus(Selector::sourceType(Bonus::HERO_BASE_SKILL)))
if(!hasBonus(Selector::sourceType()(Bonus::HERO_BASE_SKILL)))
{
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
{
@ -534,7 +534,7 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
void CGHeroInstance::recreateSecondarySkillsBonuses()
{
auto secondarySkillsBonuses = getBonuses(Selector::sourceType(Bonus::SECONDARY_SKILL));
auto secondarySkillsBonuses = getBonuses(Selector::sourceType()(Bonus::SECONDARY_SKILL));
for(auto bonus : *secondarySkillsBonuses)
removeBonus(bonus);
@ -816,7 +816,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
// figure out what to raise - pick strongest creature meeting requirements
CreatureID creatureTypeRaised = CreatureID::SKELETON;
int requiredCasualtyLevel = 1;
TConstBonusListPtr improvedNecromancy = getBonuses(Selector::type(Bonus::IMPROVED_NECROMANCY));
TConstBonusListPtr improvedNecromancy = getBonuses(Selector::type()(Bonus::IMPROVED_NECROMANCY));
if(!improvedNecromancy->empty())
{
auto getCreatureID = [necromancyLevel](std::shared_ptr<Bonus> bonus) -> CreatureID
@ -988,7 +988,7 @@ int CGHeroInstance::getSpellCost(const CSpell * sp) const
void CGHeroInstance::pushPrimSkill( PrimarySkill::PrimarySkill which, int val )
{
assert(!hasBonus(Selector::typeSubtype(Bonus::PRIMARY_SKILL, which)
.And(Selector::sourceType(Bonus::HERO_BASE_SKILL))));
.And(Selector::sourceType()(Bonus::HERO_BASE_SKILL))));
addNewBonus(std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id.getNum(), which));
}
@ -1257,9 +1257,9 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill::PrimarySkill primarySkill, si
{
if(primarySkill < PrimarySkill::EXPERIENCE)
{
auto skill = getBonusLocalFirst(Selector::type(Bonus::PRIMARY_SKILL)
.And(Selector::subtype(primarySkill))
.And(Selector::sourceType(Bonus::HERO_BASE_SKILL)));
auto skill = getBonusLocalFirst(Selector::type()(Bonus::PRIMARY_SKILL)
.And(Selector::subtype()(primarySkill))
.And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)));
assert(skill);
if(abs)
@ -1427,7 +1427,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
//primary skills
if(handler.saving)
{
const bool haveSkills = hasBonus(Selector::type(Bonus::PRIMARY_SKILL).And(Selector::sourceType(Bonus::HERO_BASE_SKILL)));
const bool haveSkills = hasBonus(Selector::type()(Bonus::PRIMARY_SKILL).And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)));
if(haveSkills)
{
@ -1435,7 +1435,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
{
int value = valOfBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, i).And(Selector::sourceType(Bonus::HERO_BASE_SKILL)));
int value = valOfBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, i).And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)));
handler.serializeInt(PrimarySkill::names[i], value, 0);
}

View File

@ -562,12 +562,12 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[591], dwellingBonus));// \nExternal dwellings %+d
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
TConstBonusListPtr bonuses = getBonuses(Selector::type(Bonus::CREATURE_GROWTH).And(Selector::subtype(level)));
TConstBonusListPtr bonuses = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH).And(Selector::subtype()(level)));
for(const auto & b : *bonuses)
ret.entries.push_back(GrowthInfo::Entry(b->val, b->Description()));
//statue-of-legion-like bonus: % to base+castle
TConstBonusListPtr bonuses2 = getBonuses(Selector::type(Bonus::CREATURE_GROWTH_PERCENT));
TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT));
for(const auto & b : *bonuses2)
ret.entries.push_back(GrowthInfo::Entry(b->val * (base + castleBonus) / 100, b->Description()));
@ -1166,7 +1166,7 @@ void CGTownInstance::deserializationFix()
void CGTownInstance::updateMoraleBonusFromArmy()
{
auto b = getExportedBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
auto b = getExportedBonusList().getFirst(Selector::sourceType()(Bonus::ARMY).And(Selector::type()(Bonus::MORALE)));
if(!b)
{
b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
@ -1187,7 +1187,7 @@ void CGTownInstance::recreateBuildingsBonuses()
static TPropagatorPtr playerProp(new CPropagatorNodeType(PLAYER));
BonusList bl;
getExportedBonusList().getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE));
getExportedBonusList().getBonuses(bl, Selector::sourceType()(Bonus::TOWN_STRUCTURE));
for(auto b : bl)
removeBonus(b);

View File

@ -1422,7 +1422,7 @@ void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler)
if(handler.saving && ID == Obj::SPELL_SCROLL)
{
const std::shared_ptr<Bonus> b = storedArtifact->getBonusLocalFirst(Selector::type(Bonus::SPELL));
const std::shared_ptr<Bonus> b = storedArtifact->getBonusLocalFirst(Selector::type()(Bonus::SPELL));
SpellID spellId(b->subtype);
handler.serializeId("spell", spellId, SpellID::NONE);

View File

@ -1712,8 +1712,8 @@ CGObjectInstance * CMapLoaderH3M::readHero(ObjectInstanceID idToBeGiven, const i
bool hasCustomPrimSkills = reader.readBool();
if(hasCustomPrimSkills)
{
auto ps = nhi->getAllBonuses(Selector::type(Bonus::PRIMARY_SKILL)
.And(Selector::sourceType(Bonus::HERO_BASE_SKILL)), nullptr);
auto ps = nhi->getAllBonuses(Selector::type()(Bonus::PRIMARY_SKILL)
.And(Selector::sourceType()(Bonus::HERO_BASE_SKILL)), nullptr);
if(ps->size())
{
logGlobal->warn("Hero %s subID=%d has set primary skills twice (in map properties and on adventure map instance). Using the latter set...", nhi->name, nhi->subID);

View File

@ -437,7 +437,7 @@ int64_t CSpell::adjustRawDamage(const spells::Caster * caster, const battle::Uni
}
});
CSelector selector = Selector::type(Bonus::SPELL_DAMAGE_REDUCTION).And(Selector::subtype(-1));
CSelector selector = Selector::type()(Bonus::SPELL_DAMAGE_REDUCTION).And(Selector::subtype()(-1));
//general spell dmg reduction
if(bearer->hasBonus(selector))

View File

@ -302,7 +302,7 @@ void BattleCast::cast(const SpellCastEnvironment * env)
if(tryMagicMirror)
{
const std::string magicMirrorCacheStr = "type_MAGIC_MIRROR";
static const auto magicMirrorSelector = Selector::type(Bonus::MAGIC_MIRROR);
static const auto magicMirrorSelector = Selector::type()(Bonus::MAGIC_MIRROR);
auto rangeGen = env->getRandomGenerator().getInt64Range(0, 99);
@ -534,7 +534,7 @@ bool BaseMechanics::adaptProblem(ESpellCastProblem::ESpellCastProblem source, Pr
return adaptGenericProblem(target);
//Recanter's Cloak or similar effect. Try to retrieve bonus
const auto b = hero->getBonusLocalFirst(Selector::type(Bonus::BLOCK_MAGIC_ABOVE));
const auto b = hero->getBonusLocalFirst(Selector::type()(Bonus::BLOCK_MAGIC_ABOVE));
//TODO what about other values and non-artifact sources?
if(b && b->val == 2 && b->source == Bonus::ARTIFACT)
{

View File

@ -75,7 +75,7 @@ public:
protected:
bool check(const Mechanics * m, const battle::Unit * target) const override
{
return target->hasBonus(Selector::type(type));
return target->hasBonus(Selector::type()(type));
}
private:
@ -115,7 +115,7 @@ protected:
std::stringstream cachingStr;
cachingStr << "type_" << Bonus::LEVEL_SPELL_IMMUNITY << "addInfo_1";
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY).And(Selector::info(1)), cachingStr.str());
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type()(Bonus::LEVEL_SPELL_IMMUNITY).And(Selector::info()(1)), cachingStr.str());
return levelImmunities->size() == 0 ||
levelImmunities->totalValue() < m->getSpellLevel() ||
@ -190,7 +190,7 @@ public:
protected:
bool check(const Mechanics * m, const battle::Unit * target) const override
{
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
TConstBonusListPtr levelImmunities = target->getBonuses(Selector::type()(Bonus::LEVEL_SPELL_IMMUNITY));
return levelImmunities->size() == 0 ||
levelImmunities->totalValue() < m->getSpellLevel() ||
m->getSpellLevel() <= 0;
@ -263,7 +263,7 @@ class ReceptiveFeatureCondition : public TargetConditionItemBase
public:
ReceptiveFeatureCondition()
{
selector = Selector::type(Bonus::RECEPTIVE);
selector = Selector::type()(Bonus::RECEPTIVE);
cachingString = "type_RECEPTIVE";
}

View File

@ -120,7 +120,7 @@ void Timed::describeEffect(std::vector<MetaString> & log, const Mechanics * m, c
{
if(bonus.val < 0)
{
BonusList unitHealth = *target->getBonuses(Selector::type(Bonus::STACK_HEALTH));
BonusList unitHealth = *target->getBonuses(Selector::type()(Bonus::STACK_HEALTH));
auto oldHealth = unitHealth.totalValue();
unitHealth.push_back(std::make_shared<Bonus>(bonus));

View File

@ -1016,7 +1016,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
applyBattleEffects(bat, attackerState, fireShield, stack, distance, true);
}
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type(Bonus::SPELL_LIKE_ATTACK));
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type()(Bonus::SPELL_LIKE_ATTACK));
if(bonus && ranged) //TODO: make it work in melee?
{
//this is need for displaying hit animation
@ -1883,7 +1883,7 @@ void CGameHandler::newTurn()
{
if (getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
getPlayerRelations(player.first, t->tempOwner) == PlayerRelations::ENEMIES)
changeFogOfWar(t->visitablePos(), t->getBonusLocalFirst(Selector::type(Bonus::DARKNESS))->val, player.first, true);
changeFogOfWar(t->visitablePos(), t->getBonusLocalFirst(Selector::type()(Bonus::DARKNESS))->val, player.first, true);
}
}
}
@ -4463,7 +4463,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
const CStack * summoner = gs->curB->battleGetStackByID(ba.stackNumber);
const CStack * destStack = gs->curB->battleGetStackByPos(target.at(0).hexValue, false);
CreatureID summonedType(summoner->getBonusLocalFirst(Selector::type(Bonus::DAEMON_SUMMONING))->subtype);//in case summoner can summon more than one type of monsters... scream!
CreatureID summonedType(summoner->getBonusLocalFirst(Selector::type()(Bonus::DAEMON_SUMMONING))->subtype);//in case summoner can summon more than one type of monsters... scream!
ui64 risedHp = summoner->getCount() * summoner->valOfBonuses(Bonus::DAEMON_SUMMONING, summonedType.toEnum());
ui64 targetHealth = destStack->getCreature()->MaxHealth() * destStack->baseAmount;
@ -4508,7 +4508,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
const CStack * stack = gs->curB->battleGetStackByID(ba.stackNumber);
SpellID spellID = SpellID(ba.actionSubtype);
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonusLocalFirst(Selector::type(Bonus::RANDOM_SPELLCASTER));
std::shared_ptr<const Bonus> randSpellcaster = stack->getBonusLocalFirst(Selector::type()(Bonus::RANDOM_SPELLCASTER));
std::shared_ptr<const Bonus> spellcaster = stack->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPELLCASTER, spellID));
//TODO special bonus for genies ability
@ -4669,7 +4669,7 @@ bool CGameHandler::makeCustomAction(BattleAction & ba)
void CGameHandler::stackEnchantedTrigger(const CStack * st)
{
auto bl = *(st->getBonuses(Selector::type(Bonus::ENCHANTED)));
auto bl = *(st->getBonuses(Selector::type()(Bonus::ENCHANTED)));
for(auto b : bl)
{
const CSpell * sp = SpellID(b->subtype).toSpell();
@ -4708,10 +4708,10 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
if (st->alive())
{
//unbind
if (st->hasBonus(Selector::type(Bonus::BIND_EFFECT)))
if (st->hasBonus(Selector::type()(Bonus::BIND_EFFECT)))
{
bool unbind = true;
BonusList bl = *(st->getBonuses(Selector::type(Bonus::BIND_EFFECT)));
BonusList bl = *(st->getBonuses(Selector::type()(Bonus::BIND_EFFECT)));
auto adjacent = gs->curB->battleAdjacentUnits(st);
for (auto b : bl)
@ -4754,7 +4754,7 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
if (st->hasBonusOfType(Bonus::POISON))
{
std::shared_ptr<const Bonus> b = st->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT, SpellID::POISON).And(Selector::type(Bonus::STACK_HEALTH)));
std::shared_ptr<const Bonus> b = st->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT, SpellID::POISON).And(Selector::type()(Bonus::STACK_HEALTH)));
if (b) //TODO: what if not?...
{
bte.val = std::max (b->val - 10, -(st->valOfBonuses(Bonus::POISON)));
@ -4802,7 +4802,7 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
}
}
}
BonusList bl = *(st->getBonuses(Selector::type(Bonus::ENCHANTER)));
BonusList bl = *(st->getBonuses(Selector::type()(Bonus::ENCHANTER)));
int side = gs->curB->whatSide(st->owner);
if(st->canCast() && gs->curB->battleGetEnchanterCounter(side) == 0)
{
@ -5428,7 +5428,7 @@ void CGameHandler::attackCasting(bool ranged, Bonus::BonusType attackMode, const
if(attacker->hasBonusOfType(attackMode))
{
std::set<SpellID> spellsToCast;
TConstBonusListPtr spells = attacker->getBonuses(Selector::type(attackMode));
TConstBonusListPtr spells = attacker->getBonuses(Selector::type()(attackMode));
for(const auto & sf : *spells)
{
spellsToCast.insert(SpellID(sf->subtype));
@ -5538,7 +5538,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
return;
int64_t acidDamage = 0;
TConstBonusListPtr acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
TConstBonusListPtr acidBreath = attacker->getBonuses(Selector::type()(Bonus::ACID_BREATH));
for(const auto & b : *acidBreath)
{
if(b->additionalInfo[0] > getRandomGenerator().nextInt(99))
@ -5569,7 +5569,7 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
if(getRandomGenerator().getDoubleRange(0, 1)() > chanceToTrigger)
return;
int bonusAdditionalInfo = attacker->getBonus(Selector::type(Bonus::TRANSMUTATION))->additionalInfo[0];
int bonusAdditionalInfo = attacker->getBonus(Selector::type()(Bonus::TRANSMUTATION))->additionalInfo[0];
if(defender->getCreature()->idNumber == bonusAdditionalInfo ||
(bonusAdditionalInfo == CAddInfo::NONE && defender->getCreature()->idNumber == attacker->getCreature()->idNumber))
@ -5611,13 +5611,13 @@ void CGameHandler::handleAfterAttackCasting(bool ranged, const CStack * attacker
if(attacker->hasBonusOfType(Bonus::DESTRUCTION, 0)) //killing by percentage
{
chanceToTrigger = attacker->valOfBonuses(Bonus::DESTRUCTION, 0) / 100.0f;
int percentageToDie = attacker->getBonus(Selector::type(Bonus::DESTRUCTION).And(Selector::subtype(0)))->additionalInfo[0];
int percentageToDie = attacker->getBonus(Selector::type()(Bonus::DESTRUCTION).And(Selector::subtype()(0)))->additionalInfo[0];
amountToDie = static_cast<int>(defender->getCount() * percentageToDie * 0.01f);
}
else if(attacker->hasBonusOfType(Bonus::DESTRUCTION, 1)) //killing by count
{
chanceToTrigger = attacker->valOfBonuses(Bonus::DESTRUCTION, 1) / 100.0f;
amountToDie = attacker->getBonus(Selector::type(Bonus::DESTRUCTION).And(Selector::subtype(1)))->additionalInfo[0];
amountToDie = attacker->getBonus(Selector::type()(Bonus::DESTRUCTION).And(Selector::subtype()(1)))->additionalInfo[0];
}
vstd::amin(chanceToTrigger, 1); //cap trigger chance at 100%
@ -5932,7 +5932,7 @@ void CGameHandler::runBattle()
{
if (stack->hasBonusOfType(Bonus::SUMMON_GUARDIANS))
{
std::shared_ptr<const Bonus> summonInfo = stack->getBonus(Selector::type(Bonus::SUMMON_GUARDIANS));
std::shared_ptr<const Bonus> summonInfo = stack->getBonus(Selector::type()(Bonus::SUMMON_GUARDIANS));
auto accessibility = getAccesibility();
CreatureID creatureData = CreatureID(summonInfo->subtype);
std::vector<BattleHex> targetHexes;
@ -5977,7 +5977,7 @@ void CGameHandler::runBattle()
auto h = gs->curB->battleGetFightingHero(i);
if (h)
{
TConstBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));
TConstBonusListPtr bl = h->getBonuses(Selector::type()(Bonus::OPENING_BATTLE_SPELL));
for (auto b : *bl)
{