]> git.localhorst.tv Git - l2e.git/commitdiff
added attack targets selection state
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 10 Aug 2012 01:45:31 +0000 (03:45 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 10 Aug 2012 01:45:31 +0000 (03:45 +0200)
19 files changed:
Debug/src/battle/states/subdir.mk
Debug/src/battle/subdir.mk
Release/src/battle/states/subdir.mk
Release/src/battle/subdir.mk
src/battle/AttackChoice.h
src/battle/BattleState.cpp
src/battle/BattleState.h
src/battle/HeroTag.cpp
src/battle/HeroTag.h
src/battle/Monster.h
src/battle/Resources.h
src/battle/TargetSelection.cpp [new file with mode: 0644]
src/battle/TargetSelection.h [new file with mode: 0644]
src/battle/states/SelectAttackType.cpp
src/battle/states/SelectTarget.cpp [new file with mode: 0644]
src/battle/states/SelectTarget.h [new file with mode: 0644]
src/graphics/Sprite.h
src/main.cpp
test-data/targeting-icons.png [new file with mode: 0644]

index 8217544fbcc22a00aecd70c7f4581b2ff40fb617..a4898a8f815e002bea0664419320cea58dae836c 100644 (file)
@@ -8,21 +8,24 @@ CPP_SRCS += \
 ../src/battle/states/SelectIkari.cpp \
 ../src/battle/states/SelectItem.cpp \
 ../src/battle/states/SelectMoveAction.cpp \
-../src/battle/states/SelectSpell.cpp 
+../src/battle/states/SelectSpell.cpp \
+../src/battle/states/SelectTarget.cpp 
 
 OBJS += \
 ./src/battle/states/SelectAttackType.o \
 ./src/battle/states/SelectIkari.o \
 ./src/battle/states/SelectItem.o \
 ./src/battle/states/SelectMoveAction.o \
-./src/battle/states/SelectSpell.o 
+./src/battle/states/SelectSpell.o \
+./src/battle/states/SelectTarget.o 
 
 CPP_DEPS += \
 ./src/battle/states/SelectAttackType.d \
 ./src/battle/states/SelectIkari.d \
 ./src/battle/states/SelectItem.d \
 ./src/battle/states/SelectMoveAction.d \
-./src/battle/states/SelectSpell.d 
+./src/battle/states/SelectSpell.d \
+./src/battle/states/SelectTarget.d 
 
 
 # Each subdirectory must supply rules for building sources it contributes
index dd0f37f011b6a0673ee15bcc7740b7c2e8b56cfd..c459c3e20b5dd083de284c8c7dafe74355120e35 100644 (file)
@@ -11,7 +11,8 @@ CPP_SRCS += \
 ../src/battle/HeroTag.cpp \
 ../src/battle/Monster.cpp \
 ../src/battle/MoveMenu.cpp \
-../src/battle/PartyLayout.cpp 
+../src/battle/PartyLayout.cpp \
+../src/battle/TargetSelection.cpp 
 
 OBJS += \
 ./src/battle/AttackChoice.o \
@@ -21,7 +22,8 @@ OBJS += \
 ./src/battle/HeroTag.o \
 ./src/battle/Monster.o \
 ./src/battle/MoveMenu.o \
-./src/battle/PartyLayout.o 
+./src/battle/PartyLayout.o \
+./src/battle/TargetSelection.o 
 
 CPP_DEPS += \
 ./src/battle/AttackChoice.d \
@@ -31,7 +33,8 @@ CPP_DEPS += \
 ./src/battle/HeroTag.d \
 ./src/battle/Monster.d \
 ./src/battle/MoveMenu.d \
-./src/battle/PartyLayout.d 
+./src/battle/PartyLayout.d \
+./src/battle/TargetSelection.d 
 
 
 # Each subdirectory must supply rules for building sources it contributes
index 6bd80356653b561eddbb6f979e554991934fdf80..23338be628e83bcd52dd101ccc37dc23f0c64fe9 100644 (file)
@@ -8,21 +8,24 @@ CPP_SRCS += \
 ../src/battle/states/SelectIkari.cpp \
 ../src/battle/states/SelectItem.cpp \
 ../src/battle/states/SelectMoveAction.cpp \
-../src/battle/states/SelectSpell.cpp 
+../src/battle/states/SelectSpell.cpp \
+../src/battle/states/SelectTarget.cpp 
 
 OBJS += \
 ./src/battle/states/SelectAttackType.o \
 ./src/battle/states/SelectIkari.o \
 ./src/battle/states/SelectItem.o \
 ./src/battle/states/SelectMoveAction.o \
-./src/battle/states/SelectSpell.o 
+./src/battle/states/SelectSpell.o \
+./src/battle/states/SelectTarget.o 
 
 CPP_DEPS += \
 ./src/battle/states/SelectAttackType.d \
 ./src/battle/states/SelectIkari.d \
 ./src/battle/states/SelectItem.d \
 ./src/battle/states/SelectMoveAction.d \
-./src/battle/states/SelectSpell.d 
+./src/battle/states/SelectSpell.d \
+./src/battle/states/SelectTarget.d 
 
 
 # Each subdirectory must supply rules for building sources it contributes
index 4ab87844e1063dfc62fa3dec9f19ebadac8ac2df..65a66230ff4dd3584b56ee18493dfcc8d804322a 100644 (file)
@@ -11,7 +11,8 @@ CPP_SRCS += \
 ../src/battle/HeroTag.cpp \
 ../src/battle/Monster.cpp \
 ../src/battle/MoveMenu.cpp \
-../src/battle/PartyLayout.cpp 
+../src/battle/PartyLayout.cpp \
+../src/battle/TargetSelection.cpp 
 
 OBJS += \
 ./src/battle/AttackChoice.o \
@@ -21,7 +22,8 @@ OBJS += \
 ./src/battle/HeroTag.o \
 ./src/battle/Monster.o \
 ./src/battle/MoveMenu.o \
-./src/battle/PartyLayout.o 
+./src/battle/PartyLayout.o \
+./src/battle/TargetSelection.o 
 
 CPP_DEPS += \
 ./src/battle/AttackChoice.d \
@@ -31,7 +33,8 @@ CPP_DEPS += \
 ./src/battle/HeroTag.d \
 ./src/battle/Monster.d \
 ./src/battle/MoveMenu.d \
-./src/battle/PartyLayout.d 
+./src/battle/PartyLayout.d \
+./src/battle/TargetSelection.d 
 
 
 # Each subdirectory must supply rules for building sources it contributes
index b11a81da0f2f689ce18b9bfbbfe3c4e998ae3048..0068e6f67e50049c1e751c7da9240bf6c1a7a499 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef BATTLE_ATTACKCHOICE_H_
 #define BATTLE_ATTACKCHOICE_H_
 
+#include "TargetSelection.h"
+
 namespace battle {
 
 class AttackChoice {
@@ -23,15 +25,18 @@ public:
        };
 
 public:
-       AttackChoice() : type(UNDECIDED) { }
+       explicit AttackChoice(BattleState *b = 0) : type(UNDECIDED), selection(b) { }
        ~AttackChoice() { }
 
 public:
        Type GetType() const { return type; }
        void SetType(Type t) { type = t; }
+       TargetSelection &Selection() { return selection; }
+       const TargetSelection &Selection() const { return selection; }
 
 private:
        Type type;
+       TargetSelection selection;
 
 };
 
index ec56169a1b261f87dd6d2172fbb947b2954e9e25..ad225173fce209625a452265c0913cf5b1d9adda 100644 (file)
@@ -53,14 +53,22 @@ void BattleState::Resize(int w, int h) {
 void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) {
        monstersLayout->CalculatePositions(background->w, background->h, monsterPositions);
        heroesLayout->CalculatePositions(background->w, background->h, heroesPositions);
-       attackChoices.resize(heroes.size());
        for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
                spellMenus.push_back(res->spellMenuPrototype);
                // TODO: insert spell menu entries
                ikariMenus.push_back(res->ikariMenuPrototype);
                // TODO: insert ikari menu entries
-               heroTags.push_back(HeroTag(&heroes[i], &attackChoices[i], res, HeroTag::Alignment((i + 1) % 2)));
+               heroTags[i] = HeroTag(&heroes[i], attackChoices + i, res, HeroTag::Alignment((i + 1) % 2));
        }
+
+       int tagHeight(attackTypeMenu.Height());
+       int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
+       int xOffset((BackgroundWidth() - 2 * tagWidth) / 2);
+       heroTagPositions[0] = Point<int>(xOffset, BackgroundHeight() - 2 * tagHeight);
+       heroTagPositions[1] = Point<int>(xOffset + tagWidth, BackgroundHeight() - 2 * tagHeight);
+       heroTagPositions[2] = Point<int>(xOffset, BackgroundHeight() - tagHeight);
+       heroTagPositions[3] = Point<int>(xOffset + tagWidth, BackgroundHeight() - tagHeight);
+
        // TODO: insert item menu entries
        itemMenu = res->itemMenuPrototype;
        LoadInventory();
@@ -88,8 +96,9 @@ void BattleState::ResumeState(Application &ctrl, SDL_Surface *screen) {
        // TODO: check for victory, defeat or run
        // reset attack choices
        activeHero = -1;
-       attackChoices.clear();
-       attackChoices.resize(heroes.size());
+       for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
+               attackChoices[i] = AttackChoice(this);
+       }
        ctrl.PushState(new SelectMoveAction(this));
 }
 
