mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-23 00:28:08 +02:00
Feature: Town Negative Bonuses. Fix: Negative bonus bearers should not be affected
This commit is contained in:
@ -404,18 +404,22 @@ void MoraleLuckBox::set(const IBonusBearer * node)
|
|||||||
text += "\n" + noLuck->Description();
|
text += "\n" + noLuck->Description();
|
||||||
bonusValue = 0;
|
bonusValue = 0;
|
||||||
}
|
}
|
||||||
else if(modifierList->empty())
|
|
||||||
text += CGI->generaltexth->arraytxt[noneTxtId];//no modifiers
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(auto& elem : *modifierList)
|
bool isListActual = false;
|
||||||
{
|
std::string addInfo = "";
|
||||||
if(elem->val != 0)
|
|
||||||
//no bonuses with value 0
|
|
||||||
text += "\n" + elem->Description();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for(auto & bonus : * modifierList)
|
||||||
|
{
|
||||||
|
if(bonus->val && bonus->effectRange != Bonus::ONLY_ENEMY_ARMY)
|
||||||
|
{
|
||||||
|
addInfo += "\n" + bonus->Description();
|
||||||
|
isListActual = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text = isListActual ? text + addInfo
|
||||||
|
: text + CGI->generaltexth->arraytxt[noneTxtId];//no modifiers
|
||||||
|
}
|
||||||
std::string imageName;
|
std::string imageName;
|
||||||
if (small)
|
if (small)
|
||||||
imageName = morale ? "IMRL30": "ILCK30";
|
imageName = morale ? "IMRL30": "ILCK30";
|
||||||
|
@ -428,6 +428,9 @@ int BonusList::totalValue() const
|
|||||||
|
|
||||||
for(std::shared_ptr<Bonus> b : bonuses)
|
for(std::shared_ptr<Bonus> b : bonuses)
|
||||||
{
|
{
|
||||||
|
if(b->effectRange == Bonus::ONLY_ENEMY_ARMY)
|
||||||
|
continue;
|
||||||
|
|
||||||
switch(b->valType)
|
switch(b->valType)
|
||||||
{
|
{
|
||||||
case Bonus::BASE_NUMBER:
|
case Bonus::BASE_NUMBER:
|
||||||
@ -452,7 +455,6 @@ int BonusList::totalValue() const
|
|||||||
{
|
{
|
||||||
vstd::amax(indepMax, b->val);
|
vstd::amax(indepMax, b->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Bonus::INDEPENDENT_MIN:
|
case Bonus::INDEPENDENT_MIN:
|
||||||
if (!hasIndepMin)
|
if (!hasIndepMin)
|
||||||
@ -464,7 +466,6 @@ int BonusList::totalValue() const
|
|||||||
{
|
{
|
||||||
vstd::amin(indepMin, b->val);
|
vstd::amin(indepMin, b->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,11 +596,14 @@ void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusLi
|
|||||||
changed();
|
changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSelector IBonusBearer::anaffectedByMoraleSelector
|
CSelector IBonusBearer::anaffectedByMoraleSelector =
|
||||||
= Selector::type()(Bonus::NON_LIVING)
|
Selector::type()(Bonus::NON_LIVING)
|
||||||
.Or(Selector::type()(Bonus::UNDEAD))
|
.Or(Selector::type()(Bonus::UNDEAD))
|
||||||
.Or(Selector::type()(Bonus::NO_MORALE))
|
.Or(Selector::type()(Bonus::SIEGE_WEAPON))
|
||||||
.Or(Selector::type()(Bonus::SIEGE_WEAPON));
|
.Or(Selector::effectRange()(Bonus::ONLY_ENEMY_ARMY).Not()
|
||||||
|
.And(Selector::type()(Bonus::NO_MORALE)
|
||||||
|
.Or(Selector::type()(Bonus::BLOCK_MORALE))
|
||||||
|
));
|
||||||
|
|
||||||
CSelector IBonusBearer::moraleSelector = Selector::type()(Bonus::MORALE);
|
CSelector IBonusBearer::moraleSelector = Selector::type()(Bonus::MORALE);
|
||||||
CSelector IBonusBearer::luckSelector = Selector::type()(Bonus::LUCK);
|
CSelector IBonusBearer::luckSelector = Selector::type()(Bonus::LUCK);
|
||||||
|
@ -56,6 +56,11 @@ public:
|
|||||||
auto thisCopy = *this;
|
auto thisCopy = *this;
|
||||||
return [thisCopy, rhs](const Bonus *b) mutable { return thisCopy(b) || rhs(b); };
|
return [thisCopy, rhs](const Bonus *b) mutable { return thisCopy(b) || rhs(b); };
|
||||||
}
|
}
|
||||||
|
CSelector Not() const
|
||||||
|
{
|
||||||
|
auto thisCopy = *this;
|
||||||
|
return [thisCopy](const Bonus *b) mutable { return !thisCopy(b); };
|
||||||
|
}
|
||||||
|
|
||||||
bool operator()(const Bonus *b) const
|
bool operator()(const Bonus *b) const
|
||||||
{
|
{
|
||||||
|
@ -186,6 +186,45 @@ struct RangeGenerator
|
|||||||
std::function<int()> myRand;
|
std::function<int()> myRand;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void BattleInfo::addOnlyEnemyArmyBonuses(const BonusList & bonusList, BattleInfo * curB, BattleInfo::BattleSide side)
|
||||||
|
{
|
||||||
|
for(auto b : bonusList)
|
||||||
|
{
|
||||||
|
if(b->effectRange != Bonus::ONLY_ENEMY_ARMY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto bCopy = std::make_shared<Bonus>(*b);
|
||||||
|
bCopy->effectRange = Bonus::NO_LIMIT;
|
||||||
|
bCopy->propagator.reset();
|
||||||
|
bCopy->limiter.reset(new StackOwnerLimiter(curB->sides[side].color));
|
||||||
|
curB->addNewBonus(bCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleInfo::setupBonusesFromTown(const CGTownInstance * town, BattleInfo * curB)
|
||||||
|
{
|
||||||
|
assert(town);
|
||||||
|
for(auto building : town->builtBuildings)
|
||||||
|
{
|
||||||
|
const auto & bonuses = town->town->buildings.at(building)->buildingBonuses;
|
||||||
|
addOnlyEnemyArmyBonuses(bonuses, curB, BattleInfo::ATTACKER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleInfo::setupBonusesFromUnits(BattleInfo * curB)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
TNodes nodes;
|
||||||
|
curB->battleGetArmyObject(i)->getRedAncestors(nodes);
|
||||||
|
for(CBonusSystemNode * n : nodes)
|
||||||
|
{
|
||||||
|
const auto & bonuses = n->getExportedBonusList();
|
||||||
|
addOnlyEnemyArmyBonuses(bonuses, curB, (BattleInfo::BattleSide)!i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town)
|
BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town)
|
||||||
{
|
{
|
||||||
CMP_stack cmpst;
|
CMP_stack cmpst;
|
||||||
@ -528,7 +567,7 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
|
|||||||
//overlay premies given
|
//overlay premies given
|
||||||
|
|
||||||
//native terrain bonuses
|
//native terrain bonuses
|
||||||
auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
|
static auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();
|
||||||
|
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::STACKS_SPEED, Bonus::TERRAIN_NATIVE, 1, 0, 0)->addLimiter(nativeTerrain));
|
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::STACKS_SPEED, Bonus::TERRAIN_NATIVE, 1, 0, 0)->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::TERRAIN_NATIVE, 1, 0, PrimarySkill::ATTACK)->addLimiter(nativeTerrain));
|
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::TERRAIN_NATIVE, 1, 0, PrimarySkill::ATTACK)->addLimiter(nativeTerrain));
|
||||||
@ -555,31 +594,13 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
|
|||||||
else
|
else
|
||||||
curB->tacticDistance = 0;
|
curB->tacticDistance = 0;
|
||||||
|
|
||||||
|
if(town)
|
||||||
// workaround bonuses affecting only enemy - DOES NOT WORK
|
setupBonusesFromTown(town, curB);
|
||||||
for(int i = 0; i < 2; i++)
|
setupBonusesFromUnits(curB);
|
||||||
{
|
|
||||||
TNodes nodes;
|
|
||||||
curB->battleGetArmyObject(i)->getRedAncestors(nodes);
|
|
||||||
for(CBonusSystemNode *n : nodes)
|
|
||||||
{
|
|
||||||
for(auto b : n->getExportedBonusList())
|
|
||||||
{
|
|
||||||
if(b->effectRange == Bonus::ONLY_ENEMY_ARMY/* && b->propagator && b->propagator->shouldBeAttached(curB)*/)
|
|
||||||
{
|
|
||||||
auto bCopy = std::make_shared<Bonus>(*b);
|
|
||||||
bCopy->effectRange = Bonus::NO_LIMIT;
|
|
||||||
bCopy->propagator.reset();
|
|
||||||
bCopy->limiter.reset(new StackOwnerLimiter(curB->sides[!i].color));
|
|
||||||
curB->addNewBonus(bCopy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return curB;
|
return curB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const CGHeroInstance * BattleInfo::getHero(PlayerColor player) const
|
const CGHeroInstance * BattleInfo::getHero(PlayerColor player) const
|
||||||
{
|
{
|
||||||
for(int i = 0; i < sides.size(); i++)
|
for(int i = 0; i < sides.size(); i++)
|
||||||
|
@ -22,6 +22,11 @@ class CStackBasicDescriptor;
|
|||||||
class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState
|
class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum BattleSide
|
||||||
|
{
|
||||||
|
ATTACKER = 0,
|
||||||
|
DEFENDER
|
||||||
|
};
|
||||||
std::array<SideInBattle, 2> sides; //sides[0] - attacker, sides[1] - defender
|
std::array<SideInBattle, 2> sides; //sides[0] - attacker, sides[1] - defender
|
||||||
si32 round, activeStack;
|
si32 round, activeStack;
|
||||||
const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
|
const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
|
||||||
@ -133,6 +138,8 @@ public:
|
|||||||
|
|
||||||
void localInit();
|
void localInit();
|
||||||
|
|
||||||
|
static void setupBonusesFromTown(const CGTownInstance * town, BattleInfo * curB); //besieged city may contain buildings with negative bonuses for enemy army.
|
||||||
|
static void setupBonusesFromUnits(BattleInfo * curB); //besieged city may contain buildings with negative bonuses for enemy army.
|
||||||
static BattleInfo * setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
|
static BattleInfo * setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
|
||||||
|
|
||||||
ui8 whatSide(PlayerColor player) const;
|
ui8 whatSide(PlayerColor player) const;
|
||||||
@ -141,6 +148,9 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
scripting::Pool * getContextPool() const override;
|
scripting::Pool * getContextPool() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void addOnlyEnemyArmyBonuses(const BonusList & bonusList, BattleInfo * curB, BattleInfo::BattleSide side);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1265,6 +1265,8 @@ void CGTownInstance::recreateBuildingsBonuses()
|
|||||||
|
|
||||||
for(auto bonus : building->buildingBonuses)
|
for(auto bonus : building->buildingBonuses)
|
||||||
{
|
{
|
||||||
|
if(bonus->effectRange == Bonus::ONLY_ENEMY_ARMY) //will be added in the 'setupBattle' to Battle node.
|
||||||
|
continue;
|
||||||
if(bonus->propagator != nullptr && bonus->propagator->getPropagatorType() == ALL_CREATURES)
|
if(bonus->propagator != nullptr && bonus->propagator->getPropagatorType() == ALL_CREATURES)
|
||||||
VLC->creh->addBonusForAllCreatures(bonus);
|
VLC->creh->addBonusForAllCreatures(bonus);
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user