mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-17 01:32:21 +02:00
proper logging of drained life and resurrected count
new struct for keeping track of healed HP (also drained life) and resurrected count
This commit is contained in:
@ -228,7 +228,7 @@ void CHealth::damage(int64_t & amount)
|
|||||||
addResurrected(getCount() - oldCount);
|
addResurrected(getCount() - oldCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHealth::heal(int64_t & amount, EHealLevel level, EHealPower power)
|
HealInfo CHealth::heal(int64_t & amount, EHealLevel level, EHealPower power)
|
||||||
{
|
{
|
||||||
const int32_t unitHealth = owner->getMaxHealth();
|
const int32_t unitHealth = owner->getMaxHealth();
|
||||||
const int32_t oldCount = getCount();
|
const int32_t oldCount = getCount();
|
||||||
@ -252,7 +252,7 @@ void CHealth::heal(int64_t & amount, EHealLevel level, EHealPower power)
|
|||||||
vstd::abetween(amount, int64_t(0), maxHeal);
|
vstd::abetween(amount, int64_t(0), maxHeal);
|
||||||
|
|
||||||
if(amount == 0)
|
if(amount == 0)
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
int64_t availableHealth = available();
|
int64_t availableHealth = available();
|
||||||
|
|
||||||
@ -263,6 +263,8 @@ void CHealth::heal(int64_t & amount, EHealLevel level, EHealPower power)
|
|||||||
addResurrected(getCount() - oldCount);
|
addResurrected(getCount() - oldCount);
|
||||||
else
|
else
|
||||||
assert(power == EHealPower::PERMANENT);
|
assert(power == EHealPower::PERMANENT);
|
||||||
|
|
||||||
|
return HealInfo(amount, getCount() - oldCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHealth::setFromTotal(const int64_t totalHealth)
|
void CHealth::setFromTotal(const int64_t totalHealth)
|
||||||
@ -834,14 +836,16 @@ void CUnitState::damage(int64_t & amount)
|
|||||||
ghostPending = true;
|
ghostPending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUnitState::heal(int64_t & amount, EHealLevel level, EHealPower power)
|
HealInfo CUnitState::heal(int64_t & amount, EHealLevel level, EHealPower power)
|
||||||
{
|
{
|
||||||
if(level == EHealLevel::HEAL && power == EHealPower::ONE_BATTLE)
|
if(level == EHealLevel::HEAL && power == EHealPower::ONE_BATTLE)
|
||||||
logGlobal->error("Heal for one battle does not make sense");
|
logGlobal->error("Heal for one battle does not make sense");
|
||||||
else if(cloned)
|
else if(cloned)
|
||||||
logGlobal->error("Attempt to heal clone");
|
logGlobal->error("Attempt to heal clone");
|
||||||
else
|
else
|
||||||
health.heal(amount, level, power);
|
return health.heal(amount, level, power);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CUnitState::afterAttack(bool ranged, bool counter)
|
void CUnitState::afterAttack(bool ranged, bool counter)
|
||||||
|
@ -107,7 +107,7 @@ public:
|
|||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void damage(int64_t & amount);
|
void damage(int64_t & amount);
|
||||||
void heal(int64_t & amount, EHealLevel level, EHealPower power);
|
HealInfo heal(int64_t & amount, EHealLevel level, EHealPower power);
|
||||||
|
|
||||||
int32_t getCount() const;
|
int32_t getCount() const;
|
||||||
int32_t getFirstHPleft() const;
|
int32_t getFirstHPleft() const;
|
||||||
@ -247,7 +247,7 @@ public:
|
|||||||
void load(const JsonNode & data) override;
|
void load(const JsonNode & data) override;
|
||||||
|
|
||||||
void damage(int64_t & amount) override;
|
void damage(int64_t & amount) override;
|
||||||
void heal(int64_t & amount, EHealLevel level, EHealPower power) override;
|
HealInfo heal(int64_t & amount, EHealLevel level, EHealPower power) override;
|
||||||
|
|
||||||
void localInit(const IUnitEnvironment * env_);
|
void localInit(const IUnitEnvironment * env_);
|
||||||
void serializeJson(JsonSerializeFormat & handler);
|
void serializeJson(JsonSerializeFormat & handler);
|
||||||
|
@ -41,6 +41,27 @@ namespace BattlePhases
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Healed HP (also drained life) and resurrected units info
|
||||||
|
struct HealInfo
|
||||||
|
{
|
||||||
|
HealInfo()
|
||||||
|
: healedHealthPoints(0), resurrectedCount(0)
|
||||||
|
{ }
|
||||||
|
HealInfo(int64_t healedHP, int32_t resurrected)
|
||||||
|
: healedHealthPoints(healedHP), resurrectedCount(resurrected)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
int64_t healedHealthPoints;
|
||||||
|
int32_t resurrectedCount;
|
||||||
|
|
||||||
|
HealInfo& operator +=(const HealInfo& other)
|
||||||
|
{
|
||||||
|
healedHealthPoints += other.healedHealthPoints;
|
||||||
|
resurrectedCount += other.resurrectedCount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class CUnitState;
|
class CUnitState;
|
||||||
|
|
||||||
class DLL_LINKAGE Unit : public IUnitInfo, public spells::Caster, public virtual IBonusBearer, public ACreature
|
class DLL_LINKAGE Unit : public IUnitInfo, public spells::Caster, public virtual IBonusBearer, public ACreature
|
||||||
@ -138,7 +159,7 @@ public:
|
|||||||
virtual void load(const JsonNode & data) = 0;
|
virtual void load(const JsonNode & data) = 0;
|
||||||
|
|
||||||
virtual void damage(int64_t & amount) = 0;
|
virtual void damage(int64_t & amount) = 0;
|
||||||
virtual void heal(int64_t & amount, EHealLevel level, EHealPower power) = 0;
|
virtual HealInfo heal(int64_t & amount, EHealLevel level, EHealPower power) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE UnitInfo
|
class DLL_LINKAGE UnitInfo
|
||||||
|
@ -122,6 +122,7 @@ int32_t Summon::summonedCreatureAmount(const Mechanics * m) const
|
|||||||
|
|
||||||
void Summon::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
void Summon::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
||||||
{
|
{
|
||||||
|
using battle::HealInfo;
|
||||||
BattleUnitsChanged pack;
|
BattleUnitsChanged pack;
|
||||||
pack.battleID = m->battle()->getBattle()->getBattleID();
|
pack.battleID = m->battle()->getBattle()->getBattleID();
|
||||||
|
|
||||||
|
@ -956,18 +956,18 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
|
|||||||
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t drainedLife = 0;
|
battle::HealInfo healInfo;
|
||||||
|
|
||||||
// only primary target
|
// only primary target
|
||||||
if(defender->alive())
|
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
|
//multiple-hex normal attack
|
||||||
std::set<const CStack*> attackedCreatures = battle.getAttackedCreatures(attacker, targetHex, bat.shot()); //creatures other than primary target
|
std::set<const CStack*> attackedCreatures = battle.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
|
||||||
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));
|
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
|
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);
|
bat.attackerChanges.changedStacks.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drainedLife > 0)
|
if (healInfo.healedHealthPoints > 0)
|
||||||
bat.flags |= BattleAttack::LIFE_DRAIN;
|
bat.flags |= BattleAttack::LIFE_DRAIN;
|
||||||
|
|
||||||
for (BattleStackAttacked & bsa : bat.bsa)
|
for (BattleStackAttacked & bsa : bat.bsa)
|
||||||
@ -1039,26 +1039,16 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
|
|||||||
totalKills += bsa.killedAmount;
|
totalKills += bsa.killedAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
addGenericDamageLog(blm, attackerState, totalDamage);
|
||||||
MetaString text;
|
|
||||||
attacker->addText(text, EMetaText::GENERAL_TXT, 376);
|
|
||||||
attacker->addNameReplacement(text);
|
|
||||||
text.replaceNumber(totalDamage);
|
|
||||||
blm.lines.push_back(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
addGenericKilledLog(blm, defender, totalKills, multipleTargets);
|
addGenericKilledLog(blm, defender, totalKills, multipleTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
// drain life effect (as well as log entry) must be applied after the attack
|
// drain life effect (as well as log entry) must be applied after the attack
|
||||||
if(drainedLife > 0)
|
if(healInfo.healedHealthPoints > 0)
|
||||||
{
|
{
|
||||||
MetaString text;
|
addGenericDrainedLifeLog(blm, attackerState, defender, healInfo.healedHealthPoints);
|
||||||
attackerState->addText(text, EMetaText::GENERAL_TXT, 361);
|
addGenericResurrectedLog(blm, attackerState, defender, healInfo.resurrectedCount);
|
||||||
attackerState->addNameReplacement(text, false);
|
|
||||||
text.replaceNumber(drainedLife);
|
|
||||||
defender->addNameReplacement(text, true);
|
|
||||||
blm.lines.push_back(std::move(text));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!fireShield.empty())
|
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;
|
BattleStackAttacked bsa;
|
||||||
if(secondary)
|
if(secondary)
|
||||||
@ -1456,14 +1446,13 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
|
|||||||
CStack::prepareAttacked(bsa, gameHandler->getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
CStack::prepareAttacked(bsa, gameHandler->getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t drainedLife = 0;
|
battle::HealInfo tmpHealInfo;
|
||||||
|
|
||||||
//life drain handling
|
//life drain handling
|
||||||
if(attackerState->hasBonusOfType(BonusType::LIFE_DRAIN) && def->isLiving())
|
if(attackerState->hasBonusOfType(BonusType::LIFE_DRAIN) && def->isLiving())
|
||||||
{
|
{
|
||||||
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(BonusType::LIFE_DRAIN) / 100;
|
int64_t toHeal = bsa.damageAmount * attackerState->valOfBonuses(BonusType::LIFE_DRAIN) / 100;
|
||||||
attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
tmpHealInfo += attackerState->heal(toHeal, EHealLevel::RESURRECT, EHealPower::PERMANENT);
|
||||||
drainedLife += toHeal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//soul steal handling
|
//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();
|
int64_t toHeal = bsa.killedAmount * attackerState->valOfBonuses(BonusType::SOUL_STEAL, subtype) * attackerState->getMaxHealth();
|
||||||
bool permanent = subtype == BonusCustomSubtype::soulStealPermanent;
|
bool permanent = subtype == BonusCustomSubtype::soulStealPermanent;
|
||||||
attackerState->heal(toHeal, EHealLevel::OVERHEAL, (permanent ? EHealPower::PERMANENT : EHealPower::ONE_BATTLE));
|
tmpHealInfo += attackerState->heal(toHeal, EHealLevel::OVERHEAL, (permanent ? EHealPower::PERMANENT : EHealPower::ONE_BATTLE));
|
||||||
drainedLife += toHeal;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*healInfo += tmpHealInfo;
|
||||||
bat.bsa.push_back(bsa); //add this stack to the list of victims after drain life has been calculated
|
bat.bsa.push_back(bsa); //add this stack to the list of victims after drain life has been calculated
|
||||||
|
|
||||||
//fire shield handling
|
//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;
|
auto fireShieldDamage = (std::min<int64_t>(def->getAvailableHealth(), bsa.damageAmount) * def->valOfBonuses(BonusType::FIRE_SHIELD)) / 100;
|
||||||
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
fireShield.push_back(std::make_pair(def, fireShieldDamage));
|
||||||
}
|
}
|
||||||
|
|
||||||
return drainedLife;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleActionProcessor::sendGenericKilledLog(const CBattleInfoCallback & battle, const CStack * defender, int32_t killed, bool multiple)
|
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)
|
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)
|
bool BattleActionProcessor::makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||||
{
|
{
|
||||||
return makeBattleActionImpl(battle, ba);
|
return makeBattleActionImpl(battle, ba);
|
||||||
|
@ -24,6 +24,7 @@ enum class BonusType;
|
|||||||
namespace battle
|
namespace battle
|
||||||
{
|
{
|
||||||
class Unit;
|
class Unit;
|
||||||
|
struct HealInfo;
|
||||||
class CUnitState;
|
class CUnitState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +54,13 @@ class BattleActionProcessor : boost::noncopyable
|
|||||||
std::set<SpellID> getSpellsForAttackCasting(TConstBonusListPtr spells, const CStack *defender);
|
std::set<SpellID> getSpellsForAttackCasting(TConstBonusListPtr spells, const CStack *defender);
|
||||||
|
|
||||||
// damage, drain life & fire shield; returns amount of drained life
|
// damage, drain life & fire shield; returns amount of drained life
|
||||||
int64_t applyBattleEffects(const CBattleInfoCallback & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary);
|
void 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;
|
||||||
|
|
||||||
void sendGenericKilledLog(const CBattleInfoCallback & battle, const CStack * defender, int32_t killed, bool multiple);
|
void sendGenericKilledLog(const CBattleInfoCallback & battle, 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) const;
|
||||||
|
void addGenericDamageLog(BattleLogMessage& blm, const std::shared_ptr<battle::CUnitState> &attackerState, int64_t damageDealt) const;
|
||||||
|
void addGenericDrainedLifeLog(BattleLogMessage& blm, const std::shared_ptr<battle::CUnitState> &attackerState, const CStack* defender, int64_t drainedLife) const;
|
||||||
|
void addGenericResurrectedLog(BattleLogMessage& blm, const std::shared_ptr<battle::CUnitState> &attackerState, const CStack* defender, int64_t resurrected) const;
|
||||||
|
|
||||||
bool canStackAct(const CBattleInfoCallback & battle, const CStack * stack);
|
bool canStackAct(const CBattleInfoCallback & battle, const CStack * stack);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user