1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Moved all once-per-hero visitable (sans Tree) to config

This commit is contained in:
Ivan Savenko
2023-01-22 22:58:53 +02:00
parent a6bda58276
commit bfd6c40f25
8 changed files with 400 additions and 298 deletions

View File

@@ -70,6 +70,15 @@ void AIMemory::markObjectVisited(const CGObjectInstance * obj)
return;
// TODO: maybe this logic belongs to CaptureObjects::shouldVisit
if(const auto * rewardable = dynamic_cast<const CRewardableObject *>(obj))
{
if (rewardable->getVisitMode() == CRewardableObject::VISIT_HERO) //we may want to visit it with another hero
return;
if (rewardable->getVisitMode() == CRewardableObject::VISIT_BONUS) //or another time
return;
}
if(dynamic_cast<const CGVisitableOPH *>(obj)) //we may want to visit it with another hero
return;

View File

@@ -1606,6 +1606,16 @@ void VCAI::markObjectVisited(const CGObjectInstance * obj)
{
if(!obj)
return;
if(const auto * rewardable = dynamic_cast<const CRewardableObject *>(obj)) //we may want to visit it with another hero
{
if (rewardable->getVisitMode() == CRewardableObject::VISIT_HERO) //we may want to visit it with another hero
return;
if (rewardable->getVisitMode() == CRewardableObject::VISIT_BONUS) //or another time
return;
}
if(dynamic_cast<const CGVisitableOPH *>(obj)) //we may want to visit it with another hero
return;
if(dynamic_cast<const CGBonusingObject *>(obj)) //or another time

View File

@@ -53,7 +53,8 @@
"config/objects/dwellings.json",
"config/objects/rewardable.json",
"config/objects/rewardablePickable.json",
"config/objects/rewardableOnceVisitable.json"
"config/objects/rewardableOnceVisitable.json",
"config/objects/rewardableOncePerHero.json"
],
"artifacts" :

View File

