1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00

Enable Limiter nesting with AllOf, AnyOf, NoneOf (#439)

* Renamed LimiterList to AllOfLimiter and added AnyOfLimiter, NoneOfLimiter
* Updated bonus schema to new limiter format
This commit is contained in:
Henning Koehler
2018-04-01 23:17:34 +12:00
committed by ArseniyShestakov
parent 6ddcb079a4
commit 82f334b503
8 changed files with 252 additions and 95 deletions

View File

@@ -567,6 +567,96 @@ void JsonUtils::resolveIdentifier(const JsonNode &node, si32 &var)
}
}
std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
{
switch(limiter.getType())
{
case JsonNode::JsonType::DATA_VECTOR:
{
const JsonVector & subLimiters = limiter.Vector();
if(subLimiters.size() == 0)
{
logMod->warn("Warning: empty limiter list");
return std::make_shared<AllOfLimiter>();
}
std::shared_ptr<AggregateLimiter> result;
int offset = 1;
// determine limiter type and offset for sub-limiters
if(subLimiters[0].getType() == JsonNode::JsonType::DATA_STRING)
{
const std::string & aggregator = subLimiters[0].String();
if(aggregator == AllOfLimiter::aggregator)
result = std::make_shared<AllOfLimiter>();
else if(aggregator == AnyOfLimiter::aggregator)
result = std::make_shared<AnyOfLimiter>();
else if(aggregator == NoneOfLimiter::aggregator)
result = std::make_shared<NoneOfLimiter>();
}
if(!result)
{
// collapse for single limiter without explicit aggregate operator
if(subLimiters.size() == 1)
return parseLimiter(subLimiters[0]);
// implicit aggregator must be allOf
result = std::make_shared<AllOfLimiter>();
offset = 0;
}
if(subLimiters.size() == offset)
logMod->warn("Warning: empty sub-limiter list");
for(int sl = offset; sl < subLimiters.size(); ++sl)
result->add(parseLimiter(subLimiters[sl]));
return result;
}
break;
case JsonNode::JsonType::DATA_STRING: //pre-defined limiters
return parseByMap(bonusLimiterMap, &limiter, "limiter type ");
break;
case JsonNode::JsonType::DATA_STRUCT: //customizable limiters
{
std::string limiterType = limiter["type"].String();
const JsonVector & parameters = limiter["parameters"].Vector();
if(limiterType == "CREATURE_TYPE_LIMITER")
{
std::shared_ptr<CCreatureTypeLimiter> creatureLimiter = std::make_shared<CCreatureTypeLimiter>();
VLC->modh->identifiers.requestIdentifier("creature", parameters[0], [=](si32 creature)
{
creatureLimiter->setCreature(CreatureID(creature));
});
creatureLimiter->includeUpgrades = parameters.size() > 1 ? parameters[1].Bool() : false;
return creatureLimiter;
}
else if(limiterType == "HAS_ANOTHER_BONUS_LIMITER")
{
std::string anotherBonusType = parameters[0].String();
auto it = bonusNameMap.find(anotherBonusType);
if(it == bonusNameMap.end())
{
logMod->error("Error: invalid ability type %s.", anotherBonusType);
}
else
{
std::shared_ptr<HasAnotherBonusLimiter> bonusLimiter = std::make_shared<HasAnotherBonusLimiter>();
bonusLimiter->type = it->second;
if(parameters.size() > 1)
{
resolveIdentifier(parameters[1], bonusLimiter->subtype);
bonusLimiter->isSubtypeRelevant = true;
}
return bonusLimiter;
}
}
else
{
logMod->error("Error: invalid customizable limiter type %s.", limiterType);
}
}
break;
default:
break;
}
return nullptr;
}
std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability)
{
auto b = std::make_shared<Bonus>();
@@ -641,61 +731,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
value = &ability["limiters"];
if (!value->isNull())
{
for (const JsonNode & limiter : value->Vector())
{
switch (limiter.getType())
{
case JsonNode::JsonType::DATA_STRING: //pre-defined limiters
b->limiter = parseByMap(bonusLimiterMap, &limiter, "limiter type ");
break;
case JsonNode::JsonType::DATA_STRUCT: //customizable limiters
{
std::shared_ptr<ILimiter> l;
if (limiter["type"].String() == "CREATURE_TYPE_LIMITER")
{
std::shared_ptr<CCreatureTypeLimiter> l2 = std::make_shared<CCreatureTypeLimiter>(); //TODO: How the hell resolve pointer to creature?
const JsonVector vec = limiter["parameters"].Vector();
VLC->modh->identifiers.requestIdentifier("creature", vec[0], [=](si32 creature)
{
l2->setCreature(CreatureID(creature));
});
if (vec.size() > 1)
{
l2->includeUpgrades = vec[1].Bool();
}
else
l2->includeUpgrades = false;
l = l2;
}
if (limiter["type"].String() == "HAS_ANOTHER_BONUS_LIMITER")
{
std::shared_ptr<HasAnotherBonusLimiter> l2 = std::make_shared<HasAnotherBonusLimiter>();
const JsonVector vec = limiter["parameters"].Vector();
std::string anotherBonusType = vec[0].String();
auto it = bonusNameMap.find(anotherBonusType);
if (it == bonusNameMap.end())
{
logMod->error("Error: invalid ability type %s.", anotherBonusType);
continue;
}
l2->type = it->second;
if (vec.size() > 1 )
{
resolveIdentifier(vec[1], l2->subtype);
l2->isSubtypeRelevant = true;
}
l = l2;
}
b->addLimiter(l);
}
break;
}
}
}
b->limiter = parseLimiter(*value);
value = &ability["propagator"];
if (!value->isNull())