1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00

Merge pull request #6010 from Opuszek/fix_abilities_propagation

Fix abilities propagation
This commit is contained in:
Ivan Savenko
2025-08-30 19:58:45 +03:00
committed by GitHub
7 changed files with 221 additions and 19 deletions

View File

@@ -952,6 +952,11 @@
"creatures.core.marksman.bonus.extraAttack" : "{Shoots twice}\nThis unit can shoot twice", "creatures.core.marksman.bonus.extraAttack" : "{Shoots twice}\nThis unit can shoot twice",
"creatures.core.azureDragon.bonus.fearful" : "{Fear}\nEnemy units have a 10% chance of freezing in fear", "creatures.core.azureDragon.bonus.fearful" : "{Fear}\nEnemy units have a 10% chance of freezing in fear",
"creatures.core.azureDragon.bonus.fearless" : "{Fearless}\nImmune to Fear ability", "creatures.core.azureDragon.bonus.fearless" : "{Fearless}\nImmune to Fear ability",
"creatures.core.halfling.bonus.lucky" : "{Lucky}\nHalfling's luck cannot be decreased below +1",
"creatures.core.nomad.bonus.sandWalker" : "{Sand walker}\nHero ignores terrain penalty on sand",
"creatures.core.rogue.bonus.visionsMonsters" : "{Visions Monsters}\nHero can see detailed informations about neutral monsters",
"creatures.core.rogue.bonus.visionsHeroes" : "{Visions Heroes}\nHero can see detailed informations about enemy heroes",
"creatures.core.rogue.bonus.visionsTowns" : "{Visions Towns}\nHero can see detailed informations about enemy towns",
"core.bonus.ADDITIONAL_ATTACK.description" : "{Additional attacks}\nUnit can attack an additional {$val} times", // TODO: alternative descriptions for melee/ranged effect range "core.bonus.ADDITIONAL_ATTACK.description" : "{Additional attacks}\nUnit can attack an additional {$val} times", // TODO: alternative descriptions for melee/ranged effect range
"core.bonus.ADDITIONAL_RETALIATION.description" : "{Additional retaliations}\nUnit can retaliate ${val} extra times", "core.bonus.ADDITIONAL_RETALIATION.description" : "{Additional retaliations}\nUnit can retaliate ${val} extra times",

View File

@@ -868,10 +868,10 @@ void CStackWindow::initBonusesList()
return info->stackNode->bonusToString(v1) < info->stackNode->bonusToString(v2); return info->stackNode->bonusToString(v1) < info->stackNode->bonusToString(v2);
}; };
// these bonuses require special handling. For example they come with own descriptions, for use in morale/luck description receivedBonuses.remove_if([](const Bonus* b)
// also, this information is already available in creature window {
receivedBonuses.remove_if(Selector::type()(BonusType::MORALE)); return !LIBRARY->bth->shouldPropagateDescription(b->type);
receivedBonuses.remove_if(Selector::type()(BonusType::LUCK)); });
std::vector<BonusList> groupedBonuses; std::vector<BonusList> groupedBonuses;
while (!receivedBonuses.empty()) while (!receivedBonuses.empty())

View File

