mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
formatting
This commit is contained in:
parent
f4c683cd5e
commit
5fda2aac9a
@ -22,7 +22,7 @@
|
||||
///SummonBoatMechanics
|
||||
bool SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
//check if spell works at all
|
||||
if(env->getRandomGenerator().nextInt(99) >= owner->getPower(schoolLevel)) //power is % chance of success
|
||||
{
|
||||
@ -42,14 +42,14 @@ bool SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env
|
||||
{
|
||||
env->complain("There is no water tile available!");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(const CGObjectInstance * obj : env->getMap()->objects)
|
||||
{
|
||||
if(obj && obj->ID == Obj::BOAT)
|
||||
{
|
||||
const CGBoat *b = static_cast<const CGBoat*>(obj);
|
||||
if(b->hero)
|
||||
if(b->hero)
|
||||
continue; //we're looking for unoccupied boat
|
||||
|
||||
double nDist = b->pos.dist2d(parameters.caster->getPosition());
|
||||
@ -58,7 +58,7 @@ bool SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env
|
||||
nearest = b;
|
||||
dist = nDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(nullptr != nearest) //we found boat to summon
|
||||
@ -83,8 +83,8 @@ bool SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env
|
||||
no.subID = parameters.caster->getBoatType();
|
||||
no.pos = summonPos + int3(1,0,0);;
|
||||
env->sendAndApply(&no);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///ScuttleBoatMechanics
|
||||
@ -101,7 +101,7 @@ bool ScuttleBoatMechanics::applyAdventureEffects(const SpellCastEnvironment* env
|
||||
env->sendAndApply(&iw);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if(!env->getMap()->isInTheMap(parameters.pos))
|
||||
{
|
||||
env->complain("Invalid dst tile for scuttle!");
|
||||
@ -115,12 +115,11 @@ bool ScuttleBoatMechanics::applyAdventureEffects(const SpellCastEnvironment* env
|
||||
env->complain("There is no boat to scuttle!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
RemoveObject ro;
|
||||
ro.id = t->visitableObjects.back()->id;
|
||||
env->sendAndApply(&ro);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
///DimensionDoorMechanics
|
||||
@ -130,8 +129,8 @@ bool DimensionDoorMechanics::applyAdventureEffects(const SpellCastEnvironment* e
|
||||
{
|
||||
env->complain("Destination is out of map!");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const TerrainTile * dest = env->getCb()->getTile(parameters.pos);
|
||||
const TerrainTile * curr = env->getCb()->getTile(parameters.caster->getSightCenter());
|
||||
|
||||
@ -140,21 +139,21 @@ bool DimensionDoorMechanics::applyAdventureEffects(const SpellCastEnvironment* e
|
||||
env->complain("Destination tile doesn't exist!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if(nullptr == curr)
|
||||
{
|
||||
env->complain("Source tile doesn't exist!");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(parameters.caster->movement <= 0)
|
||||
{
|
||||
env->complain("Hero needs movement points to cast Dimension Door!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
|
||||
if(parameters.caster->getBonusesCount(Bonus::SPELL_EFFECT, SpellID::DIMENSION_DOOR) >= owner->getPower(schoolLevel)) //limit casts per turn
|
||||
{
|
||||
InfoWindow iw;
|
||||
@ -175,7 +174,7 @@ bool DimensionDoorMechanics::applyAdventureEffects(const SpellCastEnvironment* e
|
||||
InfoWindow iw;
|
||||
iw.player = parameters.caster->tempOwner;
|
||||
iw.text.addTxt(MetaString::GENERAL_TXT, 70); //Dimension Door failed!
|
||||
env->sendAndApply(&iw);
|
||||
env->sendAndApply(&iw);
|
||||
}
|
||||
else if(env->moveHero(parameters.caster->id, parameters.pos + parameters.caster->getVisitableOffset(), true))
|
||||
{
|
||||
@ -184,7 +183,7 @@ bool DimensionDoorMechanics::applyAdventureEffects(const SpellCastEnvironment* e
|
||||
smp.val = std::max<ui32>(0, parameters.caster->movement - 300);
|
||||
env->sendAndApply(&smp);
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
///TownPortalMechanics
|
||||
@ -194,28 +193,28 @@ bool TownPortalMechanics::applyAdventureEffects(const SpellCastEnvironment * env
|
||||
{
|
||||
env->complain("Destination tile not present!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TerrainTile tile = env->getMap()->getTile(parameters.pos);
|
||||
if (tile.visitableObjects.empty() || tile.visitableObjects.back()->ID != Obj::TOWN)
|
||||
{
|
||||
env->complain("Town not found for Town Portal!");
|
||||
env->complain("Town not found for Town Portal!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CGTownInstance * town = static_cast<CGTownInstance*>(tile.visitableObjects.back());
|
||||
if (town->tempOwner != parameters.caster->tempOwner)
|
||||
{
|
||||
env->complain("Can't teleport to another player!");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (town->visitingHero)
|
||||
{
|
||||
env->complain("Can't teleport to occupied town!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (parameters.caster->getSpellSchoolLevel(owner) < 2)
|
||||
{
|
||||
si32 dist = town->pos.dist2dSQ(parameters.caster->pos);
|
||||
@ -234,31 +233,31 @@ bool TownPortalMechanics::applyAdventureEffects(const SpellCastEnvironment * env
|
||||
env->complain("This hero can only teleport to nearest town!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
env->moveHero(parameters.caster->id, town->visitablePos() + parameters.caster->getVisitableOffset() ,1);
|
||||
env->moveHero(parameters.caster->id, town->visitablePos() + parameters.caster->getVisitableOffset() ,1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
ShowWorldViewEx pack;
|
||||
|
||||
|
||||
pack.player = parameters.caster->tempOwner;
|
||||
|
||||
|
||||
const int spellLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
|
||||
for(const CGObjectInstance * obj : env->getMap()->objects)
|
||||
{
|
||||
//we need to send only not visible objects
|
||||
|
||||
//todo:we need to send only not visible objects
|
||||
|
||||
if(filterObject(obj, spellLevel))
|
||||
pack.objectPositions.push_back(ObjectPosInfo(obj));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
env->sendAndApply(&pack);
|
||||
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewAirMechanics::filterObject(const CGObjectInstance * obj, const int spellLevel) const
|
||||
|
@ -7,67 +7,66 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultSpellMechanics.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
class SummonBoatMechanics: public DefaultSpellMechanics
|
||||
#include "CDefaultSpellMechanics.h"
|
||||
|
||||
class SummonBoatMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
SummonBoatMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class ScuttleBoatMechanics: public DefaultSpellMechanics
|
||||
class ScuttleBoatMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
ScuttleBoatMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class DimensionDoorMechanics: public DefaultSpellMechanics
|
||||
class DimensionDoorMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
DimensionDoorMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
public:
|
||||
DimensionDoorMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class TownPortalMechanics: public DefaultSpellMechanics
|
||||
class TownPortalMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
TownPortalMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
public:
|
||||
TownPortalMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
class ViewMechanics: public DefaultSpellMechanics
|
||||
class ViewMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
public:
|
||||
ViewMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override;
|
||||
virtual bool filterObject(const CGObjectInstance * obj, const int spellLevel) const = 0;
|
||||
};
|
||||
|
||||
class ViewAirMechanics: public ViewMechanics
|
||||
class ViewAirMechanics: public ViewMechanics
|
||||
{
|
||||
public:
|
||||
ViewAirMechanics(CSpell * s): ViewMechanics(s){};
|
||||
public:
|
||||
ViewAirMechanics(CSpell * s): ViewMechanics(s){};
|
||||
protected:
|
||||
bool filterObject(const CGObjectInstance * obj, const int spellLevel) const override;
|
||||
};
|
||||
|
||||
class ViewEarthMechanics: public ViewMechanics
|
||||
class ViewEarthMechanics: public ViewMechanics
|
||||
{
|
||||
public:
|
||||
ViewEarthMechanics(CSpell * s): ViewMechanics(s){};
|
||||
public:
|
||||
ViewEarthMechanics(CSpell * s): ViewMechanics(s){};
|
||||
protected:
|
||||
bool filterObject(const CGObjectInstance * obj, const int spellLevel) const override;
|
||||
bool filterObject(const CGObjectInstance * obj, const int spellLevel) const override;
|
||||
};
|
||||
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "BattleSpellMechanics.h"
|
||||
@ -19,7 +18,7 @@
|
||||
std::set<const CStack *> ChainLightningMechanics::getAffectedStacks(SpellTargetingContext & ctx) const
|
||||
{
|
||||
std::set<const CStack* > attackedCres;
|
||||
|
||||
|
||||
std::set<BattleHex> possibleHexes;
|
||||
for(auto stack : ctx.cb->battleGetAllStacks())
|
||||
{
|
||||
@ -47,8 +46,8 @@ std::set<const CStack *> ChainLightningMechanics::getAffectedStacks(SpellTargeti
|
||||
if(possibleHexes.empty()) //not enough targets
|
||||
break;
|
||||
lightningHex = BattleHex::getClosestTile(stack->attackerOwned, ctx.destination, possibleHexes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return attackedCres;
|
||||
}
|
||||
|
||||
@ -63,7 +62,7 @@ void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, Battle
|
||||
env->complain ("No target stack to clone!");
|
||||
return;
|
||||
}
|
||||
const int attacker = !(bool)parameters.casterSide;
|
||||
const int attacker = !(bool)parameters.casterSide;
|
||||
|
||||
BattleStackAdded bsa;
|
||||
bsa.creID = clonedStack->type->idNumber;
|
||||
@ -78,7 +77,7 @@ void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, Battle
|
||||
ssp.which = BattleSetStackProperty::CLONED;
|
||||
ssp.val = 0;
|
||||
ssp.absolute = 1;
|
||||
env->sendAndApply(&ssp);
|
||||
env->sendAndApply(&ssp);
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
|
||||
@ -105,22 +104,22 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const CGHer
|
||||
if(maxLevel < creLevel) //tier 1-5 for basic, 1-6 for advanced, any level for expert
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
//use default algorithm only if there is no mechanics-related problem
|
||||
return DefaultSpellMechanics::isImmuneByStack(caster, obj);
|
||||
//use default algorithm only if there is no mechanics-related problem
|
||||
return DefaultSpellMechanics::isImmuneByStack(caster, obj);
|
||||
}
|
||||
|
||||
///CureMechanics
|
||||
void CureMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
|
||||
{
|
||||
DefaultSpellMechanics::applyBattle(battle, packet);
|
||||
|
||||
|
||||
for(auto stackID : packet->affectedCres)
|
||||
{
|
||||
if(vstd::contains(packet->resisted, stackID))
|
||||
{
|
||||
logGlobal->errorStream() << "Resistance to positive spell CURE";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
CStack *s = battle->getStack(stackID);
|
||||
s->popBonuses([&](const Bonus *b) -> bool
|
||||
@ -132,14 +131,14 @@ void CureMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * pac
|
||||
}
|
||||
return false; //not a spell effect
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///DispellMechanics
|
||||
void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
|
||||
{
|
||||
DefaultSpellMechanics::applyBattle(battle, packet);
|
||||
|
||||
|
||||
for(auto stackID : packet->affectedCres)
|
||||
{
|
||||
if(vstd::contains(packet->resisted, stackID))
|
||||
@ -150,7 +149,7 @@ void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast *
|
||||
{
|
||||
return Selector::sourceType(Bonus::SPELL_EFFECT)(b);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -166,7 +165,7 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const C
|
||||
* owner->power + owner->getPower(caster->getSpellSchoolLevel(owner)), caster, obj);
|
||||
if (subjectHealth > maxHealth)
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
}
|
||||
return DefaultSpellMechanics::isImmuneByStack(caster, obj);
|
||||
}
|
||||
|
||||
@ -217,8 +216,8 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, Bat
|
||||
BattleObstaclePlaced bop;
|
||||
bop.obstacle = obstacle;
|
||||
env->sendAndApply(&bop);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
switch(owner->id)
|
||||
{
|
||||
case SpellID::QUICKSAND:
|
||||
@ -253,17 +252,17 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, Bat
|
||||
placeObstacle(hex);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///WallMechanics
|
||||
std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes) const
|
||||
{
|
||||
std::vector<BattleHex> ret;
|
||||
|
||||
std::vector<BattleHex> ret;
|
||||
|
||||
//Special case - shape of obstacle depends on caster's side
|
||||
//TODO make it possible through spell config
|
||||
|
||||
@ -293,7 +292,7 @@ std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 sch
|
||||
if(schoolLvl >= 2) //advanced versions of fire wall / force field cotnains of 3 hexes
|
||||
addIfValid(centralHex.moveInDir(secondStep, false)); //moveInDir function modifies subject hex
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
///RemoveObstacleMechanics
|
||||
@ -306,7 +305,7 @@ void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * en
|
||||
env->sendAndApply(&obr);
|
||||
}
|
||||
else
|
||||
env->complain("There's no obstacle to remove!");
|
||||
env->complain("There's no obstacle to remove!");
|
||||
}
|
||||
|
||||
///SpecialRisingSpellMechanics
|
||||
@ -338,7 +337,6 @@ void SacrificeMechanics::applyBattleEffects(const SpellCastEnvironment * env, Ba
|
||||
BattleStacksRemoved bsr;
|
||||
bsr.stackIDs.insert(parameters.selectedStack->ID); //somehow it works for teleport?
|
||||
env->sendAndApply(&bsr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -350,15 +348,15 @@ ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStac
|
||||
|
||||
if(obj->count >= obj->baseAmount)
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
|
||||
|
||||
if(caster) //FIXME: Archangels can cast immune stack
|
||||
{
|
||||
auto maxHealth = calculateHealedHP(caster, obj, nullptr);
|
||||
if (maxHealth < obj->MaxHealth()) //must be able to rise at least one full creature
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
|
||||
return DefaultSpellMechanics::isImmuneByStack(caster,obj);
|
||||
}
|
||||
|
||||
return DefaultSpellMechanics::isImmuneByStack(caster,obj);
|
||||
}
|
||||
|
||||
///SummonMechanics
|
||||
@ -400,7 +398,7 @@ void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, Battl
|
||||
if(bsa.amount)
|
||||
env->sendAndApply(&bsa);
|
||||
else
|
||||
env->complain("Summoning didn't summon any!");
|
||||
env->complain("Summoning didn't summon any!");
|
||||
}
|
||||
|
||||
|
||||
@ -414,6 +412,6 @@ void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, Bat
|
||||
tiles.push_back(parameters.destination);
|
||||
bsm.tilesToMove = tiles;
|
||||
bsm.teleporting = true;
|
||||
env->sendAndApply(&bsm);
|
||||
env->sendAndApply(&bsm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,16 +7,15 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultSpellMechanics.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultSpellMechanics.h"
|
||||
|
||||
class ChainLightningMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
ChainLightningMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ChainLightningMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const override;
|
||||
};
|
||||
|
||||
@ -26,48 +25,46 @@ public:
|
||||
CloneMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
class CureMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
CureMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
CureMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DispellMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
DispellMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
};
|
||||
|
||||
class HypnotizeMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
HypnotizeMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
};
|
||||
HypnotizeMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
};
|
||||
|
||||
class ObstacleMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
ObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
class WallMechanics: public ObstacleMechanics
|
||||
{
|
||||
public:
|
||||
WallMechanics(CSpell * s): ObstacleMechanics(s){};
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr) const override;
|
||||
WallMechanics(CSpell * s): ObstacleMechanics(s){};
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr) const override;
|
||||
};
|
||||
|
||||
class RemoveObstacleMechanics: public DefaultSpellMechanics
|
||||
@ -75,23 +72,23 @@ class RemoveObstacleMechanics: public DefaultSpellMechanics
|
||||
public:
|
||||
RemoveObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
///all rising spells
|
||||
class RisingSpellMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
RisingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
RisingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
};
|
||||
|
||||
class SacrificeMechanics: public RisingSpellMechanics
|
||||
{
|
||||
public:
|
||||
SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){};
|
||||
SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){};
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
///all rising spells but SACRIFICE
|
||||
@ -99,7 +96,7 @@ class SpecialRisingSpellMechanics: public RisingSpellMechanics
|
||||
{
|
||||
public:
|
||||
SpecialRisingSpellMechanics(CSpell * s): RisingSpellMechanics(s){};
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
};
|
||||
|
||||
class SummonMechanics: public DefaultSpellMechanics
|
||||
@ -107,7 +104,7 @@ class SummonMechanics: public DefaultSpellMechanics
|
||||
public:
|
||||
SummonMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
class TeleportMechanics: public DefaultSpellMechanics
|
||||
@ -115,5 +112,5 @@ class TeleportMechanics: public DefaultSpellMechanics
|
||||
public:
|
||||
TeleportMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
@ -117,7 +117,6 @@ namespace SRSLPraserHelpers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///DefaultSpellMechanics
|
||||
void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
|
||||
{
|
||||
@ -128,7 +127,7 @@ void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCa
|
||||
battle->sides[packet->side].castSpellsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//handle countering spells
|
||||
for(auto stackID : packet->affectedCres)
|
||||
{
|
||||
@ -144,7 +143,7 @@ void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCa
|
||||
|
||||
return isSpellEffect && vstd::contains(owner->counteredSpells, spellID);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
@ -154,29 +153,29 @@ bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, Adve
|
||||
env->complain("Attempt to cast non adventure spell in adventure mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const CGHeroInstance * caster = parameters.caster;
|
||||
const int cost = caster->getSpellCost(owner);
|
||||
|
||||
|
||||
if(!caster->canCastThisSpell(owner))
|
||||
{
|
||||
env->complain("Hero cannot cast this spell!");
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(caster->mana < cost)
|
||||
{
|
||||
env->complain("Hero doesn't have enough spell points to cast this spell!");
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
AdvmapSpellCast asc;
|
||||
asc.caster = caster;
|
||||
asc.spellID = owner->id;
|
||||
env->sendAndApply(&asc);
|
||||
env->sendAndApply(&asc);
|
||||
}
|
||||
|
||||
|
||||
if(applyAdventureEffects(env, parameters))
|
||||
{
|
||||
SetMana sm;
|
||||
@ -194,27 +193,27 @@ bool DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * e
|
||||
if(owner->hasEffects())
|
||||
{
|
||||
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
|
||||
std::vector<Bonus> bonuses;
|
||||
|
||||
|
||||
owner->getEffects(bonuses, schoolLevel);
|
||||
|
||||
|
||||
for(Bonus b : bonuses)
|
||||
{
|
||||
GiveBonus gb;
|
||||
gb.id = parameters.caster->id.getNum();
|
||||
gb.bonus = b;
|
||||
env->sendAndApply(&gb);
|
||||
env->sendAndApply(&gb);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//There is no generic algorithm of adventure cast
|
||||
env->complain("Unimplemented adventure spell");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -229,11 +228,11 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
||||
sc.castedByHero = nullptr != parameters.caster;
|
||||
sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);
|
||||
sc.manaGained = 0;
|
||||
|
||||
int spellCost = 0;
|
||||
|
||||
|
||||
int spellCost = 0;
|
||||
|
||||
//calculate spell cost
|
||||
if(parameters.caster)
|
||||
if(parameters.caster)
|
||||
{
|
||||
spellCost = parameters.cb->battleGetSpellCost(owner, parameters.caster);
|
||||
|
||||
@ -249,21 +248,20 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
||||
}
|
||||
sc.manaGained = (manaChannel * spellCost) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//calculating affected creatures for all spells
|
||||
//must be vector, as in Chain Lightning order matters
|
||||
std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
|
||||
|
||||
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.destination, parameters.caster);
|
||||
std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres));
|
||||
|
||||
|
||||
for (auto cre : attackedCres)
|
||||
{
|
||||
sc.affectedCres.insert(cre->ID);
|
||||
}
|
||||
|
||||
|
||||
//checking if creatures resist
|
||||
//resistance is applied only to negative spells
|
||||
if(owner->isNegative())
|
||||
@ -271,52 +269,51 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
||||
for(auto s : attackedCres)
|
||||
{
|
||||
const int prob = std::min((s)->magicResistance(), 100); //probability of resistance in %
|
||||
|
||||
|
||||
if(env->getRandomGenerator().nextInt(99) < prob)
|
||||
{
|
||||
sc.resisted.push_back(s->ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StacksInjured si;
|
||||
|
||||
StacksInjured si;
|
||||
SpellCastContext ctx(attackedCres, sc, si);
|
||||
|
||||
|
||||
applyBattleEffects(env, parameters, ctx);
|
||||
|
||||
|
||||
env->sendAndApply(&sc);
|
||||
|
||||
|
||||
//spend mana
|
||||
if(parameters.caster)
|
||||
if(parameters.caster)
|
||||
{
|
||||
SetMana sm;
|
||||
sm.absolute = false;
|
||||
|
||||
|
||||
sm.hid = parameters.caster->id;
|
||||
sm.val = -spellCost;
|
||||
|
||||
|
||||
env->sendAndApply(&sm);
|
||||
|
||||
|
||||
if(sc.manaGained > 0)
|
||||
{
|
||||
assert(parameters.secHero);
|
||||
|
||||
|
||||
sm.hid = parameters.secHero->id;
|
||||
sm.val = sc.manaGained;
|
||||
env->sendAndApply(&sm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!si.stacks.empty()) //after spellcast info shows
|
||||
env->sendAndApply(&si);
|
||||
|
||||
|
||||
//reduce number of casts remaining
|
||||
//TODO: this should be part of BattleSpellCast apply
|
||||
if (parameters.mode == ECastingMode::CREATURE_ACTIVE_CASTING || parameters.mode == ECastingMode::ENCHANTER_CASTING)
|
||||
if (parameters.mode == ECastingMode::CREATURE_ACTIVE_CASTING || parameters.mode == ECastingMode::ENCHANTER_CASTING)
|
||||
{
|
||||
assert(parameters.casterStack);
|
||||
|
||||
|
||||
BattleSetStackProperty ssp;
|
||||
ssp.stackID = parameters.casterStack->ID;
|
||||
ssp.which = BattleSetStackProperty::CASTS;
|
||||
@ -346,7 +343,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
||||
if(!mirrorTargets.empty())
|
||||
{
|
||||
int targetHex = (*RandomGeneratorUtil::nextItem(mirrorTargets, env->getRandomGenerator()))->position;
|
||||
|
||||
|
||||
BattleSpellCastParameters mirrorParameters = parameters;
|
||||
mirrorParameters.spellLvl = 0;
|
||||
mirrorParameters.casterSide = 1-parameters.casterSide;
|
||||
@ -357,12 +354,12 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
||||
mirrorParameters.mode = ECastingMode::MAGIC_MIRROR;
|
||||
mirrorParameters.casterStack = (attackedCre);
|
||||
mirrorParameters.selectedStack = nullptr;
|
||||
|
||||
battleCast(env, mirrorParameters);
|
||||
|
||||
battleCast(env, mirrorParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DefaultSpellMechanics::calculateDuration(const CGHeroInstance * caster, int usedSpellPower) const
|
||||
@ -380,28 +377,28 @@ int DefaultSpellMechanics::calculateDuration(const CGHeroInstance * caster, int
|
||||
return 1;
|
||||
default: //other spells
|
||||
return caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER) + caster->valOfBonuses(Bonus::SPELL_DURATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui32 DefaultSpellMechanics::calculateHealedHP(const CGHeroInstance* caster, const CStack* stack, const CStack* sacrificedStack) const
|
||||
{
|
||||
int healedHealth;
|
||||
|
||||
|
||||
if(!owner->isHealingSpell())
|
||||
{
|
||||
logGlobal->errorStream() << "calculateHealedHP called for nonhealing spell "<< owner->name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const int spellPowerSkill = caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER);
|
||||
const int levelPower = owner->getPower(caster->getSpellSchoolLevel(owner));
|
||||
|
||||
|
||||
if (owner->id == SpellID::SACRIFICE && sacrificedStack)
|
||||
healedHealth = (spellPowerSkill + sacrificedStack->MaxHealth() + levelPower) * sacrificedStack->count;
|
||||
else
|
||||
healedHealth = spellPowerSkill * owner->power + levelPower; //???
|
||||
healedHealth = owner->calculateBonus(healedHealth, caster, stack);
|
||||
return std::min<ui32>(healedHealth, stack->MaxHealth() - stack->firstHPleft + (owner->isRisingSpell() ? stack->baseAmount * stack->MaxHealth() : 0));
|
||||
return std::min<ui32>(healedHealth, stack->MaxHealth() - stack->firstHPleft + (owner->isRisingSpell() ? stack->baseAmount * stack->MaxHealth() : 0));
|
||||
}
|
||||
|
||||
|
||||
@ -448,7 +445,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
|
||||
++chainLightningModifier;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(owner->hasEffects())
|
||||
{
|
||||
int stackSpellPower = 0;
|
||||
@ -531,7 +528,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
|
||||
env->sendAndApply(&sse);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(owner->isHealingSpell())
|
||||
{
|
||||
int hpGained = 0;
|
||||
@ -563,7 +560,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
|
||||
//any typical spell (commander's cure or animate dead)
|
||||
int healedHealth = parameters.usedSpellPower * owner->power + owner->getPower(parameters.spellLvl);
|
||||
hi.healedHP = std::min<ui32>(healedHealth, attackedCre->MaxHealth() - attackedCre->firstHPleft + (resurrect ? attackedCre->baseAmount * attackedCre->MaxHealth() : 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
hi.healedHP = calculateHealedHP(parameters.caster, attackedCre, parameters.selectedStack); //Casted by hero
|
||||
@ -572,14 +569,13 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
|
||||
}
|
||||
if(!shr.healedStacks.empty())
|
||||
env->sendAndApply(&shr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<BattleHex> DefaultSpellMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
|
||||
{
|
||||
using namespace SRSLPraserHelpers;
|
||||
|
||||
|
||||
std::vector<BattleHex> ret;
|
||||
std::string rng = owner->getLevelInfo(schoolLvl).range + ','; //copy + artificial comma for easier handling
|
||||
|
||||
@ -639,19 +635,18 @@ std::vector<BattleHex> DefaultSpellMechanics::rangeInHexes(BattleHex centralHex,
|
||||
|
||||
//remove duplicates (TODO check if actually needed)
|
||||
range::unique(ret);
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargetingContext & ctx) const
|
||||
{
|
||||
std::set<const CStack* > attackedCres;//std::set to exclude multiple occurrences of two hex creatures
|
||||
|
||||
|
||||
const ui8 attackerSide = ctx.cb->playerToSide(ctx.casterColor) == 1;
|
||||
const auto attackedHexes = rangeInHexes(ctx.destination, ctx.schoolLvl, attackerSide);
|
||||
|
||||
const CSpell::TargetInfo ti(owner, ctx.schoolLvl, ctx.mode);
|
||||
|
||||
|
||||
//TODO: more generic solution for mass spells
|
||||
if(owner->getLevelInfo(ctx.schoolLvl).range.size() > 1) //custom many-hex range
|
||||
{
|
||||
@ -669,17 +664,17 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
|
||||
const bool positiveToAlly = owner->isPositive() && s->owner == ctx.casterColor;
|
||||
const bool negativeToEnemy = owner->isNegative() && s->owner != ctx.casterColor;
|
||||
const bool validTarget = s->isValidTarget(!ti.onlyAlive); //todo: this should be handled by spell class
|
||||
|
||||
|
||||
//for single target spells select stacks covering destination tile
|
||||
const bool rangeCovers = ti.massive || s->coversPos(ctx.destination);
|
||||
//handle smart targeting
|
||||
const bool positivenessFlag = !ti.smart || owner->isNeutral() || positiveToAlly || negativeToEnemy;
|
||||
|
||||
return rangeCovers && positivenessFlag && validTarget;
|
||||
|
||||
return rangeCovers && positivenessFlag && validTarget;
|
||||
};
|
||||
|
||||
|
||||
TStacks stacks = ctx.cb->battleGetStacksIf(predicate);
|
||||
|
||||
|
||||
if(ti.massive)
|
||||
{
|
||||
//for massive spells add all targets
|
||||
@ -696,13 +691,13 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
|
||||
{
|
||||
attackedCres.insert(stack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(attackedCres.empty() && !stacks.empty())
|
||||
{
|
||||
attackedCres.insert(stacks.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else //custom range from attackedHexes
|
||||
@ -712,12 +707,11 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
|
||||
if(const CStack * st = ctx.cb->battleGetStackByPos(hex, ti.onlyAlive))
|
||||
attackedCres.insert(st);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return attackedCres;
|
||||
}
|
||||
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
|
||||
{
|
||||
//by default use general algorithm
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "ISpellMechanics.h"
|
||||
|
||||
class BattleSpellCast;
|
||||
@ -18,9 +17,9 @@ class StacksInjured;
|
||||
|
||||
struct SpellCastContext
|
||||
{
|
||||
SpellCastContext(std::vector<const CStack*> & attackedCres, BattleSpellCast & sc, StacksInjured & si):
|
||||
attackedCres(attackedCres), sc(sc), si(si){};
|
||||
std::vector<const CStack*> & attackedCres;
|
||||
SpellCastContext(std::vector<const CStack *> & attackedCres, BattleSpellCast & sc, StacksInjured & si):
|
||||
attackedCres(attackedCres), sc(sc), si(si){};
|
||||
std::vector<const CStack *> & attackedCres;
|
||||
BattleSpellCast & sc;
|
||||
StacksInjured & si;
|
||||
};
|
||||
@ -29,25 +28,24 @@ class DefaultSpellMechanics: public ISpellMechanics
|
||||
{
|
||||
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(SpellTargetingContext & ctx) const override;
|
||||
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
|
||||
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
|
||||
|
||||
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
|
||||
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override;
|
||||
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
protected:
|
||||
|
||||
virtual void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
|
||||
|
||||
|
||||
virtual int calculateDuration(const CGHeroInstance * caster, int usedSpellPower) const;
|
||||
|
||||
|
||||
///calculate healed HP for all spells casted by hero
|
||||
ui32 calculateHealedHP(const CGHeroInstance* caster, const CStack* stack, const CStack* sacrificedStack) const;
|
||||
|
||||
ui32 calculateHealedHP(const CGHeroInstance * caster, const CStack * stack, const CStack * sacrificedStack) const;
|
||||
|
||||
///actual adventure cast implementation
|
||||
virtual bool applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
|
||||
};
|
||||
|
@ -1,3 +1,13 @@
|
||||
/*
|
||||
* CSpellHandler.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 <cctype>
|
||||
@ -19,23 +29,11 @@
|
||||
|
||||
#include "ISpellMechanics.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* CSpellHandler.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
|
||||
*
|
||||
*/
|
||||
|
||||
namespace SpellConfig
|
||||
{
|
||||
static const std::string LEVEL_NAMES[] = {"none", "basic", "advanced", "expert"};
|
||||
|
||||
static const SpellSchoolInfo SCHOOL[4] =
|
||||
|
||||
static const SpellSchoolInfo SCHOOL[4] =
|
||||
{
|
||||
{
|
||||
ESpellSchool::AIR,
|
||||
@ -69,16 +67,15 @@ namespace SpellConfig
|
||||
SecondarySkill::EARTH_MAGIC,
|
||||
Bonus::EARTH_SPELLS
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo* cb)
|
||||
: spellLvl(0), destination(BattleHex::INVALID), casterSide(0),casterColor(PlayerColor::CANNOT_DETERMINE),caster(nullptr), secHero(nullptr),
|
||||
usedSpellPower(0),mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr), cb(cb)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///CSpell::LevelInfo
|
||||
CSpell::LevelInfo::LevelInfo()
|
||||
@ -118,14 +115,14 @@ void CSpell::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) co
|
||||
bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
assert(env);
|
||||
|
||||
|
||||
return mechanics->adventureCast(env, parameters);
|
||||
}
|
||||
|
||||
void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
|
||||
{
|
||||
assert(env);
|
||||
|
||||
|
||||
mechanics->battleCast(env, parameters);
|
||||
}
|
||||
|
||||
@ -133,19 +130,19 @@ bool CSpell::isCastableBy(const IBonusBearer * caster, bool hasSpellBook, const
|
||||
{
|
||||
if(!hasSpellBook)
|
||||
return false;
|
||||
|
||||
|
||||
const bool inSpellBook = vstd::contains(spellBook, id);
|
||||
const bool isBonus = caster->hasBonusOfType(Bonus::SPELL, id);
|
||||
|
||||
|
||||
bool inTome = false;
|
||||
|
||||
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
if(caster->hasBonusOfType(cnf.knoledgeBonus))
|
||||
{
|
||||
inTome = stop = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (isSpecialSpell())
|
||||
{
|
||||
@ -158,7 +155,7 @@ bool CSpell::isCastableBy(const IBonusBearer * caster, bool hasSpellBook, const
|
||||
else
|
||||
{
|
||||
return inSpellBook || inTome || isBonus || caster->hasBonusOfType(Bonus::SPELLS_OF_LEVEL, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const CSpell::LevelInfo & CSpell::getLevelInfo(const int level) const
|
||||
@ -172,7 +169,7 @@ const CSpell::LevelInfo & CSpell::getLevelInfo(const int level) const
|
||||
return levels.at(level);
|
||||
}
|
||||
|
||||
ui32 CSpell::calculateBonus(ui32 baseDamage, const CGHeroInstance* caster, const CStack* affectedCreature) const
|
||||
ui32 CSpell::calculateBonus(ui32 baseDamage, const CGHeroInstance * caster, const CStack * affectedCreature) const
|
||||
{
|
||||
ui32 ret = baseDamage;
|
||||
//applying sorcery secondary skill
|
||||
@ -180,17 +177,17 @@ ui32 CSpell::calculateBonus(ui32 baseDamage, const CGHeroInstance* caster, const
|
||||
{
|
||||
ret *= (100.0 + caster->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SORCERY)) / 100.0;
|
||||
ret *= (100.0 + caster->valOfBonuses(Bonus::SPELL_DAMAGE) + caster->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, id.toEnum())) / 100.0;
|
||||
|
||||
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
ret *= (100.0 + caster->valOfBonuses(cnf.damagePremyBonus)) / 100.0;
|
||||
stop = true; //only bonus from one school is used
|
||||
});
|
||||
});
|
||||
|
||||
if (affectedCreature && affectedCreature->getCreature()->level) //Hero specials like Solmyr, Deemer
|
||||
ret *= (100. + ((caster->valOfBonuses(Bonus::SPECIAL_SPELL_LEV, id.toEnum()) * caster->level) / affectedCreature->getCreature()->level)) / 100.0;
|
||||
}
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const
|
||||
@ -208,15 +205,15 @@ ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affec
|
||||
if(nullptr != affectedCreature)
|
||||
{
|
||||
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
|
||||
|
||||
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
if(affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id))
|
||||
{
|
||||
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id);
|
||||
ret /= 100;
|
||||
stop = true;//only bonus from one school is used
|
||||
}
|
||||
stop = true;//only bonus from one school is used
|
||||
}
|
||||
});
|
||||
|
||||
//general spell dmg reduction
|
||||
@ -233,7 +230,7 @@ ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affec
|
||||
}
|
||||
}
|
||||
ret = calculateBonus(ret, caster, affectedCreature);
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
|
||||
@ -241,26 +238,25 @@ 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, PlayerColor casterColor, int spellLvl, BattleHex destination, const CGHeroInstance * caster) const
|
||||
std::set<const CStack *> CSpell::getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, PlayerColor casterColor, int spellLvl, BattleHex destination, const CGHeroInstance * caster) const
|
||||
{
|
||||
ISpellMechanics::SpellTargetingContext ctx(this, cb,mode,casterColor,spellLvl,destination);
|
||||
|
||||
std::set<const CStack* > attackedCres = mechanics->getAffectedStacks(ctx);
|
||||
|
||||
//now handle immunities
|
||||
|
||||
//now handle immunities
|
||||
auto predicate = [&, this](const CStack * s)->bool
|
||||
{
|
||||
bool hitDirectly = ctx.ti.alwaysHitDirectly && s->coversPos(destination);
|
||||
bool notImmune = (ESpellCastProblem::OK == isImmuneByStack(caster, s));
|
||||
|
||||
return !(hitDirectly || notImmune);
|
||||
};
|
||||
|
||||
return !(hitDirectly || notImmune);
|
||||
};
|
||||
vstd::erase_if(attackedCres, predicate);
|
||||
|
||||
|
||||
return attackedCres;
|
||||
}
|
||||
|
||||
|
||||
CSpell::ETargetType CSpell::getTargetType() const
|
||||
{
|
||||
return targetType;
|
||||
@ -280,14 +276,13 @@ void CSpell::forEachSchool(const std::function<void(const SpellSchoolInfo &, boo
|
||||
if(school.at(cnf.id))
|
||||
{
|
||||
cb(cnf, stop);
|
||||
|
||||
|
||||
if(stop)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CSpell::isCombatSpell() const
|
||||
{
|
||||
return combatSpell;
|
||||
@ -348,12 +343,12 @@ bool CSpell::hasEffects() const
|
||||
return !levels[0].effects.empty();
|
||||
}
|
||||
|
||||
const std::string& CSpell::getIconImmune() const
|
||||
const std::string & CSpell::getIconImmune() const
|
||||
{
|
||||
return iconImmune;
|
||||
}
|
||||
|
||||
const std::string& CSpell::getCastSound() const
|
||||
const std::string & CSpell::getCastSound() const
|
||||
{
|
||||
return castSound;
|
||||
}
|
||||
@ -377,8 +372,7 @@ si32 CSpell::getProbability(const TFaction factionId) const
|
||||
return probabilities.at(factionId);
|
||||
}
|
||||
|
||||
|
||||
void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
|
||||
void CSpell::getEffects(std::vector<Bonus> & lst, const int level) const
|
||||
{
|
||||
if(level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS)
|
||||
{
|
||||
@ -408,17 +402,17 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallbac
|
||||
TStacks stacks = cb->battleGetStacksIf([=](const CStack * s){
|
||||
return s->coversPos(destination) && (isRisingSpell() || s->alive());
|
||||
});
|
||||
|
||||
|
||||
if(!stacks.empty())
|
||||
{
|
||||
bool allImmune = true;
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem problem;
|
||||
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem problem;
|
||||
|
||||
for(auto s : stacks)
|
||||
{
|
||||
ESpellCastProblem::ESpellCastProblem res = isImmuneByStack(caster,s);
|
||||
|
||||
|
||||
if(res == ESpellCastProblem::OK)
|
||||
{
|
||||
allImmune = false;
|
||||
@ -428,7 +422,7 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallbac
|
||||
problem = res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(allImmune)
|
||||
return problem;
|
||||
}
|
||||
@ -439,23 +433,22 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallbac
|
||||
if(caster && mode == ECastingMode::HERO_CASTING) //TODO why???
|
||||
{
|
||||
const CSpell::TargetInfo ti(this, caster->getSpellSchoolLevel(this), mode);
|
||||
|
||||
|
||||
if(!ti.massive)
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ESpellCastProblem::OK;
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
{
|
||||
{
|
||||
//todo: use new bonus API
|
||||
//1. Check absolute limiters
|
||||
for(auto b : absoluteLimiters)
|
||||
@ -470,16 +463,16 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
|
||||
if (obj->hasBonusOfType(b))
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
|
||||
|
||||
//check receptivity
|
||||
if (isPositive() && obj->hasBonusOfType(Bonus::RECEPTIVE)) //accept all positive spells
|
||||
return ESpellCastProblem::OK;
|
||||
return ESpellCastProblem::OK;
|
||||
|
||||
//3. Check negation
|
||||
//FIXME: Orb of vulnerability mechanics is not such trivial
|
||||
if(obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES)) //Orb of vulnerability
|
||||
return ESpellCastProblem::NOT_DECIDED;
|
||||
|
||||
|
||||
//4. Check negatable limit
|
||||
for(auto b : limiters)
|
||||
{
|
||||
@ -496,31 +489,31 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
|
||||
}
|
||||
|
||||
//6. Check elemental immunities
|
||||
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem tmp = ESpellCastProblem::NOT_DECIDED;
|
||||
|
||||
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
auto element = cnf.immunityBonus;
|
||||
|
||||
|
||||
if(obj->hasBonusOfType(element, 0)) //always resist if immune to all spells altogether
|
||||
{
|
||||
tmp = ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
else if(!isPositive()) //negative or indifferent
|
||||
{
|
||||
if((isDamageSpell() && obj->hasBonusOfType(element, 2)) || obj->hasBonusOfType(element, 1))
|
||||
{
|
||||
tmp = ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if(tmp != ESpellCastProblem::NOT_DECIDED)
|
||||
return tmp;
|
||||
|
||||
|
||||
TBonusListPtr levelImmunities = obj->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
|
||||
|
||||
if(obj->hasBonusOfType(Bonus::SPELL_IMMUNITY, id)
|
||||
@ -532,15 +525,14 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
|
||||
return ESpellCastProblem::NOT_DECIDED;
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneByStack(const CGHeroInstance* caster, const CStack* obj) const
|
||||
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
|
||||
{
|
||||
const auto immuneResult = mechanics->isImmuneByStack(caster,obj);
|
||||
|
||||
if (ESpellCastProblem::NOT_DECIDED != immuneResult)
|
||||
return immuneResult;
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
if (ESpellCastProblem::NOT_DECIDED != immuneResult)
|
||||
return immuneResult;
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
void CSpell::setIsOffensive(const bool val)
|
||||
{
|
||||
@ -568,7 +560,6 @@ void CSpell::setup()
|
||||
setupMechanics();
|
||||
}
|
||||
|
||||
|
||||
void CSpell::setupMechanics()
|
||||
{
|
||||
if(nullptr != mechanics)
|
||||
@ -576,26 +567,26 @@ void CSpell::setupMechanics()
|
||||
logGlobal->errorStream() << "Spell " << this->name << " mechanics already set";
|
||||
delete mechanics;
|
||||
}
|
||||
|
||||
mechanics = ISpellMechanics::createMechanics(this);
|
||||
|
||||
mechanics = ISpellMechanics::createMechanics(this);
|
||||
}
|
||||
|
||||
///CSpell::AnimationInfo
|
||||
CSpell::AnimationInfo::AnimationInfo()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
CSpell::AnimationInfo::~AnimationInfo()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::string CSpell::AnimationInfo::selectProjectile(const double angle) const
|
||||
{
|
||||
std::string res;
|
||||
{
|
||||
std::string res;
|
||||
double maximum = 0.0;
|
||||
|
||||
|
||||
for(const auto & info : projectile)
|
||||
{
|
||||
if(info.minimumAngle < angle && info.minimumAngle > maximum)
|
||||
@ -604,10 +595,9 @@ std::string CSpell::AnimationInfo::selectProjectile(const double angle) const
|
||||
res = info.resourceName;
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
///CSpell::TargetInfo
|
||||
CSpell::TargetInfo::TargetInfo(const CSpell * spell, const int level)
|
||||
@ -626,7 +616,7 @@ CSpell::TargetInfo::TargetInfo(const CSpell * spell, const int level, ECastingMo
|
||||
else if(mode == ECastingMode::SPELL_LIKE_ATTACK)
|
||||
{
|
||||
alwaysHitDirectly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSpell::TargetInfo::init(const CSpell * spell, const int level)
|
||||
@ -642,8 +632,7 @@ void CSpell::TargetInfo::init(const CSpell * spell, const int level)
|
||||
clearTarget = levelInfo.clearTarget;
|
||||
}
|
||||
|
||||
|
||||
bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos)
|
||||
bool DLL_LINKAGE isInScreenRange(const int3 & center, const int3 & pos)
|
||||
{
|
||||
int3 diff = pos - center;
|
||||
if(diff.x >= -9 && diff.x <= 9 && diff.y >= -8 && diff.y <= 8)
|
||||
@ -665,7 +654,7 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
|
||||
|
||||
CLegacyConfigParser parser("DATA/SPTRAITS.TXT");
|
||||
|
||||
auto readSchool = [&](JsonMap& schools, const std::string& name)
|
||||
auto readSchool = [&](JsonMap & schools, const std::string & name)
|
||||
{
|
||||
if (parser.readString() == "x")
|
||||
{
|
||||
@ -710,14 +699,14 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
|
||||
|
||||
auto& chances = lineNode["gainChance"].Struct();
|
||||
|
||||
for(size_t i = 0; i < GameConstants::F_NUMBER ; i++){
|
||||
for(size_t i = 0; i < GameConstants::F_NUMBER; i++){
|
||||
chances[ETownType::names[i]].Float() = parser.readNumber();
|
||||
}
|
||||
|
||||
auto AIVals = parser.readNumArray<si32>(GameConstants::SPELL_SCHOOL_LEVELS);
|
||||
|
||||
std::vector<std::string> descriptions;
|
||||
for(size_t i = 0; i < GameConstants::SPELL_SCHOOL_LEVELS ; i++)
|
||||
for(size_t i = 0; i < GameConstants::SPELL_SCHOOL_LEVELS; i++)
|
||||
descriptions.push_back(parser.readString());
|
||||
|
||||
parser.readString(); //ignore attributes. All data present in JSON
|
||||
@ -733,8 +722,6 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
|
||||
}
|
||||
|
||||
legacyData.push_back(lineNode);
|
||||
|
||||
|
||||
}
|
||||
while (parser.endLine() && !parser.isNextEntryEmpty());
|
||||
};
|
||||
@ -768,7 +755,7 @@ const std::string CSpellHandler::getTypeName() const
|
||||
return "spell";
|
||||
}
|
||||
|
||||
CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
CSpell * CSpellHandler::loadFromJson(const JsonNode & json)
|
||||
{
|
||||
using namespace SpellConfig;
|
||||
|
||||
@ -792,7 +779,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
logGlobal->traceStream() << __FUNCTION__ << ": loading spell " << spell->name;
|
||||
|
||||
const auto schoolNames = json["school"];
|
||||
|
||||
|
||||
for(const SpellSchoolInfo & info : SpellConfig::SCHOOL)
|
||||
{
|
||||
spell->school[info.id] = schoolNames[info.jsonName].Bool();
|
||||
@ -823,7 +810,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
spell->targetType = CSpell::OBSTACLE;
|
||||
else if(targetType == "LOCATION")
|
||||
spell->targetType = CSpell::LOCATION;
|
||||
else
|
||||
else
|
||||
logGlobal->warnStream() << "Spell " << spell->name << ". Target type " << (targetType.empty() ? "empty" : "unknown ("+targetType+")") << ". Assumed NO_TARGET.";
|
||||
|
||||
for(const auto & counteredSpell: json["counters"].Struct())
|
||||
@ -874,7 +861,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
|
||||
spell->isSpecial = flags["special"].Bool();
|
||||
|
||||
auto findBonus = [&](std::string name, std::vector<Bonus::BonusType> &vec)
|
||||
auto findBonus = [&](std::string name, std::vector<Bonus::BonusType> & vec)
|
||||
{
|
||||
auto it = bonusNameMap.find(name);
|
||||
if(it == bonusNameMap.end())
|
||||
@ -887,7 +874,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
}
|
||||
};
|
||||
|
||||
auto readBonusStruct = [&](std::string name, std::vector<Bonus::BonusType> &vec)
|
||||
auto readBonusStruct = [&](std::string name, std::vector<Bonus::BonusType> & vec)
|
||||
{
|
||||
for(auto bonusData: json[name].Struct())
|
||||
{
|
||||
@ -901,7 +888,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
|
||||
readBonusStruct("immunity", spell->immunities);
|
||||
readBonusStruct("absoluteImmunity", spell->absoluteImmunities);
|
||||
readBonusStruct("limit", spell->limiters);
|
||||
readBonusStruct("limit", spell->limiters);
|
||||
readBonusStruct("absoluteLimit", spell->absoluteLimiters);
|
||||
|
||||
|
||||
@ -914,41 +901,41 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
spell->iconScroll = graphicsNode["iconScroll"].String();
|
||||
|
||||
const JsonNode & animationNode = json["animation"];
|
||||
|
||||
auto loadAnimationQueue = [&](const std::string & jsonName, CSpell::TAnimationQueue & q)
|
||||
|
||||
auto loadAnimationQueue = [&](const std::string & jsonName, CSpell::TAnimationQueue & q)
|
||||
{
|
||||
auto queueNode = animationNode[jsonName].Vector();
|
||||
auto queueNode = animationNode[jsonName].Vector();
|
||||
for(const JsonNode & item : queueNode)
|
||||
{
|
||||
{
|
||||
CSpell::TAnimation newItem;
|
||||
newItem.verticalPosition = VerticalPosition::TOP;
|
||||
|
||||
|
||||
if(item.getType() == JsonNode::DATA_STRING)
|
||||
newItem.resourceName = item.String();
|
||||
else if(item.getType() == JsonNode::DATA_STRUCT)
|
||||
{
|
||||
newItem.resourceName = item["defName"].String();
|
||||
|
||||
|
||||
auto vPosStr = item["verticalPosition"].String();
|
||||
if("bottom" == vPosStr)
|
||||
newItem.verticalPosition = VerticalPosition::BOTTOM;
|
||||
}
|
||||
q.push_back(newItem);
|
||||
}
|
||||
q.push_back(newItem);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
loadAnimationQueue("affect", spell->animationInfo.affect);
|
||||
loadAnimationQueue("cast", spell->animationInfo.cast);
|
||||
loadAnimationQueue("hit", spell->animationInfo.hit);
|
||||
|
||||
loadAnimationQueue("hit", spell->animationInfo.hit);
|
||||
|
||||
const JsonVector & projectile = animationNode["projectile"].Vector();
|
||||
|
||||
|
||||
for(const JsonNode & item : projectile)
|
||||
{
|
||||
CSpell::ProjectileInfo info;
|
||||
info.resourceName = item["defName"].String();
|
||||
info.minimumAngle = item["minimumAngle"].Float();
|
||||
|
||||
|
||||
spell->animationInfo.projectile.push_back(info);
|
||||
}
|
||||
|
||||
@ -963,19 +950,19 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
for(int levelIndex = 0; levelIndex < levelsCount; levelIndex++)
|
||||
{
|
||||
const JsonNode & levelNode = json["levels"][LEVEL_NAMES[levelIndex]];
|
||||
|
||||
|
||||
CSpell::LevelInfo & levelObject = spell->levels[levelIndex];
|
||||
|
||||
const si32 levelPower = levelObject.power = levelNode["power"].Float();
|
||||
const si32 levelPower = levelObject.power = levelNode["power"].Float();
|
||||
|
||||
levelObject.description = levelNode["description"].String();
|
||||
levelObject.cost = levelNode["cost"].Float();
|
||||
levelObject.AIValue = levelNode["aiValue"].Float();
|
||||
levelObject.smartTarget = levelNode["targetModifier"]["smart"].Bool();
|
||||
levelObject.clearTarget = levelNode["targetModifier"]["clearTarget"].Bool();
|
||||
levelObject.clearAffected = levelNode["targetModifier"]["clearAffected"].Bool();
|
||||
levelObject.clearAffected = levelNode["targetModifier"]["clearAffected"].Bool();
|
||||
levelObject.range = levelNode["range"].String();
|
||||
|
||||
|
||||
for(const auto & elem : levelNode["effects"].Struct())
|
||||
{
|
||||
const JsonNode & bonusNode = elem.second;
|
||||
@ -992,7 +979,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
|
||||
levelObject.effects.push_back(*b);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return spell;
|
||||
@ -1013,19 +1000,18 @@ void CSpellHandler::afterLoadFinalization()
|
||||
void CSpellHandler::beforeValidate(JsonNode & object)
|
||||
{
|
||||
//handle "base" level info
|
||||
|
||||
JsonNode& levels = object["levels"];
|
||||
JsonNode& base = levels["base"];
|
||||
|
||||
|
||||
JsonNode & levels = object["levels"];
|
||||
JsonNode & base = levels["base"];
|
||||
|
||||
auto inheritNode = [&](const std::string & name){
|
||||
JsonUtils::inherit(levels[name],base);
|
||||
};
|
||||
|
||||
|
||||
inheritNode("none");
|
||||
inheritNode("basic");
|
||||
inheritNode("advanced");
|
||||
inheritNode("expert");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,13 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "../IHandlerBase.h"
|
||||
#include "../ConstTransitivePtr.h"
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "../BattleHex.h"
|
||||
#include "../HeroBonus.h"
|
||||
|
||||
|
||||
/*
|
||||
* CSpellHandler.h, part of VCMI engine
|
||||
*
|
||||
@ -18,22 +8,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class CGObjectInstance;
|
||||
#pragma once
|
||||
|
||||
#include "../IHandlerBase.h"
|
||||
#include "../ConstTransitivePtr.h"
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "../BattleHex.h"
|
||||
#include "../HeroBonus.h"
|
||||
|
||||
class CGObjectInstance;
|
||||
class CSpell;
|
||||
class ISpellMechanics;
|
||||
|
||||
class CLegacyConfigParser;
|
||||
|
||||
class CGHeroInstance;
|
||||
class CStack;
|
||||
|
||||
class CBattleInfoCallback;
|
||||
class BattleInfo;
|
||||
|
||||
struct CPackForClient;
|
||||
struct BattleSpellCast;
|
||||
|
||||
class CGameInfoCallback;
|
||||
class CRandomGenerator;
|
||||
class CMap;
|
||||
@ -42,10 +35,10 @@ struct SpellSchoolInfo
|
||||
{
|
||||
ESpellSchool id; //backlink
|
||||
Bonus::BonusType damagePremyBonus;
|
||||
Bonus::BonusType immunityBonus;
|
||||
Bonus::BonusType immunityBonus;
|
||||
std::string jsonName;
|
||||
SecondarySkill::ESecondarySkill skill;
|
||||
Bonus::BonusType knoledgeBonus;
|
||||
Bonus::BonusType knoledgeBonus;
|
||||
};
|
||||
|
||||
///callback to be provided by server
|
||||
@ -54,13 +47,13 @@ class DLL_LINKAGE SpellCastEnvironment
|
||||
public:
|
||||
virtual ~SpellCastEnvironment(){};
|
||||
virtual void sendAndApply(CPackForClient * info) const = 0;
|
||||
|
||||
|
||||
virtual CRandomGenerator & getRandomGenerator() const = 0;
|
||||
virtual void complain(const std::string & problem) const = 0;
|
||||
|
||||
|
||||
virtual const CMap * getMap() const = 0;
|
||||
virtual const CGameInfoCallback * getCb() const = 0;
|
||||
|
||||
virtual const CGameInfoCallback * getCb() const = 0;
|
||||
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0; //TODO: remove
|
||||
};
|
||||
|
||||
@ -78,14 +71,14 @@ public:
|
||||
int usedSpellPower;
|
||||
ECastingMode::ECastingMode mode;
|
||||
const CStack * casterStack;
|
||||
const CStack * selectedStack;
|
||||
const BattleInfo * cb;
|
||||
const CStack * selectedStack;
|
||||
const BattleInfo * cb;
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE AdventureSpellCastParameters
|
||||
{
|
||||
const CGHeroInstance * caster;
|
||||
int3 pos;
|
||||
int3 pos;
|
||||
};
|
||||
|
||||
enum class VerticalPosition : ui8{TOP, CENTER, BOTTOM};
|
||||
@ -93,41 +86,40 @@ enum class VerticalPosition : ui8{TOP, CENTER, BOTTOM};
|
||||
class DLL_LINKAGE CSpell
|
||||
{
|
||||
public:
|
||||
|
||||
struct ProjectileInfo
|
||||
{
|
||||
///in radians. Only positive value. Negative angle is handled by vertical flip
|
||||
double minimumAngle;
|
||||
|
||||
double minimumAngle;
|
||||
|
||||
///resource name
|
||||
std::string resourceName;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & minimumAngle & resourceName;
|
||||
}
|
||||
h & minimumAngle & resourceName;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct AnimationItem
|
||||
{
|
||||
std::string resourceName;
|
||||
VerticalPosition verticalPosition;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & resourceName & verticalPosition;
|
||||
}
|
||||
h & resourceName & verticalPosition;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef AnimationItem TAnimation;
|
||||
typedef std::vector<TAnimation> TAnimationQueue;
|
||||
|
||||
typedef std::vector<TAnimation> TAnimationQueue;
|
||||
|
||||
struct DLL_LINKAGE AnimationInfo
|
||||
{
|
||||
AnimationInfo();
|
||||
~AnimationInfo();
|
||||
|
||||
///displayed on all affected targets.
|
||||
///displayed on all affected targets.
|
||||
TAnimationQueue affect;
|
||||
|
||||
///displayed on caster.
|
||||
@ -140,14 +132,13 @@ public:
|
||||
///use selectProjectile to access
|
||||
std::vector<ProjectileInfo> projectile;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & projectile & hit & cast;
|
||||
}
|
||||
|
||||
std::string selectProjectile(const double angle) const;
|
||||
} animationInfo;
|
||||
|
||||
public:
|
||||
struct LevelInfo
|
||||
{
|
||||
@ -192,13 +183,13 @@ public:
|
||||
bool onlyAlive;
|
||||
///no immunity on primary target (mostly spell-like attack)
|
||||
bool alwaysHitDirectly;
|
||||
|
||||
|
||||
bool clearTarget;
|
||||
bool clearAffected;
|
||||
|
||||
|
||||
TargetInfo(const CSpell * spell, const int level);
|
||||
TargetInfo(const CSpell * spell, const int level, ECastingMode::ECastingMode mode);
|
||||
|
||||
|
||||
private:
|
||||
void init(const CSpell * spell, const int level);
|
||||
};
|
||||
@ -210,7 +201,7 @@ public:
|
||||
si32 level;
|
||||
|
||||
std::map<ESpellSchool, bool> school; //todo: use this instead of separate boolean fields
|
||||
|
||||
|
||||
si32 power; //spell's power
|
||||
|
||||
std::map<TFaction, si32> probabilities; //% chance to gain for castles
|
||||
@ -223,16 +214,14 @@ public:
|
||||
|
||||
CSpell();
|
||||
~CSpell();
|
||||
|
||||
bool isCastableBy(const IBonusBearer * caster, bool hasSpellBook, const std::set<SpellID> & spellBook) const;
|
||||
|
||||
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret)
|
||||
bool isCastableBy(const IBonusBearer * caster, bool hasSpellBook, const std::set<SpellID> & spellBook) const;
|
||||
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret)
|
||||
ETargetType getTargetType() const; //deprecated
|
||||
|
||||
CSpell::TargetInfo getTargetInfo(const int level) const;
|
||||
|
||||
|
||||
bool isCombatSpell() const;
|
||||
bool isAdventureSpell() const;
|
||||
bool isCreatureAbility() const;
|
||||
@ -243,29 +232,29 @@ public:
|
||||
|
||||
bool isDamageSpell() const;
|
||||
bool isHealingSpell() const;
|
||||
bool isRisingSpell() const;
|
||||
bool isRisingSpell() const;
|
||||
bool isOffensiveSpell() const;
|
||||
|
||||
bool isSpecialSpell() const;
|
||||
|
||||
bool hasEffects() const;
|
||||
void getEffects(std::vector<Bonus> &lst, const int level) const;
|
||||
|
||||
|
||||
///checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into account general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneAt(const CBattleInfoCallback * cb, const CGHeroInstance * caster, ECastingMode::ECastingMode mode, BattleHex destination) const;
|
||||
|
||||
|
||||
//internal, for use only by Mechanics classes
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneBy(const IBonusBearer *obj) const;
|
||||
|
||||
|
||||
//checks for creature immunity / anything that prevent casting *at given target* - doesn't take into account general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const;
|
||||
|
||||
|
||||
//internal, for use only by Mechanics classes. applying secondary skills
|
||||
ui32 calculateBonus(ui32 baseDamage, const CGHeroInstance * caster, const CStack * affectedCreature) const;
|
||||
|
||||
|
||||
///calculate spell damage on stack taking caster`s secondary skills and affectedCreature`s bonuses into account
|
||||
ui32 calculateDamage(const CGHeroInstance * 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, PlayerColor casterColor, int spellLvl, BattleHex destination, const CGHeroInstance * caster = nullptr) const;
|
||||
|
||||
@ -282,7 +271,7 @@ public:
|
||||
* Calls cb for each school this spell belongs to
|
||||
*
|
||||
* Set stop to true to abort looping
|
||||
*/
|
||||
*/
|
||||
void forEachSchool(const std::function<void (const SpellSchoolInfo &, bool &)> & cb) const;
|
||||
|
||||
/**
|
||||
@ -303,8 +292,8 @@ public:
|
||||
h & defaultProbability;
|
||||
h & isSpecial;
|
||||
h & castSound & iconBook & iconEffect & iconScenarioBonus & iconScroll;
|
||||
h & levels;
|
||||
h & school;
|
||||
h & levels;
|
||||
h & school;
|
||||
h & animationInfo;
|
||||
|
||||
if(!h.saving)
|
||||
@ -315,21 +304,21 @@ public:
|
||||
public:
|
||||
///Server logic. Has write access to GameState via packets.
|
||||
///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;
|
||||
|
||||
public:
|
||||
|
||||
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
|
||||
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;
|
||||
|
||||
public:
|
||||
///Client-server logic. Has direct write access to GameState.
|
||||
///Shall be called (only) when applying packets on BOTH SIDES
|
||||
|
||||
|
||||
///implementation of BattleSpellCast applying
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const;
|
||||
|
||||
|
||||
private:
|
||||
void setIsOffensive(const bool val);
|
||||
void setIsRising(const bool val);
|
||||
|
||||
|
||||
//call this after load or deserialization. cant be done in constructor.
|
||||
void setup();
|
||||
void setupMechanics();
|
||||
@ -351,9 +340,7 @@ private:
|
||||
std::vector<Bonus::BonusType> absoluteLimiters; //all of them are required to be affected, can't be negated
|
||||
|
||||
///graphics related stuff
|
||||
|
||||
std::string iconImmune;
|
||||
|
||||
std::string iconBook;
|
||||
std::string iconEffect;
|
||||
std::string iconScenarioBonus;
|
||||
@ -363,7 +350,7 @@ private:
|
||||
std::string castSound;
|
||||
|
||||
std::vector<LevelInfo> levels;
|
||||
|
||||
|
||||
ISpellMechanics * mechanics;//(!) do not serialize
|
||||
};
|
||||
|
||||
@ -393,7 +380,7 @@ public:
|
||||
{
|
||||
h & objects ;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
CSpell * loadFromJson(const JsonNode & json) override;
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ void AcidBreathDamageMechanics::applyBattleEffects(const SpellCastEnvironment *
|
||||
{
|
||||
//calculating dmg to display
|
||||
ctx.sc.dmgToDisplay = parameters.usedSpellPower;
|
||||
|
||||
|
||||
for(auto & attackedCre : ctx.attackedCres) //no immunities
|
||||
{
|
||||
BattleStackAttacked bsa;
|
||||
@ -31,7 +31,7 @@ void AcidBreathDamageMechanics::applyBattleEffects(const SpellCastEnvironment *
|
||||
bsa.attackerID = -1;
|
||||
(attackedCre)->prepareAttacked(bsa, env->getRandomGenerator());
|
||||
ctx.si.stacks.push_back(bsa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///DeathStareMechanics
|
||||
@ -41,7 +41,7 @@ void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, B
|
||||
ctx.sc.dmgToDisplay = parameters.usedSpellPower;
|
||||
if(!ctx.attackedCres.empty())
|
||||
vstd::amin(ctx.sc.dmgToDisplay, (*ctx.attackedCres.begin())->count); //stack is already reduced after attack
|
||||
|
||||
|
||||
for(auto & attackedCre : ctx.attackedCres)
|
||||
{
|
||||
BattleStackAttacked bsa;
|
||||
@ -52,15 +52,14 @@ void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, B
|
||||
bsa.attackerID = -1;
|
||||
(attackedCre)->prepareAttacked(bsa, env->getRandomGenerator());
|
||||
ctx.si.stacks.push_back(bsa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///DispellHelpfulMechanics
|
||||
void DispellHelpfulMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
|
||||
{
|
||||
DefaultSpellMechanics::applyBattle(battle, packet);
|
||||
|
||||
|
||||
for(auto stackID : packet->affectedCres)
|
||||
{
|
||||
if(vstd::contains(packet->resisted, stackID))
|
||||
@ -71,7 +70,7 @@ void DispellHelpfulMechanics::applyBattle(BattleInfo * battle, const BattleSpell
|
||||
{
|
||||
return Selector::positiveSpellEffects(b);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
|
||||
@ -90,7 +89,7 @@ ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(co
|
||||
{
|
||||
return ESpellCastProblem::NO_SPELLS_TO_DISPEL;
|
||||
}
|
||||
|
||||
//use default algorithm only if there is no mechanics-related problem
|
||||
return DefaultSpellMechanics::isImmuneByStack(caster,obj);
|
||||
|
||||
//use default algorithm only if there is no mechanics-related problem
|
||||
return DefaultSpellMechanics::isImmuneByStack(caster,obj);
|
||||
}
|
||||
|
@ -7,17 +7,17 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultSpellMechanics.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultSpellMechanics.h"
|
||||
|
||||
class AcidBreathDamageMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
AcidBreathDamageMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
class DeathStareMechanics: public DefaultSpellMechanics
|
||||
@ -25,15 +25,15 @@ class DeathStareMechanics: public DefaultSpellMechanics
|
||||
public:
|
||||
DeathStareMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
class DispellHelpfulMechanics: public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
DispellHelpfulMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
|
||||
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
};
|
||||
|
@ -17,12 +17,11 @@
|
||||
#include "BattleSpellMechanics.h"
|
||||
#include "CreatureSpellMechanics.h"
|
||||
|
||||
|
||||
///ISpellMechanics
|
||||
ISpellMechanics::ISpellMechanics(CSpell * s):
|
||||
owner(s)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
@ -32,20 +31,20 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
case SpellID::ACID_BREATH_DAMAGE:
|
||||
return new AcidBreathDamageMechanics(s);
|
||||
case SpellID::CHAIN_LIGHTNING:
|
||||
return new ChainLightningMechanics(s);
|
||||
return new ChainLightningMechanics(s);
|
||||
case SpellID::CLONE:
|
||||
return new CloneMechanics(s);
|
||||
case SpellID::CURE:
|
||||
return new CureMechanics(s);
|
||||
case SpellID::DEATH_STARE:
|
||||
return new DeathStareMechanics(s);
|
||||
return new DeathStareMechanics(s);
|
||||
case SpellID::DISPEL:
|
||||
return new DispellMechanics(s);
|
||||
return new DispellMechanics(s);
|
||||
case SpellID::DISPEL_HELPFUL_SPELLS:
|
||||
return new DispellHelpfulMechanics(s);
|
||||
case SpellID::FIRE_WALL:
|
||||
case SpellID::FORCE_FIELD:
|
||||
return new WallMechanics(s);
|
||||
return new WallMechanics(s);
|
||||
case SpellID::HYPNOTIZE:
|
||||
return new HypnotizeMechanics(s);
|
||||
case SpellID::LAND_MINE:
|
||||
@ -61,11 +60,11 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
case SpellID::SUMMON_AIR_ELEMENTAL:
|
||||
return new SummonMechanics(s);
|
||||
case SpellID::TELEPORT:
|
||||
return new TeleportMechanics(s);
|
||||
return new TeleportMechanics(s);
|
||||
case SpellID::SUMMON_BOAT:
|
||||
return new SummonBoatMechanics(s);
|
||||
case SpellID::SCUTTLE_BOAT:
|
||||
return new ScuttleBoatMechanics(s);
|
||||
case SpellID::SCUTTLE_BOAT:
|
||||
return new ScuttleBoatMechanics(s);
|
||||
case SpellID::DIMENSION_DOOR:
|
||||
return new DimensionDoorMechanics(s);
|
||||
case SpellID::FLY:
|
||||
@ -77,12 +76,12 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
return new TownPortalMechanics(s);
|
||||
case SpellID::VIEW_EARTH:
|
||||
return new ViewEarthMechanics(s);
|
||||
case SpellID::VIEW_AIR:
|
||||
case SpellID::VIEW_AIR:
|
||||
return new ViewAirMechanics(s);
|
||||
default:
|
||||
default:
|
||||
if(s->isRisingSpell())
|
||||
return new SpecialRisingSpellMechanics(s);
|
||||
else
|
||||
return new DefaultSpellMechanics(s);
|
||||
}
|
||||
else
|
||||
return new DefaultSpellMechanics(s);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CSpellHandler.h"
|
||||
@ -16,39 +16,35 @@
|
||||
class DLL_LINKAGE ISpellMechanics
|
||||
{
|
||||
public:
|
||||
|
||||
struct DLL_LINKAGE SpellTargetingContext
|
||||
{
|
||||
const CBattleInfoCallback * cb;
|
||||
const CBattleInfoCallback * cb;
|
||||
CSpell::TargetInfo ti;
|
||||
ECastingMode::ECastingMode mode;
|
||||
BattleHex destination;
|
||||
PlayerColor casterColor;
|
||||
int schoolLvl;
|
||||
|
||||
|
||||
SpellTargetingContext(const CSpell * s, const CBattleInfoCallback * c, ECastingMode::ECastingMode m, PlayerColor cc, int lvl, BattleHex dest)
|
||||
: cb(c), ti(s,lvl, m), mode(m), destination(dest), casterColor(cc), schoolLvl(lvl)
|
||||
{};
|
||||
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
ISpellMechanics(CSpell * s);
|
||||
virtual ~ISpellMechanics(){};
|
||||
|
||||
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr) const = 0;
|
||||
virtual std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const = 0;
|
||||
|
||||
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const = 0;
|
||||
|
||||
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
|
||||
virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;
|
||||
|
||||
static ISpellMechanics * createMechanics(CSpell * s);
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
|
||||
|
||||
protected:
|
||||
CSpell * owner;
|
||||
};
|
||||
virtual ~ISpellMechanics(){};
|
||||
|
||||
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
|
||||
virtual std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const = 0;
|
||||
|
||||
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const = 0;
|
||||
|
||||
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
|
||||
virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;
|
||||
|
||||
static ISpellMechanics * createMechanics(CSpell * s);
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
|
||||
protected:
|
||||
CSpell * owner;
|
||||
};
|
||||
|
@ -17,11 +17,11 @@
|
||||
ObjectPosInfo::ObjectPosInfo():
|
||||
pos(),id(Obj::NO_OBJ), subId(-1), owner(PlayerColor::CANNOT_DETERMINE)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
ObjectPosInfo::ObjectPosInfo(const CGObjectInstance * obj):
|
||||
pos(obj->pos),id(obj->ID), subId(obj->subID), owner(obj->tempOwner)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
@ -7,26 +7,26 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../int3.h"
|
||||
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
|
||||
|
||||
class CGObjectInstance;
|
||||
|
||||
|
||||
struct DLL_LINKAGE ObjectPosInfo
|
||||
{
|
||||
int3 pos;
|
||||
int3 pos;
|
||||
Obj id;
|
||||
si32 subId;
|
||||
PlayerColor owner;
|
||||
ObjectPosInfo();
|
||||
ObjectPosInfo(const CGObjectInstance * obj);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & pos & id & subId & owner;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user