| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- /*
- * Sacrifice.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 "Sacrifice.h"
- #include "Registry.h"
- #include "../ISpellMechanics.h"
- #include "../../battle/IBattleState.h"
- #include "../../battle/CBattleInfoCallback.h"
- #include "../../battle/Unit.h"
- #include "../../serializer/JsonSerializeFormat.h"
- #include "../../networkPacks/PacksForClientBattle.h"
- VCMI_LIB_NAMESPACE_BEGIN
- namespace spells
- {
- namespace effects
- {
- void Sacrifice::adjustTargetTypes(std::vector<TargetType> & types) const
- {
- if(!types.empty())
- {
- if(types[0] != AimType::CREATURE)
- {
- types.clear();
- return;
- }
- if(types.size() == 1)
- {
- types.push_back(AimType::CREATURE);
- }
- else if(types.size() > 1)
- {
- if(types[1] != AimType::CREATURE)
- types.clear();
- }
- }
- }
- bool Sacrifice::applicable(Problem & problem, const Mechanics * m) const
- {
- auto mainFilter = std::bind(&UnitEffect::getStackFilter, this, m, true, _1);
- auto predicate = std::bind(&UnitEffect::eraseByImmunityFilter, this, m, _1);
- auto targets = m->battle()->battleGetUnitsIf(mainFilter);
- vstd::erase_if(targets, predicate);
- bool targetExists = false;
- bool targetToSacrificeExists = false;
- for(auto & target : targets)
- {
- if(target->alive())
- targetToSacrificeExists = true;
- else if(target->isDead())
- targetExists = true;
- if(targetExists && targetToSacrificeExists)
- break;
- }
- if(!(targetExists && targetToSacrificeExists))
- return m->adaptProblem(ESpellCastProblem::NO_APPROPRIATE_TARGET, problem);
- return true;
- }
- bool Sacrifice::applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const
- {
- //TODO: support for multiple targets?
- if(target.empty())
- return false;
- EffectTarget healTarget;
- healTarget.emplace_back(target.front());
- if(!Heal::applicable(problem, m, healTarget))
- return false;
- if(target.size() == 2)
- {
- const auto *victim = target.at(1).unitValue;
- if(!victim)
- return false;
-
- return victim->alive() && getStackFilter(m, false, victim) && isReceptive(m, victim);
- }
- return true;
- }
- void Sacrifice::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
- {
- if(target.size() != 2)
- {
- logGlobal->error("Sacrifice effect requires 2 targets");
- return;
- }
- const battle::Unit * victim = target.back().unitValue;
- if(!victim)
- {
- logGlobal->error("No unit to Sacrifice");
- return;
- }
- EffectTarget healTarget;
- healTarget.emplace_back(target.front());
- Heal::apply(calculateHealEffectValue(m, victim), server, m, healTarget);
- BattleUnitsChanged removeUnits;
- removeUnits.battleID = m->battle()->getBattle()->getBattleID();
- removeUnits.changedStacks.emplace_back(victim->unitId(), UnitChanges::EOperation::REMOVE);
- server->apply(removeUnits);
- }
- bool Sacrifice::isValidTarget(const Mechanics * m, const battle::Unit * unit) const
- {
- return unit->isValidTarget(true);
- }
- EffectTarget Sacrifice::transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const
- {
- EffectTarget res = Heal::transformTarget(m, aimPoint, spellTarget);
- //ignore spell range for now, arbitrary range support requires redesign
- res.resize(1);
- //add victim
- if(aimPoint.size() >= 2)
- {
- const auto *victim = aimPoint.at(1).unitValue;
- if(victim && getStackFilter(m, false, victim) && isReceptive(m, victim))
- res.emplace_back(victim);
- }
- return res;
- }
- int64_t Sacrifice::calculateHealEffectValue(const Mechanics * m, const battle::Unit * victim)
- {
- return (m->getEffectPower() + victim->getMaxHealth() + m->calculateRawEffectValue(0, 1)) * victim->getCount();
- }
- }
- }
- VCMI_LIB_NAMESPACE_END
|