1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Fixes mantis tickets 2899 and 2984 (bugged hero spell specialties)

- stoneskin/haste/prayer/weakness: didnt work because there were 2 bonus objects in buffer and they were filtered out as a possible duplicate (BattleInfo::addOrUpdateUnitBonus). it was fixed by making them a single bonus.
- disrupting-ray and weakness: had opposite effect, because of missing negation
- added a new specialty types: SPECIAL_ADD_VALUE_ENCHANT and SPECIAL_FIXED_VALUE_ENCHANT. this is to make possible specialties like Aenin (fixed specialty value added to spell value) and Melody (fixed value for spell regardless of anything). These specialties can be used in mods with any heroes.
- slayer spell effect calculations was fixed to include hero Coronius-style specialty.
- finally fixed description for Labetha Conflux hero, this is a OH3 bug described here https://heroes.thelazy.net/index.php/Labetha
Changes were tested and work as intended.
commit was made in cooperation with modder Misiokles
This commit is contained in:
MikeLodz 2021-02-08 23:39:52 +01:00
parent db1f9a15b0
commit 38efbb345e
6 changed files with 62 additions and 23 deletions

View File

@ -325,6 +325,11 @@
"class" : "elementalist",
"female": true,
"spellbook": [ "stoneSkin" ],
"texts" : {
"specialty" : {
"description" : "{Stone Skin}\r\n\r\nCasts Stone Skin with increased effect, based on the level of the target unit. (The bonus is greater when used on weaker units)"
}
},
"skills":
[
{ "skill" : "wisdom", "level": "basic" },
@ -375,9 +380,9 @@
"specialty" : {
"bonuses" : {
"disruptingRay" : {
"addInfo" : 0,
"addInfo" : -2,
"subtype" : "spell.disruptingRay",
"type" : "SPECIAL_PECULIAR_ENCHANT"
"type" : "SPECIAL_ADD_VALUE_ENCHANT"
}
}
}

View File

@ -265,8 +265,9 @@
"specialty" : {
"bonuses" : {
"fortune" : {
"addInfo" : 3,
"subtype" : "spell.fortune",
"type" : "MAXED_SPELL"
"type" : "SPECIAL_FIXED_VALUE_ENCHANT"
}
}
}

View File

@ -1472,6 +1472,8 @@ JsonNode subtypeToJson(Bonus::BonusType type, int subtype)
case Bonus::SPECIAL_BLESS_DAMAGE:
case Bonus::MAXED_SPELL:
case Bonus::SPECIAL_PECULIAR_ENCHANT:
case Bonus::SPECIAL_ADD_VALUE_ENCHANT:
case Bonus::SPECIAL_FIXED_VALUE_ENCHANT:
return JsonUtils::stringNode("spell." + (*VLC->spellh)[SpellID::ESpellID(subtype)]->identifier);
case Bonus::IMPROVED_NECROMANCY:
case Bonus::SPECIAL_UPGRADE:
@ -1560,6 +1562,8 @@ std::string Bonus::nameForBonus() const
case Bonus::SPECIAL_BLESS_DAMAGE:
case Bonus::MAXED_SPELL:
case Bonus::SPECIAL_PECULIAR_ENCHANT:
case Bonus::SPECIAL_ADD_VALUE_ENCHANT:
case Bonus::SPECIAL_FIXED_VALUE_ENCHANT:
return (*VLC->spellh)[SpellID::ESpellID(subtype)]->identifier;
case Bonus::SPECIAL_UPGRADE:
return CreatureID::encode(subtype) + "2" + CreatureID::encode(additionalInfo[0]);

View File

@ -281,6 +281,8 @@ public:
BONUS_NAME(SPECIAL_BLESS_DAMAGE) /*val = spell (bless), additionalInfo = value per level in percent*/\
BONUS_NAME(MAXED_SPELL) /*val = id*/\
BONUS_NAME(SPECIAL_PECULIAR_ENCHANT) /*blesses and curses with id = val dependent on unit's level, subtype = 0 or 1 for Coronius*/\
BONUS_NAME(SPECIAL_ADD_VALUE_ENCHANT) /*specialty like Aenin, additionalInfo = value to add*/\
BONUS_NAME(SPECIAL_FIXED_VALUE_ENCHANT) /*specialty like Melody constant 3 luck, additionalInfo = value to fix.*/\
BONUS_NAME(SPECIAL_UPGRADE) /*subtype = base, additionalInfo = target */\
BONUS_NAME(DRAGON_NATURE) \
BONUS_NAME(CREATURE_DAMAGE)/*subtype 0 = both, 1 = min, 2 = max*/\

View File

@ -791,7 +791,15 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo & info)
}
if(isAffected)
{
attackDefenceDifference += SpellID(SpellID::SLAYER).toSpell()->getPower(spLevel);
if(info.attacker->hasBonusOfType(Bonus::SPECIAL_PECULIAR_ENCHANT, SpellID::SLAYER))
{
ui8 attackerTier = info.attacker->unitType()->level;
ui8 specialtyBonus = std::max(5 - attackerTier, 0);
attackDefenceDifference += specialtyBonus;
}
}
}
//bonus from attack/defense skills

