瀏覽代碼

Fixes #1051, #1042 - highlight creatures that will be affected by spell

Ivan Savenko 2 年之前
父節點
當前提交
70eac47f08

+ 7 - 10
client/battle/BattleActionsController.cpp

@@ -230,13 +230,13 @@ void BattleActionsController::castThisSpell(SpellID spellID)
 	}
 }
 
-
-void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
-{
-	if (!owner.myTurn) //we are not permit to do anything
-		return;
-
-	// This function handles mouse move over hexes and l-clicking on them.
+
+void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
+{
+	if (!owner.myTurn) //we are not permit to do anything
+		return;
+
+	// This function handles mouse move over hexes and l-clicking on them.
 	// First we decide what happens if player clicks on this hex and set appropriately
 	// consoleMsg, cursorFrame/Type and prepare lambda realizeAction.
 	//
@@ -263,9 +263,6 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
 	if (shere)
 		ourStack = shere->owner == owner.curInt->playerID;
 
-	//stack may have changed, update selection border
-	owner.stacksController->setHoveredStack(shere);
-
 	localActions.clear();
 	illegalActions.clear();
 

+ 1 - 1
client/battle/BattleInterface.cpp

@@ -902,7 +902,7 @@ void BattleInterface::show(SDL_Surface *to)
 
 	fieldController->renderBattlefield(canvas);
 
-	stacksController->updateBattleAnimations();
+	stacksController->update();
 
 	SDL_SetClipRect(to, &buf); //restoring previous clip_rect
 

+ 82 - 30
client/battle/BattleStacksController.cpp

@@ -13,6 +13,7 @@
 #include "BattleSiegeController.h"
 #include "BattleInterfaceClasses.h"
 #include "BattleInterface.h"
+#include "BattleActionsController.h"
 #include "BattleAnimationClasses.h"
 #include "BattleFieldController.h"
 #include "BattleEffectsController.h"
@@ -27,6 +28,7 @@
 #include "../gui/CAnimation.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/Canvas.h"
+#include "../../lib/spells/ISpellMechanics.h"
 
 #include "../../CCallback.h"
 #include "../../lib/battle/BattleHex.h"
@@ -69,7 +71,6 @@ static void onAnimationFinished(const CStack *stack, std::weak_ptr<CreatureAnima
 BattleStacksController::BattleStacksController(BattleInterface & owner):
 	owner(owner),
 	activeStack(nullptr),
-	mouseHoveredStack(nullptr),
 	stackToActivate(nullptr),
 	selectedStack(nullptr),
 	stackCanCastSpell(false),
@@ -242,30 +243,6 @@ void BattleStacksController::setActiveStack(const CStack *stack)
 	owner.controlPanel->blockUI(activeStack == nullptr);
 }
 
-void BattleStacksController::setHoveredStack(const CStack *stack)
-{
-	if ( stack == mouseHoveredStack )
-		 return;
-
-	if (mouseHoveredStack)
-		stackAnimation[mouseHoveredStack->ID]->setBorderColor(AnimationControls::getNoBorder());
-
-	// stack must be alive and not active (which uses gold border instead)
-	if (stack && stack->alive() && stack != activeStack)
-	{
-		mouseHoveredStack = stack;
-
-		if (mouseHoveredStack && !mouseHoveredStack->isFrozen())
-		{
-			stackAnimation[mouseHoveredStack->ID]->setBorderColor(AnimationControls::getBlueBorder());
-			if (stackAnimation[mouseHoveredStack->ID]->framesInGroup(ECreatureAnimType::MOUSEON) > 0)
-				stackAnimation[mouseHoveredStack->ID]->playOnce(ECreatureAnimType::MOUSEON);
-		}
-	}
-	else
-		mouseHoveredStack = nullptr;
-}
-
 bool BattleStacksController::stackNeedsAmountBox(const CStack * stack) const
 {
 	BattleHex currentActionTarget;
@@ -279,9 +256,6 @@ bool BattleStacksController::stackNeedsAmountBox(const CStack * stack) const
 	if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON) && stack->getCount() == 1) //do not show box for singular war machines, stacked war machines with box shown are supported as extension feature
 		return false;
 
-	if (!owner.battleActionsStarted) // do not perform any further checks since they are related to actions that will only occur after intro music
-		return true;
-
 	if(!stack->alive())
 		return false;
 
@@ -377,6 +351,12 @@ void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)
 	stackAnimation[stack->ID]->incrementFrame(float(GH.mainFPSmng->getElapsedMilliseconds()) / 1000);
 }
 
+void BattleStacksController::update()
+{
+	updateHoveredStacks();
+	updateBattleAnimations();
+}
+
 void BattleStacksController::updateBattleAnimations()
 {
 	for (auto & elem : currentAnimations)
@@ -390,7 +370,6 @@ void BattleStacksController::updateBattleAnimations()
 			elem->tryInitialize();
 	}
 
