|
@@ -32,274 +32,415 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
|
namespace JsonRandom
|
|
|
{
|
|
|
- si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue)
|
|
|
+ si32 loadVariable(std::string variableGroup, const std::string & value, const Variables & variables, si32 defaultValue)
|
|
|
+ {
|
|
|
+ if (value.empty() || value[0] != '@')
|
|
|
+ {
|
|
|
+ logMod->warn("Invalid syntax in load value! Can not load value from '%s'", value);
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string variableID = variableGroup + value;
|
|
|
+
|
|
|
+ if (variables.count(variableID) == 0)
|
|
|
+ {
|
|
|
+ logMod->warn("Invalid syntax in load value! Unknown variable '%s'", value);
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ return variables.at(variableID);
|
|
|
+ }
|
|
|
+
|
|
|
+ si32 loadValue(const JsonNode & value, CRandomGenerator & rng, const Variables & variables, si32 defaultValue)
|
|
|
{
|
|
|
if(value.isNull())
|
|
|
return defaultValue;
|
|
|
if(value.isNumber())
|
|
|
return static_cast<si32>(value.Float());
|
|
|
+ if (value.isString())
|
|
|
+ return loadVariable("number", value.String(), variables, defaultValue);
|
|
|
+
|
|
|
if(value.isVector())
|
|
|
{
|
|
|
const auto & vector = value.Vector();
|
|
|
|
|
|
size_t index= rng.getIntRange(0, vector.size()-1)();
|
|
|
- return loadValue(vector[index], rng, 0);
|
|
|
+ return loadValue(vector[index], rng, variables, 0);
|
|
|
}
|
|
|
if(value.isStruct())
|
|
|
{
|
|
|
if (!value["amount"].isNull())
|
|
|
- return static_cast<si32>(loadValue(value["amount"], rng, defaultValue));
|
|
|
- si32 min = static_cast<si32>(loadValue(value["min"], rng, 0));
|
|
|
- si32 max = static_cast<si32>(loadValue(value["max"], rng, 0));
|
|
|
+ return static_cast<si32>(loadValue(value["amount"], rng, variables, defaultValue));
|
|
|
+ si32 min = static_cast<si32>(loadValue(value["min"], rng, variables, 0));
|
|
|
+ si32 max = static_cast<si32>(loadValue(value["max"], rng, variables, 0));
|
|
|
return rng.getIntRange(min, max)();
|
|
|
}
|
|
|
return defaultValue;
|
|
|
}
|
|
|
|
|
|
- std::string loadKey(const JsonNode & value, CRandomGenerator & rng, const std::set<std::string> & valuesSet)
|
|
|
+ template<typename IdentifierType>
|
|
|
+ IdentifierType decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
|
|
|
+ {
|
|
|
+ if (value.empty() || value[0] != '@')
|
|
|
+ return IdentifierType(*VLC->identifiers()->getIdentifier(modScope, IdentifierType::entityType(), value));
|
|
|
+ else
|
|
|
+ return loadVariable(IdentifierType::entityType(), value, variables, IdentifierType::NONE);
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename IdentifierType>
|
|
|
+ IdentifierType decodeKey(const JsonNode & value, const Variables & variables)
|
|
|
+ {
|
|
|
+ if (value.String().empty() || value.String()[0] != '@')
|
|
|
+ return IdentifierType(*VLC->identifiers()->getIdentifier(IdentifierType::entityType(), value));
|
|
|
+ else
|
|
|
+ return loadVariable(IdentifierType::entityType(), value.String(), variables, IdentifierType::NONE);
|
|
|
+ }
|
|
|
+
|
|
|
+ template<>
|
|
|
+ PlayerColor decodeKey(const JsonNode & value, const Variables & variables)
|
|
|
+ {
|
|
|
+ return PlayerColor(*VLC->identifiers()->getIdentifier("playerColor", value));
|
|
|
+ }
|
|
|
+
|
|
|
+ template<>
|
|
|
+ PrimarySkill decodeKey(const JsonNode & value, const Variables & variables)
|
|
|
+ {
|
|
|
+ return PrimarySkill(*VLC->identifiers()->getIdentifier("primarySkill", value));
|
|
|
+ }
|
|
|
+
|
|
|
+ template<>
|
|
|
+ PrimarySkill decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
|
|
|
+ {
|
|
|
+ if (value.empty() || value[0] != '@')
|
|
|
+ return PrimarySkill(*VLC->identifiers()->getIdentifier(modScope, "primarySkill", value));
|
|
|
+ else
|
|
|
+ return PrimarySkill(loadVariable("primarySkill", value, variables, static_cast<int>(PrimarySkill::NONE)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Method that allows type-specific object filtering
|
|
|
+ /// Default implementation is to accept all input objects
|
|
|
+ template<typename IdentifierType>
|
|
|
+ std::set<IdentifierType> filterKeysTyped(const JsonNode & value, const std::set<IdentifierType> & valuesSet)
|
|
|
+ {
|
|
|
+ return valuesSet;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<>
|
|
|
+ std::set<ArtifactID> filterKeysTyped(const JsonNode & value, const std::set<ArtifactID> & valuesSet)
|
|
|
+ {
|
|
|
+ assert(value.isStruct());
|
|
|
+
|
|
|
+ std::set<CArtifact::EartClass> allowedClasses;
|
|
|
+ std::set<ArtifactPosition> allowedPositions;
|
|
|
+ ui32 minValue = 0;
|
|
|
+ ui32 maxValue = std::numeric_limits<ui32>::max();
|
|
|
+
|
|
|
+ if (value["class"].getType() == JsonNode::JsonType::DATA_STRING)
|
|
|
+ allowedClasses.insert(CArtHandler::stringToClass(value["class"].String()));
|
|
|
+ else
|
|
|
+ for(const auto & entry : value["class"].Vector())
|
|
|
+ allowedClasses.insert(CArtHandler::stringToClass(entry.String()));
|
|
|
+
|
|
|
+ if (value["slot"].getType() == JsonNode::JsonType::DATA_STRING)
|
|
|
+ allowedPositions.insert(ArtifactPosition::decode(value["class"].String()));
|
|
|
+ else
|
|
|
+ for(const auto & entry : value["slot"].Vector())
|
|
|
+ allowedPositions.insert(ArtifactPosition::decode(entry.String()));
|
|
|
+
|
|
|
+ if (!value["minValue"].isNull())
|
|
|
+ minValue = static_cast<ui32>(value["minValue"].Float());
|
|
|
+ if (!value["maxValue"].isNull())
|
|
|
+ maxValue = static_cast<ui32>(value["maxValue"].Float());
|
|
|
+
|
|
|
+ std::set<ArtifactID> result;
|
|
|
+
|
|
|
+ for (auto const & artID : valuesSet)
|
|
|
+ {
|
|
|
+ CArtifact * art = VLC->arth->objects[artID];
|
|
|
+
|
|
|
+ if(!vstd::iswithin(art->getPrice(), minValue, maxValue))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if(!allowedClasses.empty() && !allowedClasses.count(art->aClass))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if(!IObjectInterface::cb->isAllowed(1, art->getIndex()))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if(!allowedPositions.empty())
|
|
|
+ {
|
|
|
+ bool positionAllowed = false;
|
|
|
+ for(const auto & pos : art->getPossibleSlots().at(ArtBearer::HERO))
|
|
|
+ {
|
|
|
+ if(allowedPositions.count(pos))
|
|
|
+ positionAllowed = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!positionAllowed)
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ result.insert(artID);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<>
|
|
|
+ std::set<SpellID> filterKeysTyped(const JsonNode & value, const std::set<SpellID> & valuesSet)
|
|
|
+ {
|
|
|
+ std::set<SpellID> result = valuesSet;
|
|
|
+
|
|
|
+ if (!value["level"].isNull())
|
|
|
+ {
|
|
|
+ int32_t spellLevel = value["level"].Integer();
|
|
|
+
|
|
|
+ vstd::erase_if(result, [=](const SpellID & spell)
|
|
|
+ {
|
|
|
+ return VLC->spellh->getById(spell)->getLevel() != spellLevel;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!value["school"].isNull())
|
|
|
+ {
|
|
|
+ int32_t schoolID = VLC->identifiers()->getIdentifier("spellSchool", value["school"]).value();
|
|
|
+
|
|
|
+ vstd::erase_if(result, [=](const SpellID & spell)
|
|
|
+ {
|
|
|
+ return !VLC->spellh->getById(spell)->hasSchool(SpellSchool(schoolID));
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename IdentifierType>
|
|
|
+ std::set<IdentifierType> filterKeys(const JsonNode & value, const std::set<IdentifierType> & valuesSet, const Variables & variables)
|
|
|
{
|
|
|
if(value.isString())
|
|
|
- return value.String();
|
|
|
-
|
|
|
+ return { decodeKey<IdentifierType>(value, variables) };
|
|
|
+
|
|
|
+ assert(value.isStruct());
|
|
|
+
|
|
|
if(value.isStruct())
|
|
|
{
|
|
|
if(!value["type"].isNull())
|
|
|
- return value["type"].String();
|
|
|
+ return filterKeys(value["type"], valuesSet, variables);
|
|
|
+
|
|
|
+ std::set<IdentifierType> filteredTypes = filterKeysTyped(value, valuesSet);
|
|
|
|
|
|
if(!value["anyOf"].isNull())
|
|
|
- return RandomGeneratorUtil::nextItem(value["anyOf"].Vector(), rng)->String();
|
|
|
-
|
|
|
+ {
|
|
|
+ std::set<IdentifierType> filteredAnyOf;
|
|
|
+ for (auto const & entry : value["anyOf"].Vector())
|
|
|
+ {
|
|
|
+ std::set<IdentifierType> subset = filterKeys(entry, valuesSet, variables);
|
|
|
+ filteredAnyOf.insert(subset.begin(), subset.end());
|
|
|
+ }
|
|
|
+
|
|
|
+ vstd::erase_if(filteredTypes, [&](const IdentifierType & value)
|
|
|
+ {
|
|
|
+ return filteredAnyOf.count(value) == 0;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
if(!value["noneOf"].isNull())
|
|
|
{
|
|
|
- auto copyValuesSet = valuesSet;
|
|
|
- for(auto & s : value["noneOf"].Vector())
|
|
|
- copyValuesSet.erase(s.String());
|
|
|
-
|
|
|
- if(!copyValuesSet.empty())
|
|
|
- return *RandomGeneratorUtil::nextItem(copyValuesSet, rng);
|
|
|
+ for (auto const & entry : value["noneOf"].Vector())
|
|
|
+ {
|
|
|
+ std::set<IdentifierType> subset = filterKeys(entry, valuesSet, variables);
|
|
|
+ for (auto bannedEntry : subset )
|
|
|
+ filteredTypes.erase(bannedEntry);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ return filteredTypes;
|
|
|
}
|
|
|
-
|
|
|
- return valuesSet.empty() ? "" : *RandomGeneratorUtil::nextItem(valuesSet, rng);
|
|
|
+ return valuesSet;
|
|
|
}
|
|
|
|
|
|
- TResources loadResources(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ TResources loadResources(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
TResources ret;
|
|
|
|
|
|
if (value.isVector())
|
|
|
{
|
|
|
for (const auto & entry : value.Vector())
|
|
|
- ret += loadResource(entry, rng);
|
|
|
+ ret += loadResource(entry, rng, variables);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
for (size_t i=0; i<GameConstants::RESOURCE_QUANTITY; i++)
|
|
|
{
|
|
|
- ret[i] = loadValue(value[GameConstants::RESOURCE_NAMES[i]], rng);
|
|
|
+ ret[i] = loadValue(value[GameConstants::RESOURCE_NAMES[i]], rng, variables);
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- TResources loadResource(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ TResources loadResource(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
- std::set<std::string> defaultResources(std::begin(GameConstants::RESOURCE_NAMES), std::end(GameConstants::RESOURCE_NAMES) - 1); //except mithril
|
|
|
-
|
|
|
- std::string resourceName = loadKey(value, rng, defaultResources);
|
|
|
- si32 resourceAmount = loadValue(value, rng, 0);
|
|
|
- si32 resourceID(VLC->identifiers()->getIdentifier(value.meta, "resource", resourceName).value());
|
|
|
+ std::set<GameResID> defaultResources{
|
|
|
+ GameResID::WOOD,
|
|
|
+ GameResID::MERCURY,
|
|
|
+ GameResID::ORE,
|
|
|
+ GameResID::SULFUR,
|
|
|
+ GameResID::CRYSTAL,
|
|
|
+ GameResID::GEMS,
|
|
|
+ GameResID::GOLD
|
|
|
+ };
|
|
|
+
|
|
|
+ std::set<GameResID> potentialPicks = filterKeys(value, defaultResources, variables);
|
|
|
+ GameResID resourceID = *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
|
|
+ si32 resourceAmount = loadValue(value, rng, variables, 0);
|
|
|
|
|
|
TResources ret;
|
|
|
ret[resourceID] = resourceAmount;
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ PrimarySkill loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
+ {
|
|
|
+ std::set<PrimarySkill> defaultSkills{
|
|
|
+ PrimarySkill::ATTACK,
|
|
|
+ PrimarySkill::DEFENSE,
|
|
|
+ PrimarySkill::SPELL_POWER,
|
|
|
+ PrimarySkill::KNOWLEDGE
|
|
|
+ };
|
|
|
+ std::set<PrimarySkill> potentialPicks = filterKeys(value, defaultSkills, variables);
|
|
|
+ return *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
|
|
+ }
|
|
|
|
|
|
- std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ std::vector<si32> loadPrimaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
- std::vector<si32> ret;
|
|
|
+ std::vector<si32> ret(GameConstants::PRIMARY_SKILLS, 0);
|
|
|
+ std::set<PrimarySkill> defaultSkills{
|
|
|
+ PrimarySkill::ATTACK,
|
|
|
+ PrimarySkill::DEFENSE,
|
|
|
+ PrimarySkill::SPELL_POWER,
|
|
|
+ PrimarySkill::KNOWLEDGE
|
|
|
+ };
|
|
|
+
|
|
|
if(value.isStruct())
|
|
|
{
|
|
|
- for(const auto & name : NPrimarySkill::names)
|
|
|
+ for(const auto & pair : value.Struct())
|
|
|
{
|
|
|
- ret.push_back(loadValue(value[name], rng));
|
|
|
+ PrimarySkill id = decodeKey<PrimarySkill>(pair.second.meta, pair.first, variables);
|
|
|
+ ret[static_cast<int>(id)] += loadValue(pair.second, rng, variables);
|
|
|
}
|
|
|
}
|
|
|
if(value.isVector())
|
|
|
{
|
|
|
- ret.resize(GameConstants::PRIMARY_SKILLS, 0);
|
|
|
- std::set<std::string> defaultStats(std::begin(NPrimarySkill::names), std::end(NPrimarySkill::names));
|
|
|
for(const auto & element : value.Vector())
|
|
|
{
|
|
|
- auto key = loadKey(element, rng, defaultStats);
|
|
|
- defaultStats.erase(key);
|
|
|
- int id = vstd::find_pos(NPrimarySkill::names, key);
|
|
|
- if(id != -1)
|
|
|
- ret[id] += loadValue(element, rng);
|
|
|
+ std::set<PrimarySkill> potentialPicks = filterKeys(element, defaultSkills, variables);
|
|
|
+ PrimarySkill skillID = *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
|
|
+
|
|
|
+ defaultSkills.erase(skillID);
|
|
|
+ ret[static_cast<int>(skillID)] += loadValue(element, rng, variables);
|
|
|
}
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- std::map<SecondarySkill, si32> loadSecondary(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ SecondarySkill loadSecondary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
+ {
|
|
|
+ std::set<SecondarySkill> defaultSkills;
|
|
|
+ for(const auto & skill : VLC->skillh->objects)
|
|
|
+ if (IObjectInterface::cb->isAllowed(2, skill->getIndex()))
|
|
|
+ defaultSkills.insert(skill->getId());
|
|
|
+
|
|
|
+ std::set<SecondarySkill> potentialPicks = filterKeys(value, defaultSkills, variables);
|
|
|
+ return *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::map<SecondarySkill, si32> loadSecondaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
std::map<SecondarySkill, si32> ret;
|
|
|
if(value.isStruct())
|
|
|
{
|
|
|
for(const auto & pair : value.Struct())
|
|
|
{
|
|
|
- SecondarySkill id(VLC->identifiers()->getIdentifier(pair.second.meta, "skill", pair.first).value());
|
|
|
- ret[id] = loadValue(pair.second, rng);
|
|
|
+ SecondarySkill id = decodeKey<SecondarySkill>(pair.second.meta, pair.first, variables);
|
|
|
+ ret[id] = loadValue(pair.second, rng, variables);
|
|
|
}
|
|
|
}
|
|
|
if(value.isVector())
|
|
|
{
|
|
|
- std::set<std::string> defaultSkills;
|
|
|
+ std::set<SecondarySkill> defaultSkills;
|
|
|
for(const auto & skill : VLC->skillh->objects)
|
|
|
- {
|
|
|
- IObjectInterface::cb->isAllowed(2, skill->getIndex());
|
|
|
- auto scopeAndName = vstd::splitStringToPair(skill->getJsonKey(), ':');
|
|
|
- if(scopeAndName.first == ModScope::scopeBuiltin() || scopeAndName.first == value.meta)
|
|
|
- defaultSkills.insert(scopeAndName.second);
|
|
|
- else
|
|
|
- defaultSkills.insert(skill->getJsonKey());
|
|
|
- }
|
|
|
-
|
|
|
+ if (IObjectInterface::cb->isAllowed(2, skill->getIndex()))
|
|
|
+ defaultSkills.insert(skill->getId());
|
|
|
+
|
|
|
for(const auto & element : value.Vector())
|
|
|
{
|
|
|
- auto key = loadKey(element, rng, defaultSkills);
|
|
|
- defaultSkills.erase(key); //avoid dupicates
|
|
|
- if(auto identifier = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "skill", key))
|
|
|
- {
|
|
|
- SecondarySkill id(identifier.value());
|
|
|
- ret[id] = loadValue(element, rng);
|
|
|
- }
|
|
|
+ std::set<SecondarySkill> potentialPicks = filterKeys(element, defaultSkills, variables);
|
|
|
+ SecondarySkill skillID = *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
|
|
+
|
|
|
+ defaultSkills.erase(skillID); //avoid dupicates
|
|
|
+ ret[skillID] = loadValue(element, rng, variables);
|
|
|
}
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
- if (value.getType() == JsonNode::JsonType::DATA_STRING)
|
|
|
- return ArtifactID(VLC->identifiers()->getIdentifier("artifact", value).value());
|
|
|
-
|
|
|
- std::set<CArtifact::EartClass> allowedClasses;
|
|
|
- std::set<ArtifactPosition> allowedPositions;
|
|
|
- ui32 minValue = 0;
|
|
|
- ui32 maxValue = std::numeric_limits<ui32>::max();
|
|
|
-
|
|
|
- if (value["class"].getType() == JsonNode::JsonType::DATA_STRING)
|
|
|
- allowedClasses.insert(CArtHandler::stringToClass(value["class"].String()));
|
|
|
- else
|
|
|
- for(const auto & entry : value["class"].Vector())
|
|
|
- allowedClasses.insert(CArtHandler::stringToClass(entry.String()));
|
|
|
-
|
|
|
- if (value["slot"].getType() == JsonNode::JsonType::DATA_STRING)
|
|
|
- allowedPositions.insert(ArtifactPosition::decode(value["class"].String()));
|
|
|
- else
|
|
|
- for(const auto & entry : value["slot"].Vector())
|
|
|
- allowedPositions.insert(ArtifactPosition::decode(entry.String()));
|
|
|
-
|
|
|
- if (!value["minValue"].isNull()) minValue = static_cast<ui32>(value["minValue"].Float());
|
|
|
- if (!value["maxValue"].isNull()) maxValue = static_cast<ui32>(value["maxValue"].Float());
|
|
|
+ std::set<ArtifactID> allowedArts;
|
|
|
+ for (auto const * artifact : VLC->arth->allowedArtifacts)
|
|
|
+ allowedArts.insert(artifact->getId());
|
|
|
|
|
|
- return VLC->arth->pickRandomArtifact(rng, [=](const ArtifactID & artID) -> bool
|
|
|
- {
|
|
|
- CArtifact * art = VLC->arth->objects[artID];
|
|
|
-
|
|
|
- if(!vstd::iswithin(art->getPrice(), minValue, maxValue))
|
|
|
- return false;
|
|
|
+ std::set<ArtifactID> potentialPicks = filterKeys(value, allowedArts, variables);
|
|
|
|
|
|
- if(!allowedClasses.empty() && !allowedClasses.count(art->aClass))
|
|
|
- return false;
|
|
|
-
|
|
|
- if(!IObjectInterface::cb->isAllowed(1, art->getIndex()))
|
|
|
- return false;
|
|
|
-
|
|
|
- if(!allowedPositions.empty())
|
|
|
- {
|
|
|
- for(const auto & pos : art->getPossibleSlots().at(ArtBearer::HERO))
|
|
|
- {
|
|
|
- if(allowedPositions.count(pos))
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
- return true;
|
|
|
- });
|
|
|
+ return VLC->arth->pickRandomArtifact(rng, potentialPicks);
|
|
|
}
|
|
|
|
|
|
- std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
std::vector<ArtifactID> ret;
|
|
|
for (const JsonNode & entry : value.Vector())
|
|
|
{
|
|
|
- ret.push_back(loadArtifact(entry, rng));
|
|
|
+ ret.push_back(loadArtifact(entry, rng, variables));
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells)
|
|
|
+ SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
- if (value.getType() == JsonNode::JsonType::DATA_STRING)
|
|
|
- return SpellID(VLC->identifiers()->getIdentifier("spell", value).value());
|
|
|
+ std::set<SpellID> defaultSpells;
|
|
|
+ for(const auto & spell : VLC->spellh->objects)
|
|
|
+ if (IObjectInterface::cb->isAllowed(0, spell->getIndex()))
|
|
|
+ defaultSpells.insert(spell->getId());
|
|
|
|
|
|
- if (!value["level"].isNull())
|
|
|
- {
|
|
|
- int32_t spellLevel = value["level"].Float();
|
|
|
+ std::set<SpellID> potentialPicks = filterKeys(value, defaultSpells, variables);
|
|
|
|
|
|
- vstd::erase_if(spells, [=](const SpellID & spell)
|
|
|
- {
|
|
|
- return VLC->spellh->getById(spell)->getLevel() != spellLevel;
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- if (!value["school"].isNull())
|
|
|
- {
|
|
|
- int32_t schoolID = VLC->identifiers()->getIdentifier("spellSchool", value["school"]).value();
|
|
|
-
|
|
|
- vstd::erase_if(spells, [=](const SpellID & spell)
|
|
|
- {
|
|
|
- return !VLC->spellh->getById(spell)->hasSchool(SpellSchool(schoolID));
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- if (spells.empty())
|
|
|
+ if (potentialPicks.empty())
|
|
|
{
|
|
|
logMod->warn("Failed to select suitable random spell!");
|
|
|
return SpellID::NONE;
|
|
|
}
|
|
|
- return SpellID(*RandomGeneratorUtil::nextItem(spells, rng));
|
|
|
+ return *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
|
|
}
|
|
|
|
|
|
- std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const std::vector<SpellID> & spells)
|
|
|
+ std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
std::vector<SpellID> ret;
|
|
|
for (const JsonNode & entry : value.Vector())
|
|
|
{
|
|
|
- ret.push_back(loadSpell(entry, rng, spells));
|
|
|
+ ret.push_back(loadSpell(entry, rng, variables));
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
std::vector<PlayerColor> ret;
|
|
|
- std::set<std::string> def;
|
|
|
-
|
|
|
- for(auto & color : GameConstants::PLAYER_COLOR_NAMES)
|
|
|
- def.insert(color);
|
|
|
-
|
|
|
+ std::set<PlayerColor> defaultPlayers;
|
|
|
+ for(size_t i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
|
|
|
+ defaultPlayers.insert(PlayerColor(i));
|
|
|
+
|
|
|
for(auto & entry : value.Vector())
|
|
|
{
|
|
|
- auto key = loadKey(entry, rng, def);
|
|
|
- auto pos = vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, key);
|
|
|
- if(pos < 0)
|
|
|
- logMod->warn("Unable to determine player color %s", key);
|
|
|
- else
|
|
|
- ret.emplace_back(pos);
|
|
|
+ std::set<PlayerColor> potentialPicks = filterKeys(entry, defaultPlayers, variables);
|
|
|
+ ret.push_back(*RandomGeneratorUtil::nextItem(potentialPicks, rng));
|
|
|
}
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -323,11 +464,25 @@ namespace JsonRandom
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
CStackBasicDescriptor stack;
|
|
|
- stack.type = VLC->creh->objects[VLC->identifiers()->getIdentifier("creature", value["type"]).value()];
|
|
|
- stack.count = loadValue(value, rng);
|
|
|
+
|
|
|
+ std::set<CreatureID> defaultCreatures;
|
|
|
+ for(const auto & creature : VLC->creh->objects)
|
|
|
+ if (!creature->special)
|
|
|
+ defaultCreatures.insert(creature->getId());
|
|
|
+
|
|
|
+ std::set<CreatureID> potentialPicks = filterKeys(value, defaultCreatures, variables);
|
|
|
+ CreatureID pickedCreature;
|
|
|
+
|
|
|
+ if (!potentialPicks.empty())
|
|
|
+ pickedCreature = *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
|
|
+ else
|
|
|
+ logMod->warn("Failed to select suitable random creature!");
|
|
|
+
|
|
|
+ stack.type = VLC->creh->objects[pickedCreature];
|
|
|
+ stack.count = loadValue(value, rng, variables);
|
|
|
if (!value["upgradeChance"].isNull() && !stack.type->upgrades.empty())
|
|
|
{
|
|
|
if (int(value["upgradeChance"].Float()) > rng.nextInt(99)) // select random upgrade
|
|
@@ -338,17 +493,17 @@ namespace JsonRandom
|
|
|
return stack;
|
|
|
}
|
|
|
|
|
|
- std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng)
|
|
|
+ std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
|
|
{
|
|
|
std::vector<CStackBasicDescriptor> ret;
|
|
|
for (const JsonNode & node : value.Vector())
|
|
|
{
|
|
|
- ret.push_back(loadCreature(node, rng));
|
|
|
+ ret.push_back(loadCreature(node, rng, variables));
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value)
|
|
|
+ std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value, const Variables & variables)
|
|
|
{
|
|
|
std::vector<RandomStackInfo> ret;
|
|
|
for (const JsonNode & node : value.Vector())
|
|
@@ -374,13 +529,6 @@ namespace JsonRandom
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- //std::vector<Component> loadComponents(const JsonNode & value)
|
|
|
- //{
|
|
|
- // std::vector<Component> ret;
|
|
|
- // return ret;
|
|
|
- // //TODO
|
|
|
- //}
|
|
|
-
|
|
|
std::vector<Bonus> DLL_LINKAGE loadBonuses(const JsonNode & value)
|
|
|
{
|
|
|
std::vector<Bonus> ret;
|