mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Allow multiple destinations in BattleSpellCastParameters
This commit is contained in:
		| @@ -367,7 +367,7 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const I | |||||||
| ///ObstacleMechanics | ///ObstacleMechanics | ||||||
| void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const | void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const | ||||||
| { | { | ||||||
| 	auto placeObstacle = [&, this](BattleHex pos) | 	auto placeObstacle = [&, this](const BattleHex & pos) | ||||||
| 	{ | 	{ | ||||||
| 		static int obstacleIdToGive =  parameters.cb->obstacles.size() | 		static int obstacleIdToGive =  parameters.cb->obstacles.size() | ||||||
| 									? (parameters.cb->obstacles.back()->uniqueID+1) | 									? (parameters.cb->obstacles.back()->uniqueID+1) | ||||||
| @@ -413,6 +413,8 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, con | |||||||
| 		env->sendAndApply(&bop); | 		env->sendAndApply(&bop); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	const BattleHex destination = parameters.getFirstDestinationHex(); | ||||||
|  |  | ||||||
| 	switch(owner->id) | 	switch(owner->id) | ||||||
| 	{ | 	{ | ||||||
| 	case SpellID::QUICKSAND: | 	case SpellID::QUICKSAND: | ||||||
| @@ -437,12 +439,22 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, con | |||||||
|  |  | ||||||
| 		break; | 		break; | ||||||
| 	case SpellID::FORCE_FIELD: | 	case SpellID::FORCE_FIELD: | ||||||
| 		placeObstacle(parameters.destination); | 		if(!destination.isValid()) | ||||||
|  | 		{ | ||||||
|  | 			env->complain("Invalid destination for FORCE_FIELD"); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		placeObstacle(destination); | ||||||
| 		break; | 		break; | ||||||
| 	case SpellID::FIRE_WALL: | 	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 | 			//fire wall is build from multiple obstacles - one fire piece for each affected hex | ||||||
| 			auto affectedHexes = owner->rangeInHexes(parameters.destination, parameters.spellLvl, parameters.casterSide); | 			auto affectedHexes = owner->rangeInHexes(destination, parameters.spellLvl, parameters.casterSide); | ||||||
| 			for(BattleHex hex : affectedHexes) | 			for(BattleHex hex : affectedHexes) | ||||||
| 				placeObstacle(hex); | 				placeObstacle(hex); | ||||||
| 		} | 		} | ||||||
| @@ -493,7 +505,7 @@ std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 sch | |||||||
| ///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 | ||||||
| { | { | ||||||
| 	if(auto obstacleToRemove = parameters.cb->battleGetObstacleOnPos(parameters.destination, false)) | 	if(auto obstacleToRemove = parameters.cb->battleGetObstacleOnPos(parameters.getFirstDestinationHex(), false)) | ||||||
| 	{ | 	{ | ||||||
| 		ObstaclesRemoved obr; | 		ObstaclesRemoved obr; | ||||||
| 		obr.obstacles.insert(obstacleToRemove->uniqueID); | 		obr.obstacles.insert(obstacleToRemove->uniqueID); | ||||||
| @@ -659,9 +671,9 @@ void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, con | |||||||
| 	 | 	 | ||||||
| 	BattleStackMoved bsm; | 	BattleStackMoved bsm; | ||||||
| 	bsm.distance = -1; | 	bsm.distance = -1; | ||||||
| 	bsm.stack = parameters.selectedStack->ID; | 	bsm.stack = parameters.selectedStack->ID;//todo: use destinations | ||||||
| 	std::vector<BattleHex> tiles; | 	std::vector<BattleHex> tiles; | ||||||
| 	tiles.push_back(parameters.destination); | 	tiles.push_back(parameters.getFirstDestinationHex()); | ||||||
| 	bsm.tilesToMove = tiles; | 	bsm.tilesToMove = tiles; | ||||||
| 	bsm.teleporting = true; | 	bsm.teleporting = true; | ||||||
| 	env->sendAndApply(&bsm); | 	env->sendAndApply(&bsm); | ||||||
|   | |||||||
| @@ -265,7 +265,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS | |||||||
| 	//must be vector, as in Chain Lightning order matters | 	//must be vector, as in Chain Lightning order matters | ||||||
| 	std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector | 	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); | 	auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.getFirstDestinationHex(), parameters.caster); | ||||||
| 	std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres)); | 	std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres)); | ||||||
|  |  | ||||||
| 	logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks"; | 	logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks"; | ||||||
| @@ -363,7 +363,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS | |||||||
|  |  | ||||||
| 			BattleSpellCastParameters mirrorParameters(parameters.cb, attackedCre, owner); | 			BattleSpellCastParameters mirrorParameters(parameters.cb, attackedCre, owner); | ||||||
| 			mirrorParameters.spellLvl = 0; | 			mirrorParameters.spellLvl = 0; | ||||||
| 			mirrorParameters.destination = targetHex; | 			mirrorParameters.aimToHex(targetHex); | ||||||
| 			mirrorParameters.mode = ECastingMode::MAGIC_MIRROR; | 			mirrorParameters.mode = ECastingMode::MAGIC_MIRROR; | ||||||
| 			mirrorParameters.selectedStack = nullptr; | 			mirrorParameters.selectedStack = nullptr; | ||||||
| 			mirrorParameters.spellLvl = parameters.spellLvl; | 			mirrorParameters.spellLvl = parameters.spellLvl; | ||||||
| @@ -766,7 +766,8 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat | |||||||
| 		env->complain("MagicMirror: invalid mode"); | 		env->complain("MagicMirror: invalid mode"); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	if(!parameters.destination.isValid()) | 	BattleHex destination = parameters.getFirstDestinationHex(); | ||||||
|  | 	if(!destination.isValid()) | ||||||
| 	{ | 	{ | ||||||
| 		env->complain("MagicMirror: invalid destination"); | 		env->complain("MagicMirror: invalid destination"); | ||||||
| 		return;		 | 		return;		 | ||||||
| @@ -779,7 +780,7 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat | |||||||
| 	//must be vector, as in Chain Lightning order matters | 	//must be vector, as in Chain Lightning order matters | ||||||
| 	std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector | 	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); | 	auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, destination, parameters.caster); | ||||||
| 	std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres)); | 	std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres)); | ||||||
|  |  | ||||||
| 	logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks"; | 	logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks"; | ||||||
| @@ -839,7 +840,7 @@ void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& p | |||||||
| 	sc.side = parameters.casterSide; | 	sc.side = parameters.casterSide; | ||||||
| 	sc.id = owner->id; | 	sc.id = owner->id; | ||||||
| 	sc.skill = parameters.spellLvl; | 	sc.skill = parameters.spellLvl; | ||||||
| 	sc.tile = parameters.destination; | 	sc.tile = parameters.getFirstDestinationHex(); | ||||||
| 	sc.dmgToDisplay = 0; | 	sc.dmgToDisplay = 0; | ||||||
| 	sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING; | 	sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING; | ||||||
| 	sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1); | 	sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1); | ||||||
|   | |||||||
| @@ -115,9 +115,13 @@ bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastP | |||||||
| } | } | ||||||
|  |  | ||||||
| void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const | void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const | ||||||
| { | {	 | ||||||
| 	assert(env); | 	assert(env); | ||||||
|  | 	if(parameters.destinations.size()<1) | ||||||
|  | 	{ | ||||||
|  | 		env->complain("Spell must have at least one destination"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 	mechanics->battleCast(env, parameters); | 	mechanics->battleCast(env, parameters); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,9 +20,23 @@ | |||||||
| #include "BattleSpellMechanics.h" | #include "BattleSpellMechanics.h" | ||||||
| #include "CreatureSpellMechanics.h" | #include "CreatureSpellMechanics.h" | ||||||
|  |  | ||||||
|  | BattleSpellCastParameters::Destination::Destination(const CStack * destination): | ||||||
|  | 	stackValue(destination), | ||||||
|  | 	hexValue(destination->position) | ||||||
|  | { | ||||||
|  | 	 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | BattleSpellCastParameters::Destination::Destination(const BattleHex & destination): | ||||||
|  | 	stackValue(nullptr), | ||||||
|  | 	hexValue(destination)	 | ||||||
|  | { | ||||||
|  | 	 | ||||||
|  | } | ||||||
|  |  | ||||||
| BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell) | BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell) | ||||||
| 	: cb(cb), caster(caster), casterColor(caster->getOwner()), casterSide(cb->whatSide(casterColor)), | 	: cb(cb), caster(caster), casterColor(caster->getOwner()), casterSide(cb->whatSide(casterColor)), | ||||||
| 	destination(BattleHex::INVALID),casterHero(nullptr), | 	casterHero(nullptr), | ||||||
| 	mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr), | 	mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr), | ||||||
| 	spellLvl(-1),  effectLevel(-1), effectPower(0), enchantPower(0), effectValue(0) | 	spellLvl(-1),  effectLevel(-1), effectPower(0), enchantPower(0), effectValue(0) | ||||||
| { | { | ||||||
| @@ -31,6 +45,22 @@ BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, cons | |||||||
| 	prepare(spell); | 	prepare(spell); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void BattleSpellCastParameters::aimToHex(const BattleHex& destination) | ||||||
|  | { | ||||||
|  | 	destinations.push_back(Destination(destination)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void BattleSpellCastParameters::aimToStack(const CStack * destination) | ||||||
|  | { | ||||||
|  | 	destinations.push_back(Destination(destination)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | BattleHex BattleSpellCastParameters::getFirstDestinationHex() const | ||||||
|  | { | ||||||
|  | 	return destinations.at(0).hexValue; | ||||||
|  | } | ||||||
|  |  | ||||||
| void BattleSpellCastParameters::prepare(const CSpell * spell) | void BattleSpellCastParameters::prepare(const CSpell * spell) | ||||||
| { | { | ||||||
| 	spellLvl = caster->getSpellSchoolLevel(spell); | 	spellLvl = caster->getSpellSchoolLevel(spell); | ||||||
|   | |||||||
| @@ -30,21 +30,37 @@ public: | |||||||
| 	virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0;	//TODO: remove | 	virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0;	//TODO: remove | ||||||
| }; | }; | ||||||
|  |  | ||||||
| ///helper struct | ///all parameters of particular cast event | ||||||
| struct DLL_LINKAGE BattleSpellCastParameters | struct DLL_LINKAGE BattleSpellCastParameters | ||||||
| { | { | ||||||
| public: | public: | ||||||
|  | 	///Single spell destination.  | ||||||
|  | 	/// (assumes that anything but battle stack can share same hex) | ||||||
|  | 	struct DLL_LINKAGE Destination | ||||||
|  | 	{ | ||||||
|  | 		explicit Destination(const CStack * destination);  | ||||||
|  | 		explicit Destination(const BattleHex & destination); | ||||||
|  | 		 | ||||||
|  | 		const CStack * stackValue; | ||||||
|  | 		const BattleHex hexValue; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell); | 	BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell); | ||||||
|  | 	void aimToHex(const BattleHex & destination); | ||||||
|  | 	void aimToStack(const CStack * destination); | ||||||
|  | 	BattleHex getFirstDestinationHex() const; | ||||||
|  | 	 | ||||||
| 	const BattleInfo * cb; | 	const BattleInfo * cb; | ||||||
| 	const ISpellCaster * caster; | 	const ISpellCaster * caster; | ||||||
| 	const PlayerColor casterColor;	 | 	const PlayerColor casterColor;	 | ||||||
| 	const ui8 casterSide; | 	const ui8 casterSide; | ||||||
|  |  | ||||||
| 	BattleHex destination; | 	std::vector<Destination> destinations; | ||||||
|  |  | ||||||
| 	const CGHeroInstance * casterHero; //deprecated | 	const CGHeroInstance * casterHero; //deprecated | ||||||
| 	ECastingMode::ECastingMode mode; | 	ECastingMode::ECastingMode mode; | ||||||
| 	const CStack * casterStack; //deprecated | 	const CStack * casterStack; //deprecated | ||||||
| 	const CStack * selectedStack; | 	const CStack * selectedStack;//deprecated | ||||||
|  |  | ||||||
| 	///spell school level | 	///spell school level | ||||||
| 	int spellLvl;	 | 	int spellLvl;	 | ||||||
|   | |||||||
| @@ -3878,7 +3878,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | |||||||
| 				vstd::amin (parameters.spellLvl, 3); | 				vstd::amin (parameters.spellLvl, 3); | ||||||
| 				parameters.effectLevel = parameters.spellLvl; | 				parameters.effectLevel = parameters.spellLvl; | ||||||
| 				parameters.mode = ECastingMode::CREATURE_ACTIVE_CASTING; | 				parameters.mode = ECastingMode::CREATURE_ACTIVE_CASTING; | ||||||
| 				parameters.destination = destination; | 				parameters.aimToHex(destination);//todo: allow multiple destinations | ||||||
| 				parameters.selectedStack = nullptr; | 				parameters.selectedStack = nullptr; | ||||||
| 				spell->battleCast(spellEnv, parameters); | 				spell->battleCast(spellEnv, parameters); | ||||||
| 			} | 			} | ||||||
| @@ -4069,7 +4069,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) | |||||||
| 			const CSpell * s = SpellID(ba.additionalInfo).toSpell(); | 			const CSpell * s = SpellID(ba.additionalInfo).toSpell(); | ||||||
| 			 | 			 | ||||||
| 			BattleSpellCastParameters parameters(gs->curB, h, s); | 			BattleSpellCastParameters parameters(gs->curB, h, s); | ||||||
| 			parameters.destination = ba.destinationTile; | 			parameters.aimToHex(ba.destinationTile);//todo: allow multiple destinations | ||||||
| 			parameters.mode = ECastingMode::HERO_CASTING; | 			parameters.mode = ECastingMode::HERO_CASTING; | ||||||
| 			parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false);			 | 			parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false);			 | ||||||
|  |  | ||||||
| @@ -4222,7 +4222,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st) | |||||||
| 					BattleSpellCastParameters parameters(gs->curB, st, spell); | 					BattleSpellCastParameters parameters(gs->curB, st, spell); | ||||||
| 					parameters.spellLvl = bonus->val; | 					parameters.spellLvl = bonus->val; | ||||||
| 					parameters.effectLevel = bonus->val;//todo: recheck | 					parameters.effectLevel = bonus->val;//todo: recheck | ||||||
| 					parameters.destination = BattleHex::INVALID; | 					parameters.aimToHex(BattleHex::INVALID); | ||||||
| 					parameters.mode = ECastingMode::ENCHANTER_CASTING; | 					parameters.mode = ECastingMode::ENCHANTER_CASTING; | ||||||
| 					parameters.selectedStack = nullptr; | 					parameters.selectedStack = nullptr; | ||||||
| 					 | 					 | ||||||
| @@ -4913,7 +4913,6 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta | |||||||
| 			} | 			} | ||||||
| 			int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID))); | 			int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID))); | ||||||
| 			vstd::amin (chance, 100); | 			vstd::amin (chance, 100); | ||||||
| 			int destination = oneOfAttacked->position; |  | ||||||
|  |  | ||||||
| 			const CSpell * spell = SpellID(spellID).toSpell(); | 			const CSpell * spell = SpellID(spellID).toSpell(); | ||||||
| 			if(gs->curB->battleCanCastThisSpellHere(attacker, spell, ECastingMode::AFTER_ATTACK_CASTING, oneOfAttacked->position) != ESpellCastProblem::OK) | 			if(gs->curB->battleCanCastThisSpellHere(attacker, spell, ECastingMode::AFTER_ATTACK_CASTING, oneOfAttacked->position) != ESpellCastProblem::OK) | ||||||
| @@ -4929,7 +4928,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta | |||||||
| 				BattleSpellCastParameters parameters(gs->curB, attacker, spell); | 				BattleSpellCastParameters parameters(gs->curB, attacker, spell); | ||||||
| 				parameters.spellLvl = spellLevel; | 				parameters.spellLvl = spellLevel; | ||||||
| 				parameters.effectLevel = spellLevel; | 				parameters.effectLevel = spellLevel; | ||||||
| 				parameters.destination = destination; | 				parameters.aimToStack(oneOfAttacked); | ||||||
| 				parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; | 				parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; | ||||||
| 				parameters.selectedStack = nullptr; | 				parameters.selectedStack = nullptr; | ||||||
|  |  | ||||||
| @@ -4958,7 +4957,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) | |||||||
| 		BattleSpellCastParameters parameters(gs->curB, attacker, spell); | 		BattleSpellCastParameters parameters(gs->curB, attacker, spell); | ||||||
| 		parameters.spellLvl = 0; | 		parameters.spellLvl = 0; | ||||||
| 		parameters.effectLevel = 0; | 		parameters.effectLevel = 0; | ||||||
| 		parameters.destination = gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)->position; | 		parameters.aimToStack(gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)); | ||||||
| 		parameters.effectPower = power;	 | 		parameters.effectPower = power;	 | ||||||
| 		parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; | 		parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; | ||||||
| 		parameters.selectedStack = nullptr; | 		parameters.selectedStack = nullptr; | ||||||
| @@ -5266,7 +5265,7 @@ void CGameHandler::runBattle() | |||||||
| 				BattleSpellCastParameters parameters(gs->curB, h, spell); | 				BattleSpellCastParameters parameters(gs->curB, h, spell); | ||||||
| 				parameters.spellLvl = 3; | 				parameters.spellLvl = 3; | ||||||
| 				parameters.effectLevel = 3; | 				parameters.effectLevel = 3; | ||||||
| 				parameters.destination = BattleHex::INVALID; | 				parameters.aimToHex(BattleHex::INVALID); | ||||||
| 				parameters.mode = ECastingMode::PASSIVE_CASTING; | 				parameters.mode = ECastingMode::PASSIVE_CASTING; | ||||||
| 				parameters.selectedStack = nullptr;					 | 				parameters.selectedStack = nullptr;					 | ||||||
| 				parameters.enchantPower = b->val; | 				parameters.enchantPower = b->val; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user