Browse Source

implement spells

Laserlicht 1 year ago
parent
commit
7a541c7a42

+ 0 - 4
client/battle/BattleActionsController.cpp

@@ -864,8 +864,6 @@ void BattleActionsController::onHoverEnded()
 
 
 void BattleActionsController::onHexLeftClicked(BattleHex clickedHex)
 void BattleActionsController::onHexLeftClicked(BattleHex clickedHex)
 {
 {
-	owner.stacksController->updateHoveredStacks(true);
-
 	if (owner.stacksController->getActiveStack() == nullptr)
 	if (owner.stacksController->getActiveStack() == nullptr)
 		return;
 		return;
 
 
@@ -996,8 +994,6 @@ void BattleActionsController::activateStack()
 
 
 void BattleActionsController::onHexRightClicked(BattleHex clickedHex)
 void BattleActionsController::onHexRightClicked(BattleHex clickedHex)
 {
 {
-	owner.stacksController->updateHoveredStacks(true);
-
 	auto spellcastActionPredicate = [](PossiblePlayerBattleAction & action)
 	auto spellcastActionPredicate = [](PossiblePlayerBattleAction & action)
 	{
 	{
 		return action.spellcast();
 		return action.spellcast();

+ 37 - 4
client/battle/BattleInterfaceClasses.cpp

@@ -478,12 +478,12 @@ void StackInfoBasicPanel::initializeData(const CStack * stack)
 	auto attack = std::to_string(CGI->creatures()->getByIndex(stack->creatureIndex())->getAttack(stack->isShooter())) + "(" + std::to_string(stack->getAttack(stack->isShooter())) + ")";
 	auto attack = std::to_string(CGI->creatures()->getByIndex(stack->creatureIndex())->getAttack(stack->isShooter())) + "(" + std::to_string(stack->getAttack(stack->isShooter())) + ")";
 	auto defense = std::to_string(CGI->creatures()->getByIndex(stack->creatureIndex())->getDefense(stack->isShooter())) + "(" + std::to_string(stack->getDefense(stack->isShooter())) + ")";
 	auto defense = std::to_string(CGI->creatures()->getByIndex(stack->creatureIndex())->getDefense(stack->isShooter())) + "(" + std::to_string(stack->getDefense(stack->isShooter())) + ")";
 	auto damage = std::to_string(CGI->creatures()->getByIndex(stack->creatureIndex())->getMinDamage(stack->isShooter())) + "-" + std::to_string(stack->getMaxDamage(stack->isShooter()));
 	auto damage = std::to_string(CGI->creatures()->getByIndex(stack->creatureIndex())->getMinDamage(stack->isShooter())) + "-" + std::to_string(stack->getMaxDamage(stack->isShooter()));
-	auto health = std::to_string(CGI->creatures()->getByIndex(stack->creatureIndex())->getMaxHealth());
+	auto health = CGI->creatures()->getByIndex(stack->creatureIndex())->getMaxHealth();
 	auto morale = stack->moraleVal();
 	auto morale = stack->moraleVal();
 	auto luck = stack->luckVal();
 	auto luck = stack->luckVal();
 
 
 	auto killed = stack->getKilled();
 	auto killed = stack->getKilled();
-	auto healthRemaining = TextOperations::formatMetric(stack->getAvailableHealth(), 4);
+	auto healthRemaining = TextOperations::formatMetric(stack->getAvailableHealth() - (stack->getCount() - 1) * health, 4);
 
 
 	//primary stats*/
 	//primary stats*/
 	labels.push_back(std::make_shared<CLabel>(9, 75, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[380] + ":"));
 	labels.push_back(std::make_shared<CLabel>(9, 75, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[380] + ":"));
@@ -494,7 +494,7 @@ void StackInfoBasicPanel::initializeData(const CStack * stack)
 	labels.push_back(std::make_shared<CLabel>(69, 87, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, attack));
 	labels.push_back(std::make_shared<CLabel>(69, 87, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, attack));
 	labels.push_back(std::make_shared<CLabel>(69, 99, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, defense));
 	labels.push_back(std::make_shared<CLabel>(69, 99, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, defense));
 	labels.push_back(std::make_shared<CLabel>(69, 111, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, damage));
 	labels.push_back(std::make_shared<CLabel>(69, 111, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, damage));
-	labels.push_back(std::make_shared<CLabel>(69, 123, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, health));
+	labels.push_back(std::make_shared<CLabel>(69, 123, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(health)));
 
 
 	//morale+luck
 	//morale+luck
 	labels.push_back(std::make_shared<CLabel>(9, 131, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[384] + ":"));
 	labels.push_back(std::make_shared<CLabel>(9, 131, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[384] + ":"));
@@ -505,16 +505,49 @@ void StackInfoBasicPanel::initializeData(const CStack * stack)
 
 
 	//extra information
 	//extra information
 	labels.push_back(std::make_shared<CLabel>(9, 168, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, std::string("Killed") + ":"));
 	labels.push_back(std::make_shared<CLabel>(9, 168, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, std::string("Killed") + ":"));
-	labels.push_back(std::make_shared<CLabel>(9, 180, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, std::string("Rem He") + ":"));
+	labels.push_back(std::make_shared<CLabel>(9, 180, EFonts::FONT_TINY, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[389] + ":"));
 
 
 	labels.push_back(std::make_shared<CLabel>(69, 180, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(killed)));
 	labels.push_back(std::make_shared<CLabel>(69, 180, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(killed)));
 	labels.push_back(std::make_shared<CLabel>(69, 192, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, healthRemaining));
 	labels.push_back(std::make_shared<CLabel>(69, 192, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, healthRemaining));
+
+	//spells
+	static const Point firstPos(15, 206); // position of 1st spell box
+	static const Point offset(0, 38);  // offset of each spell box from previous
+
+	for(int i = 0; i < 3; i++)
+		icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), 78, 0, firstPos.x + offset.x * i, firstPos.y + offset.y * i));
+
+	int printed=0; //how many effect pics have been printed
+	std::vector<SpellID> spells = stack->activeSpells();
+	for(SpellID effect : spells)
+	{
+		//not all effects have graphics (for eg. Acid Breath)
+		//for modded spells iconEffect is added to SpellInt.def
+		const bool hasGraphics = (effect < SpellID::THUNDERBOLT) || (effect >= SpellID::AFTER_LAST);
+
+		if (hasGraphics)
+		{
+			//FIXME: support permanent duration
+			int duration = stack->getBonusLocalFirst(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
+
+			icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
+			labels.push_back(std::make_shared<CLabel>(firstPos.x + offset.x * printed + 46, firstPos.y + offset.y * printed + 36, EFonts::FONT_TINY, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(duration)));
+			if(++printed >= 3 || (printed == 2 && spells.size() > 3)) // interface limit reached
+				break;
+		}
+	}
+
+	if(spells.size() == 0)
+		labelsMultiline.push_back(std::make_shared<CMultiLineLabel>(Rect(firstPos.x, firstPos.y, 48, 36), EFonts::FONT_TINY, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[674]));
+	if(spells.size() > 3)
+		labelsMultiline.push_back(std::make_shared<CMultiLineLabel>(Rect(firstPos.x + offset.x * 2, firstPos.y + offset.y * 2 - 5, 48, 36), EFonts::FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, "..."));
 }
 }
 
 
 void StackInfoBasicPanel::update(const CStack * updatedInfo)
 void StackInfoBasicPanel::update(const CStack * updatedInfo)
 {
 {
 	icons.clear();
 	icons.clear();
 	labels.clear();
 	labels.clear();
+	labelsMultiline.clear();
 
 
 	initializeData(updatedInfo);
 	initializeData(updatedInfo);
 }
 }

+ 2 - 0
client/battle/BattleInterfaceClasses.h

@@ -37,6 +37,7 @@ class CFilledTexture;
 class CButton;
 class CButton;
 class CToggleButton;
 class CToggleButton;
 class CLabel;
 class CLabel;
+class CMultiLineLabel;
 class CTextBox;
 class CTextBox;
 class CAnimImage;
 class CAnimImage;
 class CPlayerInterface;
 class CPlayerInterface;
@@ -150,6 +151,7 @@ private:
 	std::shared_ptr<CPicture> background;
 	std::shared_ptr<CPicture> background;
 	std::shared_ptr<CPicture> background2;
 	std::shared_ptr<CPicture> background2;
 	std::vector<std::shared_ptr<CLabel>> labels;
 	std::vector<std::shared_ptr<CLabel>> labels;
+	std::vector<std::shared_ptr<CMultiLineLabel>> labelsMultiline;
 	std::vector<std::shared_ptr<CAnimImage>> icons;
 	std::vector<std::shared_ptr<CAnimImage>> icons;
 public:
 public:
 	StackInfoBasicPanel(const CStack * stack, Point * position, bool initializeBackground = true);
 	StackInfoBasicPanel(const CStack * stack, Point * position, bool initializeBackground = true);

+ 7 - 4
client/battle/BattleStacksController.cpp

@@ -26,6 +26,7 @@
 #include "../CMusicHandler.h"
 #include "../CMusicHandler.h"
 #include "../CGameInfo.h"
 #include "../CGameInfo.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/CGuiHandler.h"
+#include "../gui/WindowHandler.h"
 #include "../render/Colors.h"
 #include "../render/Colors.h"
 #include "../render/Canvas.h"
 #include "../render/Canvas.h"
 #include "../render/IRenderHandler.h"
 #include "../render/IRenderHandler.h"
@@ -346,7 +347,7 @@ void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)
 
 
 void BattleStacksController::tick(uint32_t msPassed)
 void BattleStacksController::tick(uint32_t msPassed)
 {
 {
-	updateHoveredStacks(false);
+	updateHoveredStacks();
 	updateBattleAnimations(msPassed);
 	updateBattleAnimations(msPassed);
 }
 }
 
 
@@ -806,11 +807,11 @@ void BattleStacksController::removeExpiredColorFilters()
 	});
 	});
 }
 }
 
 
