1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

WIP on SpellCastContext

This commit is contained in:
AlexVinS 2016-09-06 06:40:23 +03:00
parent 9ee954edcc
commit 18fc94d709
8 changed files with 85 additions and 77 deletions

View File

@ -62,9 +62,9 @@ void AntimagicMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast
}
///ChainLightningMechanics
std::set<const CStack *> ChainLightningMechanics::getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const
std::vector<const CStack *> ChainLightningMechanics::getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const
{
std::set<const CStack* > attackedCres;
std::vector<const CStack *> res;
std::set<BattleHex> possibleHexes;
for(auto stack : cb->battleGetAllStacks())
@ -85,17 +85,17 @@ std::set<const CStack *> ChainLightningMechanics::getAffectedStacks(const CBattl
auto stack = cb->battleGetStackByPos(lightningHex, true);
if(!stack)
break;
attackedCres.insert (stack);
res.push_back(stack);
for(auto hex : stack->getHexes())
{
possibleHexes.erase(hex); //can't hit same place twice
possibleHexes.erase(hex); //can't hit same stack twice
}
if(possibleHexes.empty()) //not enough targets
break;
lightningHex = BattleHex::getClosestTile(stack->attackerOwned, ctx.destination, possibleHexes);
lightningHex = BattleHex::getClosestTile(stack->attackerOwned, lightningHex, possibleHexes);
}
return attackedCres;
return res;
}
///CloneMechanics

View File

@ -44,7 +44,7 @@ class DLL_LINKAGE ChainLightningMechanics : public DefaultSpellMechanics
{
public:
ChainLightningMechanics(CSpell * s): DefaultSpellMechanics(s){};
std::set<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const override;
std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const override;
};
class DLL_LINKAGE CloneMechanics : public DefaultSpellMechanics

View File