@@ -141,16 +150,9 @@ void BattleState::RenderHeroes(SDL_Surface *screen, const Vector<int> &offset) {
 void BattleState::RenderHeroTags(SDL_Surface *screen, const Vector<int> &offset) {
        int tagHeight(attackTypeMenu.Height());
        int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
-       int xOffset((BackgroundWidth() - 2 * tagWidth) / 2);
 
-       Point<int> tagPosition[4];
-       tagPosition[0] = Point<int>(xOffset, BackgroundHeight() - 2 * tagHeight);
-       tagPosition[1] = Point<int>(xOffset + tagWidth, BackgroundHeight() - 2 * tagHeight);
-       tagPosition[2] = Point<int>(xOffset, BackgroundHeight() - tagHeight);
-       tagPosition[3] = Point<int>(xOffset + tagWidth, BackgroundHeight() - tagHeight);
-
-       for (vector<HeroTag>::size_type i(0), end(heroTags.size()); i < end; ++i) {
-               heroTags[i].Render(screen, tagWidth, tagHeight, tagPosition[i] + offset, (int)i == activeHero);
+       for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
+               heroTags[i].Render(screen, tagWidth, tagHeight, heroTagPositions[i] + offset, (int)i == activeHero);
        }
 }
 
index 96a7ce20643d5b62f4aee3d3c9f0f68103280a3a..3b293546382c1668a732eb80dff6eff64a26c500 100644 (file)
@@ -79,9 +79,17 @@ public:
        void PreviousHero() { --activeHero; }
        Hero &ActiveHero() { return heroes[activeHero]; }
        const Hero &ActiveHero() const { return heroes[activeHero]; }
+       Hero &HeroAt(std::vector<Hero>::size_type index) { return heroes[index]; }
+       const Hero &HeroAt(std::vector<Hero>::size_type index) const { return heroes[index]; }
+       const HeroTag &ActiveHeroTag() const { return heroTags[activeHero]; }
+       const HeroTag &HeroTagAt(std::vector<Hero>::size_type index) const { return heroTags[index]; }
+       const geometry::Point<int> &HeroTagPositionAt(std::vector<Hero>::size_type index) const { return heroTagPositions[index]; }
        bool HasChosenAttackType() const { return attackChoices[activeHero].GetType() != AttackChoice::UNDECIDED; }
        void SetAttackType(AttackChoice::Type t) { attackChoices[activeHero].SetType(t); }
+       TargetSelection &ActiveHeroTargets() { return attackChoices[activeHero].Selection(); }
+       const TargetSelection &ActiveHeroTargets() const { return attackChoices[activeHero].Selection(); }
        bool AttackSelectionDone() const { return activeHero >= (int) heroes.size(); }
+
        graphics::Menu</* Spell */ void *> &GetSpellMenu() { return spellMenus[activeHero]; }
        const graphics::Menu</* Spell */ void *> &GetSpellMenu() const { return spellMenus[activeHero]; }
        graphics::Menu</* Ikari or Item */ void *> &GetIkariMenu() { return ikariMenus[activeHero]; }
@@ -89,6 +97,13 @@ public:
        graphics::Menu<const common::Item *> &GetItemMenu() { return itemMenu; }
        const graphics::Menu<const common::Item *> &GetItemMenu() const { return itemMenu; }
 
+       const std::vector<geometry::Point<int> > &MonsterPositions() const { return monsterPositions; }
+       bool MonsterPositionOccupied(int index) { return index >= 0 && index < int(monsters.size()) && monsters[index].Health() > 0; }
+       const std::vector<geometry::Point<int> > &HeroesPositions() const { return heroesPositions; }
+       bool HeroPositionOccupied(int index) { return index >= 0 && index < int(heroes.size()); }
+       std::vector<Hero> &Heroes() { return heroes; }
+       const std::vector<Hero> &Heroes() const { return heroes; }
+
 public:
        geometry::Vector<int> CalculateScreenOffset(SDL_Surface *screen) const {
                return geometry::Vector<int>(
@@ -113,6 +128,7 @@ private:
        const Resources *res;
        AttackTypeMenu attackTypeMenu;
        MoveMenu moveMenu;
+       // TODO: combine all data about heros or monsters
        std::vector<geometry::Point<int> > monsterPositions;
        std::vector<geometry::Point<int> > heroesPositions;
        std::vector<Monster> monsters;
@@ -120,8 +136,9 @@ private:
        std::vector<graphics::Menu</* Spell */ void *> > spellMenus;
        graphics::Menu<const common::Item *> itemMenu;
        std::vector<graphics::Menu</* Ikari or Item */ void *> > ikariMenus;
-       std::vector<HeroTag> heroTags;
-       std::vector<AttackChoice> attackChoices;
+       HeroTag heroTags[4];
+       geometry::Point<int> heroTagPositions[4];
+       AttackChoice attackChoices[4];
        int activeHero;
 
 };
index 96dedd9269e836037804c4d1a0c822375ca20763..a83ba8b9fc1f019dd5695816db09388cb653d5fe 100644 (file)
@@ -30,8 +30,6 @@ void HeroTag::Render(SDL_Surface *screen, int width, int height, Point<int> posi
        Vector<int> alignOffset(align == LEFT ? 4 * res->heroTagFont->CharWidth() : 0, 0);
        frame->Draw(screen, position, width, height);
 
-       int yOffset((height - hero->Sprite()->Height()) / 2);
-
        // gauges
        // NOTE: assuming frame border is unit size until charsets are impemented
        int gaugeX((align == LEFT ? 10 : 6) * res->heroTagFont->CharWidth());
@@ -86,10 +84,13 @@ void HeroTag::Render(SDL_Surface *screen, int width, int height, Point<int> posi
        }
 
        // hero
-       Vector<int> heroOffset(
-                       (align == LEFT) ? yOffset : width - hero->Sprite()->Width() - yOffset,
-                       yOffset);
-       hero->Sprite()->Draw(screen, position + heroOffset, 0, hero->Health() > 0 ? 0 : 2);
+       hero->Sprite()->Draw(screen, position + HeroOffset(), 0, hero->Health() > 0 ? 0 : 2);
+}
+
+Vector<int> HeroTag::HeroOffset() const {
+       return Vector<int>(
+                       (align == LEFT) ? res->normalFont->CharWidth() : 10 * res->normalFont->CharWidth(),
+                       res->normalFont->CharWidth());
 }
 
 }
index d361252dec1e48070ad9197b8d112981eb662cf4..5f122cf5d5b77fd24eb3f1f5e3a0d9502ad46681 100644 (file)
@@ -8,7 +8,9 @@
 #ifndef BATTLE_HEROTAG_H_
 #define BATTLE_HEROTAG_H_
 
+#include "Hero.h"
 #include "../geometry/Point.h"
+#include "../geometry/Vector.h"
 
 #include <SDL.h>
 
@@ -22,7 +24,6 @@ namespace graphics {
 namespace battle {
 
 class AttackChoice;
-class Hero;
 struct Resources;
 
 class HeroTag {
@@ -34,11 +35,15 @@ public:
        };
 
 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() { }
 
 public:
+       const graphics::Sprite *HeroSprite() const { return hero->Sprite(); }
+       geometry::Vector<int> HeroOffset() const;
+
        void Render(SDL_Surface *screen, int width, int height, geometry::Point<int> position, bool active) const;
 
 private:
index 1c9218413fef2a78bd72655fb977051ba5781fcc..d3a7162111939c1f887cf4c63fa548f4575b0beb 100644 (file)
@@ -52,6 +52,8 @@ public:
 // temporary setters until loader is implemented
 public:
        void SetSprite(graphics::Sprite *s) { sprite = s; }
+       void SetMaxHealth(Uint16 m) { maxHealth = m; }
+       void SetHealth(Uint16 h) { health = h; }
 
 private:
        const char *name;
index b07e2b21f0cf60472aa769013ac729fdc29cc616..c0fb48cf159bec8ca258ab68f8eed59b37a8fcea 100644 (file)
@@ -45,6 +45,9 @@ struct Resources {
        graphics::Font *disabledFont;
 
        graphics::Sprite *menuCursor;
+       graphics::Sprite *weaponTargetCursor;
+       graphics::Sprite *magicTargetCursor;
+       graphics::Sprite *itemTargetCursor;
 
        const char *spellMenuHeadline;
        graphics::Menu</* Spell */ void *> spellMenuPrototype;
@@ -78,6 +81,10 @@ struct Resources {
        , disabledFont(0)
 
        , menuCursor(0)
+       , weaponTargetCursor(0)
+       , magicTargetCursor(0)
+       , itemTargetCursor(0)
+
        , spellMenuHeadline("")
        , inventory(0)
        , itemMenuHeadline("")
diff --git a/src/battle/TargetSelection.cpp b/src/battle/TargetSelection.cpp
new file mode 100644 (file)
index 0000000..8563907
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * TargetSelection.cpp
+ *
+ *  Created on: Aug 9, 2012
+ *      Author: holy
+ */
+
+#include "TargetSelection.h"
+
+#include "BattleState.h"
+
+namespace battle {
+
+TargetSelection::TargetSelection(BattleState *battle, bool multiple, bool atEnemy)
+: battle(battle)
+, selected(battle ? (battle->MonsterPositions().size() > battle->Heroes().size() ? battle->MonsterPositions().size() : battle->Heroes().size()) : 0, false)
+, selection(-1)
+, cursor(0)
+, multiple(multiple)
+, enemy(atEnemy) {
+       if (battle && enemy) {
+               FindNextEnemy();
+       }
+}
+
+void TargetSelection::SelectEnemies() {
+       if (TargetsEnemies()) return;
+       enemy = true;
+       UnselectAll();
+       cursor = 0;
+       FindNextEnemy();
+}
+
+void TargetSelection::SelectHeroes() {
+       if (TargetsHeroes()) return;
+       enemy = false;
+       UnselectAll();
+       cursor = 0;
+}
+
+
+void TargetSelection::Reset() {
+       UnselectAll();
+       cursor = 0;
+       if (TargetsEnemies()) {
+               FindNextEnemy();
+       }
+}
+
+
+void TargetSelection::MoveUp() {
+       if (TargetsEnemies()) return;
+       if (cursor < 2) {
+               SelectEnemies();
+       } else {
+               cursor -= 2;
+       }
+}
+
+void TargetSelection::MoveRight() {
+       if (TargetsEnemies()) {
+               cursor = (cursor + 1) % battle->MonsterPositions().size();
+               while (!battle->MonsterPositionOccupied(cursor)) {
+                       cursor = (cursor + 1) % battle->MonsterPositions().size();
+               }
+       } else {
+               cursor = (cursor + 1) % battle->Heroes().size();
+       }
+}
+
+void TargetSelection::MoveDown() {
+       if (TargetsEnemies()) {
+               SelectHeroes();
+               return;
+       }
+       int newCursor(cursor + 2 % 4);
+       if (newCursor < int(battle->Heroes().size())) {
+               cursor = newCursor;
+       }
+}
+
+void TargetSelection::MoveLeft() {
+       if (TargetsEnemies()) {
+               cursor = (cursor + battle->MonsterPositions().size() - 1) % battle->MonsterPositions().size();
+               FindNextEnemy();
+       } else {
+               cursor = (cursor + battle->Heroes().size() - 1) % battle->Heroes().size();
+       }
+}
+
+void TargetSelection::FindNextEnemy() {
+       while (!battle->MonsterPositionOccupied(cursor)) {
+               cursor = (cursor + battle->MonsterPositions().size() - 1) % battle->MonsterPositions().size();
+       }
+}
+
+}
diff --git a/src/battle/TargetSelection.h b/src/battle/TargetSelection.h
new file mode 100644 (file)
index 0000000..664e960
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * TargetSelection.h
+ *
+ *  Created on: Aug 9, 2012
+ *      Author: holy
+ */
+
+#ifndef BATTLE_TARGETSELECTION_H_
+#define BATTLE_TARGETSELECTION_H_
+
+#include <vector>
+
+namespace battle {
+
+class BattleState;
+
+class TargetSelection {
+
+public:
+       explicit TargetSelection(BattleState *battle = 0, bool multiple = false, bool atEnemy = true);
+
+public:
+       bool TargetsEnemies() const { return enemy; }
+       bool TargetsHeroes() const { return !TargetsEnemies(); }
+       bool IsSelected(int index) const { return index >= 0 && index < int(selected.size()) && selected[index]; }
+       bool HasSelected() const { return selection >= 0; }
+       int SingleSelection() const { return selection; }
+
+       bool SelectMultiple() const { return multiple; }
+       void SetMultiple() { multiple = true; }
+       bool SelectSingle() const { return !SelectMultiple(); }
+       void SetSingle() { multiple = false; }
+
+       void SelectEnemies();
+       void SelectHeroes();
+       void Select(int index) { selected[index] = true; selection = index; }
+       void Unselect(int index) { selected[index] = false; }
+       void UnselectAll() { selected.assign(selected.size(), false); selection = -1; }
+
+       void Reset();
+       void Resize(int num) { selected.resize(num, false); }
+
+       void MoveUp();
+       void MoveRight();
+       void MoveDown();
+       void MoveLeft();
+       void Select() { Select(cursor); }
+       void Unselect() { Unselect(cursor); }
+       int Current() const { return cursor; }
+       bool CurrentIsSelected() { return IsSelected(cursor); }
+
+private:
+       void FindNextEnemy();
+
+private:
+       BattleState *battle;
+       std::vector<bool> selected;
+       int selection;
+       int cursor;
+       bool multiple;
+       bool enemy;
+
+};
+
+}
+
+#endif /* BATTLE_TARGETSELECTION_H_ */
index 786277d764900f036dbfffca578d3eacfd0db114..c0073208195e923086eeadb9f744a5764545cdda 100644 (file)
@@ -11,6 +11,7 @@
 #include "SelectItem.h"
 #include "SelectMoveAction.h"
 #include "SelectSpell.h"
+#include "SelectTarget.h"
 #include "../AttackChoice.h"
 #include "../BattleState.h"
 #include "../../app/Application.h"
@@ -35,6 +36,10 @@ void SelectAttackType::ExitState(Application &c, SDL_Surface *screen) {
 }
 
 void SelectAttackType::ResumeState(Application &ctrl, SDL_Surface *screen) {
+       if (battle->ActiveHeroTargets().HasSelected()) {
+               battle->SetAttackType(battle->GetAttackTypeMenu().Selected());
+               battle->NextHero();
+       }
        if (battle->AttackSelectionDone()) {
                // pass through
                ctrl.PopState();
@@ -67,9 +72,10 @@ void SelectAttackType::HandleInput(const Input &input) {
        if (input.JustPressed(Input::ACTION_A)) {
                switch (battle->GetAttackTypeMenu().Selected()) {
                        case AttackChoice::SWORD:
-                               // TODO: switch to target select
-                               battle->SetAttackType(AttackChoice::SWORD);
-                               battle->NextHero();
+                               // TODO: detect single/multiple/all attack mode
+                               battle->ActiveHeroTargets().SetSingle();
+                               battle->ActiveHeroTargets().Reset();
+                               ctrl->PushState(new SelectTarget(battle, this, &battle->ActiveHeroTargets(), battle->Res().weaponTargetCursor, true));
                                break;
                        case AttackChoice::MAGIC:
                                if (battle->ActiveHero().CanUseMagic()) {
@@ -90,8 +96,8 @@ void SelectAttackType::HandleInput(const Input &input) {
                                throw std::logic_error("selected invalid attack type");
                }
        } else if (input.JustPressed(Input::ACTION_B)) {
-               battle->SetAttackType(AttackChoice::UNDECIDED);
                battle->PreviousHero();
+               battle->SetAttackType(AttackChoice::UNDECIDED);
                if (battle->BeforeFirstHero()) {
                        ctrl->ChangeState(new SelectMoveAction(battle));
                }
diff --git a/src/battle/states/SelectTarget.cpp b/src/battle/states/SelectTarget.cpp
new file mode 100644 (file)
index 0000000..dedf8e7
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * SelectTarget.cpp
+ *
+ *  Created on: Aug 9, 2012
+ *      Author: holy
+ */
+
+#include "SelectTarget.h"
+
+#include "SelectAttackType.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 SelectTarget::EnterState(Application &c, SDL_Surface *screen) {
+       ctrl = &c;
+}
+
+void SelectTarget::ExitState(Application &c, SDL_Surface *screen) {
+       ctrl = 0;
+}
+
+void SelectTarget::ResumeState(Application &ctrl, SDL_Surface *screen) {
+
+}
+
+void SelectTarget::PauseState(Application &ctrl, SDL_Surface *screen) {
+
+}
+
+
+void SelectTarget::Resize(int width, int height) {
+
+}
+
+
+void SelectTarget::HandleInput(const Input &input) {
+       if (input.JustPressed(Input::ACTION_A)) {
+               if (selection->CurrentIsSelected()) {
+                       ctrl->PopState(); // return control to parent
+               } else {
+                       selection->Select();
+                       if (selection->SelectSingle()) {
+                               ctrl->PopState(); // return control to parent
+                       }
+               }
+       }
+       if (input.JustPressed(Input::ACTION_B)) {
+               if (selection->CurrentIsSelected()) {
+                       selection->Unselect();
+               } else {
+                       selection->UnselectAll();
+                       ctrl->PopState(); // return control to parent
+               }
+       }
+
+       if (input.JustPressed(Input::PAD_UP)) {
+               selection->MoveUp();
+       }
+       if (input.JustPressed(Input::PAD_RIGHT)) {
+               selection->MoveRight();
+       }
+       if (input.JustPressed(Input::PAD_DOWN)) {
+               selection->MoveDown();
+       }
+       if (input.JustPressed(Input::PAD_LEFT)) {
+               selection->MoveLeft();
+       }
+}
+
+void SelectTarget::UpdateWorld(float deltaT) {
+
+}
+
+void SelectTarget::Render(SDL_Surface *screen) {
+       Vector<int> offset(battle->CalculateScreenOffset(screen));
+       parent->Render(screen);
+       RenderCursors(screen, offset);
+}
+
+void SelectTarget::RenderCursors(SDL_Surface *screen, const geometry::Vector<int> &offset) {
+       // TODO: this should be related to the enemy's width
+       Vector<int> cursorOffset(0, 0);
+       Vector<int> indicatorOffset(0, 0);
+       vector<Point<int> > positions;
+       if (selection->TargetsEnemies()) {
+               for (vector<Point<int> >::const_iterator i(battle->MonsterPositions().begin()), end(battle->MonsterPositions().end()); i != end; ++i) {
+                       positions.push_back(*i);
+               }
+       } else {
+               for (vector<Hero>::size_type i(0), end(battle->Heroes().size()); i < end; ++i) {
+                       Vector<int> positionCorrection(cursorIcon->Width() / 2, battle->HeroTagAt(i).HeroSprite()->Height() - cursorIcon->Height() / 2);
+                       positions.push_back(battle->HeroTagPositionAt(i) + battle->HeroTagAt(i).HeroOffset() + positionCorrection);
+               }
+       }
+       if (flipFlop) {
+               for (vector<Point<int> >::size_type i(0); i < positions.size(); ++i) {
+                       if (selection->IsSelected(i)) {
+                               cursorIcon->DrawTopRight(screen, positions[i] + offset);
+                       }
+               }
+       }
+       flipFlop = !flipFlop;
+       cursorIcon->DrawTopRight(screen, positions[selection->Current()] + offset + cursorOffset);
+}
+
+}
diff --git a/src/battle/states/SelectTarget.h b/src/battle/states/SelectTarget.h
new file mode 100644 (file)
index 0000000..b9085a5
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SelectTarget.h
+ *
+ *  Created on: Aug 9, 2012
+ *      Author: holy
+ */
+
+#ifndef BATTLE_SELECTTARGET_H_
+#define BATTLE_SELECTTARGET_H_
+
+#include "../../app/State.h"
+
+#include "../../geometry/Vector.h"
+
+namespace graphics { class Sprite; }
+
+namespace battle {
+
+class BattleState;
+class TargetSelection;
+class SelectAttackType;
+
+class SelectTarget
+: public app::State {
+
+public:
+       SelectTarget(BattleState *battle, SelectAttackType *parent, TargetSelection *selection, const graphics::Sprite *cursorIcon, bool startWithEnemy)
+       : ctrl(0), battle(battle), parent(parent), selection(selection), cursorIcon(cursorIcon), 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 RenderCursors(SDL_Surface *screen, const geometry::Vector<int> &offset);
+
+private:
+       app::Application *ctrl;
+       BattleState *battle;
+       SelectAttackType *parent;
+       TargetSelection *selection;
+       const graphics::Sprite *cursorIcon;
+       bool flipFlop;
+
+};
+
+}
+
+#endif /* BATTLE_SELECTTARGET_H_ */
index 4a99af421232e6638e71534944aa1d47ba23fdcd..d56c69199cd7aa3f3cea49fc7a0ccb99b8606b64 100644 (file)
@@ -26,6 +26,10 @@ public:
        int Width() const { return width; }
        int Height() const { return height; }
        void Draw(SDL_Surface *dest, geometry::Point<int> position, int col = 0, int row = 0) const;
+       void DrawTopRight(SDL_Surface *dest, geometry::Point<int> position, int col = 0, int row = 0) const {
+               geometry::Vector<int> offset(-Width(), 0);
+               Draw(dest, position + offset, col, row);
+       }
        void DrawCenter(SDL_Surface *dest, geometry::Point<int> position, int col = 0, int row = 0) const {
                geometry::Vector<int> offset(-Width() / 2, -Height() / 2);
                Draw(dest, position + offset, col, row);
index dbe50d28f55d4b8be2d4ed531507c3ae14a45e4c..5e14001b8454e922348c7260ffd7bbdec9b1e95b 100644 (file)
@@ -78,6 +78,8 @@ int main(int argc, char **argv) {
                Sprite dummySprite(monsterImg, 64, 64);
                Monster monster;
                monster.SetSprite(&dummySprite);
+               monster.SetMaxHealth(10);
+               monster.SetHealth(10);
 
                SDL_Surface *maximImg(IMG_Load("test-data/maxim.png"));
                Sprite maximSprite(maximImg, 64, 64);
@@ -193,6 +195,14 @@ int main(int argc, char **argv) {
                Sprite handCursorSprite(handCursorImg, 32, 32);
                battleRes.menuCursor = &handCursorSprite;
 
+               SDL_Surface *targetingIconsImg(IMG_Load("test-data/targeting-icons.png"));
+               Sprite weaponTargetCursor(targetingIconsImg, 32, 32);
+               battleRes.weaponTargetCursor = &weaponTargetCursor;
+               // TODO: add image for magic targeting cursor
+               battleRes.magicTargetCursor = &weaponTargetCursor;
+               // TODO: add image for item targeting cursor
+               battleRes.itemTargetCursor = &weaponTargetCursor;
+
                battleRes.spellMenuHeadline = "Please choose a spell.";
                battleRes.spellMenuPrototype = Menu</* Spell */ void *>(&normalFont, &disabledFont, &handCursorSprite, 12, 6, 8, 0, 2, 32);
                battleRes.spellMenuPrototype.Add("Reset    : 0", 0, false);
diff --git a/test-data/targeting-icons.png b/test-data/targeting-icons.png
new file mode 100644 (file)
index 0000000..64b32bf
Binary files /dev/null and b/test-data/targeting-icons.png differ