mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Scholar is now configurable object (partial)
This commit is contained in:
parent
ca368f606f
commit
e10de0594e
@ -1,7 +1,7 @@
|
||||
{
|
||||
"scholar" : {
|
||||
"index" :81,
|
||||
"handler" : "scholar",
|
||||
"handler" : "configurable",
|
||||
"base" : {
|
||||
"sounds" : {
|
||||
"visit" : ["GAZEBO"],
|
||||
@ -9,13 +9,89 @@
|
||||
}
|
||||
},
|
||||
"types" : {
|
||||
"object" : {
|
||||
"scholar" : {
|
||||
"index" : 0,
|
||||
"aiValue" : 1500,
|
||||
"rmg" : {
|
||||
"value" : 1500,
|
||||
"rarity" : 100
|
||||
}
|
||||
},
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"visitMode" : "unlimited",
|
||||
"blockedVisitable" : true,
|
||||
|
||||
"variables" : {
|
||||
"spell" : {
|
||||
"gainedSpell" : { // Note: this variable name is used by engine for H3M loading
|
||||
}
|
||||
},
|
||||
"secondarySkill" : {
|
||||
"gainedSkill" : { // Note: this variable name is used by engine for H3M loading
|
||||
}
|
||||
},
|
||||
"primarySkill" : {
|
||||
"gainedStat" : { // Note: this variable name is used by engine for H3M loading
|
||||
}
|
||||
}
|
||||
},
|
||||
"selectMode" : "selectFirst",
|
||||
"rewards" : [
|
||||
{
|
||||
"appearChance" : { "min" : 0, "max" : 33 },
|
||||
"message" : 115,
|
||||
"limiter" : {
|
||||
"canLearnSpell" : [
|
||||
"@gainedSpell"
|
||||
]
|
||||
},
|
||||
"spells" : [
|
||||
"@gainedSpell"
|
||||
]
|
||||
"removeObject" : true
|
||||
},
|
||||
{
|
||||
"appearChance" : { "min" : 33, "max" : 66 },
|
||||
"message" : 115,
|
||||
"limiter" : {
|
||||
// Hero does not have this skill at expert
|
||||
"noneOf" : [
|
||||
{
|
||||
"secondarySkill" : {
|
||||
"@gainedSkill" : 3
|
||||
}
|
||||
}
|
||||
],
|
||||
// And have either free skill slot or this skill
|
||||
"anyOf" : [
|
||||
{
|
||||
"canLearnSkills" : true
|
||||
},
|
||||
{
|
||||
"noneOf" : [
|
||||
{
|
||||
"secondarySkill" : {
|
||||
"@gainedSkill" : 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"secondary" : {
|
||||
"@gainedSkill" : 1
|
||||
},
|
||||
"removeObject" : true
|
||||
},
|
||||
{
|
||||
// Always present - fallback if hero can't learn secondary / spell
|
||||
"message" : 115,
|
||||
"primary" : {
|
||||
"@gainedStat" : 1
|
||||
},
|
||||
"removeObject" : true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,8 +280,19 @@ namespace JsonRandom
|
||||
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, const Variables & variables)
|
||||
std::vector<si32> loadPrimaries(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
||||
{
|
||||
std::vector<si32> ret;
|
||||
if(value.isStruct())
|
||||
|
@ -37,7 +37,8 @@ namespace JsonRandom
|
||||
|
||||
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 PrimarySkill loadPrimary(const JsonNode & value, CRandomGenerator & rng, const Variables & variables);
|
||||
DLL_LINKAGE std::vector<si32> loadPrimaries(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);
|
||||
|
||||
|
@ -84,7 +84,6 @@ CObjectClassesHandler::CObjectClassesHandler()
|
||||
SET_HANDLER("pandora", CGPandoraBox);
|
||||
SET_HANDLER("prison", CGHeroInstance);
|
||||
SET_HANDLER("questGuard", CGQuestGuard);
|
||||
SET_HANDLER("scholar", CGScholar);
|
||||
SET_HANDLER("seerHut", CGSeerHut);
|
||||
SET_HANDLER("sign", CGSignBottle);
|
||||
SET_HANDLER("siren", CGSirens);
|
||||
|
@ -874,132 +874,6 @@ void CGSignBottle::serializeJsonOptions(JsonSerializeFormat& handler)
|
||||
handler.serializeStruct("text", message);
|
||||
}
|
||||
|
||||
void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
EBonusType type = bonusType;
|
||||
int bid = bonusID;
|
||||
//check if the bonus if applicable, if not - give primary skill (always possible)
|
||||
int ssl = h->getSecSkillLevel(SecondarySkill(bid)); //current sec skill level, used if bonusType == 1
|
||||
if((type == SECONDARY_SKILL && ((ssl == 3) || (!ssl && !h->canLearnSkill()))) ////hero already has expert level in the skill or (don't know skill and doesn't have free slot)
|
||||
|| (type == SPELL && !h->canLearnSpell(SpellID(bid).toSpell())))
|
||||
{
|
||||
type = PRIM_SKILL;
|
||||
bid = CRandomGenerator::getDefault().nextInt(GameConstants::PRIMARY_SKILLS - 1);
|
||||
}
|
||||
|
||||
InfoWindow iw;
|
||||
iw.type = EInfoWindowMode::AUTO;
|
||||
iw.player = h->getOwner();
|
||||
iw.text.appendLocalString(EMetaText::ADVOB_TXT,115);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PRIM_SKILL:
|
||||
cb->changePrimSkill(h,static_cast<PrimarySkill>(bid),+1);
|
||||
iw.components.emplace_back(Component::EComponentType::PRIM_SKILL, bid, +1, 0);
|
||||
break;
|
||||
case SECONDARY_SKILL:
|
||||
cb->changeSecSkill(h,SecondarySkill(bid),+1);
|
||||
iw.components.emplace_back(Component::EComponentType::SEC_SKILL, bid, ssl + 1, 0);
|
||||
break;
|
||||
case SPELL:
|
||||
{
|
||||
std::set<SpellID> hlp;
|
||||
hlp.insert(SpellID(bid));
|
||||
cb->changeSpells(h,true,hlp);
|
||||
iw.components.emplace_back(Component::EComponentType::SPELL, bid, 0, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logGlobal->error("Error: wrong bonus type (%d) for Scholar!\n", static_cast<int>(type));
|
||||
return;
|
||||
}
|
||||
|
||||
cb->showInfoDialog(&iw);
|
||||
cb->removeObject(this, h->getOwner());
|
||||
}
|
||||
|
||||
void CGScholar::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
blockVisit = true;
|
||||
if(bonusType == RANDOM)
|
||||
{
|
||||
bonusType = static_cast<EBonusType>(rand.nextInt(2));
|
||||
switch(bonusType)
|
||||
{
|
||||
case PRIM_SKILL:
|
||||
bonusID = rand.nextInt(GameConstants::PRIMARY_SKILLS -1);
|
||||
break;
|
||||
case SECONDARY_SKILL:
|
||||
bonusID = rand.nextInt(static_cast<int>(VLC->skillh->size()) - 1);
|
||||
break;
|
||||
case SPELL:
|
||||
std::vector<SpellID> possibilities;
|
||||
cb->getAllowedSpells (possibilities);
|
||||
bonusID = *RandomGeneratorUtil::nextItem(possibilities, rand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGScholar::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
{
|
||||
if(handler.saving)
|
||||
{
|
||||
std::string value;
|
||||
switch(bonusType)
|
||||
{
|
||||
case PRIM_SKILL:
|
||||
value = NPrimarySkill::names[bonusID];
|
||||
handler.serializeString("rewardPrimSkill", value);
|
||||
break;
|
||||
case SECONDARY_SKILL:
|
||||
value = CSkillHandler::encodeSkill(bonusID);
|
||||
handler.serializeString("rewardSkill", value);
|
||||
break;
|
||||
case SPELL:
|
||||
value = SpellID::encode(bonusID);
|
||||
handler.serializeString("rewardSpell", value);
|
||||
break;
|
||||
case RANDOM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: unify
|
||||
const JsonNode & json = handler.getCurrent();
|
||||
bonusType = RANDOM;
|
||||
if(!json["rewardPrimSkill"].String().empty())
|
||||
{
|
||||
auto raw = VLC->identifiers()->getIdentifier(ModScope::scopeBuiltin(), "primSkill", json["rewardPrimSkill"].String());
|
||||
if(raw)
|
||||
{
|
||||
bonusType = PRIM_SKILL;
|
||||
bonusID = raw.value();
|
||||
}
|
||||
}
|
||||
else if(!json["rewardSkill"].String().empty())
|
||||
{
|
||||
auto raw = VLC->identifiers()->getIdentifier(ModScope::scopeBuiltin(), "skill", json["rewardSkill"].String());
|
||||
if(raw)
|
||||
{
|
||||
bonusType = SECONDARY_SKILL;
|
||||
bonusID = raw.value();
|
||||
}
|
||||
}
|
||||
else if(!json["rewardSpell"].String().empty())
|
||||
{
|
||||
auto raw = VLC->identifiers()->getIdentifier(ModScope::scopeBuiltin(), "spell", json["rewardSpell"].String());
|
||||
if(raw)
|
||||
{
|
||||
bonusType = SPELL;
|
||||
bonusID = raw.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGGarrison::onHeroVisit (const CGHeroInstance *h) const
|
||||
{
|
||||
auto relations = cb->gameState()->getPlayerRelations(h->tempOwner, tempOwner);
|
||||
|
@ -57,26 +57,6 @@ protected:
|
||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CGScholar : public CGObjectInstance
|
||||
{
|
||||
public:
|
||||
enum EBonusType {PRIM_SKILL, SECONDARY_SKILL, SPELL, RANDOM = 255};
|
||||
EBonusType bonusType;
|
||||
ui16 bonusID; //ID of skill/spell
|
||||
|
||||
CGScholar() : bonusType(EBonusType::RANDOM),bonusID(0){};
|
||||
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<CGObjectInstance&>(*this);
|
||||
h & bonusType;
|
||||
h & bonusID;
|
||||
}
|
||||
protected:
|
||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CGGarrison : public CArmedInstance
|
||||
{
|
||||
public:
|
||||
|
@ -1179,11 +1179,21 @@ CGObjectInstance * CMapLoaderH3M::readWitchHut(const int3 & position, std::share
|
||||
return object;
|
||||
}
|
||||
|
||||
CGObjectInstance * CMapLoaderH3M::readScholar()
|
||||
CGObjectInstance * CMapLoaderH3M::readScholar(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate)
|
||||
{
|
||||
auto * object = new CGScholar();
|
||||
object->bonusType = static_cast<CGScholar::EBonusType>(reader->readUInt8());
|
||||
object->bonusID = reader->readUInt8();
|
||||
enum class ScholarBonusType : uint8_t {
|
||||
PRIM_SKILL = 0,
|
||||
SECONDARY_SKILL = 1,
|
||||
SPELL = 2,
|
||||
RANDOM = 255
|
||||
};
|
||||
|
||||
auto * object = readGeneric(position, objectTemplate);
|
||||
//auto * rewardable = dynamic_cast<CRewardableObject*>(object);
|
||||
|
||||
/*uint8_t bonusTypeRaw =*/ reader->readUInt8();
|
||||
/*auto bonusType = static_cast<ScholarBonusType>(bonusTypeRaw);*/
|
||||
/*auto bonusID =*/ reader->readUInt8();
|
||||
reader->skipZero(6);
|
||||
return object;
|
||||
}
|
||||
@ -1491,7 +1501,7 @@ CGObjectInstance * CMapLoaderH3M::readObject(std::shared_ptr<const ObjectTemplat
|
||||
case Obj::WITCH_HUT:
|
||||
return readWitchHut(mapPosition, objectTemplate);
|
||||
case Obj::SCHOLAR:
|
||||
return readScholar();
|
||||
return readScholar(mapPosition, objectTemplate);
|
||||
|
||||
case Obj::GARRISON:
|
||||
case Obj::GARRISON2:
|
||||
|
@ -166,7 +166,7 @@ private:
|
||||
CGObjectInstance * readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);
|
||||
CGObjectInstance * readSign(const int3 & position);
|
||||
CGObjectInstance * readWitchHut(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
|
||||
CGObjectInstance * readScholar();
|
||||
CGObjectInstance * readScholar(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
|
||||
CGObjectInstance * readGarrison(const int3 & mapPosition);
|
||||
CGObjectInstance * readArtifact(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);
|
||||
CGObjectInstance * readResource(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);
|
||||
|
@ -54,7 +54,6 @@ void registerTypesMapObjects1(Serializer &s)
|
||||
s.template registerType<CGMonolith, CGSubterraneanGate>();
|
||||
s.template registerType<CGMonolith, CGWhirlpool>();
|
||||
s.template registerType<CGObjectInstance, CGSignBottle>();
|
||||
s.template registerType<CGObjectInstance, CGScholar>();
|
||||
s.template registerType<CGObjectInstance, CGKeys>();
|
||||
s.template registerType<CGKeys, CGKeymasterTent>();
|
||||
s.template registerType<CGKeys, CGBorderGuard>(); s.template registerType<IQuestObject, CGBorderGuard>();
|
||||
@ -131,7 +130,6 @@ void registerTypesMapObjectTypes(Serializer &s)
|
||||
REGISTER_GENERIC_HANDLER(CGPandoraBox);
|
||||
REGISTER_GENERIC_HANDLER(CGQuestGuard);
|
||||
REGISTER_GENERIC_HANDLER(CGResource);
|
||||
REGISTER_GENERIC_HANDLER(CGScholar);
|
||||
REGISTER_GENERIC_HANDLER(CGSeerHut);
|
||||
REGISTER_GENERIC_HANDLER(CGShipyard);
|
||||
REGISTER_GENERIC_HANDLER(CGSignBottle);
|
||||
|
@ -115,7 +115,7 @@ void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRan
|
||||
|
||||
limiter.resources = JsonRandom::loadResources(source["resources"], rng, variables);
|
||||
|
||||
limiter.primary = JsonRandom::loadPrimary(source["primary"], rng, variables);
|
||||
limiter.primary = JsonRandom::loadPrimaries(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);
|
||||
@ -150,7 +150,7 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, CRand
|
||||
reward.removeObject = source["removeObject"].Bool();
|
||||
reward.bonuses = JsonRandom::loadBonuses(source["bonuses"]);
|
||||
|
||||
reward.primary = JsonRandom::loadPrimary(source["primary"], rng, variables);
|
||||
reward.primary = JsonRandom::loadPrimaries(source["primary"], rng, variables);
|
||||
reward.secondary = JsonRandom::loadSecondaries(source["secondary"], rng, variables);
|
||||
|
||||
reward.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng, variables);
|
||||
@ -221,9 +221,8 @@ void Rewardable::Info::configureVariables(Rewardable::Configuration & object, CR
|
||||
// if (category.first == "resource")
|
||||
// value = JsonRandom::loadResource(input, rng, object.variables.values).getNum();
|
||||
|
||||
// TODO
|
||||
// if (category.first == "primarySkill")
|
||||
// value = JsonRandom::loadCreature(input, rng, object.variables.values).getNum();
|
||||
if (category.first == "primarySkill")
|
||||
value = static_cast<int>(JsonRandom::loadPrimary(input, rng, object.variables.values));
|
||||
|
||||
if (category.first == "secondarySkill")
|
||||
value = JsonRandom::loadSecondary(input, rng, object.variables.values).getNum();
|
||||
|
Loading…
Reference in New Issue
Block a user