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);
case FORCE_FIELD:
return SpellID(SpellID::FORCE_FIELD).toSpell()->rangeInHexes(pos, spellLevel, casterSide);
//TODO Fire Wall
default:
assert(0);
return std::vector<BattleHex>();

View File

@ -410,120 +410,69 @@ ESpellCastProblem::ESpellCastProblem ObstacleMechanics::canBeCast(const CBattleI
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)
{
static int obstacleIdToGive = parameters.cb->obstacles.size()
? (parameters.cb->obstacles.back()->uniqueID+1)
: 0;
const int obstacleIdToGive = parameters.cb->obstacles.size()+1;
auto obstacle = std::make_shared<SpellCreatedObstacle>();
switch(owner->id) // :/
{
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);
}
auto obstacle = std::make_shared<SpellCreatedObstacle>();
setupObstacle(obstacle.get());
obstacle->pos = pos;
obstacle->casterSide = parameters.casterSide;
obstacle->ID = owner->id;
obstacle->spellLevel = parameters.effectLevel;
obstacle->casterSpellPower = parameters.effectPower;
obstacle->uniqueID = obstacleIdToGive++;
obstacle->pos = pos;
obstacle->casterSide = parameters.casterSide;
obstacle->ID = owner->id;
obstacle->spellLevel = parameters.effectLevel;
obstacle->casterSpellPower = parameters.effectPower;
obstacle->uniqueID = obstacleIdToGive;
BattleObstaclePlaced bop;
bop.obstacle = obstacle;
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);
}
BattleObstaclePlaced bop;
bop.obstacle = obstacle;
env->sendAndApply(&bop);
}
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:
return false;
case SpellID::LAND_MINE:
return true;
case SpellID::FORCE_FIELD:
return false;
case SpellID::FIRE_WALL:
return true;
default:
return false;
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(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
@ -563,6 +512,59 @@ std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 sch
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
void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{

View File

@ -13,6 +13,7 @@
#include "CDefaultSpellMechanics.h"
class CObstacleInstance;
class SpellCreatedObstacle;
class DLL_LINKAGE HealingSpellMechanics : public DefaultSpellMechanics
{
@ -98,11 +99,37 @@ class DLL_LINKAGE ObstacleMechanics : public DefaultSpellMechanics
public:
ObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){};
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:
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
{
public:
@ -110,6 +137,26 @@ public:
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
{
public:

View File

@ -258,7 +258,6 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
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)
{
assert(parameters.casterStack);

View File

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