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

OO design for obstacle spells.

This commit is contained in:
AlexVinS 2016-09-05 13:34:48 +03:00
parent f3b7fe947c
commit 82ac035340
5 changed files with 159 additions and 110 deletions

View File

@ -131,7 +131,6 @@ std::vector<BattleHex> SpellCreatedObstacle::getAffectedTiles() const
return std::vector<BattleHex>(1, pos); return std::vector<BattleHex>(1, pos);
case FORCE_FIELD: case FORCE_FIELD:
return SpellID(SpellID::FORCE_FIELD).toSpell()->rangeInHexes(pos, spellLevel, casterSide); return SpellID(SpellID::FORCE_FIELD).toSpell()->rangeInHexes(pos, spellLevel, casterSide);
//TODO Fire Wall
default: default:
assert(0); assert(0);
return std::vector<BattleHex>(); return std::vector<BattleHex>();

View File

@ -410,120 +410,69 @@ ESpellCastProblem::ESpellCastProblem ObstacleMechanics::canBeCast(const CBattleI
return ESpellCastProblem::OK; return ESpellCastProblem::OK;
} }
void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void ObstacleMechanics::placeObstacle(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, const BattleHex & pos) const
{ {
auto placeObstacle = [&, this](const BattleHex & pos) const int obstacleIdToGive = parameters.cb->obstacles.size()+1;
{
static int obstacleIdToGive = parameters.cb->obstacles.size()
? (parameters.cb->obstacles.back()->uniqueID+1)
: 0;
auto obstacle = std::make_shared<SpellCreatedObstacle>(); auto obstacle = std::make_shared<SpellCreatedObstacle>();
switch(owner->id) // :/ setupObstacle(obstacle.get());
{
case SpellID::QUICKSAND:
obstacle->obstacleType = CObstacleInstance::QUICKSAND;
obstacle->turnsRemaining = -1;
obstacle->visibleForAnotherSide = false;
break;
case SpellID::LAND_MINE:
obstacle->obstacleType = CObstacleInstance::LAND_MINE;
obstacle->turnsRemaining = -1;
obstacle->visibleForAnotherSide = false;
break;
case SpellID::FIRE_WALL:
obstacle->obstacleType = CObstacleInstance::FIRE_WALL;
obstacle->turnsRemaining = 2;
obstacle->visibleForAnotherSide = true;
break;
case SpellID::FORCE_FIELD:
obstacle->obstacleType = CObstacleInstance::FORCE_FIELD;
obstacle->turnsRemaining = 2;
obstacle->visibleForAnotherSide = true;
break;
default:
//this function cannot be used with spells that do not create obstacles
assert(0);
}
obstacle->pos = pos; obstacle->pos = pos;
obstacle->casterSide = parameters.casterSide; obstacle->casterSide = parameters.casterSide;
obstacle->ID = owner->id; obstacle->ID = owner->id;
obstacle->spellLevel = parameters.effectLevel; obstacle->spellLevel = parameters.effectLevel;
obstacle->casterSpellPower = parameters.effectPower; obstacle->casterSpellPower = parameters.effectPower;
obstacle->uniqueID = obstacleIdToGive++; obstacle->uniqueID = obstacleIdToGive;
BattleObstaclePlaced bop; BattleObstaclePlaced bop;
bop.obstacle = obstacle; bop.obstacle = obstacle;
env->sendAndApply(&bop); env->sendAndApply(&bop);
};
const BattleHex destination = parameters.getFirstDestinationHex();
switch(owner->id)
{
case SpellID::QUICKSAND:
case SpellID::LAND_MINE:
{
std::vector<BattleHex> availableTiles;
for(int i = 0; i < GameConstants::BFIELD_SIZE; i += 1)
{
BattleHex hex = i;
if(hex.getX() > 0 && hex.getX() < 16 && !(parameters.cb->battleGetStackByPos(hex, false)) && !(parameters.cb->battleGetObstacleOnPos(hex, false)))
availableTiles.push_back(hex);
}
boost::range::random_shuffle(availableTiles);
const int patchesForSkill[] = {4, 4, 6, 8};
const int patchesToPut = std::min<int>(patchesForSkill[parameters.spellLvl], availableTiles.size());
//land mines or quicksand patches are handled as spell created obstacles
for (int i = 0; i < patchesToPut; i++)
placeObstacle(availableTiles.at(i));
}
break;
case SpellID::FORCE_FIELD:
if(!destination.isValid())
{
env->complain("Invalid destination for FORCE_FIELD");
return;
}
placeObstacle(destination);
break;
case SpellID::FIRE_WALL:
{
if(!destination.isValid())
{
env->complain("Invalid destination for FIRE_WALL");
return;
}
//fire wall is build from multiple obstacles - one fire piece for each affected hex
auto affectedHexes = owner->rangeInHexes(destination, parameters.spellLvl, parameters.casterSide);
for(BattleHex hex : affectedHexes)
placeObstacle(hex);
}
break;
default:
assert(0);
}
} }
bool ObstacleMechanics::requiresCreatureTarget() const ///PatchObstacleMechanics
void PatchObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
switch(owner->id) std::vector<BattleHex> availableTiles;
for(int i = 0; i < GameConstants::BFIELD_SIZE; i += 1)
{ {
case SpellID::QUICKSAND: BattleHex hex = i;
return false; if(hex.getX() > 0 && hex.getX() < 16 && !(parameters.cb->battleGetStackByPos(hex, false)) && !(parameters.cb->battleGetObstacleOnPos(hex, false)))
case SpellID::LAND_MINE: availableTiles.push_back(hex);
return true;
case SpellID::FORCE_FIELD:
return false;
case SpellID::FIRE_WALL:
return true;
default:
return false;
} }
boost::range::random_shuffle(availableTiles);
const int patchesForSkill[] = {4, 4, 6, 8};
const int patchesToPut = std::min<int>(patchesForSkill[parameters.spellLvl], availableTiles.size());
//land mines or quicksand patches are handled as spell created obstacles
for (int i = 0; i < patchesToPut; i++)
placeObstacle(env, parameters, availableTiles.at(i));
}
///LandMineMechanics
bool LandMineMechanics::requiresCreatureTarget() const
{
return true;
}
void LandMineMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
{
obstacle->obstacleType = CObstacleInstance::LAND_MINE;
obstacle->turnsRemaining = -1;
obstacle->visibleForAnotherSide = false;
}
///QuicksandMechanics
bool QuicksandMechanics::requiresCreatureTarget() const
{
return false;
}
void QuicksandMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
{
obstacle->obstacleType = CObstacleInstance::QUICKSAND;
obstacle->turnsRemaining = -1;
obstacle->visibleForAnotherSide = false;
} }
///WallMechanics ///WallMechanics
@ -563,6 +512,59 @@ std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 sch
return ret; return ret;
} }
///FireWallMechanics
bool FireWallMechanics::requiresCreatureTarget() const
{
return true;
}
void FireWallMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
const BattleHex destination = parameters.getFirstDestinationHex();
if(!destination.isValid())
{
env->complain("Invalid destination for FIRE_WALL");
return;
}
//firewall is build from multiple obstacles - one fire piece for each affected hex
auto affectedHexes = owner->rangeInHexes(destination, parameters.spellLvl, parameters.casterSide);
for(BattleHex hex : affectedHexes)
placeObstacle(env, parameters, hex);
}
void FireWallMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
{
obstacle->obstacleType = CObstacleInstance::FIRE_WALL;
obstacle->turnsRemaining = 2;
obstacle->visibleForAnotherSide = true;
}
///ForceFieldMechanics
bool ForceFieldMechanics::requiresCreatureTarget() const
{
return false;
}
void ForceFieldMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
const BattleHex destination = parameters.getFirstDestinationHex();
if(!destination.isValid())
{
env->complain("Invalid destination for FORCE_FIELD");
return;
}
placeObstacle(env, parameters, destination);
}
void ForceFieldMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
{
obstacle->obstacleType = CObstacleInstance::FORCE_FIELD;
obstacle->turnsRemaining = 2;
obstacle->visibleForAnotherSide = true;
}
///RemoveObstacleMechanics ///RemoveObstacleMechanics
void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {

View File

@ -13,6 +13,7 @@
#include "CDefaultSpellMechanics.h" #include "CDefaultSpellMechanics.h"
class CObstacleInstance; class CObstacleInstance;
class SpellCreatedObstacle;
class DLL_LINKAGE HealingSpellMechanics : public DefaultSpellMechanics class DLL_LINKAGE HealingSpellMechanics : public DefaultSpellMechanics
{ {
@ -98,11 +99,37 @@ class DLL_LINKAGE ObstacleMechanics : public DefaultSpellMechanics
public: public:
ObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){}; ObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){};
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
bool requiresCreatureTarget() const override; protected:
void placeObstacle(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, const BattleHex & pos) const;
virtual void setupObstacle(SpellCreatedObstacle * obstacle) const = 0;
};
class PatchObstacleMechanics : public ObstacleMechanics
{
public:
PatchObstacleMechanics(CSpell * s): ObstacleMechanics(s){};
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
}; };
class DLL_LINKAGE LandMineMechanics : public PatchObstacleMechanics
{
public:
LandMineMechanics(CSpell * s): PatchObstacleMechanics(s){};
bool requiresCreatureTarget() const override;
protected:
void setupObstacle(SpellCreatedObstacle * obstacle) const override;
};
class DLL_LINKAGE QuicksandMechanics : public PatchObstacleMechanics
{
public:
QuicksandMechanics(CSpell * s): PatchObstacleMechanics(s){};
bool requiresCreatureTarget() const override;
protected:
void setupObstacle(SpellCreatedObstacle * obstacle) const override;
};
class DLL_LINKAGE WallMechanics : public ObstacleMechanics class DLL_LINKAGE WallMechanics : public ObstacleMechanics
{ {
public: public:
@ -110,6 +137,26 @@ public:
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr) const override; std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr) const override;
}; };
class DLL_LINKAGE FireWallMechanics : public WallMechanics
{
public:
FireWallMechanics(CSpell * s): WallMechanics(s){};
bool requiresCreatureTarget() const override;
protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void setupObstacle(SpellCreatedObstacle * obstacle) const override;
};
class DLL_LINKAGE ForceFieldMechanics : public WallMechanics
{
public:
ForceFieldMechanics(CSpell * s): WallMechanics(s){};
bool requiresCreatureTarget() const override;
protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void setupObstacle(SpellCreatedObstacle * obstacle) const override;
};
class DLL_LINKAGE RemoveObstacleMechanics : public DefaultSpellMechanics class DLL_LINKAGE RemoveObstacleMechanics : public DefaultSpellMechanics
{ {
public: public:

View File

@ -258,7 +258,6 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
env->sendAndApply(&si); env->sendAndApply(&si);
//reduce number of casts remaining //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); assert(parameters.casterStack);

View File

@ -106,13 +106,15 @@ std::unique_ptr<ISpellMechanics> ISpellMechanics::createMechanics(CSpell * s)
case SpellID::EARTHQUAKE: case SpellID::EARTHQUAKE:
return make_unique<EarthquakeMechanics>(s); return make_unique<EarthquakeMechanics>(s);
case SpellID::FIRE_WALL: case SpellID::FIRE_WALL:
return make_unique<FireWallMechanics>(s);
case SpellID::FORCE_FIELD: case SpellID::FORCE_FIELD:
return make_unique<WallMechanics>(s); return make_unique<ForceFieldMechanics>(s);
case SpellID::HYPNOTIZE: case SpellID::HYPNOTIZE:
return make_unique<HypnotizeMechanics>(s); return make_unique<HypnotizeMechanics>(s);
case SpellID::LAND_MINE: case SpellID::LAND_MINE:
return make_unique<LandMineMechanics>(s);
case SpellID::QUICKSAND: case SpellID::QUICKSAND:
return make_unique<ObstacleMechanics>(s); return make_unique<QuicksandMechanics>(s);
case SpellID::REMOVE_OBSTACLE: case SpellID::REMOVE_OBSTACLE:
return make_unique<RemoveObstacleMechanics>(s); return make_unique<RemoveObstacleMechanics>(s);
case SpellID::SACRIFICE: case SpellID::SACRIFICE: