1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

vcmi: morale and luck now also IFactionMember

Not all bonus bearers have morale and luck, only faction members
This commit is contained in:
Konstantin 2023-04-30 15:04:54 +03:00
parent e37f798a68
commit a2d4c72016
6 changed files with 74 additions and 89 deletions

View File

@ -372,7 +372,7 @@ CTownTooltip::CTownTooltip(Point pos, const CGTownInstance * town)
init(InfoAboutTown(town, true));
}
void MoraleLuckBox::set(const IBonusBearer * node)
void MoraleLuckBox::set(const IFactionMember * node)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
@ -393,21 +393,21 @@ void MoraleLuckBox::set(const IBonusBearer * node)
text = CGI->generaltexth->arraytxt[textId[morale]];
boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
if (morale && node && (node->hasBonusOfType(Bonus::UNDEAD)
|| node->hasBonusOfType(Bonus::NON_LIVING)))
if (morale && node && (node->getBonusBearer()->hasBonusOfType(Bonus::UNDEAD)
|| node->getBonusBearer()->hasBonusOfType(Bonus::NON_LIVING)))
{
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
bonusValue = 0;
}
else if(morale && node && node->hasBonusOfType(Bonus::NO_MORALE))
else if(morale && node && node->getBonusBearer()->hasBonusOfType(Bonus::NO_MORALE))
{
auto noMorale = node->getBonus(Selector::type()(Bonus::NO_MORALE));
auto noMorale = node->getBonusBearer()->getBonus(Selector::type()(Bonus::NO_MORALE));
text += "\n" + noMorale->Description();
bonusValue = 0;
}
else if (!morale && node && node->hasBonusOfType(Bonus::NO_LUCK))
else if (!morale && node && node->getBonusBearer()->hasBonusOfType(Bonus::NO_LUCK))
{
auto noLuck = node->getBonus(Selector::type()(Bonus::NO_LUCK));
auto noLuck = node->getBonusBearer()->getBonus(Selector::type()(Bonus::NO_LUCK));
text += "\n" + noLuck->Description();
bonusValue = 0;
}

View File

@ -16,7 +16,7 @@ VCMI_LIB_NAMESPACE_BEGIN
class CGGarrison;
struct InfoAboutArmy;
class CArmedInstance;
class IBonusBearer;
class IFactionMember;
VCMI_LIB_NAMESPACE_END
@ -170,7 +170,7 @@ public:
bool morale; //true if morale, false if luck
bool small;
void set(const IBonusBearer *node);
void set(const IFactionMember *node);
MoraleLuckBox(bool Morale, const Rect &r, bool Small=false);
};

View File

@ -14,6 +14,8 @@
VCMI_LIB_NAMESPACE_BEGIN
class BonusList;
namespace PrimarySkill
{
enum PrimarySkill : int8_t;
@ -50,6 +52,18 @@ public:
Returns primskill of creature or hero.
*/
int getPrimSkillLevel(PrimarySkill::PrimarySkill id) const;
/**
Returns morale or luck of creature or hero.
*/
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(std::shared_ptr<const BonusList> & bonusList) const;
int LuckValAndBonusList(std::shared_ptr<const BonusList> & bonusList) const;
};
VCMI_LIB_NAMESPACE_END

View File

@ -88,6 +88,55 @@ int IFactionMember::getPrimSkillLevel(PrimarySkill::PrimarySkill id) const
return std::max(ret, minSkillValue); //otherwise, some artifacts may cause negative skill value effect, sp=0 works in old saves
}
int IFactionMember::MoraleValAndBonusList(TConstBonusListPtr & bonusList) const
{
static const auto unaffectedByMoraleSelector = Selector::type()(Bonus::NON_LIVING).Or(Selector::type()(Bonus::UNDEAD))
.Or(Selector::type()(Bonus::SIEGE_WEAPON)).Or(Selector::type()(Bonus::NO_MORALE));
static const std::string cachingStrUn = "IFactionMember::unaffectedByMoraleSelector";
auto unaffected = getBonusBearer()->hasBonus(unaffectedByMoraleSelector, cachingStrUn);
if(unaffected)
{
if(bonusList && !bonusList->empty())
bonusList = std::make_shared<const BonusList>();
return 0;
}
static const auto moraleSelector = Selector::type()(Bonus::MORALE);
static const std::string cachingStrMor = "type_MORALE";
bonusList = getBonusBearer()->getBonuses(moraleSelector, cachingStrMor);
return std::clamp(bonusList->totalValue(), -3, +3);
}
int IFactionMember::LuckValAndBonusList(TConstBonusListPtr & bonusList) const
{
if(getBonusBearer()->hasBonusOfType(Bonus::NO_LUCK))
{
if(bonusList && !bonusList->empty())
bonusList = std::make_shared<const BonusList>();
return 0;
}
static const auto luckSelector = Selector::type()(Bonus::LUCK);
static const std::string cachingStrLuck = "type_LUCK";
bonusList = getBonusBearer()->getBonuses(luckSelector, cachingStrLuck);
return std::clamp(bonusList->totalValue(), -3, +3);
}
int IFactionMember::MoraleVal() const
{
TConstBonusListPtr tmp = nullptr;
return MoraleValAndBonusList(tmp);
}
int IFactionMember::LuckVal() const
{
TConstBonusListPtr tmp = nullptr;
return LuckValAndBonusList(tmp);
}
ui32 ICreature::MaxHealth() const
{
const std::string cachingStr = "type_STACK_HEALTH";
@ -114,7 +163,7 @@ ui32 ICreature::Speed(int turn, bool useBind) const
bool ICreature::isLiving() const //TODO: theoreticaly there exists "LIVING" bonus in stack experience documentation
{
static const std::string cachingStr = "IBonusBearer::isLiving";
static const std::string cachingStr = "ICreature::isLiving";
static const CSelector selector = Selector::type()(Bonus::UNDEAD)
.Or(Selector::type()(Bonus::NON_LIVING))
.Or(Selector::type()(Bonus::GARGOYLE))

View File

@ -606,22 +606,6 @@ void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusLi
changed();
}
CSelector IBonusBearer::anaffectedByMoraleSelector =
Selector::type()(Bonus::NON_LIVING)
.Or(Selector::type()(Bonus::UNDEAD))
.Or(Selector::type()(Bonus::SIEGE_WEAPON))
.Or(Selector::type()(Bonus::NO_MORALE));
CSelector IBonusBearer::moraleSelector = Selector::type()(Bonus::MORALE);
CSelector IBonusBearer::luckSelector = Selector::type()(Bonus::LUCK);
IBonusBearer::IBonusBearer()
:anaffectedByMorale(this, anaffectedByMoraleSelector),
moraleValue(this, moraleSelector, 0),
luckValue(this, luckSelector, 0)
{
}
int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
{
return valOfBonuses(Selector::type()(type).And(selector));
@ -685,47 +669,6 @@ bool IBonusBearer::hasBonusFrom(Bonus::BonusSource source, ui32 sourceID) const
return hasBonus(Selector::source(source,sourceID), fmt.str());
}
int IBonusBearer::MoraleVal() const
{
if(anaffectedByMorale.getHasBonus())
return 0;
return std::clamp(moraleValue.getValue(), -3, +3);
}
int IBonusBearer::LuckVal() const
{
if(hasBonusOfType(Bonus::NO_LUCK))
return 0;
return std::clamp(luckValue.getValue(), -3, +3);
}
int IBonusBearer::MoraleValAndBonusList(TConstBonusListPtr & bonusList) const
{
if(anaffectedByMorale.getHasBonus())
{
if(!bonusList->empty())
bonusList = std::make_shared<const BonusList>();
return 0;
}
return std::clamp(moraleValue.getValueAndList(bonusList), -3, +3);
}
int IBonusBearer::LuckValAndBonusList(TConstBonusListPtr & bonusList) const
{
if(hasBonusOfType(Bonus::NO_LUCK))
{
if(!bonusList->empty())
bonusList = std::make_shared<const BonusList>();
return 0;
}
return std::clamp(luckValue.getValueAndList(bonusList), -3, +3);
}
std::shared_ptr<const Bonus> IBonusBearer::getBonus(const CSelector &selector) const
{
auto bonuses = getAllBonuses(selector, Selector::all);

View File

@ -663,20 +663,12 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusL
class DLL_LINKAGE IBonusBearer
{
private:
static CSelector anaffectedByMoraleSelector;
CCheckProxy anaffectedByMorale;
static CSelector moraleSelector;
CTotalsProxy moraleValue;
static CSelector luckSelector;
CTotalsProxy luckValue;
public:
//new bonusing node interface
// * selector is predicate that tests if HeroBonus matches our criteria
// * root is node on which call was made (nullptr will be replaced with this)
//interface
IBonusBearer();
IBonusBearer() = default;
virtual ~IBonusBearer() = default;
virtual TConstBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr, const std::string &cachingStr = "") const = 0;
int valOfBonuses(const CSelector &selector, const std::string &cachingStr = "") const;
@ -693,19 +685,6 @@ public:
bool hasBonusOfType(Bonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype)
bool hasBonusFrom(Bonus::BonusSource source, ui32 sourceID) const;
//various hlp functions for non-trivial values
//used for stacks and creatures only
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;
virtual int64_t getTreeVersion() const = 0;
};