mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-13 22:06:58 +02:00
Implemented basic version of configurable Witch Hut
This commit is contained in:
parent
79b7518b0e
commit
fd01a25352
@ -528,13 +528,16 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target) cons
|
||||
}
|
||||
}
|
||||
|
||||
float RewardEvaluator::evaluateWitchHutSkillScore(const CGWitchHut * hut, const CGHeroInstance * hero, HeroRole role) const
|
||||
float RewardEvaluator::evaluateWitchHutSkillScore(const CGObjectInstance * hut, const CGHeroInstance * hero, HeroRole role) const
|
||||
{
|
||||
auto rewardable = dynamic_cast<const CRewardableObject *>(hut);
|
||||
assert(rewardable);
|
||||
|
||||
auto skill = SecondarySkill(*rewardable->configuration.getVariable("secondarySkill", "gainedSkill"));
|
||||
|
||||
if(!hut->wasVisited(hero->tempOwner))
|
||||
return role == HeroRole::SCOUT ? 2 : 0;
|
||||
|
||||
auto skill = SecondarySkill(hut->ability);
|
||||
|
||||
if(hero->getSecSkillLevel(skill) != SecSkillLevel::NONE
|
||||
|| hero->secSkills.size() >= GameConstants::SKILL_PER_HERO)
|
||||
return 0;
|
||||
@ -575,7 +578,7 @@ float RewardEvaluator::getSkillReward(const CGObjectInstance * target, const CGH
|
||||
case Obj::LIBRARY_OF_ENLIGHTENMENT:
|
||||
return 8;
|
||||
case Obj::WITCH_HUT:
|
||||
return evaluateWitchHutSkillScore(dynamic_cast<const CGWitchHut *>(target), hero, role);
|
||||
return evaluateWitchHutSkillScore(target, hero, role);
|
||||
case Obj::PANDORAS_BOX:
|
||||
//Can contains experience, spells, or skills (only on custom maps)
|
||||
return 2.5f;
|
||||
|
@ -18,8 +18,6 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGWitchHut;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
namespace NKAI
|
||||
@ -43,7 +41,7 @@ public:
|
||||
float getResourceRequirementStrength(int resType) const;
|
||||
float getStrategicalValue(const CGObjectInstance * target) const;
|
||||
float getTotalResourceRequirementStrength(int resType) const;
|
||||
float evaluateWitchHutSkillScore(const CGWitchHut * hut, const CGHeroInstance * hero, HeroRole role) const;
|
||||
float evaluateWitchHutSkillScore(const CGObjectInstance * hut, const CGHeroInstance * hero, HeroRole role) const;
|
||||
float getSkillReward(const CGObjectInstance * target, const CGHeroInstance * hero, HeroRole role) const;
|
||||
int32_t getGoldReward(const CGObjectInstance * target, const CGHeroInstance * hero) const;
|
||||
uint64_t getUpgradeArmyReward(const CGTownInstance * town, const BuildingInfo & bi) const;
|
||||
|
@ -90,7 +90,7 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
|
||||
{
|
||||
auto allResources = cb->getResourceAmount();
|
||||
auto income = estimateIncome();
|
||||
GameResID resourceType = EGameResID::INVALID;
|
||||
GameResID resourceType = EGameResID::NONE;
|
||||
TResource amountToCollect = 0;
|
||||
|
||||
using resPair = std::pair<GameResID, TResource>;
|
||||
@ -129,7 +129,7 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (resourceType == EGameResID::INVALID) //no needed resources has 0 income,
|
||||
if (resourceType == EGameResID::NONE) //no needed resources has 0 income,
|
||||
{
|
||||
//find the one which takes longest to collect
|
||||
using timePair = std::pair<GameResID, float>;
|
||||
|
@ -52,6 +52,7 @@
|
||||
"config/objects/moddables.json",
|
||||
"config/objects/creatureBanks.json",
|
||||
"config/objects/dwellings.json",
|
||||
"config/objects/rewardableGeneric.json",
|
||||
"config/objects/rewardableOncePerWeek.json",
|
||||
"config/objects/rewardablePickable.json",
|
||||
"config/objects/rewardableOnceVisitable.json",
|
||||
|
@ -587,26 +587,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"witchHut" : {
|
||||
"index" :113,
|
||||
"handler" : "witch",
|
||||
"base" : {
|
||||
"sounds" : {
|
||||
"visit" : ["GAZEBO"]
|
||||
}
|
||||
},
|
||||
"types" : {
|
||||
"object" : {
|
||||
"index" : 0,
|
||||
"aiValue" : 1500,
|
||||
"rmg" : {
|
||||
"zoneLimit" : 3,
|
||||
"value" : 1500,
|
||||
"rarity" : 80
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"questGuard" : {
|
||||
"index" :215,
|
||||
"handler" : "questGuard",
|
||||
|
@ -220,7 +220,7 @@ Keep in mind, that all randomization is performed on map load and on object rese
|
||||
```jsonc
|
||||
"resources": [
|
||||
{
|
||||
"list" : [ "wood", "ore" ],
|
||||
"anyOf" : [ "wood", "ore" ],
|
||||
"amount" : 10
|
||||
},
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ private:
|
||||
std::string identifier;
|
||||
|
||||
public:
|
||||
CSkill(const SecondarySkill & id = SecondarySkill::DEFAULT, std::string identifier = "default", bool obligatoryMajor = false, bool obligatoryMinor = false);
|
||||
CSkill(const SecondarySkill & id = SecondarySkill::NONE, std::string identifier = "default", bool obligatoryMajor = false, bool obligatoryMinor = false);
|
||||
~CSkill() = default;
|
||||
|
||||
enum class Obligatory : ui8
|
||||
|
@ -32,38 +32,71 @@ 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;
|
||||
}
|
||||
|
||||
template<typename IdentifierType>
|
||||
IdentifierType decodeKey(const JsonNode & value)
|
||||
IdentifierType decodeKey(const std::string & modScope, const std::string & value, const Variables & variables)
|
||||
{
|
||||
return IdentifierType(*VLC->identifiers()->getIdentifier(IdentifierType::entityType(), value));
|
||||
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<>
|
||||
PrimarySkill decodeKey(const JsonNode & value)
|
||||
PrimarySkill decodeKey(const JsonNode & value, const Variables & variables)
|
||||
{
|
||||
return PrimarySkill(*VLC->identifiers()->getIdentifier("primarySkill", value));
|
||||
}
|
||||
@ -143,7 +176,7 @@ namespace JsonRandom
|
||||
|
||||
if (!value["level"].isNull())
|
||||
{
|
||||
int32_t spellLevel = value["level"].Float();
|
||||
int32_t spellLevel = value["level"].Integer();
|
||||
|
||||
vstd::erase_if(result, [=](const SpellID & spell)
|
||||
{
|
||||
@ -164,17 +197,17 @@ namespace JsonRandom
|
||||
}
|
||||
|
||||
template<typename IdentifierType>
|
||||
std::set<IdentifierType> filterKeys(const JsonNode & value, const std::set<IdentifierType> & valuesSet)
|
||||
std::set<IdentifierType> filterKeys(const JsonNode & value, const std::set<IdentifierType> & valuesSet, const Variables & variables)
|
||||
{
|
||||
if(value.isString())
|
||||
return { decodeKey<IdentifierType>(value) };
|
||||
return { decodeKey<IdentifierType>(value, variables) };
|
||||
|
||||
assert(value.isStruct());
|
||||
|
||||
if(value.isStruct())
|
||||
{
|
||||
if(!value["type"].isNull())
|
||||
return filterKeys(value["type"], valuesSet);
|
||||
return filterKeys(value["type"], valuesSet, variables);
|
||||
|
||||
std::set<IdentifierType> filteredTypes = filterKeysTyped(value, valuesSet);
|
||||
|
||||
@ -183,7 +216,7 @@ namespace JsonRandom
|
||||
std::set<IdentifierType> filteredAnyOf;
|
||||
for (auto const & entry : value["anyOf"].Vector())
|
||||
{
|
||||
std::set<IdentifierType> subset = filterKeys(entry, valuesSet);
|
||||
std::set<IdentifierType> subset = filterKeys(entry, valuesSet, variables);
|
||||
filteredAnyOf.insert(subset.begin(), subset.end());
|
||||
}
|
||||
|
||||
@ -197,7 +230,7 @@ namespace JsonRandom
|
||||
{
|
||||
for (auto const & entry : value["noneOf"].Vector())
|
||||
{
|
||||
std::set<IdentifierType> subset = filterKeys(entry, valuesSet);
|
||||
std::set<IdentifierType> subset = filterKeys(entry, valuesSet, variables);
|
||||
for (auto bannedEntry : subset )
|
||||
filteredTypes.erase(bannedEntry);
|
||||
}
|
||||
@ -208,25 +241,25 @@ namespace JsonRandom
|
||||
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<GameResID> defaultResources{
|
||||
GameResID::WOOD,
|
||||
@ -238,9 +271,9 @@ namespace JsonRandom
|
||||
GameResID::GOLD
|
||||
};
|
||||
|
||||
std::set<GameResID> potentialPicks = filterKeys(value, defaultResources);
|
||||
std::set<GameResID> potentialPicks = filterKeys(value, defaultResources, variables);
|
||||
GameResID resourceID = *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
||||
si32 resourceAmount = loadValue(value, rng, 0);
|
||||
si32 resourceAmount = loadValue(value, rng, variables, 0);
|
||||
|
||||
TResources ret;
|
||||
ret[resourceID] = resourceAmount;
|
||||
@ -248,14 +281,14 @@ namespace JsonRandom
|
||||
}
|
||||
|
||||
|
||||
std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng)
|
||||
std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
||||
{
|
||||
std::vector<si32> ret;
|
||||
if(value.isStruct())
|
||||
{
|
||||
for(const auto & name : NPrimarySkill::names)
|
||||
{
|
||||
ret.push_back(loadValue(value[name], rng));
|
||||
ret.push_back(loadValue(value[name], rng, variables));
|
||||
}
|
||||
}
|
||||
if(value.isVector())
|
||||
@ -271,25 +304,36 @@ namespace JsonRandom
|
||||
|
||||
for(const auto & element : value.Vector())
|
||||
{
|
||||
std::set<PrimarySkill> potentialPicks = filterKeys(element, defaultSkills);
|
||||
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);
|
||||
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())
|
||||
@ -301,45 +345,45 @@ namespace JsonRandom
|
||||
|
||||
for(const auto & element : value.Vector())
|
||||
{
|
||||
std::set<SecondarySkill> potentialPicks = filterKeys(element, defaultSkills);
|
||||
std::set<SecondarySkill> potentialPicks = filterKeys(element, defaultSkills, variables);
|
||||
SecondarySkill skillID = *RandomGeneratorUtil::nextItem(potentialPicks, rng);
|
||||
|
||||
defaultSkills.erase(skillID); //avoid dupicates
|
||||
ret[skillID] = loadValue(element, rng);
|
||||
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)
|
||||
{
|
||||
std::set<ArtifactID> allowedArts;
|
||||
for (auto const * artifact : VLC->arth->allowedArtifacts)
|
||||
allowedArts.insert(artifact->getId());
|
||||
|
||||
std::set<ArtifactID> potentialPicks = filterKeys(value, allowedArts);
|
||||
std::set<ArtifactID> potentialPicks = filterKeys(value, allowedArts, variables);
|
||||
|
||||
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)
|
||||
{
|
||||
std::set<SpellID> defaultSpells;
|
||||
for(const auto & spell : VLC->spellh->objects)
|
||||
if (IObjectInterface::cb->isAllowed(0, spell->getIndex()))
|
||||
defaultSpells.insert(spell->getId());
|
||||
|
||||
std::set<SpellID> potentialPicks = filterKeys(value, defaultSpells);
|
||||
std::set<SpellID> potentialPicks = filterKeys(value, defaultSpells, variables);
|
||||
|
||||
if (potentialPicks.empty())
|
||||
{
|
||||
@ -349,12 +393,12 @@ namespace JsonRandom
|
||||
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;
|
||||
}
|
||||
@ -399,7 +443,7 @@ namespace JsonRandom
|
||||
return ret;
|
||||
}
|
||||
|
||||
CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng)
|
||||
CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
||||
{
|
||||
CStackBasicDescriptor stack;
|
||||
|
||||
@ -408,7 +452,7 @@ namespace JsonRandom
|
||||
if (!creature->special)
|
||||
defaultCreatures.insert(creature->getId());
|
||||
|
||||
std::set<CreatureID> potentialPicks = filterKeys(value, defaultCreatures);
|
||||
std::set<CreatureID> potentialPicks = filterKeys(value, defaultCreatures, variables);
|
||||
CreatureID pickedCreature;
|
||||
|
||||
if (!potentialPicks.empty())
|
||||
@ -417,7 +461,7 @@ namespace JsonRandom
|
||||
logMod->warn("Failed to select suitable random creature!");
|
||||
|
||||
stack.type = VLC->creh->objects[pickedCreature];
|
||||
stack.count = loadValue(value, rng);
|
||||
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
|
||||
@ -428,17 +472,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())
|
||||
@ -464,13 +508,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;
|
||||
|
@ -24,6 +24,8 @@ class CStackBasicDescriptor;
|
||||
|
||||
namespace JsonRandom
|
||||
{
|
||||
using Variables = std::map<std::string, int>;
|
||||
|
||||
struct DLL_LINKAGE RandomStackInfo
|
||||
{
|
||||
std::vector<const CCreature *> allowedCreatures;
|
||||
@ -31,29 +33,29 @@ namespace JsonRandom
|
||||
si32 maxAmount;
|
||||
};
|
||||
|
||||
DLL_LINKAGE si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0);
|
||||
DLL_LINKAGE si32 loadValue(const JsonNode & value, CRandomGenerator & rng, const Variables & variables, si32 defaultValue = 0);
|
||||
|
||||
DLL_LINKAGE TResources loadResources(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE TResources loadResource(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE std::map<SecondarySkill, si32> loadSecondary(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE TResources loadResources(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE TResources loadResource(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE SecondarySkill loadSecondary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE std::map<SecondarySkill, si32> loadSecondaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
|
||||
DLL_LINKAGE ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
|
||||
DLL_LINKAGE SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells = {});
|
||||
DLL_LINKAGE std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const std::vector<SpellID> & spells = {});
|
||||
DLL_LINKAGE SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
|
||||
DLL_LINKAGE CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value);
|
||||
DLL_LINKAGE CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value, const Variables & variables);
|
||||
|
||||
DLL_LINKAGE std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE std::vector<HeroTypeID> loadHeroes(const JsonNode & value, CRandomGenerator & rng);
|
||||
DLL_LINKAGE std::vector<HeroClassID> loadHeroClasses(const JsonNode & value, CRandomGenerator & rng);
|
||||
|
||||
DLL_LINKAGE std::vector<Bonus> loadBonuses(const JsonNode & value);
|
||||
//DLL_LINKAGE std::vector<Component> loadComponents(const JsonNode & value);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -308,8 +308,7 @@ class SecondarySkillBase : public IdentifierBase
|
||||
public:
|
||||
enum Type : int32_t
|
||||
{
|
||||
WRONG = -2,
|
||||
DEFAULT = -1,
|
||||
NONE = -1,
|
||||
PATHFINDING = 0,
|
||||
ARCHERY,
|
||||
LOGISTICS,
|
||||
@ -938,7 +937,7 @@ public:
|
||||
COUNT,
|
||||
|
||||
WOOD_AND_ORE = 127, // special case for town bonus resource
|
||||
INVALID = -1
|
||||
NONE = -1
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -37,17 +37,15 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const
|
||||
{
|
||||
BankConfig bc;
|
||||
JsonRandom::Variables emptyVariables;
|
||||
|
||||
bc.chance = static_cast<ui32>(level["chance"].Float());
|
||||
bc.guards = JsonRandom::loadCreatures(level["guards"], rng);
|
||||
|
||||
std::vector<SpellID> spells;
|
||||
IObjectInterface::cb->getAllowedSpells(spells);
|
||||
bc.guards = JsonRandom::loadCreatures(level["guards"], rng, emptyVariables);
|
||||
|
||||
bc.resources = ResourceSet(level["reward"]["resources"]);
|
||||
bc.creatures = JsonRandom::loadCreatures(level["reward"]["creatures"], rng);
|
||||
bc.artifacts = JsonRandom::loadArtifacts(level["reward"]["artifacts"], rng);
|
||||
bc.spells = JsonRandom::loadSpells(level["reward"]["spells"], rng, spells);
|
||||
bc.creatures = JsonRandom::loadCreatures(level["reward"]["creatures"], rng, emptyVariables);
|
||||
bc.artifacts = JsonRandom::loadArtifacts(level["reward"]["artifacts"], rng, emptyVariables);
|
||||
bc.spells = JsonRandom::loadSpells(level["reward"]["spells"], rng, emptyVariables);
|
||||
|
||||
return bc;
|
||||
}
|
||||
@ -105,10 +103,12 @@ static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature *
|
||||
|
||||
IObjectInfo::CArmyStructure CBankInfo::minGuards() const
|
||||
{
|
||||
JsonRandom::Variables emptyVariables;
|
||||
|
||||
std::vector<IObjectInfo::CArmyStructure> armies;
|
||||
for(auto configEntry : config)
|
||||
{
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"], emptyVariables);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
for(auto & stack : stacks)
|
||||
{
|
||||
@ -126,10 +126,12 @@ IObjectInfo::CArmyStructure CBankInfo::minGuards() const
|
||||
|
||||
IObjectInfo::CArmyStructure CBankInfo::maxGuards() const
|
||||
{
|
||||
JsonRandom::Variables emptyVariables;
|
||||
|
||||
std::vector<IObjectInfo::CArmyStructure> armies;
|
||||
for(auto configEntry : config)
|
||||
{
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"], emptyVariables);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
for(auto & stack : stacks)
|
||||
{
|
||||
@ -147,12 +149,13 @@ IObjectInfo::CArmyStructure CBankInfo::maxGuards() const
|
||||
|
||||
TPossibleGuards CBankInfo::getPossibleGuards() const
|
||||
{
|
||||
JsonRandom::Variables emptyVariables;
|
||||
TPossibleGuards out;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & guardsInfo = configEntry["guards"];
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo);
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo, emptyVariables);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
|
||||
|
||||
@ -187,12 +190,13 @@ std::vector<PossibleReward<TResources>> CBankInfo::getPossibleResourcesReward()
|
||||
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> CBankInfo::getPossibleCreaturesReward() const
|
||||
{
|
||||
JsonRandom::Variables emptyVariables;
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> aproximateReward;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & guardsInfo = configEntry["reward"]["creatures"];
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo);
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo, emptyVariables);
|
||||
|
||||
for(auto stack : stacks)
|
||||
{
|
||||
|
@ -95,7 +95,6 @@ CObjectClassesHandler::CObjectClassesHandler()
|
||||
SET_HANDLER("monolith", CGMonolith);
|
||||
SET_HANDLER("subterraneanGate", CGSubterraneanGate);
|
||||
SET_HANDLER("whirlpool", CGWhirlpool);
|
||||
SET_HANDLER("witch", CGWitchHut);
|
||||
SET_HANDLER("terrain", CGTerrainPatch);
|
||||
|
||||
#undef SET_HANDLER_CLASS
|
||||
|
@ -35,8 +35,7 @@ public:
|
||||
{
|
||||
AObjectTypeHandler::serialize(h, version);
|
||||
|
||||
if (version >= 816)
|
||||
h & objectInfo;
|
||||
h & objectInfo;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -256,9 +256,11 @@ void MarketInstanceConstructor::initializeObject(CGMarket * market) const
|
||||
|
||||
void MarketInstanceConstructor::randomizeObject(CGMarket * object, CRandomGenerator & rng) const
|
||||
{
|
||||
JsonRandom::Variables emptyVariables;
|
||||
|
||||
if(auto * university = dynamic_cast<CGUniversity *>(object))
|
||||
{
|
||||
for(auto skill : JsonRandom::loadSecondary(predefinedOffer, rng))
|
||||
for(auto skill : JsonRandom::loadSecondaries(predefinedOffer, rng, emptyVariables))
|
||||
university->skills.push_back(skill.first.getNum());
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,8 @@ void DwellingInstanceConstructor::randomizeObject(CGDwelling * object, CRandomGe
|
||||
}
|
||||
else if(guards.getType() == JsonNode::JsonType::DATA_VECTOR) //custom guards (eg. Elemental Conflux)
|
||||
{
|
||||
for(auto & stack : JsonRandom::loadCreatures(guards, rng))
|
||||
JsonRandom::Variables emptyVariables;
|
||||
for(auto & stack : JsonRandom::loadCreatures(guards, rng, emptyVariables))
|
||||
{
|
||||
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->getId(), stack.count));
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ void ShrineInstanceConstructor::initTypeData(const JsonNode & config)
|
||||
|
||||
void ShrineInstanceConstructor::randomizeObject(CGShrine * shrine, CRandomGenerator & rng) const
|
||||
{
|
||||
JsonRandom::Variables emptyVariables;
|
||||
|
||||
auto visitTextParameter = parameters["visitText"];
|
||||
|
||||
if (visitTextParameter.isNumber())
|
||||
@ -31,12 +33,7 @@ void ShrineInstanceConstructor::randomizeObject(CGShrine * shrine, CRandomGenera
|
||||
shrine->visitText.appendRawString(visitTextParameter.String());
|
||||
|
||||
if(shrine->spell == SpellID::NONE) // shrine has no predefined spell
|
||||
{
|
||||
std::vector<SpellID> possibilities;
|
||||
shrine->cb->getAllowedSpells(possibilities);
|
||||
|
||||
shrine->spell =JsonRandom::loadSpell(parameters["spell"], rng, possibilities);
|
||||
}
|
||||
shrine->spell =JsonRandom::loadSpell(parameters["spell"], rng, emptyVariables);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -253,7 +253,7 @@ CGHeroInstance::CGHeroInstance():
|
||||
{
|
||||
setNodeType(HERO);
|
||||
ID = Obj::HERO;
|
||||
secSkills.emplace_back(SecondarySkill::DEFAULT, -1);
|
||||
secSkills.emplace_back(SecondarySkill::NONE, -1);
|
||||
blockVisit = true;
|
||||
}
|
||||
|
||||
@ -315,7 +315,7 @@ void CGHeroInstance::initHero(CRandomGenerator & rand)
|
||||
pushPrimSkill(static_cast<PrimarySkill>(g), type->heroClass->primarySkillInitial[g]);
|
||||
}
|
||||
}
|
||||
if(secSkills.size() == 1 && secSkills[0] == std::pair<SecondarySkill,ui8>(SecondarySkill::DEFAULT, -1)) //set secondary skills to default
|
||||
if(secSkills.size() == 1 && secSkills[0] == std::pair<SecondarySkill,ui8>(SecondarySkill::NONE, -1)) //set secondary skills to default
|
||||
secSkills = type->secSkillsInit;
|
||||
|
||||
if (gender == EHeroGender::DEFAULT)
|
||||
@ -1580,7 +1580,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
||||
bool normalSkills = false;
|
||||
for(const auto & p : secSkills)
|
||||
{
|
||||
if(p.first == SecondarySkill(SecondarySkill::DEFAULT))
|
||||
if(p.first == SecondarySkill(SecondarySkill::NONE))
|
||||
defaultSkills = true;
|
||||
else
|
||||
normalSkills = true;
|
||||
@ -1618,7 +1618,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
||||
secSkills.clear();
|
||||
if(secondarySkills.getType() == JsonNode::JsonType::DATA_NULL)
|
||||
{
|
||||
secSkills.emplace_back(SecondarySkill::DEFAULT, -1);
|
||||
secSkills.emplace_back(SecondarySkill::NONE, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -90,7 +90,6 @@ public:
|
||||
|
||||
// POSSIBLE
|
||||
// class DLL_LINKAGE CGSignBottle : public CGObjectInstance //signs and ocean bottles
|
||||
// class DLL_LINKAGE CGWitchHut : public CPlayersVisited
|
||||
// class DLL_LINKAGE CGScholar : public CGObjectInstance
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -842,98 +842,6 @@ void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler)
|
||||
}
|
||||
}
|
||||
|
||||
void CGWitchHut::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
if (allowedAbilities.empty()) //this can happen for RMG and RoE maps.
|
||||
{
|
||||
auto defaultAllowed = VLC->skillh->getDefaultAllowed();
|
||||
|
||||
// Necromancy and Leadership can't be learned by default
|
||||
defaultAllowed[SecondarySkill::NECROMANCY] = false;
|
||||
defaultAllowed[SecondarySkill::LEADERSHIP] = false;
|
||||
|
||||
for(int i = 0; i < defaultAllowed.size(); i++)
|
||||
if (defaultAllowed[i] && cb->isAllowed(2, i))
|
||||
allowedAbilities.insert(SecondarySkill(i));
|
||||
}
|
||||
ability = *RandomGeneratorUtil::nextItem(allowedAbilities, rand);
|
||||
}
|
||||
|
||||
void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.type = EInfoWindowMode::AUTO;
|
||||
iw.player = h->getOwner();
|
||||
if(!wasVisited(h->tempOwner))
|
||||
cb->setObjProperty(id, CGWitchHut::OBJPROP_VISITED, h->tempOwner.getNum());
|
||||
ui32 txt_id;
|
||||
if(h->getSecSkillLevel(SecondarySkill(ability))) //you already know this skill
|
||||
{
|
||||
txt_id =172;
|
||||
}
|
||||
else if(!h->canLearnSkill()) //already all skills slots used
|
||||
{
|
||||
txt_id = 173;
|
||||
}
|
||||
else //give sec skill
|
||||
{
|
||||
iw.components.emplace_back(Component::EComponentType::SEC_SKILL, ability, 1, 0);
|
||||
txt_id = 171;
|
||||
cb->changeSecSkill(h, SecondarySkill(ability), 1, true);
|
||||
}
|
||||
|
||||
iw.text.appendLocalString(EMetaText::ADVOB_TXT,txt_id);
|
||||
iw.text.replaceLocalString(EMetaText::SEC_SKILL_NAME, ability);
|
||||
cb->showInfoDialog(&iw);
|
||||
}
|
||||
|
||||
std::string CGWitchHut::getHoverText(PlayerColor player) const
|
||||
{
|
||||
std::string hoverName = getObjectName();
|
||||
if(wasVisited(player))
|
||||
{
|
||||
hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s)
|
||||
boost::algorithm::replace_first(hoverName, "%s", VLC->skillh->getByIndex(ability)->getNameTranslated());
|
||||
}
|
||||
return hoverName;
|
||||
}
|
||||
|
||||
std::string CGWitchHut::getHoverText(const CGHeroInstance * hero) const
|
||||
{
|
||||
std::string hoverName = getHoverText(hero->tempOwner);
|
||||
if(wasVisited(hero->tempOwner) && hero->getSecSkillLevel(SecondarySkill(ability))) //hero knows that ability
|
||||
hoverName += "\n\n" + VLC->generaltexth->allTexts[357]; // (Already learned)
|
||||
return hoverName;
|
||||
}
|
||||
|
||||
void CGWitchHut::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
{
|
||||
//TODO: unify allowed abilities with others - make them std::vector<bool>
|
||||
|
||||
std::vector<bool> temp;
|
||||
size_t skillCount = VLC->skillh->size();
|
||||
temp.resize(skillCount, false);
|
||||
|
||||
auto standard = VLC->skillh->getDefaultAllowed(); //todo: for WitchHut default is all except Leadership and Necromancy
|
||||
|
||||
if(handler.saving)
|
||||
{
|
||||
for(SecondarySkill i(0); i < SecondarySkill(skillCount); ++i)
|
||||
if(vstd::contains(allowedAbilities, i))
|
||||
temp[i] = true;
|
||||
}
|
||||
|
||||
handler.serializeLIC("allowedSkills", &CSkillHandler::decodeSkill, &CSkillHandler::encodeSkill, standard, temp);
|
||||
|
||||
if(!handler.saving)
|
||||
{
|
||||
allowedAbilities.clear();
|
||||
for(si32 i = 0; i < skillCount; ++i)
|
||||
if(temp[i])
|
||||
allowedAbilities.insert(SecondarySkill(i));
|
||||
}
|
||||
}
|
||||
|
||||
void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
InfoWindow iw;
|
||||
|
@ -57,26 +57,6 @@ protected:
|
||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CGWitchHut : public CTeamVisited
|
||||
{
|
||||
public:
|
||||
std::set<SecondarySkill> allowedAbilities;
|
||||
SecondarySkill ability;
|
||||
|
||||
std::string getHoverText(PlayerColor player) const override;
|
||||
std::string getHoverText(const CGHeroInstance * hero) const override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void initObj(CRandomGenerator & rand) override;
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CTeamVisited&>(*this);
|
||||
h & allowedAbilities;
|
||||
h & ability;
|
||||
}
|
||||
protected:
|
||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CGScholar : public CGObjectInstance
|
||||
{
|
||||
public:
|
||||
|
@ -1139,23 +1139,40 @@ CGObjectInstance * CMapLoaderH3M::readSign(const int3 & mapPosition)
|
||||
return object;
|
||||
}
|
||||
|
||||
CGObjectInstance * CMapLoaderH3M::readWitchHut()
|
||||
CGObjectInstance * CMapLoaderH3M::readWitchHut(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate)
|
||||
{
|
||||
auto * object = new CGWitchHut();
|
||||
auto * object = readGeneric(position, objectTemplate);
|
||||
auto * rewardable = dynamic_cast<CRewardableObject*>(object);
|
||||
|
||||
assert(rewardable);
|
||||
|
||||
// AB and later maps have allowed abilities defined in H3M
|
||||
if(features.levelAB)
|
||||
{
|
||||
reader->readBitmaskSkills(object->allowedAbilities, false);
|
||||
std::set<SecondarySkill> allowedAbilities;
|
||||
reader->readBitmaskSkills(allowedAbilities, false);
|
||||
|
||||
if(object->allowedAbilities.size() != 1)
|
||||
if(allowedAbilities.size() != 1)
|
||||
{
|
||||
auto defaultAllowed = VLC->skillh->getDefaultAllowed();
|
||||
|
||||
for(int skillID = 0; skillID < VLC->skillh->size(); ++skillID)
|
||||
if(defaultAllowed[skillID])
|
||||
object->allowedAbilities.insert(SecondarySkill(skillID));
|
||||
allowedAbilities.insert(SecondarySkill(skillID));
|
||||
}
|
||||
|
||||
JsonVector anyOfList;
|
||||
|
||||
for (auto const & skill : allowedAbilities)
|
||||
{
|
||||
JsonNode entry;
|
||||
entry.String() = VLC->skills()->getById(skill)->getJsonKey();
|
||||
anyOfList.push_back(entry);
|
||||
}
|
||||
JsonNode variable;
|
||||
variable.Vector() = anyOfList;
|
||||
|
||||
rewardable->configuration.presetVariable("secondarySkill", "gainedSkill", variable);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
@ -1458,7 +1475,7 @@ CGObjectInstance * CMapLoaderH3M::readObject(std::shared_ptr<const ObjectTemplat
|
||||
return readSeerHut(mapPosition, objectInstanceID);
|
||||
|
||||
case Obj::WITCH_HUT:
|
||||
return readWitchHut();
|
||||
return readWitchHut(mapPosition, objectTemplate);
|
||||
case Obj::SCHOLAR:
|
||||
return readScholar();
|
||||
|
||||
@ -1717,7 +1734,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const int3 & mapPosition, const Objec
|
||||
{
|
||||
if(!object->secSkills.empty())
|
||||
{
|
||||
if(object->secSkills[0].first != SecondarySkill::DEFAULT)
|
||||
if(object->secSkills[0].first != SecondarySkill::NONE)
|
||||
logGlobal->debug("Map '%s': Hero %s subID=%d has set secondary skills twice (in map properties and on adventure map instance). Using the latter set...", mapName, object->getNameTextID(), object->subID);
|
||||
object->secSkills.clear();
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ private:
|
||||
CGObjectInstance * readSeerHut(const int3 & initialPos, const ObjectInstanceID & idToBeGiven);
|
||||
CGObjectInstance * readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);
|
||||
CGObjectInstance * readSign(const int3 & position);
|
||||
CGObjectInstance * readWitchHut();
|
||||
CGObjectInstance * readWitchHut(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
|
||||
CGObjectInstance * readScholar();
|
||||
CGObjectInstance * readGarrison(const int3 & mapPosition);
|
||||
CGObjectInstance * readArtifact(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);
|
||||
|
@ -147,7 +147,6 @@ void registerTypesMapObjectTypes(Serializer &s)
|
||||
REGISTER_GENERIC_HANDLER(CGWhirlpool);
|
||||
REGISTER_GENERIC_HANDLER(CGTownInstance);
|
||||
REGISTER_GENERIC_HANDLER(CGUniversity);
|
||||
REGISTER_GENERIC_HANDLER(CGWitchHut);
|
||||
REGISTER_GENERIC_HANDLER(HillFort);
|
||||
|
||||
#undef REGISTER_GENERIC_HANDLER
|
||||
@ -177,7 +176,6 @@ void registerTypesMapObjects2(Serializer &s)
|
||||
s.template registerType<CGObjectInstance, CRewardableObject>();
|
||||
|
||||
s.template registerType<CGObjectInstance, CTeamVisited>();
|
||||
s.template registerType<CTeamVisited, CGWitchHut>();
|
||||
s.template registerType<CTeamVisited, CGShrine>();
|
||||
s.template registerType<CTeamVisited, CCartographer>();
|
||||
s.template registerType<CTeamVisited, CGObelisk>();
|
||||
|
@ -24,6 +24,38 @@ ui16 Rewardable::Configuration::getResetDuration() const
|
||||
return resetParameters.period;
|
||||
}
|
||||
|
||||
std::optional<int> Rewardable::Configuration::getVariable(const std::string & category, const std::string & name) const
|
||||
{
|
||||
std::string variableID = category + '@' + name;
|
||||
|
||||
if (variables.values.count(variableID))
|
||||
return variables.values.at(variableID);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
JsonNode Rewardable::Configuration::getPresetVariable(const std::string & category, const std::string & name) const
|
||||
{
|
||||
std::string variableID = category + '@' + name;
|
||||
|
||||
if (variables.values.count(variableID))
|
||||
return variables.preset.at(variableID);
|
||||
else
|
||||
return JsonNode();
|
||||
}
|
||||
|
||||
void Rewardable::Configuration::presetVariable(const std::string & category, const std::string & name, const JsonNode & value)
|
||||
{
|
||||
std::string variableID = category + '@' + name;
|
||||
variables.preset[variableID] = value;
|
||||
}
|
||||
|
||||
void Rewardable::Configuration::initVariable(const std::string & category, const std::string & name, int value)
|
||||
{
|
||||
std::string variableID = category + '@' + name;
|
||||
variables.values[variableID] = value;
|
||||
}
|
||||
|
||||
void Rewardable::ResetInfo::serializeJson(JsonSerializeFormat & handler)
|
||||
{
|
||||
handler.serializeInt("period", period);
|
||||
@ -39,6 +71,11 @@ void Rewardable::VisitInfo::serializeJson(JsonSerializeFormat & handler)
|
||||
handler.serializeInt("visitType", visitType);
|
||||
}
|
||||
|
||||
void Rewardable::Variables::serializeJson(JsonSerializeFormat & handler)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Rewardable::Configuration::serializeJson(JsonSerializeFormat & handler)
|
||||
{
|
||||
handler.serializeStruct("onSelect", onSelect);
|
||||
|
@ -62,7 +62,6 @@ struct DLL_LINKAGE ResetInfo
|
||||
/// if true - reset list of visitors (heroes & players) on reset
|
||||
bool visitors;
|
||||
|
||||
|
||||
/// if true - re-randomize rewards on a new week
|
||||
bool rewards;
|
||||
|
||||
@ -86,7 +85,7 @@ struct DLL_LINKAGE VisitInfo
|
||||
|
||||
/// Event to which this reward is assigned
|
||||
EEventType visitType;
|
||||
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
@ -98,6 +97,23 @@ struct DLL_LINKAGE VisitInfo
|
||||
}
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE Variables
|
||||
{
|
||||
/// List of variables used by this object in their current values
|
||||
std::map<std::string, int> values;
|
||||
|
||||
/// List of per-instance preconfigured variables, e.g. from map
|
||||
std::map<std::string, JsonNode> preset;
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & values;
|
||||
h & preset;
|
||||
}
|
||||
};
|
||||
|
||||
/// Base class that can handle granting rewards to visiting heroes.
|
||||
struct DLL_LINKAGE Configuration
|
||||
{
|
||||
@ -116,6 +132,9 @@ struct DLL_LINKAGE Configuration
|
||||
/// how and when should the object be reset
|
||||
Rewardable::ResetInfo resetParameters;
|
||||
|
||||
/// List of variables shoread between all limiters and rewards
|
||||
Rewardable::Variables variables;
|
||||
|
||||
/// if true - player can refuse visiting an object (e.g. Tomb)
|
||||
bool canRefuse = false;
|
||||
|
||||
@ -124,6 +143,11 @@ struct DLL_LINKAGE Configuration
|
||||
|
||||
EVisitMode getVisitMode() const;
|
||||
ui16 getResetDuration() const;
|
||||
|
||||
std::optional<int> getVariable(const std::string & category, const std::string & name) const;
|
||||
JsonNode getPresetVariable(const std::string & category, const std::string & name) const;
|
||||
void presetVariable(const std::string & category, const std::string & name, const JsonNode & value);
|
||||
void initVariable(const std::string & category, const std::string & name, int value);
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
|
||||
|
@ -102,26 +102,23 @@ Rewardable::LimitersList Rewardable::Info::configureSublimiters(Rewardable::Conf
|
||||
|
||||
void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRandomGenerator & rng, Rewardable::Limiter & limiter, const JsonNode & source) const
|
||||
{
|
||||
std::vector<SpellID> spells;
|
||||
IObjectInterface::cb->getAllowedSpells(spells);
|
||||
auto const & variables = object.variables.values;
|
||||
|
||||
limiter.dayOfWeek = JsonRandom::loadValue(source["dayOfWeek"], rng, variables);
|
||||
limiter.daysPassed = JsonRandom::loadValue(source["daysPassed"], rng, variables);
|
||||
limiter.heroExperience = JsonRandom::loadValue(source["heroExperience"], rng, variables);
|
||||
limiter.heroLevel = JsonRandom::loadValue(source["heroLevel"], rng, variables);
|
||||
|
||||
limiter.dayOfWeek = JsonRandom::loadValue(source["dayOfWeek"], rng);
|
||||
limiter.daysPassed = JsonRandom::loadValue(source["daysPassed"], rng);
|
||||
limiter.heroExperience = JsonRandom::loadValue(source["heroExperience"], rng);
|
||||
limiter.heroLevel = JsonRandom::loadValue(source["heroLevel"], rng)
|
||||
+ JsonRandom::loadValue(source["minLevel"], rng); // VCMI 1.1 compatibilty
|
||||
limiter.manaPercentage = JsonRandom::loadValue(source["manaPercentage"], rng, variables);
|
||||
limiter.manaPoints = JsonRandom::loadValue(source["manaPoints"], rng, variables);
|
||||
|
||||
limiter.manaPercentage = JsonRandom::loadValue(source["manaPercentage"], rng);
|
||||
limiter.manaPoints = JsonRandom::loadValue(source["manaPoints"], rng);
|
||||
limiter.resources = JsonRandom::loadResources(source["resources"], rng, variables);
|
||||
|
||||
limiter.resources = JsonRandom::loadResources(source["resources"], rng);
|
||||
|
||||
limiter.primary = JsonRandom::loadPrimary(source["primary"], rng);
|
||||
limiter.secondary = JsonRandom::loadSecondary(source["secondary"], rng);
|
||||
limiter.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng);
|
||||
limiter.spells = JsonRandom::loadSpells(source["spells"], rng, spells);
|
||||
limiter.creatures = JsonRandom::loadCreatures(source["creatures"], rng);
|
||||
limiter.primary = JsonRandom::loadPrimary(source["primary"], rng, variables);
|
||||
limiter.secondary = JsonRandom::loadSecondaries(source["secondary"], rng, variables);
|
||||
limiter.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng, variables);
|
||||
limiter.spells = JsonRandom::loadSpells(source["spells"], rng, variables);
|
||||
limiter.creatures = JsonRandom::loadCreatures(source["creatures"], rng, variables);
|
||||
|
||||
limiter.players = JsonRandom::loadColors(source["colors"], rng);
|
||||
limiter.heroes = JsonRandom::loadHeroes(source["heroes"], rng);
|
||||
@ -134,36 +131,32 @@ void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRan
|
||||
|
||||
void Rewardable::Info::configureReward(Rewardable::Configuration & object, CRandomGenerator & rng, Rewardable::Reward & reward, const JsonNode & source) const
|
||||
{
|
||||
reward.resources = JsonRandom::loadResources(source["resources"], rng);
|
||||
auto const & variables = object.variables.values;
|
||||
|
||||
reward.heroExperience = JsonRandom::loadValue(source["heroExperience"], rng)
|
||||
+ JsonRandom::loadValue(source["gainedExp"], rng); // VCMI 1.1 compatibilty
|
||||
reward.resources = JsonRandom::loadResources(source["resources"], rng, variables);
|
||||
|
||||
reward.heroLevel = JsonRandom::loadValue(source["heroLevel"], rng)
|
||||
+ JsonRandom::loadValue(source["gainedLevels"], rng); // VCMI 1.1 compatibilty
|
||||
reward.heroExperience = JsonRandom::loadValue(source["heroExperience"], rng, variables);
|
||||
reward.heroLevel = JsonRandom::loadValue(source["heroLevel"], rng, variables);
|
||||
|
||||
reward.manaDiff = JsonRandom::loadValue(source["manaPoints"], rng);
|
||||
reward.manaOverflowFactor = JsonRandom::loadValue(source["manaOverflowFactor"], rng);
|
||||
reward.manaPercentage = JsonRandom::loadValue(source["manaPercentage"], rng, -1);
|
||||
reward.manaDiff = JsonRandom::loadValue(source["manaPoints"], rng, variables);
|
||||
reward.manaOverflowFactor = JsonRandom::loadValue(source["manaOverflowFactor"], rng, variables);
|
||||
reward.manaPercentage = JsonRandom::loadValue(source["manaPercentage"], rng, variables, -1);
|
||||
|
||||
reward.movePoints = JsonRandom::loadValue(source["movePoints"], rng);
|
||||
reward.movePercentage = JsonRandom::loadValue(source["movePercentage"], rng, -1);
|
||||
reward.movePoints = JsonRandom::loadValue(source["movePoints"], rng, variables);
|
||||
reward.movePercentage = JsonRandom::loadValue(source["movePercentage"], rng, variables, -1);
|
||||
|
||||
reward.removeObject = source["removeObject"].Bool();
|
||||
reward.bonuses = JsonRandom::loadBonuses(source["bonuses"]);
|
||||
|
||||
reward.primary = JsonRandom::loadPrimary(source["primary"], rng);
|
||||
reward.secondary = JsonRandom::loadSecondary(source["secondary"], rng);
|
||||
reward.primary = JsonRandom::loadPrimary(source["primary"], rng, variables);
|
||||
reward.secondary = JsonRandom::loadSecondaries(source["secondary"], rng, variables);
|
||||
|
||||
std::vector<SpellID> spells;
|
||||
IObjectInterface::cb->getAllowedSpells(spells);
|
||||
|
||||
reward.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng);
|
||||
reward.spells = JsonRandom::loadSpells(source["spells"], rng, spells);
|
||||
reward.creatures = JsonRandom::loadCreatures(source["creatures"], rng);
|
||||
reward.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng, variables);
|
||||
reward.spells = JsonRandom::loadSpells(source["spells"], rng, variables);
|
||||
reward.creatures = JsonRandom::loadCreatures(source["creatures"], rng, variables);
|
||||
if(!source["spellCast"].isNull() && source["spellCast"].isStruct())
|
||||
{
|
||||
reward.spellCast.first = JsonRandom::loadSpell(source["spellCast"]["spell"], rng);
|
||||
reward.spellCast.first = JsonRandom::loadSpell(source["spellCast"]["spell"], rng, variables);
|
||||
reward.spellCast.second = source["spellCast"]["schoolLevel"].Integer();
|
||||
}
|
||||
|
||||
@ -185,11 +178,48 @@ void Rewardable::Info::configureResetInfo(Rewardable::Configuration & object, CR
|
||||
resetParameters.rewards = source["rewards"].Bool();
|
||||
}
|
||||
|
||||
void Rewardable::Info::configureVariables(Rewardable::Configuration & object, CRandomGenerator & rng, const JsonNode & source) const
|
||||
{
|
||||
for(const auto & category : source.Struct())
|
||||
{
|
||||
for(const auto & entry : category.second.Struct())
|
||||
{
|
||||
JsonNode preset = object.getPresetVariable(category.first, entry.first);
|
||||
int32_t value = -1;
|
||||
|
||||
if (category.first == "number")
|
||||
value = JsonRandom::loadValue(entry.second, rng, object.variables.values);
|
||||
|
||||
if (category.first == "artifact")
|
||||
value = JsonRandom::loadArtifact(entry.second, rng, object.variables.values).getNum();
|
||||
|
||||
if (category.first == "spell")
|
||||
value = JsonRandom::loadSpell(entry.second, rng, object.variables.values).getNum();
|
||||
|
||||
// TODO
|
||||
// if (category.first == "creature")
|
||||
// value = JsonRandom::loadCreature(entry.second, rng, object.variables.values).type->getId();
|
||||
|
||||
// TODO
|
||||
// if (category.first == "resource")
|
||||
// value = JsonRandom::loadResource(entry.second, rng, object.variables.values).getNum();
|
||||
|
||||
// TODO
|
||||
// if (category.first == "primarySkill")
|
||||
// value = JsonRandom::loadCreature(entry.second, rng, object.variables.values).getNum();
|
||||
|
||||
if (category.first == "secondarySkill")
|
||||
value = JsonRandom::loadSecondary(entry.second, rng, object.variables.values).getNum();
|
||||
|
||||
object.initVariable(category.first, entry.first, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rewardable::Info::configureRewards(
|
||||
Rewardable::Configuration & object,
|
||||
CRandomGenerator & rng, const
|
||||
JsonNode & source,
|
||||
std::map<si32, si32> & thrownDice,
|
||||
Rewardable::EEventType event,
|
||||
const std::string & modeName) const
|
||||
{
|
||||
@ -200,21 +230,27 @@ void Rewardable::Info::configureRewards(
|
||||
if (!reward["appearChance"].isNull())
|
||||
{
|
||||
JsonNode chance = reward["appearChance"];
|
||||
si32 diceID = static_cast<si32>(chance["dice"].Float());
|
||||
std::string diceID = std::to_string(chance["dice"].Integer());
|
||||
|
||||
if (thrownDice.count(diceID) == 0)
|
||||
thrownDice[diceID] = rng.getIntRange(0, 99)();
|
||||
auto diceValue = object.getVariable("dice", diceID);
|
||||
|
||||
if (!diceValue.has_value())
|
||||
{
|
||||
object.initVariable("dice", diceID, rng.getIntRange(0, 99)());
|
||||
diceValue = object.getVariable("dice", diceID);
|
||||
}
|
||||
assert(diceValue.has_value());
|
||||
|
||||
if (!chance["min"].isNull())
|
||||
{
|
||||
int min = static_cast<int>(chance["min"].Float());
|
||||
if (min > thrownDice[diceID])
|
||||
if (min > *diceValue)
|
||||
continue;
|
||||
}
|
||||
if (!chance["max"].isNull())
|
||||
{
|
||||
int max = static_cast<int>(chance["max"].Float());
|
||||
if (max <= thrownDice[diceID])
|
||||
if (max <= *diceValue)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -240,11 +276,11 @@ void Rewardable::Info::configureObject(Rewardable::Configuration & object, CRand
|
||||
{
|
||||
object.info.clear();
|
||||
|
||||
std::map<si32, si32> thrownDice;
|
||||
configureVariables(object, rng, parameters["variables"]);
|
||||
|
||||
configureRewards(object, rng, parameters["rewards"], thrownDice, Rewardable::EEventType::EVENT_FIRST_VISIT, "rewards");
|
||||
configureRewards(object, rng, parameters["onVisited"], thrownDice, Rewardable::EEventType::EVENT_ALREADY_VISITED, "onVisited");
|
||||
configureRewards(object, rng, parameters["onEmpty"], thrownDice, Rewardable::EEventType::EVENT_NOT_AVAILABLE, "onEmpty");
|
||||
configureRewards(object, rng, parameters["rewards"], Rewardable::EEventType::EVENT_FIRST_VISIT, "rewards");
|
||||
configureRewards(object, rng, parameters["onVisited"], Rewardable::EEventType::EVENT_ALREADY_VISITED, "onVisited");
|
||||
configureRewards(object, rng, parameters["onEmpty"], Rewardable::EEventType::EVENT_NOT_AVAILABLE, "onEmpty");
|
||||
|
||||
object.onSelect = loadMessage(parameters["onSelectMessage"], TextIdentifier(objectTextID, "onSelect"));
|
||||
|
||||
|
@ -32,7 +32,8 @@ class DLL_LINKAGE Info : public IObjectInfo
|
||||
JsonNode parameters;
|
||||
std::string objectTextID;
|
||||
|
||||
void configureRewards(Rewardable::Configuration & object, CRandomGenerator & rng, const JsonNode & source, std::map<si32, si32> & thrownDice, Rewardable::EEventType mode, const std::string & textPrefix) const;
|
||||
void configureVariables(Rewardable::Configuration & object, CRandomGenerator & rng, const JsonNode & source) const;
|
||||
void configureRewards(Rewardable::Configuration & object, CRandomGenerator & rng, const JsonNode & source, Rewardable::EEventType mode, const std::string & textPrefix) const;
|
||||
|
||||
void configureLimiter(Rewardable::Configuration & object, CRandomGenerator & rng, Rewardable::Limiter & limiter, const JsonNode & source) const;
|
||||
Rewardable::LimitersList configureSublimiters(Rewardable::Configuration & object, CRandomGenerator & rng, const JsonNode & source) const;
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../CCreatureSet.h"
|
||||
#include "../ResourceSet.h"
|
||||
#include "../spells/ExternalCaster.h"
|
||||
#include "Configuration.h"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user