-
 	bool hadAnimations = !currentAnimations.empty();
 	vstd::erase(currentAnimations, nullptr);
 
@@ -674,7 +653,6 @@ void BattleStacksController::endAction(const BattleAction* action)
 
 void BattleStacksController::startAction(const BattleAction* action)
 {
-	setHoveredStack(nullptr);
 	removeExpiredColorFilters();
 }
 
@@ -819,3 +797,77 @@ void BattleStacksController::removeExpiredColorFilters()
 		return true;
 	});
 }
+
+void BattleStacksController::updateHoveredStacks()
+{
+	auto newStacks = selectHoveredStacks();
+
+	for (auto const * stack : mouseHoveredStacks)
+	{
+		if (vstd::contains(newStacks, stack))
+			continue;
+
+		if (stack == activeStack)
+			stackAnimation[stack->ID]->setBorderColor(AnimationControls::getGoldBorder());
+		else
+			stackAnimation[stack->ID]->setBorderColor(AnimationControls::getNoBorder());
+	}
+
+	for (auto const * stack : newStacks)
+	{
+		if (vstd::contains(mouseHoveredStacks, stack))
+			continue;
+
+		stackAnimation[stack->ID]->setBorderColor(AnimationControls::getBlueBorder());
+		if (stackAnimation[stack->ID]->framesInGroup(ECreatureAnimType::MOUSEON) > 0)
+			stackAnimation[stack->ID]->playOnce(ECreatureAnimType::MOUSEON);
+
+	}
+
+	mouseHoveredStacks = newStacks;
+}
+
+std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
+{
+	auto hoveredHex = owner.fieldController->getHoveredHex();
+
+	if (!hoveredHex.isValid())
+		return {};
+
+	const spells::Caster *caster = nullptr;
+	const CSpell *spell = nullptr;
+
+	spells::Mode mode = spells::Mode::HERO;
+
+	if(owner.actionsController->spellcastingModeActive())//hero casts spell
+	{
+		spell = owner.actionsController->selectedSpell().toSpell();
+		caster = owner.getActiveHero();
+	}
+	else if(owner.stacksController->activeStackSpellToCast() != SpellID::NONE)//stack casts spell
+	{
+		spell = SpellID(owner.stacksController->activeStackSpellToCast()).toSpell();
+		caster = owner.stacksController->getActiveStack();
+		mode = spells::Mode::CREATURE_ACTIVE;
+	}
+
+	if(caster && spell) //when casting spell
+	{
+		spells::Target target;
+		target.emplace_back(hoveredHex);
+
+		spells::BattleCast event(owner.curInt->cb.get(), caster, mode, spell);
+		auto mechanics = spell->battleMechanics(&event);
+		return mechanics->getAffectedStacks(target);
+	}
+
+	if(hoveredHex.isValid())
+	{
+		const CStack * const stack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true);
+
+		if (stack)
+			return {stack};
+	}
+
+	return {};
+}

+ 10 - 4
client/battle/BattleStacksController.h

@@ -70,8 +70,8 @@ class BattleStacksController
 	/// currently active stack; nullptr - no one
 	const CStack *activeStack;
 
-	/// stack below mouse pointer, used for border animation
-	const CStack *mouseHoveredStack;
+	/// stacks below mouse pointer (multiple stacks possible while spellcasting), used for border animation
+	std::vector<const CStack *> mouseHoveredStacks;
 
 	///when animation is playing, we should wait till the end to make the next stack active; nullptr of none
 	const CStack *stackToActivate;
@@ -94,6 +94,12 @@ class BattleStacksController
 
 	void executeAttackAnimations();
 	void removeExpiredColorFilters();
+
+	void updateBattleAnimations();
+	void updateHoveredStacks();
+
+	std::vector<const CStack *> selectHoveredStacks();
+
 public:
 	BattleStacksController(BattleInterface & owner);
 
@@ -117,7 +123,6 @@ public:
 	void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
 
 	void setActiveStack(const CStack *stack);
-	void setHoveredStack(const CStack *stack);
 	void setSelectedStack(const CStack *stack);
 
 	void showAliveStack(Canvas & canvas, const CStack * stack);
@@ -130,11 +135,12 @@ public:
 	/// If effect from same (target, source) already exists, it will be updated
 	void setStackColorFilter(const ColorFilter & effect, const CStack * target, const CSpell *source, bool persistent);
 	void addNewAnim(BattleAnimation *anim); //adds new anim to pendingAnims
-	void updateBattleAnimations();
 
 	const CStack* getActiveStack() const;
 	const CStack* getSelectedStack() const;
 
+	void update();
+
 	/// returns position of animation needed to place stack in specific hex
 	Point getStackPositionAtHex(BattleHex hexNum, const CStack * creature) const;