@@ -84,207 +84,6 @@
}
}
},
"arena" : {
"index" : 4,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPAREN"],
"visit" : ["NOMAD"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 3000,
"rmg" : {
"value" : 3000,
"rarity" : 50
}
}
}
},
"marlettoTower" : {
"index" : 23,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPSWAR"],
"visit" : ["NOMAD"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
}
}
}
},
"gardenOfRevelation" : {
"index" : 32,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPGARD"],
"visit" : ["GETPROTECTION"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
}
}
}
},
"libraryOfEnlightenment" : {
"index" : 41,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 12000,
"rmg" : {
"value" : 12000,
"rarity" : 20
}
}
}
},
"mercenaryCamp" : {
"index" : 51,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPMERC"],
"visit" : ["NOMAD"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
}
}
}
},
"starAxis" :{
"index" : 61,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPSTAR"],
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
}
}
}
},
"treeOfKnowledge" : {
"index" : 102,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 2500,
"rmg" : {
"mapLimit" : 100,
"value" : 2500,
"rarity" : 50
}
}
}
},
"schoolOfMagic" : {
"index" : 47,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPMAGI"],
"visit" : ["FAERIE"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1000,
"rmg" : {
"value" : 1000,
"rarity" : 50
}
}
}
},
"schoolOfWar" : {
"index" : 107,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPSWAR"],
"visit" : ["MILITARY"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1000,
"rmg" : {
"value" : 1000,
"rarity" : 50
}
}
}
},
"learningStone" : {
"index" : 100,
"handler": "oncePerHero",
"base" : {
"sounds" : {
"ambient" : ["LOOPLEAR"],
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 200
}
},
"objectWoG" : { "index" : 1 } // WoG object? Present on VCMI_Tests 2011
}
},
"buoy" : {
"index" : 11,
"handler": "bonusingObject",

View File

@@ -0,0 +1,362 @@
{
/// These are objects that covered by concept of "configurable object" and have their entire configuration in this config
"arena" : {
"index" : 4,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPAREN"],
"visit" : ["NOMAD"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 3000,
"rmg" : {
"value" : 3000,
"rarity" : 50
},
"onSelectMessage" : 0,
"onVisitedMessage" : 1,
"visitMode" : "hero",
"selectMode" : "selectPlayer",
"rewards" : [
{
"primary" : { "attack" : 2 }
},
{
"primary" : { "defence" : 2 }
}
]
}
}
},
"marlettoTower" : {
"index" : 23,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPSWAR"],
"visit" : ["NOMAD"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
},
"onVisitedMessage" : 40,
"visitMode" : "hero",
"selectMode" : "selectPlayer",
"rewards" : [
{
"message" : 39,
"primary" : { "defence" : 1 }
}
]
}
}
},
"gardenOfRevelation" : {
"index" : 32,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPGARD"],
"visit" : ["GETPROTECTION"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
},
"onVisitedMessage" : 60,
"visitMode" : "hero",
"selectMode" : "selectPlayer",
"rewards" : [
{
"message" : 59,
"primary" : { "knowledge" : 1 }
}
]
}
}
},
"libraryOfEnlightenment" : {
"index" : 41,
"handler": "configurable",
"base" : {
"sounds" : {
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 12000,
"rmg" : {
"value" : 12000,
"rarity" : 20
},
"onVisitedMessage" : 67,
"onEmptyMessage" : 68,
"visitMode" : "hero",
"selectMode" : "selectFirst",
"rewards" : [
{
"limiter" : {
"minLevel" : 10
},
"message" : 59,
"primary" : {
"attack" : 2,
"defence" : 2,
"spellpower" : 2,
"knowledge" : 2
}
},
{
"limiter" : {
"minLevel" : 8,
"secondary" : { "diplomacy" : 1 }
},
"message" : 59,
"primary" : {
"attack" : 2,
"defence" : 2,
"spellpower" : 2,
"knowledge" : 2
}
},
{
"limiter" : {
"minLevel" : 6,
"secondary" : { "diplomacy" : 2 }
},
"message" : 59,
"primary" : {
"attack" : 2,
"defence" : 2,
"spellpower" : 2,
"knowledge" : 2
}
},
{
"limiter" : {
"minLevel" : 4,
"secondary" : { "diplomacy" : 3 }
},
"message" : 59,
"primary" : {
"attack" : 2,
"defence" : 2,
"spellpower" : 2,
"knowledge" : 2
}
}
]
}
}
},
"mercenaryCamp" : {
"index" : 51,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPMERC"],
"visit" : ["NOMAD"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
},
"onVisitedMessage" : 81,
"visitMode" : "hero",
"selectMode" : "selectPlayer",
"rewards" : [
{
"message" : 80,
"primary" : { "attack" : 1 }
}
]
}
}
},
"starAxis" :{
"index" : 61,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPSTAR"],
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 100
},
"onVisitedMessage" : 101,
"visitMode" : "hero",
"selectMode" : "selectPlayer",
"rewards" : [
{
"message" : 100,
"primary" : { "spellpower" : 1 }
}
]
}
}
},
"treeOfKnowledge" : {
"index" : 102,
"handler": "oncePerHero", //TODO: configurable
"base" : {
"sounds" : {
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 2500,
"rmg" : {
"mapLimit" : 100,
"value" : 2500,
"rarity" : 50
}
}
}
},
"schoolOfMagic" : {
"index" : 47,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPMAGI"],
"visit" : ["FAERIE"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1000,
"rmg" : {
"value" : 1000,
"rarity" : 50
},
"onSelectMessage" : 71,
"onVisitedMessage" : 72,
"onEmptyMessage" : 73,
"visitMode" : "hero",
"selectMode" : "selectPlayer",
"canRefuse" : true,
"rewards" : [
{
"limiter" : { "resources" : { "gold" : 1000 } },
"resources" : { "gold" : -1000 },
"primary" : { "spellpower" : 2 }
},
{
"limiter" : { "resources" : { "gold" : 1000 } },
"resources" : { "gold" : -1000 },
"primary" : { "knowledge" : 2 }
}
]
}
}
},
"schoolOfWar" : {
"index" : 107,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPSWAR"],
"visit" : ["MILITARY"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1000,
"rmg" : {
"value" : 1000,
"rarity" : 50
},
"onSelectMessage" : 158,
"onVisitedMessage" : 159,
"onEmptyMessage" : 160,
"visitMode" : "hero",
"selectMode" : "selectPlayer",
"canRefuse" : true,
"rewards" : [
{
"limiter" : { "resources" : { "gold" : 1000 } },
"resources" : { "gold" : -1000 },
"primary" : { "attack" : 1 }
},
{
"limiter" : { "resources" : { "gold" : 1000 } },
"resources" : { "gold" : -1000 },
"primary" : { "defence" : 1 }
}
]
}
}
},
"learningStone" : {
"index" : 100,
"handler": "configurable",
"base" : {
"sounds" : {
"ambient" : ["LOOPLEAR"],
"visit" : ["GAZEBO"]
}
},
"types" : {
"object" : {
"index" : 0,
"aiValue" : 1500,
"rmg" : {
"value" : 1500,
"rarity" : 200
},
"onVisitedMessage" : 144,
"visitMode" : "hero",
"selectMode" : "selectFirst",
"rewards" : [
{
"message" : 143,
"gainedExp" : 1000
}
]
}
}
},
}

