diff --git a/lib/CDefObjInfoHandler.h b/lib/CDefObjInfoHandler.h index f32486a11..3c314af89 100644 --- a/lib/CDefObjInfoHandler.h +++ b/lib/CDefObjInfoHandler.h @@ -16,6 +16,7 @@ class CBinaryReader; class CLegacyConfigParser; class JsonNode; +class CRandomGenerator; class DLL_LINKAGE ObjectTemplate { @@ -128,7 +129,7 @@ public: virtual CGObjectInstance * create(ObjectTemplate tmpl) const = 0; - virtual void configureObject(CGObjectInstance * object) const = 0; + virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const = 0; }; diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index b797066d9..bfb529db7 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -120,6 +120,19 @@ void CIdentifierStorage::tryRequestIdentifier(std::string type, const JsonNode & requestIdentifier(ObjectCallback(name.meta, pair.first, type, pair.second, callback, true)); } +boost::optional CIdentifierStorage::getIdentifier(std::string scope, std::string type, std::string name, bool silent) +{ + auto pair = splitString(name, ':'); // remoteScope:name + auto idList = getPossibleIdentifiers(ObjectCallback(scope, pair.first, type, pair.second, std::function(), silent)); + + if (idList.size() == 1) + return idList.front().id; + if (!silent) + logGlobal->errorStream() << "Failed to resolve identifier " << name << " from mod " << scope; + + return boost::optional(); +} + boost::optional CIdentifierStorage::getIdentifier(std::string type, const JsonNode & name, bool silent) { auto pair = splitString(name.String(), ':'); // remoteScope:name diff --git a/lib/CModHandler.h b/lib/CModHandler.h index dfd042466..c845bc8cc 100644 --- a/lib/CModHandler.h +++ b/lib/CModHandler.h @@ -70,6 +70,7 @@ public: void tryRequestIdentifier(std::string type, const JsonNode & name, const std::function & callback); /// get identifier immediately. If identifier is not know and not silent call will result in error message + boost::optional getIdentifier(std::string scope, std::string type, std::string name, bool silent = false); boost::optional getIdentifier(std::string type, const JsonNode & name, bool silent = false); boost::optional getIdentifier(const JsonNode & name, bool silent = false); diff --git a/lib/CObjectConstructor.cpp b/lib/CObjectConstructor.cpp index 3ce38894b..6838f9c95 100644 --- a/lib/CObjectConstructor.cpp +++ b/lib/CObjectConstructor.cpp @@ -1,6 +1,10 @@ #include "StdInc.h" #include "CObjectConstructor.h" +#include "CRandomGenerator.h" +#include "StringConstants.h" +#include "CCreatureHandler.h" + /* * CObjectConstructor.cpp, part of VCMI engine * @@ -11,54 +15,224 @@ * */ +namespace { + si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0) + { + if (value.isNull()) + return defaultValue; + if (value.getType() == JsonNode::DATA_FLOAT) + return value.Float(); + si32 min = value["min"].Float(); + si32 max = value["max"].Float(); + return rng.getIntRange(min, max)(); + } + + TResources loadResources(const JsonNode & value, CRandomGenerator & rng) + { + TResources ret; + for (size_t i=0; i loadPrimary(const JsonNode & value, CRandomGenerator & rng) + { + std::vector ret; + for (auto & name : PrimarySkill::names) + { + ret.push_back(loadValue(value[name], rng)); + } + return ret; + } + + std::map loadSecondary(const JsonNode & value, CRandomGenerator & rng) + { + std::map ret; + for (auto & pair : value.Struct()) + { + SecondarySkill id(VLC->modh->identifiers.getIdentifier(pair.second.meta, "skill", pair.first).get()); + ret[id] = loadValue(pair.second, rng); + } + return ret; + } + + std::vector loadArtifacts(const JsonNode & value, CRandomGenerator & rng) + { + std::vector ret; + for (const JsonNode & entry : value.Vector()) + { + ArtifactID art(VLC->modh->identifiers.getIdentifier("artifact", entry).get()); + ret.push_back(art); + } + return ret; + } + + std::vector loadSpells(const JsonNode & value, CRandomGenerator & rng) + { + std::vector ret; + for (const JsonNode & entry : value.Vector()) + { + SpellID spell(VLC->modh->identifiers.getIdentifier("spell", entry).get()); + ret.push_back(spell); + } + return ret; + } + + std::vector loadCreatures(const JsonNode & value, CRandomGenerator & rng) + { + std::vector ret; + for (auto & pair : value.Struct()) + { + CStackBasicDescriptor stack; + stack.type = VLC->creh->creatures[VLC->modh->identifiers.getIdentifier(pair.second.meta, "creature", pair.first).get()]; + stack.count = loadValue(pair.second, rng); + ret.push_back(stack); + } + return ret; + } + + std::vector loadBonuses(const JsonNode & value) + { + std::vector ret; + for (const JsonNode & entry : value.Vector()) + { + Bonus * bonus = JsonUtils::parseBonus(entry); + ret.push_back(*bonus); + delete bonus; + } + return ret; + } + + std::vector loadComponents(const JsonNode & value) + { + //TODO + } + + MetaString loadMessage(const JsonNode & value) + { + MetaString ret; + if (value.getType() == JsonNode::DATA_FLOAT) + ret.addTxt(MetaString::ADVOB_TXT, value.Float()); + else + ret << value.String(); + return ret; + } + + bool testForKey(const JsonNode & value, const std::string & key) + { + for( auto & reward : value["rewards"].Vector() ) + { + if (!reward[key].isNull()) + return true; + } + return false; + } +} + void CRandomRewardObjectInfo::init(const JsonNode & objectConfig) { parameters = objectConfig; } -void CRandomRewardObjectInfo::configureObject(CObjectWithReward * object) const +void CRandomRewardObjectInfo::configureObject(CObjectWithReward * object, CRandomGenerator & rng) const { + for (const JsonNode & reward : parameters["rewards"].Vector()) + { + const JsonNode & limiter = reward["limiter"]; + CVisitInfo info; + // load limiter + info.limiter.numOfGrants = loadValue(limiter["numOfGrants"], rng); + info.limiter.dayOfWeek = loadValue(limiter["dayOfWeek"], rng); + info.limiter.minLevel = loadValue(limiter["minLevel"], rng); + info.limiter.resources = loadResources(limiter["resources"], rng); + info.limiter.primary = loadPrimary(limiter["primary"], rng); + info.limiter.secondary = loadSecondary(limiter["secondary"], rng); + info.limiter.artifacts = loadArtifacts(limiter["artifacts"], rng); + info.limiter.creatures = loadCreatures(limiter["creatures"], rng); + + info.reward.resources = loadResources(reward["resources"], rng); + + info.reward.gainedExp = loadValue(reward["gainedExp"], rng); + info.reward.gainedLevels = loadValue(reward["gainedLevels"], rng); + + info.reward.manaDiff = loadValue(reward["manaPoints"], rng); + info.reward.manaPercentage = loadValue(reward["manaPercentage"], rng, -1); + + info.reward.movePoints = loadValue(reward["movePoints"], rng); + info.reward.movePercentage = loadValue(reward["movePercentage"], rng, -1); + + info.reward.bonuses = loadBonuses(reward["bonuses"]); + + info.reward.primary = loadPrimary(reward["primary"], rng); + info.reward.secondary = loadSecondary(reward["secondary"], rng); + + info.reward.artifacts = loadArtifacts(reward["artifacts"], rng); + info.reward.spells = loadSpells(reward["spells"], rng); + info.reward.creatures = loadCreatures(reward["creatures"], rng); + } + + object->onSelect = loadMessage(parameters["onSelectMessage"]); + object->onVisited = loadMessage(parameters["onVisitedMessage"]); + object->onEmpty = loadMessage(parameters["onEmptyMessage"]); + + //TODO: visitMode and selectMode + + object->soundID = parameters["soundID"].Float(); + object->resetDuration = parameters["resetDuration"].Float(); + object->canRefuse =parameters["canRefuse"].Bool(); } bool CRandomRewardObjectInfo::givesResources() const { + return testForKey(parameters, "resources"); } bool CRandomRewardObjectInfo::givesExperience() const { + return testForKey(parameters, "gainedExp") || testForKey(parameters, "gainedLevels"); } bool CRandomRewardObjectInfo::givesMana() const { + return testForKey(parameters, "manaPoints") || testForKey(parameters, "manaPercentage"); } bool CRandomRewardObjectInfo::givesMovement() const { + return testForKey(parameters, "movePoints") || testForKey(parameters, "movePercentage"); } bool CRandomRewardObjectInfo::givesPrimarySkills() const { + return testForKey(parameters, "primary"); } bool CRandomRewardObjectInfo::givesSecondarySkills() const { + return testForKey(parameters, "secondary"); } bool CRandomRewardObjectInfo::givesArtifacts() const { + return testForKey(parameters, "artifacts"); } bool CRandomRewardObjectInfo::givesCreatures() const { + return testForKey(parameters, "spells"); } bool CRandomRewardObjectInfo::givesSpells() const { + return testForKey(parameters, "creatures"); } bool CRandomRewardObjectInfo::givesBonuses() const { + return testForKey(parameters, "bonuses"); } CObjectWithRewardConstructor::CObjectWithRewardConstructor() @@ -77,9 +251,9 @@ CGObjectInstance * CObjectWithRewardConstructor::create(ObjectTemplate tmpl) con return ret; } -void CObjectWithRewardConstructor::configureObject(CGObjectInstance * object) const +void CObjectWithRewardConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const { - objectInfo.configureObject(dynamic_cast(object)); + objectInfo.configureObject(dynamic_cast(object), rng); } const IObjectInfo * CObjectWithRewardConstructor::getObjectInfo(ObjectTemplate tmpl) const diff --git a/lib/CObjectConstructor.h b/lib/CObjectConstructor.h index bec5d7208..27a88c22f 100644 --- a/lib/CObjectConstructor.h +++ b/lib/CObjectConstructor.h @@ -33,7 +33,7 @@ public: bool givesBonuses() const override; - void configureObject(CObjectWithReward * object) const; + void configureObject(CObjectWithReward * object, CRandomGenerator & rng) const; CRandomRewardObjectInfo() {} @@ -51,7 +51,7 @@ public: CGObjectInstance * create(ObjectTemplate tmpl) const override; - void configureObject(CGObjectInstance * object) const override; + void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const override; };