-void BattleStacksController::updateHoveredStacks(bool clear)
+void BattleStacksController::updateHoveredStacks()
 {
 {
 	auto newStacks = selectHoveredStacks();
 	auto newStacks = selectHoveredStacks();
 
 
-	if(clear)
+	if(newStacks.size() == 0)
 		owner.windowObject->updateStackInfoWindow(nullptr);
 		owner.windowObject->updateStackInfoWindow(nullptr);
 
 
 	for(const auto * stack : mouseHoveredStacks)
 	for(const auto * stack : mouseHoveredStacks)
@@ -818,7 +819,6 @@ void BattleStacksController::updateHoveredStacks(bool clear)
 		if (vstd::contains(newStacks, stack))
 		if (vstd::contains(newStacks, stack))
 			continue;
 			continue;
 
 
-		owner.windowObject->updateStackInfoWindow(nullptr);
 		if (stack == activeStack)
 		if (stack == activeStack)
 			stackAnimation[stack->unitId()]->setBorderColor(AnimationControls::getGoldBorder());
 			stackAnimation[stack->unitId()]->setBorderColor(AnimationControls::getGoldBorder());
 		else
 		else
@@ -836,6 +836,9 @@ void BattleStacksController::updateHoveredStacks(bool clear)
 			stackAnimation[stack->unitId()]->playOnce(ECreatureAnimType::MOUSEON);
 			stackAnimation[stack->unitId()]->playOnce(ECreatureAnimType::MOUSEON);
 	}
 	}
 
 
+	if(mouseHoveredStacks != newStacks)
+		GH.windows().totalRedraw(); //fix for frozen stack info window and blue border in action bar
+
 	mouseHoveredStacks = newStacks;
 	mouseHoveredStacks = newStacks;
 }
 }
 
 

+ 2 - 2
client/battle/BattleStacksController.h

@@ -125,8 +125,8 @@ public:
 
 
 	void showAliveStack(Canvas & canvas, const CStack * stack);
 	void showAliveStack(Canvas & canvas, const CStack * stack);
 	void showStack(Canvas & canvas, const CStack * stack);
 	void showStack(Canvas & canvas, const CStack * stack);
-	
-	void updateHoveredStacks(bool clear);
+
+	void updateHoveredStacks();
 
 
 	void collectRenderableObjects(BattleRenderer & renderer);
 	void collectRenderableObjects(BattleRenderer & renderer);