mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
trigger Drain Life effects after the attack
- animation and sound are played after the attack - amount of drained life appears after damage dealt in the battle log
This commit is contained in:
@@ -1048,17 +1048,19 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t drainedLife = 0;
|
||||||
|
|
||||||
// only primary target
|
// only primary target
|
||||||
if(defender->alive())
|
if(defender->alive())
|
||||||
applyBattleEffects(bat, blm, attackerState, fireShield, defender, distance, false);
|
drainedLife += applyBattleEffects(bat, attackerState, fireShield, defender, distance, false);
|
||||||
|
|
||||||
//multiple-hex normal attack
|
//multiple-hex normal attack
|
||||||
std::set<const CStack*> attackedCreatures = gs->curB->getAttackedCreatures(attacker, targetHex, bat.shot()); //creatures other than primary target
|
std::set<const CStack*> attackedCreatures = gs->curB->getAttackedCreatures(attacker, targetHex, bat.shot()); //creatures other than primary target
|
||||||
|
|
||||||
for(const CStack * stack : attackedCreatures)
|
for(const CStack * stack : attackedCreatures)
|
||||||
{
|
{
|
||||||
if(stack != defender && stack->alive()) //do not hit same stack twice
|
if(stack != defender && stack->alive()) //do not hit same stack twice
|
||||||
applyBattleEffects(bat, blm, attackerState, fireShield, stack, distance, true);
|
drainedLife += applyBattleEffects(bat, attackerState, fireShield, stack, distance, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type()(Bonus::SPELL_LIKE_ATTACK));
|
std::shared_ptr<const Bonus> bonus = attacker->getBonusLocalFirst(Selector::type()(Bonus::SPELL_LIKE_ATTACK));
|
||||||
@@ -1086,7 +1088,7 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
{
|
{
|
||||||
if(stack != defender && stack->alive()) //do not hit same stack twice
|
if(stack != defender && stack->alive()) //do not hit same stack twice
|
||||||
{
|
{
|
||||||
applyBattleEffects(bat, blm, attackerState, fireShield, stack, distance, true);
|
drainedLife += applyBattleEffects(bat, attackerState, fireShield, stack, distance, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1134,6 +1136,29 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
|
|
||||||
addGenericKilledLog(blm, defender, totalKills, multipleTargets);
|
addGenericKilledLog(blm, defender, totalKills, multipleTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// drain life effect (as well as log entry) must be applied after the attack
|
||||||
|
if(drainedLife > 0)
|
||||||
|
{
|
||||||
|
BattleAttack bat;
|
||||||
|
bat.stackAttacking = attacker->unitId();
|
||||||
|
{
|
||||||
|
CustomEffectInfo customEffect;
|
||||||
|
customEffect.sound = soundBase::DRAINLIF;
|
||||||
|
customEffect.effect = 52;
|
||||||
|
customEffect.stack = attackerState->unitId();
|
||||||
|
bat.customEffects.push_back(std::move(customEffect));
|
||||||
|
}
|
||||||
|
sendAndApply(&bat);
|
||||||
|
|
||||||
|
MetaString text;
|
||||||
|
attackerState->addText(text, MetaString::GENERAL_TXT, 361);
|
||||||
|
attackerState->addNameReplacement(text, false);
|
||||||
|
text.addReplacement(drainedLife);
|
||||||
|
defender->addNameReplacement(text, true);
|
||||||
|
blm.lines.push_back(std::move(text));
|
||||||
|
}
|
||||||
|
|
||||||
sendAndApply(&blm);
|
sendAndApply(&blm);
|
||||||
|
|
||||||
if(!fireShield.empty())
|
if(!fireShield.empty())
|
||||||
@@ -1179,7 +1204,8 @@ void CGameHandler::makeAttack(const CStack * attacker, const CStack * defender,
|
|||||||
|
|
||||||
handleAfterAttackCasting(ranged, attacker, defender);
|
handleAfterAttackCasting(ranged, attacker, defender);
|
||||||
}
|
}
|
||||||
void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary)
|
|
||||||
|
int64_t CGameHandler::applyBattleEffects(BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary)
|
||||||
{
|
{
|
||||||
BattleStackAttacked bsa;
|
BattleStackAttacked bsa;
|
||||||
if(secondary)
|
if(secondary)
|
||||||
@@ -1208,34 +1234,14 @@ void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm
|
|||||||
CStack::prepareAttacked(bsa, getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
CStack::prepareAttacked(bsa, getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
||||||
}
|
}
|
||||||
|
|
||||||
auto addLifeDrain = [&](int64_t & toHeal, EHealLevel level, EHealPower power)
|
int64_t drainedLife = 0;
|
||||||
{
|
|
||||||
attackerState->heal(toHeal, level, power);
|
|
||||||
|
|
||||||
if(toHeal > 0)
|
|
||||||
{
|
|
||||||
CustomEffectInfo customEffect;
|
|
||||||
customEffect.sound = soundBase::DRAINLIF;
|
|
||||||
customEffect.effect = 52;
|
|
||||||
customEffect.stack = attackerState->unitId();
|
|
||||||
bat.customEffects.push_back(customEffect);
|
|
||||||
|
|
||||||
MetaString text;
|
|
||||||
attackerState->addText(text, MetaString::GENERAL_TXT, 361);
|
|
||||||
attackerState->addNameReplacement(text, false);
|
|
||||||
text.addReplacement((int)toHeal);
|
|
||||||
def->addNameReplacement(text, true);
|
|
||||||
blm.lines.push_back(text);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//life drain handling
|
//life drain handling
|
||||||
if(attackerState->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
if(attackerState->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
||||||
{
|
{
|
||||||
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(Bonus::LIFE_DRAIN) / 100;
|
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(Bonus::LIFE_DRAIN) / 100;
|
||||||
|
attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
||||||
if(toHeal > 0)
|
drainedLife += toHeal;
|
||||||
addLifeDrain(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//soul steal handling
|
//soul steal handling
|
||||||
@@ -1248,7 +1254,8 @@ void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm
|
|||||||
if(attackerState->hasBonusOfType(Bonus::SOUL_STEAL, subtype))
|
if(attackerState->hasBonusOfType(Bonus::SOUL_STEAL, subtype))
|
||||||
{
|
{
|
||||||
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(Bonus::SOUL_STEAL, subtype) * attackerState->MaxHealth();
|
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(Bonus::SOUL_STEAL, subtype) * attackerState->MaxHealth();
|
||||||
addLifeDrain(toHeal, EHealLevel::OVERHEAL, ((subtype == 0) ? EHealPower::ONE_BATTLE : EHealPower::PERMANENT));
|
attackerState->heal(toHeal, EHealLevel::OVERHEAL, ((subtype == 0) ? EHealPower::ONE_BATTLE : EHealPower::PERMANENT));
|
||||||
|
drainedLife += toHeal;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1263,6 +1270,8 @@ void CGameHandler::applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm
|
|||||||
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
||||||
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return drainedLife;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple)
|
void CGameHandler::sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple)
|
||||||
|
@@ -126,7 +126,8 @@ public:
|
|||||||
|
|
||||||
void makeAttack(const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
|
void makeAttack(const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
|
||||||
|
|
||||||
void applyBattleEffects(BattleAttack & bat, BattleLogMessage & blm, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary); //damage, drain life & fire shield
|
// damage, drain life & fire shield; returns amount of drained life
|
||||||
|
int64_t applyBattleEffects(BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary);
|
||||||
|
|
||||||
void sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple);
|
void sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple);
|
||||||
void addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple);
|
void addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple);
|
||||||
|
Reference in New Issue
Block a user