1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Cleaned up BattleHero class

This commit is contained in:
Ivan Savenko
2022-12-12 23:31:18 +02:00
parent c172e3c8e0
commit e7206cb759
9 changed files with 100 additions and 77 deletions

View File

@ -93,7 +93,6 @@ BattleStackAnimation::BattleStackAnimation(BattleInterface & owner, const CStack
void AttackAnimation::nextFrame() void AttackAnimation::nextFrame()
{ {
assert(myAnim->getType() == group);
if(myAnim->getType() != group) if(myAnim->getType() != group)
{ {
myAnim->setType(group); myAnim->setType(group);

View File

@ -328,6 +328,12 @@ public:
void nextFrame() override; void nextFrame() override;
}; };
class HeroAnimation : public BattleAnimation
{
public:
HeroAnimation(BattleInterface * owner_, const CStack * shooter);
};
/// Class that waits till projectile of certain shooter hits a target /// Class that waits till projectile of certain shooter hits a target
class WaitingProjectileAnimation : public BattleAnimation class WaitingProjectileAnimation : public BattleAnimation
{ {

View File

@ -43,9 +43,7 @@ namespace EBattleEffect
}; };
} }
namespace EHeroAnimType enum class EHeroAnimType
{
enum Type
{ {
HOLDING = 0, HOLDING = 0,
IDLE = 1, // idling movement that happens from time to time IDLE = 1, // idling movement that happens from time to time
@ -53,7 +51,6 @@ enum Type
VICTORY = 3, // when enemy stack killed or huge damage is dealt VICTORY = 3, // when enemy stack killed or huge damage is dealt
CAST_SPELL = 4 // spellcasting CAST_SPELL = 4 // spellcasting
}; };
}
namespace ECreatureAnimType namespace ECreatureAnimType
{ {

View File

@ -39,7 +39,7 @@ BattleControlPanel::BattleControlPanel(BattleInterface & owner, const Point & po
bOptions = std::make_shared<CButton> (Point( 3, 5), "icm003.def", CGI->generaltexth->zelp[381], std::bind(&BattleControlPanel::bOptionsf,this), SDLK_o); bOptions = std::make_shared<CButton> (Point( 3, 5), "icm003.def", CGI->generaltexth->zelp[381], std::bind(&BattleControlPanel::bOptionsf,this), SDLK_o);
bSurrender = std::make_shared<CButton> (Point( 54, 5), "icm001.def", CGI->generaltexth->zelp[379], std::bind(&BattleControlPanel::bSurrenderf,this), SDLK_s); bSurrender = std::make_shared<CButton> (Point( 54, 5), "icm001.def", CGI->generaltexth->zelp[379], std::bind(&BattleControlPanel::bSurrenderf,this), SDLK_s);
bFlee = std::make_shared<CButton> (Point(105, 5), "icm002.def", CGI->generaltexth->zelp[380], std::bind(&BattleControlPanel::bFleef,this), SDLK_r); bFlee = std::make_shared<CButton> (Point(105, 5), "icm002.def", CGI->generaltexth->zelp[380], std::bind(&BattleControlPanel::bFleef,this), SDLK_r);
bAutofight = std::make_shared<CButton> (Point(157, 5), "icm004.def", CGI->generaltexth->zelp[382], std::bind(&BattleControlPanel::bAutofightf,this), SDLK_a); bAutofight = std::make_shared<CButton> (Point(158, 5), "icm004.def", CGI->generaltexth->zelp[382], std::bind(&BattleControlPanel::bAutofightf,this), SDLK_a);
bSpell = std::make_shared<CButton> (Point(645, 5), "icm005.def", CGI->generaltexth->zelp[385], std::bind(&BattleControlPanel::bSpellf,this), SDLK_c); bSpell = std::make_shared<CButton> (Point(645, 5), "icm005.def", CGI->generaltexth->zelp[385], std::bind(&BattleControlPanel::bSpellf,this), SDLK_c);
bWait = std::make_shared<CButton> (Point(696, 5), "icm006.def", CGI->generaltexth->zelp[386], std::bind(&BattleControlPanel::bWaitf,this), SDLK_w); bWait = std::make_shared<CButton> (Point(696, 5), "icm006.def", CGI->generaltexth->zelp[386], std::bind(&BattleControlPanel::bWaitf,this), SDLK_w);
bDefence = std::make_shared<CButton> (Point(747, 5), "icm007.def", CGI->generaltexth->zelp[387], std::bind(&BattleControlPanel::bDefencef,this), SDLK_d); bDefence = std::make_shared<CButton> (Point(747, 5), "icm007.def", CGI->generaltexth->zelp[387], std::bind(&BattleControlPanel::bDefencef,this), SDLK_d);

View File

@ -107,7 +107,6 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
queue->moveTo(Point(pos.x, pos.y - queue->pos.h)); queue->moveTo(Point(pos.x, pos.y - queue->pos.h));
} }
CPlayerInterface::battleInt = this; CPlayerInterface::battleInt = this;
//initializing armies //initializing armies
@ -142,10 +141,6 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
} }
attackingHero = std::make_shared<BattleHero>(battleImage, false, hero1->tempOwner, hero1->tempOwner == curInt->playerID ? hero1 : nullptr, *this); attackingHero = std::make_shared<BattleHero>(battleImage, false, hero1->tempOwner, hero1->tempOwner == curInt->playerID ? hero1 : nullptr, *this);
auto img = attackingHero->animation->getImage(0, 0, true);
if(img)
attackingHero->pos = genRect(img->height(), img->width(), pos.x - 43, pos.y - 19);
} }
@ -166,10 +161,6 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
} }
defendingHero = std::make_shared<BattleHero>(battleImage, true, hero2->tempOwner, hero2->tempOwner == curInt->playerID ? hero2 : nullptr, *this); defendingHero = std::make_shared<BattleHero>(battleImage, true, hero2->tempOwner, hero2->tempOwner == curInt->playerID ? hero2 : nullptr, *this);
auto img = defendingHero->animation->getImage(0, 0, true);
if(img)
defendingHero->pos = genRect(img->height(), img->width(), pos.x + 693, pos.y - 19);
} }
obstacleController.reset(new BattleObstacleController(*this)); obstacleController.reset(new BattleObstacleController(*this));
@ -588,7 +579,7 @@ void BattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
fieldController->redrawBackgroundWithHexes(); fieldController->redrawBackgroundWithHexes();
} }
void BattleInterface::setHeroAnimation(ui8 side, int phase) void BattleInterface::setHeroAnimation(ui8 side, EHeroAnimType phase)
{ {
if(side == BattleSide::ATTACKER) if(side == BattleSide::ATTACKER)
{ {
@ -714,9 +705,6 @@ void BattleInterface::endAction(const BattleAction* action)
{ {
const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber); const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber);
if(action->actionType == EActionType::HERO_SPELL)
setHeroAnimation(action->side, EHeroAnimType::HOLDING);
stacksController->endAction(action); stacksController->endAction(action);
queue->update(); queue->update();

View File

@ -138,7 +138,7 @@ private:
void showInterface(SDL_Surface * to); void showInterface(SDL_Surface * to);
void setHeroAnimation(ui8 side, int phase); void setHeroAnimation(ui8 side, EHeroAnimType phase);
void executeSpellCast(); //called when a hero casts a spell void executeSpellCast(); //called when a hero casts a spell

View File

@ -47,8 +47,8 @@
void BattleConsole::showAll(SDL_Surface * to) void BattleConsole::showAll(SDL_Surface * to)
{ {
Point consolePos(pos.x + 10, pos.y + 17); Point consolePos(pos.x + 10, pos.y + 19);
Point textPos (pos.x + pos.w/2, pos.y + 17); Point textPos (pos.x + pos.w/2, pos.y + 19);
if (!consoleText.empty()) if (!consoleText.empty())
{ {
@ -160,46 +160,60 @@ void BattleConsole::clear()
void BattleHero::render(Canvas & canvas) void BattleHero::render(Canvas & canvas)
{ {
auto flagFrame = flagAnimation->getImage(flagAnim, 0, true); size_t groupIndex = static_cast<size_t>(phase);
if(!flagFrame) auto flagFrame = flagAnimation->getImage(flagCurrentFrame, 0, true);
return; auto heroFrame = animation->getImage(currentFrame, groupIndex, true);
//animation of flag Point heroPosition = pos.center() - heroFrame->dimensions() / 2;
Point flagPosition = pos.topLeft(); Point flagPosition = pos.center() - flagFrame->dimensions() / 2;
if(flip) if(flip)
flagPosition += Point(61, 39); flagPosition += Point(-4, -41);
else else
flagPosition += Point(72, 39); flagPosition += Point(4, -41);
auto heroFrame = animation->getImage(currentFrame, phase, true);
canvas.draw(flagFrame, flagPosition); canvas.draw(flagFrame, flagPosition);
canvas.draw(heroFrame, pos.topLeft()); canvas.draw(heroFrame, heroPosition);
if(++animCount >= 4) //FIXME: un-hardcode speed
flagCurrentFrame += 0.25f;
currentFrame += 0.25f;
if(flagCurrentFrame >= flagAnimation->size(0))
flagCurrentFrame -= flagAnimation->size(0);
if(currentFrame >= animation->size(groupIndex))
{ {
animCount = 0; currentFrame -= animation->size(groupIndex);
if(++flagAnim >= flagAnimation->size(0)) if (phaseFinishedCallback)
flagAnim = 0; {
phaseFinishedCallback();
if(++currentFrame >= lastFrame) phaseFinishedCallback = std::function<void()>();
switchToNextPhase(); }
} }
} }
void BattleHero::setPhase(int newPhase) float BattleHero::getFrame() const
{
return currentFrame;
}
void BattleHero::onPhaseFinished(const std::function<void()> & callback)
{
phaseFinishedCallback = callback;
}
void BattleHero::setPhase(EHeroAnimType newPhase)
{ {
nextPhase = newPhase; nextPhase = newPhase;
switchToNextPhase(); //immediately switch to next phase and then restore idling phase switchToNextPhase(); //immediately switch to next phase and then restore idling phase
nextPhase = 0; nextPhase = EHeroAnimType::HOLDING;
} }
void BattleHero::hover(bool on) void BattleHero::hover(bool on)
{ {
//TODO: Make lines below work properly //TODO: BROKEN CODE
if (on) if (on)
CCS->curh->changeGraphic(ECursor::COMBAT, 5); CCS->curh->changeGraphic(ECursor::COMBAT, 5);
else else
@ -208,25 +222,25 @@ void BattleHero::hover(bool on)
void BattleHero::clickLeft(tribool down, bool previousState) void BattleHero::clickLeft(tribool down, bool previousState)
{ {
if(myOwner->actionsController->spellcastingModeActive()) //we are casting a spell if(owner.actionsController->spellcastingModeActive()) //we are casting a spell
return; return;
if(boost::logic::indeterminate(down)) if(boost::logic::indeterminate(down))
return; return;
if(!myHero || down || !myOwner->myTurn) if(!myHero || down || !owner.myTurn)
return; return;
if(myOwner->getCurrentPlayerInterface()->cb->battleCanCastSpell(myHero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions if(owner.getCurrentPlayerInterface()->cb->battleCanCastSpell(myHero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions
{ {
BattleHex hoveredHex = myOwner->fieldController->getHoveredHex(); BattleHex hoveredHex = owner.fieldController->getHoveredHex();
//do nothing when any hex is hovered - hero's animation overlaps battlefield //do nothing when any hex is hovered - hero's animation overlaps battlefield
if ( hoveredHex != BattleHex::INVALID ) if ( hoveredHex != BattleHex::INVALID )
return; return;
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0); CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
GH.pushIntT<CSpellWindow>(myHero, myOwner->getCurrentPlayerInterface()); GH.pushIntT<CSpellWindow>(myHero, owner.getCurrentPlayerInterface());
} }
} }
@ -236,44 +250,47 @@ void BattleHero::clickRight(tribool down, bool previousState)
return; return;
Point windowPosition; Point windowPosition;
windowPosition.x = (!flip) ? myOwner->pos.topLeft().x + 1 : myOwner->pos.topRight().x - 79; windowPosition.x = (!flip) ? owner.pos.topLeft().x + 1 : owner.pos.topRight().x - 79;
windowPosition.y = myOwner->pos.y + 135; windowPosition.y = owner.pos.y + 135;
InfoAboutHero targetHero; InfoAboutHero targetHero;
if(down && (myOwner->myTurn || settings["session"]["spectate"].Bool())) if(down && (owner.myTurn || settings["session"]["spectate"].Bool()))
{ {
auto h = flip ? myOwner->defendingHeroInstance : myOwner->attackingHeroInstance; auto h = flip ? owner.defendingHeroInstance : owner.attackingHeroInstance;
targetHero.initFromHero(h, InfoAboutHero::EInfoLevel::INBATTLE); targetHero.initFromHero(h, InfoAboutHero::EInfoLevel::INBATTLE);
GH.pushIntT<HeroInfoWindow>(targetHero, &windowPosition); GH.pushIntT<HeroInfoWindow>(targetHero, &windowPosition);
} }
} }
void BattleHero::switchToNextPhase() void BattleHero::switchToNextPhase()
{
if(phase != nextPhase)
{ {
phase = nextPhase; phase = nextPhase;
currentFrame = 0.f;
firstFrame = 0; if (phaseFinishedCallback)
{
lastFrame = static_cast<int>(animation->size(phase)); phaseFinishedCallback();
phaseFinishedCallback = std::function<void()>();
} }
currentFrame = firstFrame;
} }
BattleHero::BattleHero(const std::string & animationPath, bool flipG, PlayerColor player, const CGHeroInstance * hero, const BattleInterface & owner): BattleHero::BattleHero(const std::string & animationPath, bool flipG, PlayerColor player, const CGHeroInstance * hero, const BattleInterface & owner):
flip(flipG), flip(flipG),
myHero(hero), myHero(hero),
myOwner(&owner), owner(owner),
phase(1), phase(EHeroAnimType::HOLDING),
nextPhase(0), nextPhase(EHeroAnimType::HOLDING),
flagAnim(0), currentFrame(0.f),
animCount(0) flagCurrentFrame(0.f)
{ {
animation = std::make_shared<CAnimation>(animationPath); animation = std::make_shared<CAnimation>(animationPath);
animation->preload(); animation->preload();
if(flipG)
pos.w = 64;
pos.h = 136;
pos.x = owner.pos.x + (flipG ? (owner.pos.w - pos.w) : 0);
pos.y = owner.pos.y;
if(flip)
animation->verticalFlip(); animation->verticalFlip();
if(flip) if(flip)

View File

@ -9,6 +9,7 @@
*/ */
#pragma once #pragma once
#include "BattleConstants.h"
#include "../gui/CIntObject.h" #include "../gui/CIntObject.h"
#include "../../lib/battle/BattleHex.h" #include "../../lib/battle/BattleHex.h"
#include "../windows/CWindowObject.h" #include "../windows/CWindowObject.h"
@ -77,23 +78,30 @@ public:
/// Hero battle animation /// Hero battle animation
class BattleHero : public CIntObject class BattleHero : public CIntObject
{ {
void switchToNextPhase();
public:
bool flip; //false if it's attacking hero, true otherwise bool flip; //false if it's attacking hero, true otherwise
std::function<void()> phaseFinishedCallback;
std::shared_ptr<CAnimation> animation; std::shared_ptr<CAnimation> animation;
std::shared_ptr<CAnimation> flagAnimation; std::shared_ptr<CAnimation> flagAnimation;
const CGHeroInstance * myHero; //this animation's hero instance const CGHeroInstance * myHero; //this animation's hero instance
const BattleInterface * myOwner; //battle interface to which this animation is assigned const BattleInterface & owner; //battle interface to which this animation is assigned
int phase; //stage of animation
int nextPhase; //stage of animation to be set after current phase is fully displayed
int currentFrame, firstFrame, lastFrame; //frame of animation
size_t flagAnim; EHeroAnimType phase; //stage of animation
ui8 animCount; //for flag animation EHeroAnimType nextPhase; //stage of animation to be set after current phase is fully displayed
float currentFrame; //frame of animation
float flagCurrentFrame;
void switchToNextPhase();
public:
void render(Canvas & canvas); //prints next frame of animation to to void render(Canvas & canvas); //prints next frame of animation to to
void setPhase(int newPhase); //sets phase of hero animation void setPhase(EHeroAnimType newPhase); //sets phase of hero animation
float getFrame() const;
void onPhaseFinished(const std::function<void()> &);
void hover(bool on) override; void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override; //call-in void clickLeft(tribool down, bool previousState) override; //call-in
void clickRight(tribool down, bool previousState) override; //call-in void clickRight(tribool down, bool previousState) override; //call-in

View File

@ -160,6 +160,14 @@ struct Rect : public SDL_Rect
{ {
return Point(x+w,y+h); return Point(x+w,y+h);
} }
Point center() const
{
return Point(x+w/2,y+h/2);
}
Point dimensions() const
{
return Point(w,h);
}
Rect operator+(const Rect &p) const //moves this rect by p's rect position Rect operator+(const Rect &p) const //moves this rect by p's rect position
{ {
return Rect(x+p.x,y+p.y,w,h); return Rect(x+p.x,y+p.y,w,h);