Merge pull request #5726 from IvanSavenko/breath

Configurable multi-hex attacks
This commit is contained in:
Ivan Savenko
2025-05-21 17:10:59 +03:00
committed by GitHub
15 changed files with 408 additions and 191 deletions
+73 -53
View File
@@ -192,6 +192,77 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
}
}
static void loadBonusAddInfo(CAddInfo & var, BonusType type, const JsonNode & node)
{
const auto & getFirstValue = [](const JsonNode & jsonNode) -> const JsonNode &
{
if (jsonNode.isVector())
return jsonNode[0];
else
return jsonNode;
};
const JsonNode & value = node["addInfo"];
if (value.isNull())
return;
switch (type)
{
case BonusType::IMPROVED_NECROMANCY:
case BonusType::SPECIAL_ADD_VALUE_ENCHANT:
case BonusType::SPECIAL_FIXED_VALUE_ENCHANT:
case BonusType::DESTRUCTION:
case BonusType::LIMITED_SHOOTING_RANGE:
case BonusType::ACID_BREATH:
case BonusType::SPELLCASTER:
case BonusType::FEROCITY:
case BonusType::PRIMARY_SKILL:
// 1 number
var = getFirstValue(value).Integer();
break;
case BonusType::SPECIAL_UPGRADE:
case BonusType::TRANSMUTATION:
// 1 creature ID
LIBRARY->identifiers()->requestIdentifier("creature", getFirstValue(value), [&](si32 identifier) { var = identifier; });
break;
case BonusType::DEATH_STARE:
// 1 spell ID
LIBRARY->identifiers()->requestIdentifier("spell", getFirstValue(value), [&](si32 identifier) { var = identifier; });
break;
case BonusType::SPELL_BEFORE_ATTACK:
case BonusType::SPELL_AFTER_ATTACK:
// 3 numbers
var.resize(3);
var[0] = value[0].Integer();
var[1] = value[1].Integer();
var[2] = value[2].Integer();
break;
case BonusType::MULTIHEX_UNIT_ATTACK:
case BonusType::MULTIHEX_ENEMY_ATTACK:
case BonusType::MULTIHEX_ANIMATION:
for (const auto & sequence : value.Vector())
{
static const std::map<char, int> charToDirection = {
{ 'f', 1 }, { 'l', 6}, {'r', 2}, {'b', 4}
};
int converted = 0;
for (const auto & ch : boost::adaptors::reverse(sequence.String()))
{
char chLower = std::tolower(ch);
if (charToDirection.count(chLower))
converted = 10 * converted + charToDirection.at(chLower);
}
var.push_back(converted);
}
break;
default:
for(const auto & i : bonusNameMap)
if(i.second == type)
logMod->warn("Bonus type %s does not supports addInfo!", i.first );
}
}
static void loadBonusSourceInstance(BonusSourceID & sourceInstance, BonusSource sourceType, const JsonNode & node)
{
if (node.isNull())
@@ -384,57 +455,6 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonVector & ability_vec)
return b;
}
void JsonUtils::resolveAddInfo(CAddInfo & var, const JsonNode & node)
{
const JsonNode & value = node["addInfo"];
if (!value.isNull())
{
switch (value.getType())
{
case JsonNode::JsonType::DATA_INTEGER:
var = static_cast<si32>(value.Integer());
break;
case JsonNode::JsonType::DATA_FLOAT:
var = static_cast<si32>(value.Float());
break;
case JsonNode::JsonType::DATA_STRING:
LIBRARY->identifiers()->requestIdentifier(value, [&](si32 identifier)
{
var = identifier;
});
break;
case JsonNode::JsonType::DATA_VECTOR:
{
const JsonVector & vec = value.Vector();
var.resize(vec.size());
for(int i = 0; i < vec.size(); i++)
{
switch(vec[i].getType())
{
case JsonNode::JsonType::DATA_INTEGER:
var[i] = static_cast<si32>(vec[i].Integer());
break;
case JsonNode::JsonType::DATA_FLOAT:
var[i] = static_cast<si32>(vec[i].Float());
break;
case JsonNode::JsonType::DATA_STRING:
LIBRARY->identifiers()->requestIdentifier(vec[i], [&var,i](si32 identifier)
{
var[i] = identifier;
});
break;
default:
logMod->error("Error! Wrong identifier used for value of addInfo[%d].", i);
}
}
break;
}
default:
logMod->error("Error! Wrong identifier used for value of addInfo.");
}
}
}
std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
{
switch(limiter.getType())
@@ -665,7 +685,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
b->stacking = ability["stacking"].String();
resolveAddInfo(b->additionalInfo, ability);
loadBonusAddInfo(b->additionalInfo, b->type, ability);
b->turnsRemain = static_cast<si32>(ability["turns"].Float());
@@ -832,7 +852,7 @@ CSelector JsonUtils::parseSelector(const JsonNode & ability)
value = &ability["addInfo"];
if(!value->isNull())
{
resolveAddInfo(info, ability["addInfo"]);
loadBonusAddInfo(info, type, ability["addInfo"]);
ret = ret.And(Selector::info()(info));
}
value = &ability["effectRange"];
-1
View File
@@ -26,7 +26,6 @@ namespace JsonUtils
bool parseBonus(const JsonNode & ability, Bonus * placement);
std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter);
CSelector parseSelector(const JsonNode &ability);
void resolveAddInfo(CAddInfo & var, const JsonNode & node);
}
VCMI_LIB_NAMESPACE_END