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

vcmi: allows parsing selectors from JSON

Supports anyOf, allOf, noneOf,
and all selectors from Selector namespace.
Can be useful to define selectors in JSON when required
This commit is contained in:
Konstantin 2023-03-09 02:18:30 +03:00
parent f13a934c47
commit 0540e1531d
2 changed files with 115 additions and 0 deletions

View File

@ -969,6 +969,119 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
return true;
}
CSelector JsonUtils::parseSelector(const JsonNode & ability)
{
CSelector ret = Selector::all;
// Recursive parsers for anyOf, allOf, noneOf
const auto * value = &ability["allOf"];
if(value->isVector())
{
for(const auto & andN : value->Vector())
ret = ret.And(parseSelector(andN));
}
value = &ability["anyOf"];
if(value->isVector())
{
CSelector base = Selector::none;
for(const auto & andN : value->Vector())
base.Or(parseSelector(andN));
ret = ret.And(base);
}
value = &ability["noneOf"];
if(value->isVector())
{
CSelector base = Selector::all;
for(const auto & andN : value->Vector())
base.And(parseSelector(andN));
ret = ret.And(base.Not());
}
// Actual selector parser
value = &ability["type"];
if(value->isString())
{
auto it = bonusNameMap.find(value->String());
if(it != bonusNameMap.end())
ret = ret.And(Selector::type()(it->second));
}
value = &ability["subtype"];
if(!value->isNull())
{
TBonusSubtype subtype;
resolveIdentifier(subtype, ability, "subtype");
ret = ret.And(Selector::subtype()(subtype));
}
value = &ability["sourceType"];
Bonus::BonusSource src = Bonus::OTHER; //Fixes for GCC false maybe-uninitialized
si32 id = 0;
auto sourceIDRelevant = false;
auto sourceTypeRelevant = false;
if(value->isString())
{
auto it = bonusSourceMap.find(value->String());
if(it != bonusSourceMap.end())
{
src = it->second;
sourceTypeRelevant = true;
}
}
value = &ability["sourceID"];
if(!value->isNull())
{
sourceIDRelevant = true;
resolveIdentifier(id, ability, "sourceID");
}
if(sourceIDRelevant && sourceTypeRelevant)
ret = ret.And(Selector::source(src, id));
else if(sourceTypeRelevant)
ret = ret.And(Selector::sourceTypeSel(src));
value = &ability["targetSourceType"];
if(value->isString())
{
auto it = bonusSourceMap.find(value->String());
if(it != bonusSourceMap.end())
ret = ret.And(Selector::targetSourceType()(it->second));
}
value = &ability["valueType"];
if(value->isString())
{
auto it = bonusValueMap.find(value->String());
if(it != bonusValueMap.end())
ret = ret.And(Selector::valueType(it->second));
}
CAddInfo info;
value = &ability["addInfo"];
if(!value->isNull())
{
resolveAddInfo(info, ability["addInfo"]);
ret = ret.And(Selector::info()(info));
}
value = &ability["effectRange"];
if(value->isString())
{
auto it = bonusLimitEffect.find(value->String());
if(it != bonusLimitEffect.end())
ret = ret.And(Selector::effectRange()(it->second));
}
value = &ability["lastsTurns"];
if(value->isNumber())
ret = ret.And(Selector::turns(value->Integer()));
value = &ability["lastsDays"];
if(value->isNumber())
ret = ret.And(Selector::days(value->Integer()));
return ret;
}
//returns first Key with value equal to given one
template<class Key, class Val>
Key reverseMapFirst(const Val & val, const std::map<Key, Val> & map)

View File

@ -17,6 +17,7 @@ typedef std::map <std::string, JsonNode> JsonMap;
typedef std::vector <JsonNode> JsonVector;
struct Bonus;
class CSelector;
class ResourceID;
class CAddInfo;
class ILimiter;
@ -175,6 +176,7 @@ namespace JsonUtils
DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode &ability, BuildingID building, std::string description);
DLL_LINKAGE bool parseBonus(const JsonNode &ability, Bonus *placement);
DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
DLL_LINKAGE CSelector parseSelector(const JsonNode &ability);
DLL_LINKAGE void resolveIdentifier(si32 &var, const JsonNode &node, std::string name);
DLL_LINKAGE void resolveIdentifier(const JsonNode &node, si32 &var);
DLL_LINKAGE void resolveAddInfo(CAddInfo & var, const JsonNode & node);