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

formatting

This commit is contained in:
AlexVinS 2015-02-26 20:59:18 +03:00
parent f4c683cd5e
commit 5fda2aac9a
14 changed files with 427 additions and 475 deletions

View File

@ -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

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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

View File

@ -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;
};

View File

@ -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 &center, 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");
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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)
{
}

View File

@ -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;
}
}
};