@ -119,9 +119,15 @@ namespace SRSLPraserHelpers
}
SpellCastContext::SpellCastContext(const DefaultSpellMechanics * mechanics_, const BattleSpellCastParameters & parameters):
mechanics(mechanics_), attackedCres(), sc(), si()
mechanics(mechanics_), attackedCres(), sc(), si(), mode(parameters.mode)
{
prepareBattleCast(parameters);
logGlobal->debugStream() << "Started spell cast. Spell: " << mechanics->owner->name << "; mode:" << mode;
}
SpellCastContext::~SpellCastContext()
{
logGlobal->debugStream() << "Finished spell cast. Spell: " << mechanics->owner->name << "; mode:" << mode;
}
void SpellCastContext::prepareBattleCast(const BattleSpellCastParameters & parameters)
@ -182,16 +188,48 @@ void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCa
}
}
void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const
{
logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
if(nullptr == parameters.caster)
{
env->complain("No spell-caster provided.");
return;
}
std::vector <const CStack*> reflected;//for magic mirror
castNormal(env, parameters, reflected);
//Magic Mirror effect
for(auto & attackedCre : reflected)
{
TStacks mirrorTargets = parameters.cb->battleGetStacksIf([this, parameters](const CStack * battleStack)
{
//Get all enemy stacks. Magic mirror can reflect to immune creature (with no effect)
return battleStack->owner == parameters.casterColor && battleStack->isValidTarget(false);
});
if(!mirrorTargets.empty())
{
int targetHex = (*RandomGeneratorUtil::nextItem(mirrorTargets, env->getRandomGenerator()))->position;
BattleSpellCastParameters mirrorParameters(parameters.cb, attackedCre, owner);
mirrorParameters.spellLvl = 0;
mirrorParameters.aimToHex(targetHex);
mirrorParameters.mode = ECastingMode::MAGIC_MIRROR;
mirrorParameters.selectedStack = nullptr;
mirrorParameters.spellLvl = parameters.spellLvl;
mirrorParameters.effectLevel = parameters.effectLevel;
mirrorParameters.effectPower = parameters.effectPower;
mirrorParameters.effectValue = parameters.effectValue;
mirrorParameters.enchantPower = parameters.enchantPower;
castMagicMirror(env, mirrorParameters);
}
}
}
void DefaultSpellMechanics::castNormal(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, std::vector <const CStack*> & reflected) const
{
SpellCastContext ctx(this, parameters);
//check it there is opponent hero
@ -221,12 +259,11 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
}
logGlobal->debugStream() << "spellCost: " << spellCost;
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.caster, parameters.spellLvl, parameters.getFirstDestinationHex());
std::copy(creatures.begin(), creatures.end(), std::back_inserter(ctx.attackedCres));
ctx.attackedCres = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.caster, parameters.spellLvl, parameters.getFirstDestinationHex());
logGlobal->debugStream() << "will affect: " << ctx.attackedCres.size() << " stacks";
std::vector <const CStack*> reflected;//for magic mirror
//checking if creatures resist
handleResistance(env, ctx.attackedCres, ctx.sc);
//it is actual spell and can be reflected to single target, no recurrence
@ -293,35 +330,25 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
if(!ctx.si.stacks.empty()) //after spellcast info shows
env->sendAndApply(&ctx.si);
}
void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const
{
SpellCastContext ctx(this, parameters);
logGlobal->debugStream() << "Finished spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
//Magic Mirror effect
for(auto & attackedCre : reflected)
{
TStacks mirrorTargets = parameters.cb->battleGetStacksIf([this, parameters](const CStack * battleStack)
{
//Get all enemy stacks. Magic mirror can reflect to immune creature (with no effect)
return battleStack->owner == parameters.casterColor && battleStack->isValidTarget(false);
});
//calculating affected creatures for all spells
ctx.attackedCres = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.caster, parameters.spellLvl, parameters.getFirstDestinationHex());
if(!mirrorTargets.empty())
{
int targetHex = (*RandomGeneratorUtil::nextItem(mirrorTargets, env->getRandomGenerator()))->position;
logGlobal->debugStream() << "will affect: " << ctx.attackedCres.size() << " stacks";
BattleSpellCastParameters mirrorParameters(parameters.cb, attackedCre, owner);
mirrorParameters.spellLvl = 0;
mirrorParameters.aimToHex(targetHex);
mirrorParameters.mode = ECastingMode::MAGIC_MIRROR;
mirrorParameters.selectedStack = nullptr;
mirrorParameters.spellLvl = parameters.spellLvl;
mirrorParameters.effectLevel = parameters.effectLevel;
mirrorParameters.effectPower = parameters.effectPower;
mirrorParameters.effectValue = parameters.effectValue;
mirrorParameters.enchantPower = parameters.enchantPower;
castMagicMirror(env, mirrorParameters);
}
}
handleResistance(env, ctx.attackedCres, ctx.sc);
applyBattleEffects(env, parameters, ctx);
ctx.sendCastPacket(env);
if(!ctx.si.stacks.empty()) //after spellcast info shows
env->sendAndApply(&ctx.si);
}
void DefaultSpellMechanics::battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
@ -610,7 +637,7 @@ std::vector<BattleHex> DefaultSpellMechanics::rangeInHexes(BattleHex centralHex,
return ret;
}
std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const
std::vector<const CStack *> DefaultSpellMechanics::getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const
{
std::set<const CStack* > attackedCres;//std::set to exclude multiple occurrences of two hex creatures
@ -678,7 +705,10 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(const CBattleI
}
}
return attackedCres;
std::vector<const CStack *> res;
std::copy(attackedCres.begin(), attackedCres.end(), std::back_inserter(res));
return res;
}
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const ISpellCaster * caster) const
@ -721,31 +751,6 @@ void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast
}
}
void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, BattleSpellCastParameters& parameters) const
{
logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
BattleHex destination = parameters.getFirstDestinationHex();
SpellCastContext ctx(this, parameters);
//calculating affected creatures for all spells
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.caster, parameters.spellLvl, destination);
std::copy(creatures.begin(), creatures.end(), std::back_inserter(ctx.attackedCres));
logGlobal->debugStream() << "will affect: " << ctx.attackedCres.size() << " stacks";
handleResistance(env, ctx.attackedCres, ctx.sc);
applyBattleEffects(env, parameters, ctx);
ctx.sendCastPacket(env);
if(!ctx.si.stacks.empty()) //after spellcast info shows
env->sendAndApply(&ctx.si);
logGlobal->debugStream() << "Finished spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
}
void DefaultSpellMechanics::handleResistance(const SpellCastEnvironment * env, std::vector<const CStack* >& attackedCres, BattleSpellCast& sc) const
{
//checking if creatures resist

View File

@ -22,8 +22,10 @@ public:
std::vector<const CStack *> attackedCres;//must be vector, as in Chain Lightning order matters
BattleSpellCast sc;//todo: make private
StacksInjured si;
ECastingMode::ECastingMode mode;
SpellCastContext(const DefaultSpellMechanics * mechanics_, const BattleSpellCastParameters & parameters);
virtual ~SpellCastContext();
void addDamageToDisplay(const si32 value);
void setDamageToDisplay(const si32 value);
@ -40,7 +42,7 @@ public:
DefaultSpellMechanics(CSpell * s): ISpellMechanics(s){};
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const override;
std::set<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const override;
std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const override;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ISpellCaster * caster) const override;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
@ -49,7 +51,7 @@ public:
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override final;
void battleCast(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const override final;
void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const override;
@ -60,7 +62,8 @@ protected:
void doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const;
private:
void castMagicMirror(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;
void castNormal(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, std::vector <const CStack*> & reflected) const;
void castMagicMirror(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const;
void handleResistance(const SpellCastEnvironment * env, std::vector<const CStack*> & attackedCres, BattleSpellCast & sc) const;
friend class SpellCastContext;

View File

@ -119,7 +119,7 @@ bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastP
return adventureMechanics->adventureCast(env, parameters);
}
void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
void CSpell::battleCast(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const
{
assert(env);
if(parameters.destinations.size()<1)
@ -211,11 +211,11 @@ std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl,
return mechanics->rangeInHexes(centralHex,schoolLvl,side,outDroppedHexes);
}
std::set<const CStack *> CSpell::getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, const ISpellCaster * caster, int spellLvl, BattleHex destination) const
std::vector<const CStack *> CSpell::getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, const ISpellCaster * caster, int spellLvl, BattleHex destination) const
{
SpellTargetingContext ctx(this, mode, caster, spellLvl, destination);
std::set<const CStack* > attackedCres = mechanics->getAffectedStacks(cb, ctx);
std::vector<const CStack *> attackedCres = mechanics->getAffectedStacks(cb, ctx);
//now handle immunities
auto predicate = [&, this](const CStack * s)->bool

View File

@ -218,7 +218,7 @@ public:
ui32 calculateDamage(const ISpellCaster * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const;
///selects from allStacks actually affected stacks
std::set<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, const ISpellCaster * caster, int spellLvl, BattleHex destination) const;
std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, const ISpellCaster * caster, int spellLvl, BattleHex destination) const;
si32 getCost(const int skillLevel) const;
@ -279,7 +279,7 @@ public:
///May be executed on client side by (future) non-cheat-proof scripts.
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;
void battleCast(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const;
public:
///Client-server logic. Has direct write access to GameState.

View File

@ -97,7 +97,7 @@ public:
virtual ~ISpellMechanics(){};
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
virtual std::set<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const = 0;
virtual std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, SpellTargetingContext & ctx) const = 0;
virtual ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ISpellCaster * caster) const = 0;
@ -106,7 +106,7 @@ public:
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const = 0;
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;
virtual void battleCast(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const = 0;
virtual void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const = 0;

View File

@ -842,7 +842,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
//TODO: should spell override creature`s projectile?
std::set<const CStack*> attackedCreatures = SpellID(bonus->subtype).toSpell()->getAffectedStacks(gs->curB, ECastingMode::SPELL_LIKE_ATTACK, att, bonus->val, targetHex);
auto attackedCreatures = SpellID(bonus->subtype).toSpell()->getAffectedStacks(gs->curB, ECastingMode::SPELL_LIKE_ATTACK, att, bonus->val, targetHex);
//TODO: get exact attacked hex for defender