mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-14 10:12:59 +02:00
84f53485e2
Now first aid is passive battle spell, and skill just bumps specific spell power for this spell. Everything about healing is handled into Heal spell effect.
159 lines
4.2 KiB
C++
159 lines
4.2 KiB
C++
/*
|
|
* Heal.cpp, part of VCMI engine
|
|
*
|
|
* Authors: listed in file AUTHORS in main folder
|
|
*
|
|
* License: GNU General Public License v2.0 or later
|
|
* Full text of license available in license.txt file, in main folder
|
|
*
|
|
*/
|
|
#include "StdInc.h"
|
|
|
|
#include "Heal.h"
|
|
#include "Registry.h"
|
|
#include "../ISpellMechanics.h"
|
|
|
|
#include "../../NetPacks.h"
|
|
#include "../../battle/IBattleState.h"
|
|
#include "../../battle/CUnitState.h"
|
|
#include "../../battle/CBattleInfoCallback.h"
|
|
#include "../../battle/Unit.h"
|
|
#include "../../serializer/JsonSerializeFormat.h"
|
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
|
static const std::string EFFECT_NAME = "core:heal";
|
|
|
|
namespace spells
|
|
{
|
|
namespace effects
|
|
{
|
|
|
|
VCMI_REGISTER_SPELL_EFFECT(Heal, EFFECT_NAME);
|
|
|
|
void Heal::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
|
{
|
|
apply(m->getEffectValue(), server, m, target);
|
|
}
|
|
|
|
void Heal::apply(int64_t value, ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
|
{
|
|
BattleLogMessage logMessage;
|
|
BattleUnitsChanged pack;
|
|
prepareHealEffect(value, pack, logMessage, *server->getRNG(), m, target);
|
|
if(!pack.changedStacks.empty())
|
|
server->apply(&pack);
|
|
if(!logMessage.lines.empty())
|
|
server->apply(&logMessage);
|
|
}
|
|
|
|
bool Heal::isValidTarget(const Mechanics * m, const battle::Unit * unit) const
|
|
{
|
|
const bool onlyAlive = healLevel == EHealLevel::HEAL;
|
|
const bool validInGenaral = unit->isValidTarget(!onlyAlive);
|
|
|
|
if(!validInGenaral)
|
|
return false;
|
|
|
|
auto injuries = unit->getTotalHealth() - unit->getAvailableHealth();
|
|
|
|
if(injuries == 0)
|
|
return false;
|
|
|
|
if(minFullUnits > 0)
|
|
{
|
|
auto hpGained = std::min(m->getEffectValue(), injuries);
|
|
if(hpGained < minFullUnits * unit->MaxHealth())
|
|
return false;
|
|
}
|
|
|
|
if(unit->isDead())
|
|
{
|
|
//check if alive unit blocks resurrection
|
|
for(const BattleHex & hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
|
|
{
|
|
auto blocking = m->battle()->battleGetUnitsIf([hex, unit](const battle::Unit * other)
|
|
{
|
|
return other->isValidTarget(false) && other->coversPos(hex) && other != unit;
|
|
});
|
|
|
|
if(!blocking.empty())
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Heal::serializeJsonUnitEffect(JsonSerializeFormat & handler)
|
|
{
|
|
static const std::vector<std::string> HEAL_LEVEL_MAP =
|
|
{
|
|
"heal",
|
|
"resurrect",
|
|
"overHeal"
|
|
};
|
|
|
|
static const std::vector<std::string> HEAL_POWER_MAP =
|
|
{
|
|
"oneBattle",
|
|
"permanent"
|
|
};
|
|
|
|
handler.serializeEnum("healLevel", healLevel, EHealLevel::HEAL, HEAL_LEVEL_MAP);
|
|
handler.serializeEnum("healPower", healPower, EHealPower::PERMANENT, HEAL_POWER_MAP);
|
|
handler.serializeInt("minFullUnits", minFullUnits);
|
|
}
|
|
|
|
void Heal::prepareHealEffect(int64_t value, BattleUnitsChanged & pack, BattleLogMessage & logMessage, RNG & rng, const Mechanics * m, const EffectTarget & target) const
|
|
{
|
|
for(const auto & oneTarget : target)
|
|
{
|
|
const battle::Unit * unit = oneTarget.unitValue;
|
|
|
|
if(unit)
|
|
{
|
|
auto unitHPgained = m->applySpellBonus(value, unit);
|
|
|
|
auto state = unit->acquire();
|
|
const auto countBeforeHeal = state->getCount();
|
|
state->heal(unitHPgained, healLevel, healPower);
|
|
|
|
if(const auto resurrectedCount = std::max(0, state->getCount() - countBeforeHeal))
|
|
{
|
|
// %d %s rise from the dead!
|
|
// in the table first comes plural string, then the singular one
|
|
MetaString resurrectText;
|
|
state->addText(resurrectText, MetaString::GENERAL_TXT, 116, resurrectedCount == 1);
|
|
state->addNameReplacement(resurrectText);
|
|
resurrectText.addReplacement(resurrectedCount);
|
|
logMessage.lines.push_back(std::move(resurrectText));
|
|
}
|
|
else if (unitHPgained > 0 && m->caster->getCasterUnitId() >= 0) //Show text about healed HP if healed by unit
|
|
{
|
|
MetaString healText;
|
|
auto casterUnit = dynamic_cast<const battle::CUnitState*>(m->caster)->acquire();
|
|
healText.addTxt(MetaString::GENERAL_TXT, 414);
|
|
casterUnit->addNameReplacement(healText, false);
|
|
state->addNameReplacement(healText, false);
|
|
healText.addReplacement((int)unitHPgained);
|
|
logMessage.lines.push_back(std::move(healText));
|
|
}
|
|
|
|
if(unitHPgained > 0)
|
|
{
|
|
UnitChanges info(state->unitId(), UnitChanges::EOperation::RESET_STATE);
|
|
info.healthDelta = unitHPgained;
|
|
state->save(info.data);
|
|
pack.changedStacks.push_back(info);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
VCMI_LIB_NAMESPACE_END
|