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:
parent
9ee954edcc
commit
18fc94d709
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user