From 62c0a1d0ac98eb51418e4daa59e80b6cc97b522f Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Fri, 10 Aug 2012 19:23:13 +0200 Subject: [PATCH] added and implemented swap heroes state --- Debug/src/battle/states/subdir.mk | 9 +- Release/src/battle/states/subdir.mk | 9 +- src/battle/BattleState.cpp | 8 +- src/battle/BattleState.h | 2 + src/battle/HeroTag.cpp | 73 ++++++------ src/battle/HeroTag.h | 23 ++-- src/battle/Resources.h | 4 +- src/battle/states/SelectMoveAction.cpp | 3 +- src/battle/states/SwapHeroes.cpp | 148 +++++++++++++++++++++++++ src/battle/states/SwapHeroes.h | 60 ++++++++++ src/main.cpp | 3 + test-data/swap-cursor.png | Bin 0 -> 395 bytes 12 files changed, 284 insertions(+), 58 deletions(-) create mode 100644 src/battle/states/SwapHeroes.cpp create mode 100644 src/battle/states/SwapHeroes.h create mode 100644 test-data/swap-cursor.png diff --git a/Debug/src/battle/states/subdir.mk b/Debug/src/battle/states/subdir.mk index a4898a8..e937fef 100644 --- a/Debug/src/battle/states/subdir.mk +++ b/Debug/src/battle/states/subdir.mk @@ -9,7 +9,8 @@ CPP_SRCS += \ ../src/battle/states/SelectItem.cpp \ ../src/battle/states/SelectMoveAction.cpp \ ../src/battle/states/SelectSpell.cpp \ -../src/battle/states/SelectTarget.cpp +../src/battle/states/SelectTarget.cpp \ +../src/battle/states/SwapHeroes.cpp OBJS += \ ./src/battle/states/SelectAttackType.o \ @@ -17,7 +18,8 @@ OBJS += \ ./src/battle/states/SelectItem.o \ ./src/battle/states/SelectMoveAction.o \ ./src/battle/states/SelectSpell.o \ -./src/battle/states/SelectTarget.o +./src/battle/states/SelectTarget.o \ +./src/battle/states/SwapHeroes.o CPP_DEPS += \ ./src/battle/states/SelectAttackType.d \ @@ -25,7 +27,8 @@ CPP_DEPS += \ ./src/battle/states/SelectItem.d \ ./src/battle/states/SelectMoveAction.d \ ./src/battle/states/SelectSpell.d \ -./src/battle/states/SelectTarget.d +./src/battle/states/SelectTarget.d \ +./src/battle/states/SwapHeroes.d # Each subdirectory must supply rules for building sources it contributes diff --git a/Release/src/battle/states/subdir.mk b/Release/src/battle/states/subdir.mk index 23338be..245dd34 100644 --- a/Release/src/battle/states/subdir.mk +++ b/Release/src/battle/states/subdir.mk @@ -9,7 +9,8 @@ CPP_SRCS += \ ../src/battle/states/SelectItem.cpp \ ../src/battle/states/SelectMoveAction.cpp \ ../src/battle/states/SelectSpell.cpp \ -../src/battle/states/SelectTarget.cpp +../src/battle/states/SelectTarget.cpp \ +../src/battle/states/SwapHeroes.cpp OBJS += \ ./src/battle/states/SelectAttackType.o \ @@ -17,7 +18,8 @@ OBJS += \ ./src/battle/states/SelectItem.o \ ./src/battle/states/SelectMoveAction.o \ ./src/battle/states/SelectSpell.o \ -./src/battle/states/SelectTarget.o +./src/battle/states/SelectTarget.o \ +./src/battle/states/SwapHeroes.o CPP_DEPS += \ ./src/battle/states/SelectAttackType.d \ @@ -25,7 +27,8 @@ CPP_DEPS += \ ./src/battle/states/SelectItem.d \ ./src/battle/states/SelectMoveAction.d \ ./src/battle/states/SelectSpell.d \ -./src/battle/states/SelectTarget.d +./src/battle/states/SelectTarget.d \ +./src/battle/states/SwapHeroes.d # Each subdirectory must supply rules for building sources it contributes diff --git a/src/battle/BattleState.cpp b/src/battle/BattleState.cpp index 3f734f8..cbea81a 100644 --- a/src/battle/BattleState.cpp +++ b/src/battle/BattleState.cpp @@ -18,6 +18,7 @@ #include "../geometry/operators.h" #include "../graphics/Sprite.h" +#include #include using app::Application; @@ -47,6 +48,11 @@ void BattleState::AddHero(const Hero &h) { heroes.push_back(h); } +void BattleState::SwapHeroes(std::vector::size_type lhs, std::vector::size_type rhs) { + if (lhs < 0 || lhs >= heroes.size() || rhs < 0 || rhs >= heroes.size() || lhs == rhs) return; + std::swap(heroes[lhs], heroes[rhs]); +} + void BattleState::Resize(int w, int h) { @@ -61,7 +67,7 @@ void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) { LoadSpellMenu(i); ikariMenus.push_back(res->ikariMenuPrototype); LoadIkariMenu(i); - heroTags[i] = HeroTag(&heroes[i], attackChoices + i, res, HeroTag::Alignment((i + 1) % 2)); + heroTags[i] = HeroTag(this, i); } int tagHeight(attackTypeMenu.Height()); diff --git a/src/battle/BattleState.h b/src/battle/BattleState.h index 93e1e2b..57c037f 100644 --- a/src/battle/BattleState.h +++ b/src/battle/BattleState.h @@ -82,6 +82,7 @@ public: const Hero &ActiveHero() const { return heroes[activeHero]; } Hero &HeroAt(std::vector::size_type index) { return heroes[index]; } const Hero &HeroAt(std::vector::size_type index) const { return heroes[index]; } + void SwapHeroes(std::vector::size_type lhs, std::vector::size_type rhs); const HeroTag &ActiveHeroTag() const { return heroTags[activeHero]; } const HeroTag &HeroTagAt(std::vector::size_type index) const { return heroTags[index]; } const geometry::Point &HeroTagPositionAt(std::vector::size_type index) const { return heroTagPositions[index]; } @@ -89,6 +90,7 @@ public: void SetAttackType(AttackChoice::Type t) { attackChoices[activeHero].SetType(t); } AttackChoice &ActiveHeroAttackChoice() { return attackChoices[activeHero]; } const AttackChoice &ActiveHeroAttackChoice() const { return attackChoices[activeHero]; } + const AttackChoice &AttackChoiceAt(std::vector::size_type index) const { return attackChoices[index]; } TargetSelection &ActiveHeroTargets() { return attackChoices[activeHero].Selection(); } const TargetSelection &ActiveHeroTargets() const { return attackChoices[activeHero].Selection(); } bool AttackSelectionDone() const { return activeHero >= (int) heroes.size(); } diff --git a/src/battle/HeroTag.cpp b/src/battle/HeroTag.cpp index 3f9be08..6212f36 100644 --- a/src/battle/HeroTag.cpp +++ b/src/battle/HeroTag.cpp @@ -8,6 +8,7 @@ #include "HeroTag.h" #include "AttackChoice.h" +#include "BattleState.h" #include "Hero.h" #include "Resources.h" #include "../geometry/operators.h" @@ -23,74 +24,80 @@ using graphics::Frame; namespace battle { +const graphics::Sprite *HeroTag::HeroSprite() const { + return battle->HeroAt(index).Sprite(); +} + void HeroTag::Render(SDL_Surface *screen, int width, int height, Point position, bool active) const { // frame - const Frame *frame(active ? res->activeHeroTagFrame : res->heroTagFrame); + const Frame *frame(active ? battle->Res().activeHeroTagFrame : battle->Res().heroTagFrame); Vector frameOffset(frame->BorderWidth(), frame->BorderHeight()); - Vector alignOffset(align == LEFT ? 4 * res->heroTagFont->CharWidth() : 0, 0); + Vector alignOffset((index % 2) ? 4 * battle->Res().heroTagFont->CharWidth() : 0, 0); frame->Draw(screen, position, width, height); + const Hero &hero(battle->HeroAt(index)); + // gauges // NOTE: assuming frame border is unit size until charsets are impemented - int gaugeX((align == LEFT ? 10 : 6) * res->heroTagFont->CharWidth()); + int gaugeX(((index % 2) ? 10 : 6) * battle->Res().heroTagFont->CharWidth()); // 4 units reserved for hero, gaugeX already includes frame offset - int gaugeWidth(width - gaugeX - (align == LEFT ? 1 : 5) * res->heroTagFont->CharWidth()); + int gaugeWidth(width - gaugeX - ((index % 2) ? 1 : 5) * battle->Res().heroTagFont->CharWidth()); // health gauge, second line - Vector healthGaugeOffset(gaugeX, frameOffset.Y() + res->heroTagFont->CharHeight()); - res->healthGauge->Draw(screen, position + healthGaugeOffset, gaugeWidth, hero->RelativeHealth(255)); + Vector healthGaugeOffset(gaugeX, frameOffset.Y() + battle->Res().heroTagFont->CharHeight()); + battle->Res().healthGauge->Draw(screen, position + healthGaugeOffset, gaugeWidth, hero.RelativeHealth(255)); // mana gauge, third line - Vector manaGaugeOffset(gaugeX, frameOffset.Y() + 2 * res->heroTagFont->CharHeight()); - res->manaGauge->Draw(screen, position + manaGaugeOffset, gaugeWidth, hero->RelativeMana(255)); + Vector manaGaugeOffset(gaugeX, frameOffset.Y() + 2 * battle->Res().heroTagFont->CharHeight()); + battle->Res().manaGauge->Draw(screen, position + manaGaugeOffset, gaugeWidth, hero.RelativeMana(255)); // ikari gauge, fourth line - Vector ikariGaugeOffset(gaugeX, frameOffset.Y() + 3 * res->heroTagFont->CharHeight()); - res->ikariGauge->Draw(screen, position + ikariGaugeOffset, gaugeWidth, hero->RelativeIP(255)); + Vector ikariGaugeOffset(gaugeX, frameOffset.Y() + 3 * battle->Res().heroTagFont->CharHeight()); + battle->Res().ikariGauge->Draw(screen, position + ikariGaugeOffset, gaugeWidth, hero.RelativeIP(255)); // labels - int labelX((align == LEFT ? 5 : 1) * res->heroTagFont->CharWidth()); + int labelX(((index % 2) ? 5 : 1) * battle->Res().heroTagFont->CharWidth()); // level Vector levelLabelOffset(gaugeX, frameOffset.Y()); - res->heroTagLabels->Draw(screen, position + levelLabelOffset, 0, 0); + battle->Res().heroTagLabels->Draw(screen, position + levelLabelOffset, 0, 0); // hp - Vector healthLabelOffset(labelX, frameOffset.Y() + res->heroTagFont->CharHeight()); - res->heroTagLabels->Draw(screen, position + healthLabelOffset, 0, 1); + Vector healthLabelOffset(labelX, frameOffset.Y() + battle->Res().heroTagFont->CharHeight()); + battle->Res().heroTagLabels->Draw(screen, position + healthLabelOffset, 0, 1); // mp - Vector manaLabelOffset(labelX, frameOffset.Y() + 2 * res->heroTagFont->CharHeight()); - res->heroTagLabels->Draw(screen, position + manaLabelOffset, 0, 2); + Vector manaLabelOffset(labelX, frameOffset.Y() + 2 * battle->Res().heroTagFont->CharHeight()); + battle->Res().heroTagLabels->Draw(screen, position + manaLabelOffset, 0, 2); // cm - Vector moveLabelOffset(labelX, frameOffset.Y() + 3 * res->heroTagFont->CharHeight()); - res->heroTagLabels->Draw(screen, position + moveLabelOffset, 0, 3); + Vector moveLabelOffset(labelX, frameOffset.Y() + 3 * battle->Res().heroTagFont->CharHeight()); + battle->Res().heroTagLabels->Draw(screen, position + moveLabelOffset, 0, 3); // ip - Vector ikariLabelOffset(labelX + 3 * res->heroTagFont->CharWidth(), frameOffset.Y() + 3 * res->heroTagFont->CharHeight()); - res->heroTagLabels->Draw(screen, position + ikariLabelOffset, 0, 4); + Vector ikariLabelOffset(labelX + 3 * battle->Res().heroTagFont->CharWidth(), frameOffset.Y() + 3 * battle->Res().heroTagFont->CharHeight()); + battle->Res().heroTagLabels->Draw(screen, position + ikariLabelOffset, 0, 4); // numbers // level - Vector levelNumberOffset(gaugeX + res->heroTagLabels->Width(), levelLabelOffset.Y()); - res->heroTagFont->DrawNumber(hero->Level(), screen, position + levelNumberOffset, 2); + Vector levelNumberOffset(gaugeX + battle->Res().heroTagLabels->Width(), levelLabelOffset.Y()); + battle->Res().heroTagFont->DrawNumber(hero.Level(), screen, position + levelNumberOffset, 2); // health - Vector healthNumberOffset(labelX + res->heroTagLabels->Width(), healthLabelOffset.Y()); - res->heroTagFont->DrawNumber(hero->Health(), screen, position + healthNumberOffset, 3); + Vector healthNumberOffset(labelX + battle->Res().heroTagLabels->Width(), healthLabelOffset.Y()); + battle->Res().heroTagFont->DrawNumber(hero.Health(), screen, position + healthNumberOffset, 3); //mana - Vector manaNumberOffset(labelX + res->heroTagLabels->Width(), manaLabelOffset.Y()); - res->heroTagFont->DrawNumber(hero->Mana(), screen, position + manaNumberOffset, 3); + Vector manaNumberOffset(labelX + battle->Res().heroTagLabels->Width(), manaLabelOffset.Y()); + battle->Res().heroTagFont->DrawNumber(hero.Mana(), screen, position + manaNumberOffset, 3); // name - res->normalFont->DrawString(hero->Name(), screen, position + frameOffset + alignOffset, 5); + battle->Res().normalFont->DrawString(hero.Name(), screen, position + frameOffset + alignOffset, 5); // attack icon - if (choice->GetType() != AttackChoice::UNDECIDED) { - Vector attackIconOffset(labelX + res->heroTagLabels->Width(), frameOffset.Y() + 3 * res->heroTagFont->CharHeight()); - res->attackChoiceIcons->Draw(screen, position + attackIconOffset, 0, choice->GetType()); + if (battle->AttackChoiceAt(index).GetType() != AttackChoice::UNDECIDED) { + Vector attackIconOffset(labelX + battle->Res().heroTagLabels->Width(), frameOffset.Y() + 3 * battle->Res().heroTagFont->CharHeight()); + battle->Res().attackChoiceIcons->Draw(screen, position + attackIconOffset, 0, battle->AttackChoiceAt(index).GetType()); } // hero - hero->Sprite()->Draw(screen, position + HeroOffset(), 0, hero->Health() > 0 ? 0 : 2); + HeroSprite()->Draw(screen, position + HeroOffset(), 0, battle->HeroAt(index).Health() > 0 ? 0 : 2); } Vector HeroTag::HeroOffset() const { return Vector( - (align == LEFT) ? res->normalFont->CharWidth() : 10 * res->normalFont->CharWidth(), - res->normalFont->CharWidth()); + (index % 2) ? battle->Res().normalFont->CharWidth() : 10 * battle->Res().normalFont->CharWidth(), + battle->Res().normalFont->CharWidth()); } } diff --git a/src/battle/HeroTag.h b/src/battle/HeroTag.h index 5f122cf..c21f857 100644 --- a/src/battle/HeroTag.h +++ b/src/battle/HeroTag.h @@ -23,34 +23,25 @@ namespace graphics { namespace battle { -class AttackChoice; -struct Resources; +class BattleState; class HeroTag { public: - enum Alignment { - LEFT, - RIGHT - }; - -public: - HeroTag() : hero(0), choice(0), res(0), align(LEFT) { }; - HeroTag(const Hero *hero, const AttackChoice *choice, const Resources *res, Alignment align) - : hero(hero), choice(choice), res(res), align(align) { } + HeroTag() : battle(0), index(0) { }; + HeroTag(const BattleState *battle, int heroIndex) + : battle(battle), index(heroIndex) { } ~HeroTag() { } public: - const graphics::Sprite *HeroSprite() const { return hero->Sprite(); } + const graphics::Sprite *HeroSprite() const; geometry::Vector HeroOffset() const; void Render(SDL_Surface *screen, int width, int height, geometry::Point position, bool active) const; private: - const Hero *hero; - const AttackChoice *choice; - const Resources *res; - Alignment align; + const BattleState *battle; + int index; }; diff --git a/src/battle/Resources.h b/src/battle/Resources.h index 1e86f64..89c99ef 100644 --- a/src/battle/Resources.h +++ b/src/battle/Resources.h @@ -26,6 +26,7 @@ namespace battle { struct Resources { + graphics::Sprite *swapCursor; graphics::Sprite *moveIcons; graphics::Sprite *attackIcons; graphics::Sprite *attackChoiceIcons; @@ -70,7 +71,8 @@ struct Resources { Resources() - : moveIcons(0) + : swapCursor(0) + , moveIcons(0) , attackIcons(0) , attackChoiceIcons(0) diff --git a/src/battle/states/SelectMoveAction.cpp b/src/battle/states/SelectMoveAction.cpp index c728db0..de8e97b 100644 --- a/src/battle/states/SelectMoveAction.cpp +++ b/src/battle/states/SelectMoveAction.cpp @@ -8,6 +8,7 @@ #include "SelectMoveAction.h" #include "SelectAttackType.h" +#include "SwapHeroes.h" #include "../BattleState.h" #include "../MoveMenu.h" #include "../../app/Application.h" @@ -59,7 +60,7 @@ void SelectMoveAction::HandleInput(const Input &input) { battle->NextHero(); break; case MoveMenu::CHANGE: - // TODO: switch to change state + ctrl->PushState(new SwapHeroes(battle, this)); break; case MoveMenu::RUN: // TODO: switch to run state diff --git a/src/battle/states/SwapHeroes.cpp b/src/battle/states/SwapHeroes.cpp new file mode 100644 index 0000000..ab1e6fd --- /dev/null +++ b/src/battle/states/SwapHeroes.cpp @@ -0,0 +1,148 @@ +/* + * SwapHeroes.cpp + * + * Created on: Aug 10, 2012 + * Author: holy + */ + +#include "SwapHeroes.h" + +#include "SelectMoveAction.h" +#include "../BattleState.h" +#include "../../app/Application.h" +#include "../../app/Input.h" +#include "../../geometry/operators.h" +#include "../../geometry/Point.h" + +using app::Application; +using app::Input; +using geometry::Point; +using geometry::Vector; +using std::vector; + +namespace battle { + +void SwapHeroes::EnterState(Application &c, SDL_Surface *screen) { + ctrl = &c; +} + +void SwapHeroes::ExitState(Application &c, SDL_Surface *screen) { + ctrl = 0; +} + +void SwapHeroes::ResumeState(Application &ctrl, SDL_Surface *screen) { + +} + +void SwapHeroes::PauseState(Application &ctrl, SDL_Surface *screen) { + +} + + +void SwapHeroes::Resize(int width, int height) { + +} + + +void SwapHeroes::HandleInput(const Input &input) { + if (input.JustPressed(Input::ACTION_A)) { + if (selected != -1 && cursor != selected) { + battle->SwapHeroes(cursor, selected); + selected = -1; + } else { + selected = cursor; + } + } + if (input.JustPressed(Input::ACTION_B)) { + if (cursor == selected) { + selected = -1; + } else { + ctrl->PopState(); + } + } + + if (input.JustPressed(Input::PAD_UP)) { + MoveUp(); + } + if (input.JustPressed(Input::PAD_RIGHT)) { + MoveRight(); + } + if (input.JustPressed(Input::PAD_DOWN)) { + MoveDown(); + } + if (input.JustPressed(Input::PAD_LEFT)) { + MoveLeft(); + } +} + + +void SwapHeroes::MoveUp() { + if (cursor < 2) { + if (battle->HeroPositionOccupied(cursor + 2)) { + cursor += 2; + } + } else { + cursor -= 2; + } +} + +void SwapHeroes::MoveRight() { + if (cursor < 3 && battle->HeroPositionOccupied(cursor + 1)) { + ++cursor; + } else { + cursor = 0; + } +} + +void SwapHeroes::MoveDown() { + if (cursor < 2) { + if (battle->HeroPositionOccupied(cursor + 2)) { + cursor += 2; + } + } else { + cursor -= 2; + } +} + +void SwapHeroes::MoveLeft() { + if (cursor > 0) { + --cursor; + } else { + cursor = battle->Heroes().size(); + } +} + + +void SwapHeroes::UpdateWorld(float deltaT) { + +} + +void SwapHeroes::Render(SDL_Surface *screen) { + Vector offset(battle->CalculateScreenOffset(screen)); + parent->Render(screen); + RenderCursors(screen, offset); +} + +void SwapHeroes::RenderCursors(SDL_Surface *screen, const geometry::Vector &offset) { + // offset the cursor by 1/8th to the left and bottom + Vector cursorOffset(battle->Res().swapCursor->Width() / -8, battle->Res().swapCursor->Height() / 8); + Vector indicatorOffset(0, 0); + vector > positions; + for (vector::size_type i(0), end(battle->Heroes().size()); i < end; ++i) { + Vector positionCorrection(battle->Res().swapCursor->Width() / 2, battle->HeroTagAt(i).HeroSprite()->Height() - battle->Res().swapCursor->Height() / 2); + // indicator offsets are inverted for heroes + positionCorrection -= cursorOffset; + positions.push_back(battle->HeroTagPositionAt(i) + battle->HeroTagAt(i).HeroOffset() + positionCorrection); + } + if (flipFlop) { + for (vector >::size_type i(0); i < positions.size(); ++i) { + if (selected == int(i)) { + battle->Res().swapCursor->DrawTopRight(screen, positions[i] + offset); + } + } + } + flipFlop = !flipFlop; + battle->Res().swapCursor->DrawTopRight(screen, positions[cursor] + offset + cursorOffset); +} + +} diff --git a/src/battle/states/SwapHeroes.h b/src/battle/states/SwapHeroes.h new file mode 100644 index 0000000..07dba71 --- /dev/null +++ b/src/battle/states/SwapHeroes.h @@ -0,0 +1,60 @@ +/* + * SwapHeroes.h + * + * Created on: Aug 10, 2012 + * Author: holy + */ + +#ifndef BATTLE_SWAPHEROES_H_ +#define BATTLE_SWAPHEROES_H_ + +#include "../../app/State.h" + +#include "../../geometry/Vector.h" + +namespace battle { + +class BattleState; +class SelectMoveAction; + +class SwapHeroes +: public app::State { + +public: + SwapHeroes(BattleState *battle, SelectMoveAction *parent) + : ctrl(0), battle(battle), parent(parent), cursor(0), selected(-1), flipFlop(true) { } + +public: + virtual void EnterState(app::Application &ctrl, SDL_Surface *screen); + virtual void ExitState(app::Application &ctrl, SDL_Surface *screen); + virtual void ResumeState(app::Application &ctrl, SDL_Surface *screen); + virtual void PauseState(app::Application &ctrl, SDL_Surface *screen); + + virtual void Resize(int width, int height); + + virtual void HandleInput(const app::Input &); + virtual void UpdateWorld(float deltaT); + virtual void Render(SDL_Surface *); + +private: + void MoveUp(); + void MoveRight(); + void MoveDown(); + void MoveLeft(); + +private: + void RenderCursors(SDL_Surface *screen, const geometry::Vector &offset); + +private: + app::Application *ctrl; + BattleState *battle; + SelectMoveAction *parent; + int cursor; + int selected; + bool flipFlop; + +}; + +} + +#endif /* BATTLE_SWAPHEROES_H_ */ diff --git a/src/main.cpp b/src/main.cpp index a267250..a59818a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -135,6 +135,9 @@ int main(int argc, char **argv) { battle::Resources battleRes; + SDL_Surface *swapCursorImg(IMG_Load("test-data/swap-cursor.png")); + Sprite swapCursorSprite(swapCursorImg, 32, 32); + battleRes.swapCursor = &swapCursorSprite; SDL_Surface *attackIconsImg(IMG_Load("test-data/attack-type-icons.png")); Sprite attackIconsSprite(attackIconsImg, 32, 32); battleRes.attackIcons = &attackIconsSprite; diff --git a/test-data/swap-cursor.png b/test-data/swap-cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..0a857a849c590b331d9408f49665ff930902f059 GIT binary patch literal 395 zcmV;60d)R}P)l)X(AYhrv z%{99R%w+T1+uZE;=g)1kR;4bTtoZ zpg#@}nVre%DLY&iI(I