View File

@ -151,10 +151,16 @@ void Timed::prepareEffects(SetStackEffect & sse, const Mechanics * m, const Effe
std::vector<Bonus> converted;
convertBonus(m, duration, converted);
std::shared_ptr<const Bonus> bonus = nullptr;
std::shared_ptr<const Bonus> peculiarBonus = nullptr;
std::shared_ptr<const Bonus> addedValueBonus = nullptr;
std::shared_ptr<const Bonus> fixedValueBonus = nullptr;
auto casterHero = dynamic_cast<const CGHeroInstance *>(m->caster);
if(casterHero)
bonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPECIAL_PECULIAR_ENCHANT, m->getSpellIndex()));
{
peculiarBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPECIAL_PECULIAR_ENCHANT, m->getSpellIndex()));
addedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPECIAL_ADD_VALUE_ENCHANT, m->getSpellIndex()));
fixedValueBonus = casterHero->getBonusLocalFirst(Selector::typeSubtype(Bonus::SPECIAL_FIXED_VALUE_ENCHANT, m->getSpellIndex()));
}
//TODO: does hero specialty should affects his stack casting spells?
for(auto & t : target)
@ -175,16 +181,17 @@ void Timed::prepareEffects(SetStackEffect & sse, const Mechanics * m, const Effe
if(describe)
describeEffect(sse.battleLog, m, converted, affected);
si32 power = 0;
const auto tier = std::max(affected->creatureLevel(), 1); //don't divide by 0 for certain creatures (commanders, war machines)
//Apply hero specials - peculiar enchants
const auto tier = std::max(affected->creatureLevel(), 1); //don't divide by 0 for certain creatures (commanders, war machines)
if(bonus)
if(peculiarBonus)
{
switch(bonus->additionalInfo[0])
si32 power = 0;
switch (peculiarBonus->additionalInfo[0])
{
case 0: //normal
switch(tier)
switch (tier)
{
case 1:
case 2:
@ -199,23 +206,35 @@ void Timed::prepareEffects(SetStackEffect & sse, const Mechanics * m, const Effe
power = 1;
break;
}
for(const Bonus & b : converted)
{
Bonus specialBonus(b);
specialBonus.val = power; //it doesn't necessarily make sense for some spells, use it wisely
specialBonus.turnsRemain = duration;
//additional premy to given effect
buffer.push_back(specialBonus);
}
break;
case 1: //only Coronius as yet
case 1:
//Coronius style specialty bonus.
//Please note that actual Coronius isnt here, because Slayer is a spell that doesnt affect monster stats and is used only in calculateDmgRange
power = std::max(5 - tier, 0);
Bonus specialBonus(Bonus::N_TURNS, Bonus::PRIMARY_SKILL, Bonus::SPELL_EFFECT, power, m->getSpellIndex(), PrimarySkill::ATTACK);
specialBonus.turnsRemain = duration;
buffer.push_back(specialBonus);
break;
}
if(m->isNegativeSpell()) {
//negative spells like weakness are defined in json with negative numbers, so we need do same here
power = -1 * power;
}
for(Bonus& b : buffer)
{
b.val += power;
}
}
else if(addedValueBonus)
{
for(Bonus& b : buffer)
{
b.val += addedValueBonus->additionalInfo[0];
}
}
else if(fixedValueBonus)
{
for(Bonus& b : buffer)
{
b.val = fixedValueBonus->additionalInfo[0];
}
}
if(casterHero && casterHero->hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, m->getSpellIndex())) //TODO: better handling of bonus percentages
{