mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	OO design for obstacle spells.
This commit is contained in:
		| @@ -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>(); | ||||
|   | ||||
| @@ -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 | ||||
| { | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user