View File

@@ -69,7 +69,6 @@
"artifacts" : [ { "class" : "MINOR" } ]
}
]
}
}
},

View File

@@ -359,6 +359,11 @@ bool CRewardableObject::wasVisited(const CGHeroInstance * h) const
}
}
CRewardableObject::EVisitMode CRewardableObject::getVisitMode() const
{
return EVisitMode(visitMode);
}
void CRewardInfo::loadComponents(std::vector<Component> & comps,
const CGHeroInstance * h) const
{
@@ -663,44 +668,6 @@ void CGVisitableOPH::initObj(CRandomGenerator & rand)
{
switch(ID)
{
case Obj::ARENA:
info.resize(2);
info[0].reward.primary[PrimarySkill::ATTACK] = 2;
info[1].reward.primary[PrimarySkill::DEFENSE] = 2;
onSelect.addTxt(MetaString::ADVOB_TXT, 0);
onVisited.addTxt(MetaString::ADVOB_TXT, 1);
canRefuse = true;
break;
case Obj::MERCENARY_CAMP:
info.resize(1);
info[0].reward.primary[PrimarySkill::ATTACK] = 1;
info[0].message.addTxt(MetaString::ADVOB_TXT, 80);
onVisited.addTxt(MetaString::ADVOB_TXT, 81);
break;
case Obj::MARLETTO_TOWER:
info.resize(1);
info[0].reward.primary[PrimarySkill::DEFENSE] = 1;
info[0].message.addTxt(MetaString::ADVOB_TXT, 39);
onVisited.addTxt(MetaString::ADVOB_TXT, 40);
break;
case Obj::STAR_AXIS:
info.resize(1);
info[0].reward.primary[PrimarySkill::SPELL_POWER] = 1;
info[0].message.addTxt(MetaString::ADVOB_TXT, 100);
onVisited.addTxt(MetaString::ADVOB_TXT, 101);
break;
case Obj::GARDEN_OF_REVELATION:
info.resize(1);
info[0].reward.primary[PrimarySkill::KNOWLEDGE] = 1;
info[0].message.addTxt(MetaString::ADVOB_TXT, 59);
onVisited.addTxt(MetaString::ADVOB_TXT, 60);
break;
case Obj::LEARNING_STONE:
info.resize(1);
info[0].reward.gainedExp = 1000;
info[0].message.addTxt(MetaString::ADVOB_TXT, 143);
onVisited.addTxt(MetaString::ADVOB_TXT, 144);
break;
case Obj::TREE_OF_KNOWLEDGE:
info.resize(1);
canRefuse = true;
@@ -726,54 +693,6 @@ void CGVisitableOPH::initObj(CRandomGenerator & rand)
break;
}
break;
case Obj::LIBRARY_OF_ENLIGHTENMENT:
{
selectMode = SELECT_FIRST;
onVisited.addTxt(MetaString::ADVOB_TXT, 67);
onEmpty.addTxt(MetaString::ADVOB_TXT, 68);
CVisitInfo visit;
visit.reward.primary[PrimarySkill::ATTACK] = 2;
visit.reward.primary[PrimarySkill::DEFENSE] = 2;
visit.reward.primary[PrimarySkill::KNOWLEDGE] = 2;
visit.reward.primary[PrimarySkill::SPELL_POWER] = 2;
visit.message.addTxt(MetaString::ADVOB_TXT, 66);
static_assert(SecSkillLevel::LEVELS_SIZE == 4, "Behavior of Library of Enlignment may not be correct");
for (int i=0; i<SecSkillLevel::LEVELS_SIZE; i++)
{
visit.limiter.minLevel = 10 - i * 2;
visit.limiter.secondary[SecondarySkill::DIPLOMACY] = i;
info.push_back(visit);
}
break;
}
case Obj::SCHOOL_OF_MAGIC:
info.resize(2);
info[0].reward.primary[PrimarySkill::SPELL_POWER] = 1;
info[1].reward.primary[PrimarySkill::KNOWLEDGE] = 1;
info[0].limiter.resources[Res::GOLD] = 1000;
info[0].reward.resources[Res::GOLD] = -1000;
info[1].limiter.resources[Res::GOLD] = 1000;
info[1].reward.resources[Res::GOLD] = -1000;
onSelect.addTxt(MetaString::ADVOB_TXT, 71);
onVisited.addTxt(MetaString::ADVOB_TXT, 72);
onEmpty.addTxt(MetaString::ADVOB_TXT, 73);
canRefuse = true;
break;
case Obj::SCHOOL_OF_WAR:
info.resize(2);
info[0].reward.primary[PrimarySkill::ATTACK] = 1;
info[1].reward.primary[PrimarySkill::DEFENSE] = 1;
info[0].limiter.resources[Res::GOLD] = 1000;
info[0].reward.resources[Res::GOLD] = -1000;
info[1].limiter.resources[Res::GOLD] = 1000;
info[1].reward.resources[Res::GOLD] = -1000;
onSelect.addTxt(MetaString::ADVOB_TXT, 158);
onVisited.addTxt(MetaString::ADVOB_TXT, 159);
onEmpty.addTxt(MetaString::ADVOB_TXT, 160);
canRefuse = true;
break;
}
}

View File

@@ -198,15 +198,7 @@ class DLL_LINKAGE CRewardableObject : public CArmedInstance
/// grants reward to hero
void grantRewardBeforeLevelup(const CVisitInfo & reward, const CGHeroInstance * hero) const;
protected:
/// controls selection of reward granted to player
enum ESelectMode
{
SELECT_FIRST, // first reward that matches limiters
SELECT_PLAYER, // player can select from all allowed rewards
SELECT_RANDOM // reward will be selected from allowed randomly
};
public:
enum EVisitMode
{
VISIT_UNLIMITED, // any number of times. Side effect - object hover text won't contain visited/not visited text
@@ -216,6 +208,15 @@ protected:
VISIT_PLAYER // every player can visit object once
};
protected:
/// controls selection of reward granted to player
enum ESelectMode
{
SELECT_FIRST, // first reward that matches limiters
SELECT_PLAYER, // player can select from all allowed rewards
SELECT_RANDOM // reward will be selected from allowed randomly
};
/// filters list of visit info and returns rewards that can be granted to current hero
virtual std::vector<ui32> getAvailableRewards(const CGHeroInstance * hero) const;
@@ -247,6 +248,8 @@ protected:
bool canRefuse;
public:
EVisitMode getVisitMode() const;
void setPropertyDer(ui8 what, ui32 val) override;
std::string getHoverText(PlayerColor player) const override;
std::string getHoverText(const CGHeroInstance * hero) const override;