mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
Merge pull request #5620 from IvanSavenko/adela_fix
Better support for Adela specialty (+new modding functionality for it)
This commit is contained in:
@@ -182,7 +182,7 @@
|
||||
{
|
||||
"type" : "HAS_ANOTHER_BONUS_LIMITER",
|
||||
"parameters" : [
|
||||
"GENERAL_DAMAGE_PREMY",
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"type" : "SPELL_EFFECT",
|
||||
@@ -191,7 +191,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"updater" : "TIMES_HERO_LEVEL",
|
||||
"updater" : "TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL",
|
||||
"val" : 3
|
||||
}
|
||||
}
|
||||
|
@@ -72,7 +72,7 @@
|
||||
"anyOf" : [
|
||||
{
|
||||
"type" : "string",
|
||||
"enum" : [ "TIMES_HERO_LEVEL", "TIMES_STACK_LEVEL", "ARMY_MOVEMENT", "BONUS_OWNER_UPDATER" ]
|
||||
"enum" : [ "TIMES_HERO_LEVEL", "TIMES_STACK_LEVEL", "DIVIDE_STACK_LEVEL", "BONUS_OWNER_UPDATER", "TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL" ]
|
||||
},
|
||||
{
|
||||
"description" : "updater",
|
||||
@@ -82,7 +82,7 @@
|
||||
"properties" : {
|
||||
"type" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "GROWS_WITH_LEVEL", "ARMY_MOVEMENT" ],
|
||||
"enum" : [ "GROWS_WITH_LEVEL" ],
|
||||
"description" : "type"
|
||||
},
|
||||
"parameters" : {
|
||||
|
@@ -63,20 +63,27 @@ Usage:
|
||||
|
||||
Remark: The stack level for war machines is 0.
|
||||
|
||||
## ARMY_MOVEMENT
|
||||
## DIVIDE_STACK_LEVEL
|
||||
|
||||
- Type: Complex
|
||||
- Parameters: basePerSpeed, dividePerSpeed, additionalMultiplier, maxValue
|
||||
- Effect: Updates val to `val+= max((floor(basePerSpeed / dividePerSpeed) * additionalMultiplier), maxValue)`
|
||||
- Remark: this updater is designed for MOVEMENT bonus to match H3 army movement rules (in the example - actual movement updater, which produces values same as in default movement.txt).
|
||||
- Example:
|
||||
- Type: Simple
|
||||
- Effect: Updates val to `val / stackLevel`
|
||||
|
||||
```json
|
||||
"updater" : {
|
||||
"parameters" : [ 20, 3, 10, 700 ],
|
||||
"type" : "ARMY_MOVEMENT"
|
||||
}
|
||||
```
|
||||
Usage:
|
||||
|
||||
`"updater" : "DIVIDE_STACK_LEVEL"`
|
||||
|
||||
Remark: The stack level for war machines is 0.
|
||||
|
||||
## TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL
|
||||
|
||||
- Type: Simple
|
||||
- Effect: Same effect as `TIMES_HERO_LEVEL` combined with `DIVIDE_STACK_LEVEL`: `val * heroLevel / stackLevel`
|
||||
|
||||
Intended to be used as hero bonus (such as specialty, skill, or artifact), for bonuses that affect units (Example: Adela Bless specialty)
|
||||
|
||||
Usage:
|
||||
|
||||
`"updater" : "TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL"`
|
||||
|
||||
## BONUS_OWNER_UPDATER
|
||||
|
||||
|
@@ -40,25 +40,39 @@ All parameters but type are optional.
|
||||
// TODO
|
||||
"effectRange" : "EFFECT_RANGE",
|
||||
|
||||
// TODO
|
||||
// This sections allows to define 'limiter', which allows to limit bonus and only apply it under specific conditions
|
||||
// Typical conditions are "affect only specific creature", or "affect only if target has another, specific bonus"
|
||||
// See Bonus Limiters list below for full list of supported limiters
|
||||
"limiters" : [
|
||||
"PREDEFINED_LIMITER", optional_parameters (...), //whhich one is preferred?
|
||||
{"type" : LIMITER_TYPE, "parameters" : [1,2,3]}
|
||||
],
|
||||
|
||||
// TODO
|
||||
// Normally, only entities that are located "below" bonus source are affected by the bonus
|
||||
// For example, bonus on creature will only affect creature itself,
|
||||
// bonus on hero will affect hero itself and all its units, and player bonus will affect all objects owned by player
|
||||
// Propagator allows bonus to affect "upwards" entities.
|
||||
// For example, creature that has bonus with battle-wide propagator will affect all units in combat, and not just unit itself
|
||||
// See Bonus Propagators list below for full list of supported propagators
|
||||
"propagator" : ["PROPAGATOR_TYPE", optional_parameters (...)],
|
||||
|
||||
// TODO
|
||||
// Updaters allow to modify bonus depending on context.
|
||||
// For example, it can be used to scale bonus based on hero or unit level
|
||||
// See Bonus Updaters list below for full list of supported updaters
|
||||
"updater" : {Bonus Updater},
|
||||
|
||||
// TODO
|
||||
// This is special type of propagator, that is only activated when bonus is being propagated upwards,
|
||||
// using its propagator. It has no effect on bonuses without propagator
|
||||
"propagationUpdater" : {Bonus Updater, but works during propagation},
|
||||
|
||||
// TODO
|
||||
"description" : "",
|
||||
|
||||
// TODO
|
||||
// Stacking string allows to block stacking of bonuses from different entities
|
||||
// For example, devils and archdevils (different entities) both have battle-wide debuff to luck
|
||||
// Normally, having both such units in combat would result in bonus stacking, providing -2 debuff to luck in total
|
||||
// If such behavior is undesired, both such unit must have same, non-empty stacking string
|
||||
// String can contain any text, as long as it not empty and is same for both of such creatures
|
||||
"stacking" : ""
|
||||
}
|
||||
```
|
||||
|
@@ -55,6 +55,10 @@ void CBonusSystemNode::getAllParents(TCNodes & out) const //retrieves list of pa
|
||||
{
|
||||
for(auto * parent : parentsToInherit)
|
||||
{
|
||||
// Diamond found! One of the parents of the targeted node can be discovered in two ways.
|
||||
// For example, a hero has been attached to both the player node and the global node (to which the player node is also attached).
|
||||
// This is illegal and can be a source of duplicate bonuses.
|
||||
assert(out.count(parent) == 0);
|
||||
out.insert(parent);
|
||||
parent->getAllParents(out);
|
||||
}
|
||||
@@ -63,13 +67,10 @@ void CBonusSystemNode::getAllParents(TCNodes & out) const //retrieves list of pa
|
||||
void CBonusSystemNode::getAllBonusesRec(BonusList &out, const CSelector & selector) const
|
||||
{
|
||||
BonusList beforeUpdate;
|
||||
TCNodes lparents;
|
||||
getAllParents(lparents);
|
||||
|
||||
for(const auto * parent : lparents)
|
||||
{
|
||||
for(const auto * parent : parentsToInherit)
|
||||
parent->getAllBonusesRec(beforeUpdate, selector);
|
||||
}
|
||||
|
||||
bonuses.getAllBonuses(beforeUpdate);
|
||||
|
||||
for(const auto & b : beforeUpdate)
|
||||
@@ -79,18 +80,7 @@ void CBonusSystemNode::getAllBonusesRec(BonusList &out, const CSelector & select
|
||||
? getUpdatedBonus(b, b->updater)
|
||||
: b;
|
||||
|
||||
//do not add bonus with updater
|
||||
bool bonusExists = false;
|
||||
for(const auto & bonus : out)
|
||||
{
|
||||
if (bonus == updated)
|
||||
bonusExists = true;
|
||||
if (bonus->updater && bonus->updater == updated->updater)
|
||||
bonusExists = true;
|
||||
}
|
||||
|
||||
if (!bonusExists)
|
||||
out.push_back(updated);
|
||||
out.push_back(updated);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -166,15 +166,21 @@ HasAnotherBonusLimiter::HasAnotherBonusLimiter(BonusType bonus, BonusSubtypeID _
|
||||
|
||||
ILimiter::EDecision HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
//TODO: proper selector config with parsing of JSON
|
||||
auto mySelector = Selector::type()(type);
|
||||
boost::container::static_vector<CSelector, 4> selectorSegments;
|
||||
|
||||
if (type != BonusType::NONE)
|
||||
selectorSegments.push_back(Selector::type()(type));
|
||||
if(isSubtypeRelevant)
|
||||
mySelector = mySelector.And(Selector::subtype()(subtype));
|
||||
selectorSegments.push_back(Selector::subtype()(subtype));
|
||||
if(isSourceRelevant && isSourceIDRelevant)
|
||||
mySelector = mySelector.And(Selector::source(source, sid));
|
||||
selectorSegments.push_back(Selector::source(source, sid));
|
||||
else if (isSourceRelevant)
|
||||
mySelector = mySelector.And(Selector::sourceTypeSel(source));
|
||||
selectorSegments.push_back(Selector::sourceTypeSel(source));
|
||||
|
||||
auto mySelector = selectorSegments.empty() ? Selector::none : selectorSegments[0];
|
||||
|
||||
for (size_t i = 1; i <selectorSegments.size(); ++i)
|
||||
mySelector = mySelector.And(selectorSegments[i]);
|
||||
|
||||
//if we have a bonus of required type accepted, limiter should accept also this bonus
|
||||
if(context.alreadyAccepted.getFirst(mySelector))
|
||||
|
@@ -108,72 +108,53 @@ JsonNode TimesHeroLevelUpdater::toJsonNode() const
|
||||
return JsonNode("TIMES_HERO_LEVEL");
|
||||
}
|
||||
|
||||
ArmyMovementUpdater::ArmyMovementUpdater():
|
||||
base(20),
|
||||
divider(3),
|
||||
multiplier(10),
|
||||
max(700)
|
||||
{
|
||||
}
|
||||
|
||||
ArmyMovementUpdater::ArmyMovementUpdater(int base, int divider, int multiplier, int max):
|
||||
base(base),
|
||||
divider(divider),
|
||||
multiplier(multiplier),
|
||||
max(max)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<Bonus> ArmyMovementUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
||||
std::shared_ptr<Bonus> TimesHeroLevelDivideStackLevelUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context)
|
||||
{
|
||||
if(context.getNodeType() == CBonusSystemNode::HERO)
|
||||
{
|
||||
auto newBonus = TimesHeroLevelUpdater::createUpdatedBonus(b, context);
|
||||
newBonus->updater = divideStackLevel;
|
||||
return newBonus;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
std::string ArmyMovementUpdater::toString() const
|
||||
std::string TimesHeroLevelDivideStackLevelUpdater::toString() const
|
||||
{
|
||||
return "ArmyMovementUpdater";
|
||||
return "TimesHeroLevelDivideStackLevelUpdater";
|
||||
}
|
||||
|
||||
JsonNode ArmyMovementUpdater::toJsonNode() const
|
||||
JsonNode TimesHeroLevelDivideStackLevelUpdater::toJsonNode() const
|
||||
{
|
||||
JsonNode root;
|
||||
|
||||
root["type"].String() = "ARMY_MOVEMENT";
|
||||
root["parameters"].Vector().emplace_back(base);
|
||||
root["parameters"].Vector().emplace_back(divider);
|
||||
root["parameters"].Vector().emplace_back(multiplier);
|
||||
root["parameters"].Vector().emplace_back(max);
|
||||
|
||||
return root;
|
||||
return JsonNode("TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL");
|
||||
}
|
||||
|
||||
std::shared_ptr<Bonus> TimesStackLevelUpdater::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> TimesStackLevelUpdater::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();
|
||||
auto newBonus = std::make_shared<Bonus>(*b);
|
||||
newBonus->val *= level;
|
||||
return newBonus;
|
||||
return apply(b, level);
|
||||
}
|
||||
else if(context.getNodeType() == CBonusSystemNode::STACK_BATTLE)
|
||||
|
||||
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)
|
||||
{
|
||||
int level = stack.unitType()->getLevel();
|
||||
auto newBonus = std::make_shared<Bonus>(*b);
|
||||
newBonus->val *= level;
|
||||
return newBonus;
|
||||
}
|
||||
return apply(b, stack.unitType()->getLevel());
|
||||
|
||||
// If these are not handled here, the final outcome may potentially be incorrect.
|
||||
else
|
||||
{
|
||||
int level = dynamic_cast<const CStackInstance*>(stack.base)->getLevel();
|
||||
auto newBonus = std::make_shared<Bonus>(*b);
|
||||
newBonus->val *= level;
|
||||
return newBonus;
|
||||
}
|
||||
int level = dynamic_cast<const CStackInstance*>(stack.base)->getLevel();
|
||||
return apply(b, level);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
@@ -188,6 +169,46 @@ JsonNode TimesStackLevelUpdater::toJsonNode() const
|
||||
return JsonNode("TIMES_STACK_LEVEL");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
std::string OwnerUpdater::toString() const
|
||||
{
|
||||
return "OwnerUpdater";
|
||||
|
@@ -88,6 +88,7 @@ public:
|
||||
|
||||
class DLL_LINKAGE TimesStackLevelUpdater : public IUpdater
|
||||
{
|
||||
std::shared_ptr<Bonus> apply(const std::shared_ptr<Bonus> & b, int level) const;
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler & h)
|
||||
{
|
||||
@@ -99,22 +100,13 @@ public:
|
||||
JsonNode toJsonNode() const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ArmyMovementUpdater : public IUpdater
|
||||
class DLL_LINKAGE DivideStackLevelUpdater : public IUpdater
|
||||
{
|
||||
std::shared_ptr<Bonus> apply(const std::shared_ptr<Bonus> & b, int level) const;
|
||||
public:
|
||||
si32 base;
|
||||
si32 divider;
|
||||
si32 multiplier;
|
||||
si32 max;
|
||||
ArmyMovementUpdater();
|
||||
ArmyMovementUpdater(int base, int divider, int multiplier, int max);
|
||||
template <typename Handler> void serialize(Handler & h)
|
||||
{
|
||||
h & static_cast<IUpdater &>(*this);
|
||||
h & base;
|
||||
h & divider;
|
||||
h & multiplier;
|
||||
h & max;
|
||||
}
|
||||
|
||||
std::shared_ptr<Bonus> createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) override;
|
||||
@@ -122,6 +114,25 @@ public:
|
||||
JsonNode toJsonNode() const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE TimesHeroLevelDivideStackLevelUpdater : public TimesHeroLevelUpdater
|
||||
{
|
||||
std::shared_ptr<DivideStackLevelUpdater> divideStackLevel;
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler & h)
|
||||
{
|
||||
h & static_cast<TimesHeroLevelUpdater &>(*this);
|
||||
h & divideStackLevel;
|
||||
}
|
||||
|
||||
TimesHeroLevelDivideStackLevelUpdater()
|
||||
: divideStackLevel(std::make_shared<DivideStackLevelUpdater>())
|
||||
{}
|
||||
|
||||
std::shared_ptr<Bonus> createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE OwnerUpdater : public IUpdater
|
||||
{
|
||||
protected:
|
||||
|
@@ -328,8 +328,9 @@ static TUpdaterPtr parseUpdater(const JsonNode & updaterJson)
|
||||
const std::map<std::string, std::function<TUpdaterPtr()>> bonusUpdaterMap =
|
||||
{
|
||||
{"TIMES_HERO_LEVEL", std::make_shared<TimesHeroLevelUpdater>},
|
||||
{"TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL", std::make_shared<TimesHeroLevelDivideStackLevelUpdater>},
|
||||
{"DIVIDE_STACK_LEVEL", std::make_shared<DivideStackLevelUpdater>},
|
||||
{"TIMES_STACK_LEVEL", std::make_shared<TimesStackLevelUpdater>},
|
||||
{"ARMY_MOVEMENT", std::make_shared<ArmyMovementUpdater>},
|
||||
{"BONUS_OWNER_UPDATER", std::make_shared<OwnerUpdater>}
|
||||
};
|
||||
|
||||
@@ -354,24 +355,6 @@ static TUpdaterPtr parseUpdater(const JsonNode & updaterJson)
|
||||
updater->stepSize = static_cast<int>(param[1].Integer());
|
||||
return updater;
|
||||
}
|
||||
else if (updaterJson["type"].String() == "ARMY_MOVEMENT")
|
||||
{
|
||||
auto updater = std::make_shared<ArmyMovementUpdater>();
|
||||
if(updaterJson["parameters"].isVector())
|
||||
{
|
||||
const auto & param = updaterJson["parameters"].Vector();
|
||||
if(param.size() < 4)
|
||||
logMod->warn("Invalid ARMY_MOVEMENT parameters, using default!");
|
||||
else
|
||||
{
|
||||
updater->base = static_cast<si32>(param.at(0).Integer());
|
||||
updater->divider = static_cast<si32>(param.at(1).Integer());
|
||||
updater->multiplier = static_cast<si32>(param.at(2).Integer());
|
||||
updater->max = static_cast<si32>(param.at(3).Integer());
|
||||
}
|
||||
return updater;
|
||||
}
|
||||
}
|
||||
else
|
||||
logMod->warn("Unknown updater type \"%s\"", updaterJson["type"].String());
|
||||
break;
|
||||
@@ -522,47 +505,52 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
|
||||
}
|
||||
else if(limiterType == "HAS_ANOTHER_BONUS_LIMITER")
|
||||
{
|
||||
std::string anotherBonusType = parameters[0].String();
|
||||
auto it = bonusNameMap.find(anotherBonusType);
|
||||
if(it == bonusNameMap.end())
|
||||
auto bonusLimiter = std::make_shared<HasAnotherBonusLimiter>();
|
||||
|
||||
if (!parameters[0].isNull())
|
||||
{
|
||||
logMod->error("Error: invalid ability type %s.", anotherBonusType);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto bonusLimiter = std::make_shared<HasAnotherBonusLimiter>();
|
||||
bonusLimiter->type = it->second;
|
||||
auto findSource = [&](const JsonNode & parameter)
|
||||
std::string anotherBonusType = parameters[0].String();
|
||||
auto it = bonusNameMap.find(anotherBonusType);
|
||||
if(it != bonusNameMap.end())
|
||||
{
|
||||
if(parameter.getType() == JsonNode::JsonType::DATA_STRUCT)
|
||||
bonusLimiter->type = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
logMod->error("Error: invalid ability type %s.", anotherBonusType);
|
||||
}
|
||||
}
|
||||
|
||||
auto findSource = [&](const JsonNode & parameter)
|
||||
{
|
||||
if(parameter.getType() == JsonNode::JsonType::DATA_STRUCT)
|
||||
{
|
||||
auto sourceIt = bonusSourceMap.find(parameter["type"].String());
|
||||
if(sourceIt != bonusSourceMap.end())
|
||||
{
|
||||
auto sourceIt = bonusSourceMap.find(parameter["type"].String());
|
||||
if(sourceIt != bonusSourceMap.end())
|
||||
{
|
||||
bonusLimiter->source = sourceIt->second;
|
||||
bonusLimiter->isSourceRelevant = true;
|
||||
if(!parameter["id"].isNull()) {
|
||||
loadBonusSourceInstance(bonusLimiter->sid, bonusLimiter->source, parameter["id"]);
|
||||
bonusLimiter->isSourceIDRelevant = true;
|
||||
}
|
||||
bonusLimiter->source = sourceIt->second;
|
||||
bonusLimiter->isSourceRelevant = true;
|
||||
if(!parameter["id"].isNull()) {
|
||||
loadBonusSourceInstance(bonusLimiter->sid, bonusLimiter->source, parameter["id"]);
|
||||
bonusLimiter->isSourceIDRelevant = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if(parameters.size() > 1)
|
||||
{
|
||||
if(findSource(parameters[1]) && parameters.size() == 2)
|
||||
return bonusLimiter;
|
||||
else
|
||||
{
|
||||
loadBonusSubtype(bonusLimiter->subtype, bonusLimiter->type, parameters[1]);
|
||||
bonusLimiter->isSubtypeRelevant = true;
|
||||
if(parameters.size() > 2)
|
||||
findSource(parameters[2]);
|
||||
}
|
||||
}
|
||||
return bonusLimiter;
|
||||
return false;
|
||||
};
|
||||
if(parameters.size() > 1)
|
||||
{
|
||||
if(findSource(parameters[1]) && parameters.size() == 2)
|
||||
return bonusLimiter;
|
||||
else
|
||||
{
|
||||
loadBonusSubtype(bonusLimiter->subtype, bonusLimiter->type, parameters[1]);
|
||||
bonusLimiter->isSubtypeRelevant = true;
|
||||
if(parameters.size() > 2)
|
||||
findSource(parameters[2]);
|
||||
}
|
||||
}
|
||||
return bonusLimiter;
|
||||
}
|
||||
else if(limiterType == "CREATURE_ALIGNMENT_LIMITER")
|
||||
{
|
||||
|
@@ -104,7 +104,6 @@ void registerTypes(Serializer &s)
|
||||
s.template registerType<TimesHeroLevelUpdater>(44);
|
||||
s.template registerType<TimesStackLevelUpdater>(45);
|
||||
s.template registerType<OwnerUpdater>(46);
|
||||
s.template registerType<ArmyMovementUpdater>(47);
|
||||
s.template registerType<ILimiter>(48);
|
||||
s.template registerType<AnyOfLimiter>(49);
|
||||
s.template registerType<NoneOfLimiter>(50);
|
||||
@@ -294,6 +293,8 @@ void registerTypes(Serializer &s)
|
||||
s.template registerType<SetResearchedSpells>(242);
|
||||
s.template registerType<SaveLocalState>(243);
|
||||
s.template registerType<LobbyDelete>(244);
|
||||
s.template registerType<TimesHeroLevelDivideStackLevelUpdater>(245);
|
||||
s.template registerType<DivideStackLevelUpdater>(246);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
Reference in New Issue
Block a user