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
|
/*
* 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 <vcmi/spells/Spell.h>
#include "../ISpellMechanics.h"
#include "../../battle/IBattleState.h"
#include "../../battle/CBattleInfoCallback.h"
#include "../../battle/Unit.h"
#include "../../bonuses/BonusList.h"
#include "../../networkPacks/PacksForClientBattle.h"
#include "../../networkPacks/SetStackEffect.h"
#include "../../serializer/JsonSerializeFormat.h"
VCMI_LIB_NAMESPACE_BEGIN
namespace spells
{
namespace effects
{
void Dispel::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
{
const bool describe = server->describeChanges();
SetStackEffect sse;
BattleLogMessage blm;
blm.battleID = m->battle()->getBattle()->getBattleID();
sse.battleID = m->battle()->getBattle()->getBattleID();
for(const 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, EMetaText::GENERAL_TXT, -555, true);
unit->addNameReplacement(line, true);
blm.lines.push_back(std::move(line));
}
std::vector<Bonus> buffer;
auto bl = getBonuses(m, unit);
for(const auto& item : *bl)
buffer.emplace_back(*item);
if(!buffer.empty())
sse.toRemove.emplace_back(unit->unitId(), buffer);
}
}
if(!sse.toRemove.empty())
server->apply(sse);
if(describe && !blm.lines.empty())
server->apply(blm);
}
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<const BonusList> Dispel::getBonuses(const Mechanics * m, const battle::Unit * unit) const
{
auto sel = [=](const Bonus * bonus)
{
if(bonus->source == BonusSource::SPELL_EFFECT)
{
const Spell * sourceSpell = bonus->sid.as<SpellID>().toEntity(m->spells());
if(!sourceSpell)
return false;//error
//Special case: DISRUPTING_RAY and ACID_BREATH_DEFENSE are "immune" to dispel
//Other even PERMANENT effects can be removed (f.e. BIND)
if(sourceSpell->getIndex() == SpellID::DISRUPTING_RAY || sourceSpell->getIndex() == SpellID::ACID_BREATH_DEFENSE)
return false;
//Special case: do not remove lifetime marker
if(sourceSpell->getIndex() == SpellID::CLONE)
return false;
//stack may have inherited effects
if(sourceSpell->isAdventure())
return false;
if(sourceSpell->getIndex() == m->getSpellIndex())
return false;
auto positiveness = sourceSpell->getPositiveness();
if(boost::logic::indeterminate(positiveness))
{
if(neutral)
return true;
}
else if(positiveness)
{
if(positive)
return true;
}
else
{
if(negative)
return true;
}
}
return false;
};
CSelector selector(sel);
return unit->getBonuses(selector);
}
}
}
VCMI_LIB_NAMESPACE_END
|