Explorar o código

proper logging of drained life and resurrected count

new struct for keeping track of healed HP (also drained life) and resurrected count
MichalZr6 hai 1 ano
pai
achega
65d22f17ae

+ 8 - 4
lib/battle/CUnitState.cpp

@@ -228,7 +228,7 @@ void CHealth::damage(int64_t & amount)
 	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 oldCount = getCount();
@@ -252,7 +252,7 @@ void CHealth::heal(int64_t & amount, EHealLevel level, EHealPower power)
 	vstd::abetween(amount, int64_t(0), maxHeal);
 
 	if(amount == 0)
-		return;
+		return {};
 
 	int64_t availableHealth = available();
 
@@ -263,6 +263,8 @@ void CHealth::heal(int64_t & amount, EHealLevel level, EHealPower power)
 		addResurrected(getCount() - oldCount);
 	else
 		assert(power == EHealPower::PERMANENT);
+
+	return HealInfo(amount, getCount() - oldCount);
 }
 
 void CHealth::setFromTotal(const int64_t totalHealth)
@@ -834,14 +836,16 @@ void CUnitState::damage(int64_t & amount)
 		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)
 		logGlobal->error("Heal for one battle does not make sense");
 	else if(cloned)
 		logGlobal->error("Attempt to heal clone");
 	else
-		health.heal(amount, level, power);
+		return health.heal(amount, level, power);
+
+	return {};
 }
 
 void CUnitState::afterAttack(bool ranged, bool counter)

+ 2 - 2
lib/battle/CUnitState.h

@@ -107,7 +107,7 @@ public:
 	void reset();
 
 	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 getFirstHPleft() const;
@@ -247,7 +247,7 @@ public:
 	void load(const JsonNode & data) 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 serializeJson(JsonSerializeFormat & handler);

+ 22 - 1
lib/battle/Unit.h

@@ -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 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 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

+ 1 - 0
lib/spells/effects/Summon.cpp

@@ -122,6 +122,7 @@ int32_t Summon::summonedCreatureAmount(const Mechanics * m) const
 
 void Summon::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
 {
+	using battle::HealInfo;
 	BattleUnitsChanged pack;
 	pack.battleID = m->battle()->getBattle()->getBattleID();
 

+ 55 - 28
server/battles/BattleActionProcessor.cpp

@@ -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);

+ 6 - 2
server/battles/BattleActionProcessor.h

@@ -24,6 +24,7 @@ enum class BonusType;
 namespace battle
 {
 class Unit;
+struct HealInfo;
 class CUnitState;
 }
 
@@ -53,10 +54,13 @@ class BattleActionProcessor : boost::noncopyable
 	std::set<SpellID> getSpellsForAttackCasting(TConstBonusListPtr spells, const CStack *defender);
 
 	// 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 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);