2023-04-30 14:31:20 +03:00
|
|
|
/*
|
2023-04-30 16:52:48 +03:00
|
|
|
* Updaters.cpp, part of VCMI engine
|
2023-04-30 14:31:20 +03:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "StdInc.h"
|
|
|
|
|
2023-04-30 16:52:48 +03:00
|
|
|
#include "Updaters.h"
|
|
|
|
#include "Limiters.h"
|
2024-02-13 13:18:10 +02:00
|
|
|
#include "../json/JsonNode.h"
|
2023-04-30 14:31:20 +03:00
|
|
|
#include "../mapObjects/CGHeroInstance.h"
|
|
|
|
#include "../CStack.h"
|
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
2025-03-28 23:06:03 +08:00
|
|
|
std::shared_ptr<Bonus> IUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string IUpdater::toString() const
|
|
|
|
{
|
|
|
|
return typeid(*this).name();
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonNode IUpdater::toJsonNode() const
|
|
|
|
{
|
2024-02-13 13:18:10 +02:00
|
|
|
return JsonNode();
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
2025-03-28 23:06:03 +08:00
|
|
|
void IUpdater::visitLimiter(AggregateLimiter& limiter)
|
|
|
|
{
|
|
|
|
for (auto& limit : limiter.limiters)
|
|
|
|
limit->acceptUpdater(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IUpdater::visitLimiter(CCreatureTypeLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(HasAnotherBonusLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(CreatureTerrainLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(CreatureLevelLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(FactionLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(CreatureAlignmentLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(OppositeSideLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(RankRangeLimiter& limiter) {}
|
|
|
|
void IUpdater::visitLimiter(UnitOnHexLimiter& limiter) {}
|
|
|
|
|
2023-04-30 14:31:20 +03:00
|
|
|
GrowsWithLevelUpdater::GrowsWithLevelUpdater(int valPer20, int stepSize) : valPer20(valPer20), stepSize(stepSize)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2025-03-28 23:06:03 +08:00
|
|
|
std::shared_ptr<Bonus> GrowsWithLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
|
|
|
if(context.getNodeType() == CBonusSystemNode::HERO)
|
|
|
|
{
|
|
|
|
int level = dynamic_cast<const CGHeroInstance &>(context).level;
|
|
|
|
int steps = stepSize ? level / stepSize : level;
|
|
|
|
//rounding follows format for HMM3 creature specialty bonus
|
|
|
|
int newVal = (valPer20 * steps + 19) / 20;
|
|
|
|
//return copy of bonus with updated val
|
2024-01-17 12:50:00 +00:00
|
|
|
auto newBonus = std::make_shared<Bonus>(*b);
|
2023-04-30 14:31:20 +03:00
|
|
|
newBonus->val = newVal;
|
|
|
|
return newBonus;
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GrowsWithLevelUpdater::toString() const
|
|
|
|
{
|
|
|
|
return boost::str(boost::format("GrowsWithLevelUpdater(valPer20=%d, stepSize=%d)") % valPer20 % stepSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonNode GrowsWithLevelUpdater::toJsonNode() const
|
|
|
|
{
|
2024-02-13 13:18:10 +02:00
|
|
|
JsonNode root;
|
2023-04-30 14:31:20 +03:00
|
|
|
|
|
|
|
root["type"].String() = "GROWS_WITH_LEVEL";
|
2024-02-13 13:18:10 +02:00
|
|
|
root["parameters"].Vector().emplace_back(valPer20);
|
2023-04-30 14:31:20 +03:00
|
|
|
if(stepSize > 1)
|
2024-02-13 13:18:10 +02:00
|
|
|
root["parameters"].Vector().emplace_back(stepSize);
|
2023-04-30 14:31:20 +03:00
|
|
|
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
2025-03-28 23:06:03 +08:00
|
|
|
std::shared_ptr<Bonus> TimesHeroLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
|
|
|
if(context.getNodeType() == CBonusSystemNode::HERO)
|
|
|
|
{
|
|
|
|
int level = dynamic_cast<const CGHeroInstance &>(context).level;
|
2024-01-17 12:50:00 +00:00
|
|
|
auto newBonus = std::make_shared<Bonus>(*b);
|
2023-04-30 14:31:20 +03:00
|
|
|
newBonus->val *= level;
|
|
|
|
return newBonus;
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string TimesHeroLevelUpdater::toString() const
|
|
|
|
{
|
|
|
|
return "TimesHeroLevelUpdater";
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonNode TimesHeroLevelUpdater::toJsonNode() const
|
|
|
|
{
|
2024-02-13 13:18:10 +02:00
|
|
|
return JsonNode("TIMES_HERO_LEVEL");
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
std::shared_ptr<Bonus> TimesHeroLevelDivideStackLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
if(context.getNodeType() == CBonusSystemNode::HERO)
|
|
|
|
{
|
|
|
|
auto newBonus = TimesHeroLevelUpdater::createUpdatedBonus(b, context);
|
|
|
|
newBonus->updater = divideStackLevel;
|
|
|
|
return newBonus;
|
|
|
|
}
|
|
|
|
return b;
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
std::string TimesHeroLevelDivideStackLevelUpdater::toString() const
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
return "TimesHeroLevelDivideStackLevelUpdater";
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
JsonNode TimesHeroLevelDivideStackLevelUpdater::toJsonNode() const
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
return JsonNode("TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL");
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
std::shared_ptr<Bonus> TimesStackLevelUpdater::apply(const std::shared_ptr<Bonus> & b, int level) const
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
auto newBonus = std::make_shared<Bonus>(*b);
|
|
|
|
newBonus->val *= level;
|
|
|
|
newBonus->updater = nullptr; // prevent double-apply
|
|
|
|
return newBonus;
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
2025-03-28 23:06:03 +08:00
|
|
|
std::shared_ptr<Bonus> TimesStackLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
2024-09-09 19:03:56 +08:00
|
|
|
if(context.getNodeType() == CBonusSystemNode::STACK_INSTANCE || context.getNodeType() == CBonusSystemNode::COMMANDER)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
|
|
|
int level = dynamic_cast<const CStackInstance &>(context).getLevel();
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
return apply(b, level);
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
|
|
|
|
if(context.getNodeType() == CBonusSystemNode::STACK_BATTLE)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
|
|
|
const auto & stack = dynamic_cast<const CStack &>(context);
|
2024-09-09 19:03:56 +08:00
|
|
|
//update if stack doesn't have an instance (summons, war machines)
|
2023-04-30 14:31:20 +03:00
|
|
|
if(stack.base == nullptr)
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
return apply(b, stack.unitType()->getLevel());
|
|
|
|
|
2024-09-09 19:03:56 +08:00
|
|
|
// If these are not handled here, the final outcome may potentially be incorrect.
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
int level = dynamic_cast<const CStackInstance*>(stack.base)->getLevel();
|
|
|
|
return apply(b, level);
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string TimesStackLevelUpdater::toString() const
|
|
|
|
{
|
|
|
|
return "TimesStackLevelUpdater";
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonNode TimesStackLevelUpdater::toJsonNode() const
|
|
|
|
{
|
2024-02-13 13:18:10 +02:00
|
|
|
return JsonNode("TIMES_STACK_LEVEL");
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
Better support for Adela specialty (+new modding functionality for it)
Fixes Adela specialty that was apparently broken back in #1518 and
replaced with logic that was clearly not tested - it was neither
functional, nor it was following H3 behavior.
- `HAS_ANOTHER_BONUS_LIMITER` now accepts `null` in place of bonus type,
for cases when limiting is needed by bonus source or bonus subtype. This
allows Adela Bless specialty to always work, irregardless of which
bonuses are provided by Bless.
- Implemented `DIVIDE_STACK_LEVEL` updater that functions same as
`TIMES_STACK_LEVEL`, but it divides bonus value, instead of multiplying
it (to make Adela specialty weaker for high-tier units, as in H3)
- Implemented `TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL` updater that
combines two existing updaters, to implement `val * heroLevel /
unitLevel` formula needed for Adela specialty
- Removed deprecated `ARMY_MOVEMENT` updater. Its functionality has
already been removed in 1.6.X releases, and it was remaining only as a
placeholder
- Updated modding documentation to account for these changes & to remove
some TODO's
Fixed regression from #777 that could led to either duplicated bonuses
or to multiple application of updaters. It introduced double-recursion -
node parents were gathered recursively, and then bonuses were also
collected recursively within each parent. This created situation where
updater could be applied different number of times. For example, hero
bonus that is propagated to unit in combat could be selected directly,
or via hero->combat unit chain, or via hero->garrison unit->combat unit
chains, leading to different calls to updaters if updater handles
garrison unit node type
2025-04-11 15:04:30 +03:00
|
|
|
std::shared_ptr<Bonus> DivideStackLevelUpdater::apply(const std::shared_ptr<Bonus> & b, int level) const
|
|
|
|
{
|
|
|
|
auto newBonus = std::make_shared<Bonus>(*b);
|
|
|
|
newBonus->val /= level;
|
|
|
|
newBonus->updater = nullptr; // prevent double-apply
|
|
|
|
return newBonus;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<Bonus> DivideStackLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
|
|
|
{
|
|
|
|
if(context.getNodeType() == CBonusSystemNode::STACK_INSTANCE || context.getNodeType() == CBonusSystemNode::COMMANDER)
|
|
|
|
{
|
|
|
|
int level = dynamic_cast<const CStackInstance &>(context).getLevel();
|
|
|
|
return apply(b, level);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(context.getNodeType() == CBonusSystemNode::STACK_BATTLE)
|
|
|
|
{
|
|
|
|
const auto & stack = dynamic_cast<const CStack &>(context);
|
|
|
|
//update if stack doesn't have an instance (summons, war machines)
|
|
|
|
if(stack.base == nullptr)
|
|
|
|
return apply(b, stack.unitType()->getLevel());
|
|
|
|
|
|
|
|
// If these are not handled here, the final outcome may potentially be incorrect.
|
|
|
|
int level = dynamic_cast<const CStackInstance*>(stack.base)->getLevel();
|
|
|
|
return apply(b, level);
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string DivideStackLevelUpdater::toString() const
|
|
|
|
{
|
|
|
|
return "DivideStackLevelUpdater";
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonNode DivideStackLevelUpdater::toJsonNode() const
|
|
|
|
{
|
|
|
|
return JsonNode("DIVIDE_STACK_LEVEL");
|
|
|
|
}
|
|
|
|
|
2023-04-30 14:31:20 +03:00
|
|
|
std::string OwnerUpdater::toString() const
|
|
|
|
{
|
|
|
|
return "OwnerUpdater";
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonNode OwnerUpdater::toJsonNode() const
|
|
|
|
{
|
2024-02-13 13:18:10 +02:00
|
|
|
return JsonNode("BONUS_OWNER_UPDATER");
|
2023-04-30 14:31:20 +03:00
|
|
|
}
|
|
|
|
|
2025-03-28 23:06:03 +08:00
|
|
|
std::shared_ptr<Bonus> OwnerUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
2023-04-30 14:31:20 +03:00
|
|
|
{
|
2025-03-28 23:06:03 +08:00
|
|
|
owner = context.getOwner();
|
|
|
|
|
2023-04-30 14:31:20 +03:00
|
|
|
if(owner == PlayerColor::UNFLAGGABLE)
|
|
|
|
owner = PlayerColor::NEUTRAL;
|
|
|
|
|
|
|
|
std::shared_ptr<Bonus> updated =
|
2024-07-08 20:57:14 +00:00
|
|
|
std::make_shared<Bonus>(*b);
|
2025-03-28 23:06:03 +08:00
|
|
|
updated->limiter = b->limiter;
|
2025-04-26 02:15:25 +08:00
|
|
|
if (updated->limiter)
|
|
|
|
updated->limiter->acceptUpdater(*this);
|
2023-04-30 14:31:20 +03:00
|
|
|
return updated;
|
|
|
|
}
|
|
|
|
|
2025-03-28 23:06:03 +08:00
|
|
|
void OwnerUpdater::visitLimiter(OppositeSideLimiter& limiter)
|
|
|
|
{
|
|
|
|
limiter.owner = owner;
|
|
|
|
}
|
|
|
|
|
2024-02-11 23:09:01 +02:00
|
|
|
VCMI_LIB_NAMESPACE_END
|