@@ -1,4 +1,14 @@
{ {
"ARTIFACT_GROWING":
{
"blockDescriptionPropagation": true
},
"ARTIFACT_CHARGE":
{
"blockDescriptionPropagation": true
},
"ADDITIONAL_ATTACK": "ADDITIONAL_ATTACK":
{ {
}, },
@@ -10,6 +20,31 @@
"ATTACKS_ALL_ADJACENT": "ATTACKS_ALL_ADJACENT":
{ {
}, },
"BASE_TILE_MOVEMENT_COST":
{
"blockDescriptionPropagation": true
},
"BATTLE_NO_FLEEING":
{
"blockDescriptionPropagation": true
},
"BEFORE_BATTLE_REPOSITION":
{
"blockDescriptionPropagation": true
},
"BEFORE_BATTLE_REPOSITION_BLOCK":
{
"blockDescriptionPropagation": true
},
"BIND_EFFECT":
{
"blockDescriptionPropagation": true
},
"BLOCKS_RANGED_RETALIATION": "BLOCKS_RANGED_RETALIATION":
{ {
@@ -39,11 +74,32 @@
"CHARGE_IMMUNITY": "CHARGE_IMMUNITY":
{ {
}, },
"COMBAT_MANA_BONUS":
{
"blockDescriptionPropagation": true
},
"CREATURE_GROWTH":
{
"blockDescriptionPropagation": true
},
"CREATURE_GROWTH_PERCENT":
{
"blockDescriptionPropagation": true
},
"DARKNESS": "DARKNESS":
{ {
"hidden": true "hidden": true
}, },
"DISGUISED":
{
"hidden": true,
"blockDescriptionPropagation": true
},
"DEATH_STARE": "DEATH_STARE":
{ {
@@ -65,11 +121,6 @@
{ {
}, },
"DISGUISED":
{
"hidden": true
},
"ENCHANTER": "ENCHANTER":
{ {
}, },
@@ -112,6 +163,17 @@
"bonusSubtype.movementTeleporting" : null, "bonusSubtype.movementTeleporting" : null,
} }
}, },
"FLYING_MOVEMENT":
{
"blockDescriptionPropagation": true
},
"FREE_SHIP_BOARDING":
{
"blockDescriptionPropagation": true
},
"FREE_SHOOTING": "FREE_SHOOTING":
{ {
@@ -119,10 +181,12 @@
"FULL_MAP_DARKNESS": "FULL_MAP_DARKNESS":
{ {
"blockDescriptionPropagation": true
}, },
"FULL_MAP_SCOUTING": "FULL_MAP_SCOUTING":
{ {
"blockDescriptionPropagation": true
}, },
"GARGOYLE": "GARGOYLE":
@@ -137,6 +201,11 @@
"bonusSubtype.damageTypeMelee" : null, "bonusSubtype.damageTypeMelee" : null,
} }
}, },
"GENERATE_RESOURCE":
{
"blockDescriptionPropagation": true
},
"HATE": "HATE":
{ {
@@ -150,6 +219,21 @@
{ {
}, },
"HERO_EXPERIENCE_GAIN_PERCENT":
{
"blockDescriptionPropagation": true
},
"HERO_SPELL_CASTS_PER_COMBAT_TURN":
{
"blockDescriptionPropagation": true
},
"IMPROVED_NECROMANCY":
{
"blockDescriptionPropagation": true
},
"JOUSTING": "JOUSTING":
{ {
}, },
@@ -164,12 +248,19 @@
"LEARN_BATTLE_SPELL_CHANCE": "LEARN_BATTLE_SPELL_CHANCE":
{ {
"hidden": true "hidden": true,
"blockDescriptionPropagation": true
}, },
"LEARN_BATTLE_SPELL_LEVEL_LIMIT": "LEARN_BATTLE_SPELL_LEVEL_LIMIT":
{ {
"hidden": true "hidden": true,
"blockDescriptionPropagation": true
},
"LEARN_MEETING_SPELL_LIMIT":
{
"blockDescriptionPropagation": true
}, },
"LEVEL_SPELL_IMMUNITY": "LEVEL_SPELL_IMMUNITY":
@@ -188,6 +279,11 @@
{ {
"creatureNature" : true "creatureNature" : true
}, },
"LUCK":
{
"blockDescriptionPropagation": true
},
"MANA_CHANNELING": "MANA_CHANNELING":
{ {
@@ -205,6 +301,26 @@
{ {
}, },
"MAGIC_SCHOOL_SKILL":
{
"blockDescriptionPropagation": true
},
"MANA_PERCENTAGE_REGENERATION":
{
"blockDescriptionPropagation": true
},
"MANA_PER_KNOWLEDGE_PERCENTAGE":
{
"blockDescriptionPropagation": true
},
"MAX_LEARNABLE_SPELL_LEVEL":
{
"blockDescriptionPropagation": true
},
"MECHANICAL": "MECHANICAL":
{ {
"creatureNature" : true "creatureNature" : true
@@ -214,6 +330,16 @@
{ {
}, },
"MORALE":
{
"blockDescriptionPropagation": true
},
"MOVEMENT":
{
"blockDescriptionPropagation": true
},
"NEGATIVE_EFFECTS_IMMUNITY" : "NEGATIVE_EFFECTS_IMMUNITY" :
{ {
}, },
@@ -241,7 +367,8 @@
"NO_TERRAIN_PENALTY": "NO_TERRAIN_PENALTY":
{ {
"hidden": true "hidden": true,
"blockDescriptionPropagation": true
}, },
"NON_LIVING": "NON_LIVING":
@@ -270,9 +397,24 @@
{ {
}, },
"PRIMARY_SKILL":
{
"blockDescriptionPropagation": true
},
"REBIRTH": "REBIRTH":
{ {
}, },
"RESOURCES_CONSTANT_BOOST":
{
"blockDescriptionPropagation": true
},
"RESOURCES_TOWN_MULTIPLYING_BOOST":
{
"blockDescriptionPropagation": true
},
"RETURN_AFTER_STRIKE": "RETURN_AFTER_STRIKE":
{ {
@@ -282,6 +424,11 @@
{ {
}, },
"ROUGH_TERRAIN_DISCOUNT":
{
"blockDescriptionPropagation": true
},
"SIEGE_WEAPON": "SIEGE_WEAPON":
{ {
"creatureNature" : true "creatureNature" : true
@@ -299,6 +446,11 @@
{ {
}, },
"SIGHT_RADIUS":
{
"blockDescriptionPropagation": true
},
"SOUL_STEAL": "SOUL_STEAL":
{ {
}, },
@@ -350,6 +502,11 @@
"SUMMON_GUARDIANS": "SUMMON_GUARDIANS":
{ {
}, },
"SURRENDER_DISCOUNT":
{
"blockDescriptionPropagation": true
},
"TWO_HEX_ATTACK_BREATH": "TWO_HEX_ATTACK_BREATH":
{ {
@@ -370,25 +527,46 @@
"TRANSMUTATION_IMMUNITY": "TRANSMUTATION_IMMUNITY":
{ {
}, },
"THIEVES_GUILD_ACCESS":
{
"blockDescriptionPropagation": true
},
"UNDEAD": "UNDEAD":
{ {
"creatureNature" : true, "creatureNature" : true,
}, },
"UNDEAD_RAISE_PERCENTAGE":
{
"blockDescriptionPropagation": true
},
"UNLIMITED_RETALIATIONS": "UNLIMITED_RETALIATIONS":
{ {
}, },
"VISIONS": "VISIONS":
{ {
"hidden": true "hidden": true,
"blockDescriptionPropagation": true
}, },
"VULNERABLE_FROM_BACK": "VULNERABLE_FROM_BACK":
{ {
}, },
"WANDERING_CREATURES_JOIN_BONUS":
{
"blockDescriptionPropagation": true
},
"WATER_WALKING":
{
"blockDescriptionPropagation": true
},
"WIDE_BREATH": "WIDE_BREATH":
{ {
}, },

View File

@@ -512,7 +512,8 @@
{ {
"type" : "LUCK", "type" : "LUCK",
"val" : 1, "val" : 1,
"valueType" : "INDEPENDENT_MAX" "valueType" : "INDEPENDENT_MAX",
"description" : "PLACEHOLDER"
} }
}, },
"graphics" : "graphics" :
@@ -621,7 +622,8 @@
{ {
"type" : "NO_TERRAIN_PENALTY", "type" : "NO_TERRAIN_PENALTY",
"subtype" : "terrain.sand", "subtype" : "terrain.sand",
"propagator" : "HERO" "propagator" : "HERO",
"description" : "PLACEHOLDER"
} }
}, },
"graphics" : "graphics" :
@@ -652,7 +654,8 @@
"subtype" : "visionsMonsters", "subtype" : "visionsMonsters",
"val" : 3, "val" : 3,
"valueType" : "INDEPENDENT_MAX", "valueType" : "INDEPENDENT_MAX",
"propagator" : "HERO" "propagator" : "HERO",
"description" : "PLACEHOLDER"
}, },
"visionsHeroes" : "visionsHeroes" :
{ {
@@ -660,7 +663,8 @@
"subtype" : "visionsHeroes", "subtype" : "visionsHeroes",
"val" : 3, "val" : 3,
"valueType" : "INDEPENDENT_MAX", "valueType" : "INDEPENDENT_MAX",
"propagator" : "HERO" "propagator" : "HERO",
"description" : "PLACEHOLDER"
}, },
"visionsTowns" : "visionsTowns" :
{ {
@@ -668,7 +672,8 @@
"subtype" : "visionsTowns", "subtype" : "visionsTowns",
"val" : 3, "val" : 3,
"valueType" : "INDEPENDENT_MAX", "valueType" : "INDEPENDENT_MAX",
"propagator" : "HERO" "propagator" : "HERO",
"description" : "PLACEHOLDER"
} }
}, },
"graphics" : "graphics" :

View File

@@ -15,6 +15,11 @@
"type" : "boolean", "type" : "boolean",
"description" : "If set to true, this bonus will be considered 'creature nature' bonus, and such creature won't be automatically granted LIVING bonus" "description" : "If set to true, this bonus will be considered 'creature nature' bonus, and such creature won't be automatically granted LIVING bonus"
}, },
"blockDescriptionPropagation" : {
"type" : "boolean",
"description" : "If set to true, this ability description will not be displayed if a creature receives it by propagation"
},
"description" : { "description" : {
"type" : "string" "type" : "string"

View File

@@ -142,6 +142,7 @@ void CBonusTypeHandler::loadItem(const JsonNode & source, CBonusType & dest, con
dest.identifier = name; dest.identifier = name;
dest.hidden = source["hidden"].Bool(); //Null -> false dest.hidden = source["hidden"].Bool(); //Null -> false
dest.creatureNature = source["creatureNature"].Bool(); //Null -> false dest.creatureNature = source["creatureNature"].Bool(); //Null -> false
dest.blockDescriptionPropagation = source["blockDescriptionPropagation"].Bool(); //Null -> false
if (!dest.hidden) if (!dest.hidden)
LIBRARY->generaltexth->registerString( "vcmi", dest.getDescriptionTextID(), source["description"]); LIBRARY->generaltexth->registerString( "vcmi", dest.getDescriptionTextID(), source["description"]);
@@ -196,6 +197,12 @@ bool CBonusTypeHandler::isCreatureNatureBonus(BonusType bonus) const
return bonusTypes.at(static_cast<int>(bonus))->creatureNature; return bonusTypes.at(static_cast<int>(bonus))->creatureNature;
} }
bool CBonusTypeHandler::shouldPropagateDescription(BonusType bonus) const
{
return !bonusTypes.at(static_cast<int>(bonus))->blockDescriptionPropagation;
}
std::vector<BonusType> CBonusTypeHandler::getAllObjets() const std::vector<BonusType> CBonusTypeHandler::getAllObjets() const
{ {
std::vector<BonusType> ret; std::vector<BonusType> ret;

View File

@@ -38,6 +38,7 @@ private:
bool creatureNature = false; bool creatureNature = false;
bool hidden = true; bool hidden = true;
bool blockDescriptionPropagation = false;
}; };
class DLL_LINKAGE CBonusTypeHandler : public IBonusTypeHandler class DLL_LINKAGE CBonusTypeHandler : public IBonusTypeHandler
@@ -57,6 +58,7 @@ public:
const std::string & bonusToString(BonusType bonus) const; const std::string & bonusToString(BonusType bonus) const;
bool isCreatureNatureBonus(BonusType bonus) const; bool isCreatureNatureBonus(BonusType bonus) const;
bool shouldPropagateDescription(BonusType bonus) const;
std::vector<BonusType> getAllObjets() const; std::vector<BonusType> getAllObjets() const;
private: private: