浏览代码

OO design for obstacle spells.

AlexVinS 9 年之前
父节点
当前提交
82ac035340

+ 0 - 1
lib/CObstacleInstance.cpp

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

+ 104 - 102
lib/spells/BattleSpellMechanics.cpp

@@ -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;
-
-		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);
-		}
+	const int obstacleIdToGive = parameters.cb->obstacles.size()+1;
 
-		obstacle->pos = pos;
-		obstacle->casterSide = parameters.casterSide;
-		obstacle->ID = owner->id;
-		obstacle->spellLevel = parameters.effectLevel;
-		obstacle->casterSpellPower = parameters.effectPower;
-		obstacle->uniqueID = obstacleIdToGive++;
+	auto obstacle = std::make_shared<SpellCreatedObstacle>();
+	setupObstacle(obstacle.get());
 
-		BattleObstaclePlaced bop;
-		bop.obstacle = obstacle;
-		env->sendAndApply(&bop);
-	};
+	obstacle->pos = pos;
+	obstacle->casterSide = parameters.casterSide;
+	obstacle->ID = owner->id;
+	obstacle->spellLevel = parameters.effectLevel;
+	obstacle->casterSpellPower = parameters.effectPower;
+	obstacle->uniqueID = obstacleIdToGive;
 
-	const BattleHex destination = parameters.getFirstDestinationHex();
+	BattleObstaclePlaced bop;
+	bop.obstacle = obstacle;
+	env->sendAndApply(&bop);
+}
 
-	switch(owner->id)
+///PatchObstacleMechanics
+void PatchObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
+{
+	std::vector<BattleHex> availableTiles;
+	for(int i = 0; i < GameConstants::BFIELD_SIZE; i += 1)
 	{
-	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);
+		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());
+	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));
-		}
+	//land mines or quicksand patches are handled as spell created obstacles
+	for (int i = 0; i < patchesToPut; i++)
+		placeObstacle(env, parameters, 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);
-	}
+///LandMineMechanics
+bool LandMineMechanics::requiresCreatureTarget() const
+{
+	return true;
 }
 
-bool ObstacleMechanics::requiresCreatureTarget() const
+void LandMineMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
 {
-	switch(owner->id)
-	{
-	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;
-	}
+	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
 {

+ 48 - 1
lib/spells/BattleSpellMechanics.h

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

+ 0 - 1
lib/spells/CDefaultSpellMechanics.cpp

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

+ 4 - 2
lib/spells/ISpellMechanics.cpp

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