mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
Use generic format for commander bonuses instead of old list-based one
This commit is contained in:
@@ -3,9 +3,9 @@
|
|||||||
//Commander receives these bonuses on level-up
|
//Commander receives these bonuses on level-up
|
||||||
"bonusPerLevel":
|
"bonusPerLevel":
|
||||||
[
|
[
|
||||||
["CREATURE_DAMAGE", 2, "creatureDamageMin", 0 ], //+2 minimum damage
|
{ "type" : "CREATURE_DAMAGE", "val" : 2, "subtype" : "creatureDamageMin" }, //+2 minimum damage
|
||||||
["CREATURE_DAMAGE", 4, "creatureDamageMax", 0 ], //+4 maximum damage
|
{ "type" : "CREATURE_DAMAGE", "val" : 4, "subtype" : "creatureDamageMax" }, //+4 maximum damage
|
||||||
["STACK_HEALTH", 20, null, 0 ] //+20 hp
|
{ "type" : "STACK_HEALTH", "val" : 20 } //+20 hp
|
||||||
],
|
],
|
||||||
//Value of bonuses given by each skill level
|
//Value of bonuses given by each skill level
|
||||||
"skillLevels":
|
"skillLevels":
|
||||||
@@ -22,20 +22,71 @@
|
|||||||
"abilityRequirements":
|
"abilityRequirements":
|
||||||
//Two secondary skills needed for each special ability
|
//Two secondary skills needed for each special ability
|
||||||
[
|
[
|
||||||
{"ability": ["ENEMY_DEFENCE_REDUCTION", 50, null, 0 ], "skills": [0, 1]},
|
{
|
||||||
{"ability": ["FEAR", 0, null, 0 ], "skills": [0, 2]},
|
"ability": [{ "type" : "ENEMY_DEFENCE_REDUCTION", "val": 50 }],
|
||||||
{"ability": ["ALWAYS_MAXIMUM_DAMAGE", 0, null, 0 ], "skills": [0, 3]},
|
"skills": [0, 1]
|
||||||
{"ability": [["SHOOTER", 0, null, 0 ], ["NO_MELEE_PENALTY", 0, null, 0 ]], "skills": [0, 4]},
|
},
|
||||||
{"ability": ["BLOCKS_RETALIATION", 0, null, 0 ], "skills": [0,5]},
|
{
|
||||||
{"ability": ["UNLIMITED_RETALIATIONS", 0, null, 0 ], "skills": [1, 2]},
|
"ability": [{ "type" : "FEAR", "val": 0 }],
|
||||||
{"ability": ["ATTACKS_ALL_ADJACENT", 0, null, 0 ], "skills": [1, 3]},
|
"skills": [0, 2]
|
||||||
{"ability": ["NONE", 30, null, 0 ], "skills": [1, 4]}, // TODO: Implement bonus that gives chance to completely block one enemy attack per turn
|
},
|
||||||
{"ability": ["FIRE_SHIELD", 1, null, 0 ], "skills": [1, 5]},
|
{
|
||||||
{"ability": ["ADDITIONAL_ATTACK", 1, null, 0 ], "skills": [2, 3]},
|
"ability": [{ "type" : "ALWAYS_MAXIMUM_DAMAGE", "val": 0 }],
|
||||||
{"ability": ["HP_REGENERATION", 50, null, 0 ], "skills": [2, 4]},
|
"skills": [0, 3]
|
||||||
{"ability": ["SPELL_AFTER_ATTACK", 30, "spell.paralyze", 0 ], "skills": [2, 5]},
|
},
|
||||||
{"ability": ["JOUSTING", 5, null, 0 ], "skills": [3, 4]},
|
{
|
||||||
{"ability": ["DEATH_STARE", 1, "deathStareCommander", 0 ], "skills": [3,5]},
|
"ability": [
|
||||||
{"ability": ["FLYING", 0, "movementFlying", 0 ], "skills": [4,5]}
|
{ "type" : "SHOOTER", "val": 0 },
|
||||||
|
{ "type" : "NO_MELEE_PENALTY", "val": 0 }
|
||||||
|
],
|
||||||
|
"skills": [0, 4]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "BLOCKS_RETALIATION", "val": 0 }],
|
||||||
|
"skills": [0,5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "UNLIMITED_RETALIATIONS", "val": 0 }],
|
||||||
|
"skills": [1, 2]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "ATTACKS_ALL_ADJACENT", "val": 0 }],
|
||||||
|
"skills": [1, 3]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// TODO: Implement bonus that gives chance to completely block one enemy attack per turn
|
||||||
|
"ability": [{ "type" : "NONE", "val": 30 }],
|
||||||
|
"skills": [1, 4]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "FIRE_SHIELD", "val": 1 }],
|
||||||
|
"skills": [1, 5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "ADDITIONAL_ATTACK", "val": 1 }],
|
||||||
|
"skills": [2, 3]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "HP_REGENERATION", "val": 50 }],
|
||||||
|
"skills": [2, 4]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "SPELL_AFTER_ATTACK", "val": 30, "subtype" : "spell.paralyze" }],
|
||||||
|
"skills": [2, 5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "JOUSTING", "val": 5 }],
|
||||||
|
"skills": [3, 4]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "DEATH_STARE", "val": 1, "subtype" : "deathStareCommander" }],
|
||||||
|
"skills": [3,5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ability": [{ "type" : "FLYING", "val": 0, "subtype" : "movementFlying" }],
|
||||||
|
"skills": [4,5]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -470,6 +470,16 @@ CCreatureHandler::CCreatureHandler()
|
|||||||
|
|
||||||
void CCreatureHandler::loadCommanders()
|
void CCreatureHandler::loadCommanders()
|
||||||
{
|
{
|
||||||
|
const auto & parseBonusWithCompatibility = [](const JsonNode & node)
|
||||||
|
{
|
||||||
|
// MOD COMPATIBILITY: 1.6 mods use old, vector format.
|
||||||
|
// NOTE: please also remove parseBonus itself - commanders is the last place that uses it
|
||||||
|
if (node.isVector())
|
||||||
|
return JsonUtils::parseBonus(node.Vector());
|
||||||
|
else
|
||||||
|
return JsonUtils::parseBonus(node);
|
||||||
|
};
|
||||||
|
|
||||||
auto configResource = JsonPath::builtin("config/commanders.json");
|
auto configResource = JsonPath::builtin("config/commanders.json");
|
||||||
|
|
||||||
std::string modSource = LIBRARY->modh->findResourceOrigin(configResource);
|
std::string modSource = LIBRARY->modh->findResourceOrigin(configResource);
|
||||||
@@ -480,7 +490,7 @@ void CCreatureHandler::loadCommanders()
|
|||||||
|
|
||||||
for (auto bonus : config["bonusPerLevel"].Vector())
|
for (auto bonus : config["bonusPerLevel"].Vector())
|
||||||
{
|
{
|
||||||
commanderLevelPremy.push_back(JsonUtils::parseBonus(bonus.Vector()));
|
commanderLevelPremy.push_back(parseBonusWithCompatibility(bonus));
|
||||||
}
|
}
|
||||||
|
|
||||||
int level = 0;
|
int level = 0;
|
||||||
@@ -497,15 +507,20 @@ void CCreatureHandler::loadCommanders()
|
|||||||
for (auto ability : config["abilityRequirements"].Vector())
|
for (auto ability : config["abilityRequirements"].Vector())
|
||||||
{
|
{
|
||||||
std::pair <std::vector<std::shared_ptr<Bonus> >, std::pair <ui8, ui8> > a;
|
std::pair <std::vector<std::shared_ptr<Bonus> >, std::pair <ui8, ui8> > a;
|
||||||
JsonVector & abilities = ability["ability"].Vector();
|
JsonNode & abilities = ability["ability"];
|
||||||
a.first = std::vector<std::shared_ptr<Bonus> >();
|
|
||||||
if (abilities[0].isVector())
|
if (abilities[0].isString()) // old format with single bonus
|
||||||
for (int i = 0; i < abilities.size(); i++)
|
{
|
||||||
a.first.push_back(JsonUtils::parseBonus(abilities[i].Vector()));
|
a.first.push_back(parseBonusWithCompatibility(abilities));
|
||||||
else
|
}
|
||||||
a.first.push_back(JsonUtils::parseBonus(ability["ability"].Vector()));
|
else
|
||||||
a.second.first = static_cast<ui8>(ability["skills"].Vector()[0].Float());
|
{
|
||||||
a.second.second = static_cast<ui8>(ability["skills"].Vector()[1].Float());
|
for (const auto & ability : abilities.Vector())
|
||||||
|
a.first.push_back(parseBonusWithCompatibility(ability));
|
||||||
|
}
|
||||||
|
|
||||||
|
a.second.first = static_cast<ui8>(ability["skills"][0].Float());
|
||||||
|
a.second.second = static_cast<ui8>(ability["skills"][1].Float());
|
||||||
skillRequirements.push_back (a);
|
skillRequirements.push_back (a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user