|
@@ -956,18 +956,18 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
|
|
|
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
|
|
}
|
|
|
|
|
|
- int64_t drainedLife = 0;
|
|
|
+ battle::HealInfo healInfo;
|
|
|
|
|
|
// only primary target
|
|
|
if(defender->alive())
|
|
|
- drainedLife += applyBattleEffects(battle, bat, attackerState, fireShield, defender, distance, false);
|
|
|
+ applyBattleEffects(battle, bat, attackerState, fireShield, defender, &healInfo, distance, false);
|
|
|
|
|
|
//multiple-hex normal attack
|
|
|
std::set<const CStack*> attackedCreatures = battle.getAttackedCreatures(attacker, targetHex, bat.shot()); //creatures other than primary target
|
|
|
for(const CStack * stack : attackedCreatures)
|
|
|
{
|
|
|
if(stack != defender && stack->alive()) //do not hit same stack twice
|
|
|
- drainedLife += applyBattleEffects(battle, bat, attackerState, fireShield, stack, distance, true);
|
|
|
+ applyBattleEffects(battle, bat, attackerState, fireShield, stack, &healInfo, distance, true);
|
|
|
}
|
|
|
|
|
|
std::shared_ptr<const Bonus> bonus = attacker->getFirstBonus(Selector::type()(BonusType::SPELL_LIKE_ATTACK));
|
|
@@ -995,7 +995,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
|
|
|
{
|
|
|
if(stack != defender && stack->alive()) //do not hit same stack twice
|
|
|
{
|
|
|
- drainedLife += applyBattleEffects(battle, bat, attackerState, fireShield, stack, distance, true);
|
|
|
+ applyBattleEffects(battle, bat, attackerState, fireShield, stack, &healInfo, distance, true);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1019,7 +1019,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
|
|
|
bat.attackerChanges.changedStacks.push_back(info);
|
|
|
}
|
|
|
|
|
|
- if (drainedLife > 0)
|
|
|
+ if (healInfo.healedHealthPoints > 0)
|
|
|
bat.flags |= BattleAttack::LIFE_DRAIN;
|
|
|
|
|
|
for (BattleStackAttacked & bsa : bat.bsa)
|
|
@@ -1039,26 +1039,16 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
|
|
|
totalKills += bsa.killedAmount;
|
|
|
}
|
|
|
|
|
|
- {
|
|
|
- MetaString text;
|
|
|
- attacker->addText(text, EMetaText::GENERAL_TXT, 376);
|
|
|
- attacker->addNameReplacement(text);
|
|
|
- text.replaceNumber(totalDamage);
|
|
|
- blm.lines.push_back(text);
|
|
|
- }
|
|
|
+ addGenericDamageLog(blm, attackerState, totalDamage);
|
|
|
|
|
|
addGenericKilledLog(blm, defender, totalKills, multipleTargets);
|
|
|
}
|
|
|
|
|
|
// drain life effect (as well as log entry) must be applied after the attack
|
|
|
- if(drainedLife > 0)
|
|
|
+ if(healInfo.healedHealthPoints > 0)
|
|
|
{
|
|
|
- MetaString text;
|
|
|
- attackerState->addText(text, EMetaText::GENERAL_TXT, 361);
|
|
|
- attackerState->addNameReplacement(text, false);
|
|
|
- text.replaceNumber(drainedLife);
|
|
|
- defender->addNameReplacement(text, true);
|
|
|
- blm.lines.push_back(std::move(text));
|
|
|
+ addGenericDrainedLifeLog(blm, attackerState, defender, healInfo.healedHealthPoints);
|
|
|
+ addGenericResurrectedLog(blm, attackerState, defender, healInfo.resurrectedCount);
|
|
|
}
|
|
|
|
|
|
if(!fireShield.empty())
|
|
@@ -1435,7 +1425,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary)
|
|
|
+void BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, battle::HealInfo * healInfo, int distance, bool secondary) const
|
|
|
{
|
|
|
BattleStackAttacked bsa;
|
|
|
if(secondary)
|
|
@@ -1456,14 +1446,13 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
|
|
|
CStack::prepareAttacked(bsa, gameHandler->getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
|
|
}
|
|
|
|
|
|
- int64_t drainedLife = 0;
|
|
|
+ battle::HealInfo tmpHealInfo;
|
|
|
|
|
|
//life drain handling
|
|
|
if(attackerState->hasBonusOfType(BonusType::LIFE_DRAIN) && def->isLiving())
|
|
|
{
|
|
|
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(BonusType::LIFE_DRAIN) / 100;
|
|
|
- attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
|
|
- drainedLife += toHeal;
|
|
|
+ tmpHealInfo += attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
|
|
}
|
|
|
|
|
|
//soul steal handling
|
|
@@ -1477,12 +1466,12 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
|
|
|
{
|
|
|
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(BonusType::SOUL_STEAL, subtype) * attackerState->getMaxHealth();
|
|
|
bool permanent = subtype == BonusCustomSubtype::soulStealPermanent;
|
|
|
- attackerState->heal(toHeal, EHealLevel::OVERHEAL, (permanent ? EHealPower::PERMANENT : EHealPower::ONE_BATTLE));
|
|
|
- drainedLife += toHeal;
|
|
|
+ tmpHealInfo += attackerState->heal(toHeal, EHealLevel::OVERHEAL, (permanent ? EHealPower::PERMANENT : EHealPower::ONE_BATTLE));
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ *healInfo += tmpHealInfo;
|
|
|
bat.bsa.push_back(bsa); //add this stack to the list of victims after drain life has been calculated
|
|
|
|
|
|
//fire shield handling
|
|
@@ -1499,8 +1488,6 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
|
|
|
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(BonusType::FIRE_SHIELD)) / 100;
|
|
|
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
|
|
}
|
|
|
-
|
|
|
- return drainedLife;
|
|
|
}
|
|
|
|
|
|
void BattleActionProcessor::sendGenericKilledLog(const CBattleInfoCallback & battle, const CStack * defender, int32_t killed, bool multiple)
|
|
@@ -1514,7 +1501,7 @@ void BattleActionProcessor::sendGenericKilledLog(const CBattleInfoCallback & bat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void BattleActionProcessor::addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple)
|
|
|
+void BattleActionProcessor::addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple) const
|
|
|
{
|
|
|
if(killed > 0)
|
|
|
{
|
|
@@ -1542,6 +1529,46 @@ void BattleActionProcessor::addGenericKilledLog(BattleLogMessage & blm, const CS
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void BattleActionProcessor::addGenericDamageLog(BattleLogMessage& blm, const std::shared_ptr<battle::CUnitState> &attackerState, int64_t damageDealt) const
|
|
|
+{
|
|
|
+ MetaString text;
|
|
|
+ attackerState->addText(text, EMetaText::GENERAL_TXT, 376);
|
|
|
+ attackerState->addNameReplacement(text);
|
|
|
+ text.replaceNumber(damageDealt);
|
|
|
+ blm.lines.push_back(std::move(text));
|
|
|
+}
|
|
|
+
|
|
|
+void BattleActionProcessor::addGenericDrainedLifeLog(BattleLogMessage& blm, const std::shared_ptr<battle::CUnitState>& attackerState, const CStack* defender, int64_t drainedLife) const
|
|
|
+{
|
|
|
+ MetaString text;
|
|
|
+ attackerState->addText(text, EMetaText::GENERAL_TXT, 361);
|
|
|
+ attackerState->addNameReplacement(text);
|
|
|
+ text.replaceNumber(drainedLife);
|
|
|
+ defender->addNameReplacement(text);
|
|
|
+ blm.lines.push_back(std::move(text));
|
|
|
+}
|
|
|
+
|
|
|
+void BattleActionProcessor::addGenericResurrectedLog(BattleLogMessage& blm, const std::shared_ptr<battle::CUnitState>& attackerState, const CStack* defender, int64_t resurrected) const
|
|
|
+{
|
|
|
+ if (resurrected > 0)
|
|
|
+ {
|
|
|
+ auto text = blm.lines.back().toString();
|
|
|
+ text.pop_back(); // erase '.' at the end of line with life drain info
|
|
|
+ MetaString ms = MetaString::createFromRawString(text);
|
|
|
+ if (resurrected == 1)
|
|
|
+ {
|
|
|
+ ms.appendLocalString(EMetaText::GENERAL_TXT, 363); // "\n and one rises from the dead."
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ms.appendLocalString(EMetaText::GENERAL_TXT, 364); // "\n and %d rise from the dead."
|
|
|
+ ms.replaceNumber(resurrected);
|
|
|
+ }
|
|
|
+ blm.lines[blm.lines.size() - 1] = std::move(ms);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
bool BattleActionProcessor::makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
|
|
{
|
|
|
return makeBattleActionImpl(battle, ba);
|