1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
/*
* Dispel.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 "Dispel.h"
#include "Registry.h"
#include "../ISpellMechanics.h"
#include "../CSpellHandler.h"
#include "../../NetPacks.h"
#include "../../battle/IBattleState.h"
#include "../../battle/Unit.h"
#include "../../serializer/JsonSerializeFormat.h"
static const std::string EFFECT_NAME = "core:dispel";
namespace spells
{
namespace effects
{
VCMI_REGISTER_SPELL_EFFECT(Dispel, EFFECT_NAME);
Dispel::Dispel()
: UnitEffect()
{
}
Dispel::~Dispel() = default;
void Dispel::apply(BattleStateProxy * battleState, RNG & rng, const Mechanics * m, const EffectTarget & target) const
{
SetStackEffect sse;
prepareEffects(sse, rng, m, target, battleState->describe);
if(!sse.toRemove.empty())
battleState->apply(&sse);
}
bool Dispel::isValidTarget(const Mechanics * m, const battle::Unit * unit) const
{
if(getBonuses(m, unit)->empty())
return false;
return UnitEffect::isValidTarget(m, unit);
}
void Dispel::serializeJsonUnitEffect(JsonSerializeFormat & handler)
{
handler.serializeBool("dispelPositive", positive);
handler.serializeBool("dispelNegative", negative);
handler.serializeBool("dispelNeutral", neutral);
}
std::shared_ptr<BonusList> Dispel::getBonuses(const Mechanics * m, const battle::Unit * unit) const
{
auto addSelector = [=](const Bonus * bonus)
{
if(bonus->source == Bonus::SPELL_EFFECT)
{
const CSpell * sourceSpell = SpellID(bonus->sid).toSpell();
if(!sourceSpell)
return false;//error
if(bonus->sid == m->getSpellIndex())
return false;
if(positive && sourceSpell->isPositive())
return true;
if(negative && sourceSpell->isNegative())
return true;
if(neutral && sourceSpell->isNeutral())
return true;
}
return false;
};
CSelector selector = CSelector(mainSelector).And(CSelector(addSelector));
return unit->getBonuses(selector);
}
bool Dispel::mainSelector(const Bonus * bonus)
{
if(bonus->source == Bonus::SPELL_EFFECT)
{
const CSpell * sourceSpell = SpellID(bonus->sid).toSpell();
if(!sourceSpell)
return false;//error
//Special case: DISRUPTING_RAY is "immune" to dispell
//Other even PERMANENT effects can be removed (f.e. BIND)
if(sourceSpell->id == SpellID::DISRUPTING_RAY)
return false;
//Special case:do not remove lifetime marker
if(sourceSpell->id == SpellID::CLONE)
return false;
//stack may have inherited effects
if(sourceSpell->isAdventureSpell())
return false;
return true;
}
//not spell effect
return false;
}
void Dispel::prepareEffects(SetStackEffect & pack, RNG & rng, const Mechanics * m, const EffectTarget & target, bool describe) const
{
for(auto & t : target)
{
const battle::Unit * unit = t.unitValue;
if(unit)
{
//special case for DISPEL_HELPFUL_SPELLS
if(describe && positive && !negative && !neutral)
{
MetaString line;
unit->addText(line, MetaString::GENERAL_TXT, -555, true);
unit->addNameReplacement(line, true);
pack.battleLog.push_back(std::move(line));
}
std::vector<Bonus> buffer;
auto bl = getBonuses(m, unit);
for(auto item : *bl)
buffer.emplace_back(*item);
if(!buffer.empty())
pack.toRemove.push_back(std::make_pair(unit->unitId(), buffer));
}
}
}
}
}
|