]> git.localhorst.tv Git - l2e.git/commitdiff
Merge branch 'master' into feature-33-capsules
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 9 Dec 2012 14:33:14 +0000 (15:33 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 9 Dec 2012 14:33:14 +0000 (15:33 +0100)
I am a dork

52 files changed:
l2e.cbp
src/battle/AttackChoice.h
src/battle/BattleState.cpp
src/battle/BattleState.h
src/battle/Capsule.cpp [new file with mode: 0644]
src/battle/Capsule.h [new file with mode: 0644]
src/battle/NumberAnimation.cpp
src/battle/TargetSelection.cpp
src/battle/TargetSelection.h
src/battle/fwd.h
src/battle/states/PerformAttacks.cpp
src/battle/states/PerformAttacks.h
src/common/Capsule.cpp [new file with mode: 0644]
src/common/Capsule.h [new file with mode: 0644]
src/common/GameState.cpp
src/common/GameState.h
src/common/Stats.h
src/common/fwd.h
src/graphics/Animation.cpp
src/graphics/Animation.h
src/graphics/ComplexAnimation.cpp
src/graphics/ComplexAnimation.h
src/graphics/Font.cpp
src/graphics/Menu.cpp
src/graphics/Menu.h
src/graphics/SimpleAnimation.cpp
src/graphics/SimpleAnimation.h
src/loader/Caster.cpp
src/loader/Caster.h
src/main.cpp
src/map/MapState.cpp
src/menu/CapsuleChangeMenu.cpp [new file with mode: 0644]
src/menu/CapsuleChangeMenu.h [new file with mode: 0644]
src/menu/CapsuleFeedMenu.cpp [new file with mode: 0644]
src/menu/CapsuleFeedMenu.h [new file with mode: 0644]
src/menu/CapsuleMenu.cpp [new file with mode: 0644]
src/menu/CapsuleMenu.h [new file with mode: 0644]
src/menu/CapsuleNameMenu.cpp [new file with mode: 0644]
src/menu/CapsuleNameMenu.h [new file with mode: 0644]
src/menu/ConfigMenu.cpp
src/menu/InventoryMenu.cpp
src/menu/PartyMenu.cpp
src/menu/Resources.cpp
src/menu/Resources.h
src/menu/ScenarioMenu.cpp
src/menu/SpellMenu.cpp
src/menu/fwd.h
test-data/capsulebg.png [new file with mode: 0644]
test-data/capsules.l2h [new file with mode: 0644]
test-data/capsules.l2s [new file with mode: 0644]
test-data/flash.png [new file with mode: 0644]
test-data/test.l2s

diff --git a/l2e.cbp b/l2e.cbp
index 33396a0b26933b85b4dd236feac6a6876cc54726..64f428d99f9a85cb1cdd955bad0b71bec476c544 100644 (file)
--- a/l2e.cbp
+++ b/l2e.cbp
@@ -11,7 +11,7 @@
                                <Option object_output="obj\W32_Debug\" />
                                <Option type="1" />
                                <Option compiler="gcc" />
-                               <Option parameters="test-data/constants.l2s  test-data/ikaris.l2s  test-data/items.l2s  test-data/maps.l2s  test-data/spells.l2s  test-data/test.l2s" />
+                               <Option parameters="test-data/capsules.l2s  test-data/constants.l2s  test-data/ikaris.l2s  test-data/items.l2s  test-data/maps.l2s  test-data/spells.l2s  test-data/test.l2s" />
                                <Option projectLinkerOptionsRelation="2" />
                                <Compiler>
                                        <Add option="-g" />
@@ -30,7 +30,7 @@
                                <Option object_output="obj\W32\" />
                                <Option type="1" />
                                <Option compiler="gcc" />
-                               <Option parameters="test-data/constants.l2s  test-data/ikaris.l2s  test-data/items.l2s  test-data/maps.l2s  test-data/spells.l2s  test-data/test.l2s" />
+                               <Option parameters="test-data/capsules.l2s  test-data/constants.l2s  test-data/ikaris.l2s  test-data/items.l2s  test-data/maps.l2s  test-data/spells.l2s  test-data/test.l2s" />
                                <Option projectLinkerOptionsRelation="2" />
                                <Compiler>
                                        <Add option="-O3" />
@@ -68,6 +68,8 @@
                <Unit filename="src\battle\AttackTypeMenu.h" />
                <Unit filename="src\battle\BattleState.cpp" />
                <Unit filename="src\battle\BattleState.h" />
+               <Unit filename="src\battle\Capsule.cpp" />
+               <Unit filename="src\battle\Capsule.h" />
                <Unit filename="src\battle\Hero.cpp" />
                <Unit filename="src\battle\Hero.h" />
                <Unit filename="src\battle\HeroTag.cpp" />
                <Unit filename="src\battle\states\SelectTarget.h" />
                <Unit filename="src\battle\states\SwapHeroes.cpp" />
                <Unit filename="src\battle\states\SwapHeroes.h" />
+               <Unit filename="src\common\Capsule.cpp" />
+               <Unit filename="src\common\Capsule.h" />
                <Unit filename="src\common\GameConfig.cpp" />
                <Unit filename="src\common\GameConfig.h" />
                <Unit filename="src\common\GameState.cpp" />
                <Unit filename="src\map\Trigger.cpp" />
                <Unit filename="src\map\Trigger.h" />
                <Unit filename="src\map\fwd.h" />
+               <Unit filename="src\menu\CapsuleChangeMenu.cpp" />
+               <Unit filename="src\menu\CapsuleChangeMenu.h" />
+               <Unit filename="src\menu\CapsuleFeedMenu.cpp" />
+               <Unit filename="src\menu\CapsuleFeedMenu.h" />
+               <Unit filename="src\menu\CapsuleNameMenu.cpp" />
+               <Unit filename="src\menu\CapsuleNameMenu.h" />
+               <Unit filename="src\menu\CapsuleMenu.cpp" />
+               <Unit filename="src\menu\CapsuleMenu.h" />
                <Unit filename="src\menu\ChangeHero.cpp" />
                <Unit filename="src\menu\ChangeHero.h" />
                <Unit filename="src\menu\ConfigMenu.cpp" />
index 8577976ce708d6eeb16a13fe752e6998af54df9c..b73e4203b54ef9f710867b5008b3bd636dc36e82 100644 (file)
@@ -1,8 +1,12 @@
 #ifndef BATTLE_ATTACKCHOICE_H_
 #define BATTLE_ATTACKCHOICE_H_
 
+namespace common {
+       class Item;
+       class Spell;
+}
+
 #include "TargetSelection.h"
-#include "../common/fwd.h"
 
 namespace battle {
 
index 36b4af53752714d58d1fc356230709b2aeaec988..085a85371530678e0d578fa1fb8560aeb3299382 100644 (file)
@@ -47,6 +47,10 @@ void BattleState::AddHero(const Hero &h) {
        ++numHeroes;
 }
 
+void BattleState::SetCapsule(const Capsule &c) {
+       capsule = c;
+}
+
 void BattleState::NextHero() {
        ++activeHero;
        while (activeHero < numHeroes && heroes[activeHero].Health() == 0) {
@@ -83,6 +87,8 @@ void BattleState::OnEnterState(SDL_Surface *screen) {
                smallHeroTags[i] = SmallHeroTag(this, i);
        }
 
+       capsule.Position() = heroesLayout->CalculatePosition(4, background->w, background->h);
+
        for (int i(0); i < int(monsters.size()); ++i) {
                monsters[i].Position() = monstersLayout->CalculatePosition(i, background->w, background->h);
        }
@@ -171,9 +177,7 @@ class OrderCompare {
        public:
                OrderCompare(BattleState *battle) : battle(battle) { }
                bool operator ()(const BattleState::Order &lhs, const BattleState::Order &rhs) {
-                       int lagl(lhs.isMonster ? battle->MonsterAt(lhs.index).GetStats().Agility() : battle->HeroAt(lhs.index).GetStats().Agility());
-                       int ragl(rhs.isMonster ? battle->MonsterAt(rhs.index).GetStats().Agility() : battle->HeroAt(rhs.index).GetStats().Agility());
-                       return lagl > ragl;
+                       return lhs.GetStats(*battle).Agility() > rhs.GetStats(*battle).Agility();
                }
        private:
                BattleState *battle;
@@ -182,12 +186,15 @@ class OrderCompare {
 void BattleState::CalculateAttackOrder() {
        attackOrder.reserve(monsters.size() + NumHeroes());
        for (int i(0); i < NumHeroes(); ++i) {
-               attackOrder.push_back(Order(i, false));
+               attackOrder.push_back(Order(Order::HERO, i));
        }
        for (vector<Monster>::size_type i(0), end(monsters.size()); i < end; ++i) {
-               attackOrder.push_back(Order(i, true));
+               attackOrder.push_back(Order(Order::MONSTER, i));
                MonsterAt(i).GetAttackChoice() = AttackChoice(this);
        }
+       if (capsule.Active() && capsule.Health() > 0) {
+               attackOrder.push_back(Order(Order::CAPSULE));
+       }
        std::sort(attackOrder.begin(), attackOrder.end(), OrderCompare(this));
 }
 
@@ -198,10 +205,12 @@ void BattleState::NextAttack() {
        }
        ++attackCursor;
        while (attackCursor < int(attackOrder.size())) {
-               if (attackOrder[attackCursor].isMonster) {
+               if (attackOrder[attackCursor].IsMonster()) {
                        if (MonsterAt(attackOrder[attackCursor].index).Health() > 0) break;
-               } else {
+               } else if (attackOrder[attackCursor].IsHero()) {
                        if (HeroAt(attackOrder[attackCursor].index).Health() > 0) break;
+               } else {
+                       if (capsule.Active() && capsule.Health() > 0) break;
                }
                ++attackCursor;
        }
@@ -213,23 +222,20 @@ bool BattleState::AttacksFinished() const {
 }
 
 void BattleState::CalculateDamage() {
-       if (CurrentAttack().isMonster) {
+       if (CurrentAttack().IsMonster()) {
                DecideMonsterAttack(MonsterAt(CurrentAttack().index));
+       } else if (CurrentAttack().IsCapsule()) {
+               DecideCapsuleAttack();
        }
-       AttackChoice &ac(CurrentAttack().isMonster ? MonsterAt(CurrentAttack().index).GetAttackChoice() : HeroAt(CurrentAttack().index).GetAttackChoice());
+       AttackChoice &ac = CurrentAttack().GetAttackChoice(*this);
        if (ac.GetType() == AttackChoice::DEFEND) return;
        TargetSelection &ts(ac.Selection());
 
-       if (CurrentAttack().isMonster) {
-               const Stats &attackerStats(MonsterAt(CurrentAttack().index).GetStats());
-               CalculateDamage(attackerStats, ts);
-       } else {
-               const Stats &attackerStats(HeroAt(CurrentAttack().index).GetStats());
-               CalculateDamage(attackerStats, ts);
-       }
+       const Stats &attackerStats = CurrentAttack().GetStats(*this);
+       CalculateDamage(attackerStats, ts);
 }
 
-void BattleState::DecideMonsterAttack(Monster &m) const {
+void BattleState::DecideMonsterAttack(Monster &m) {
        AttackChoice &ac(m.GetAttackChoice());
        TargetSelection &ts(ac.Selection());
        ac.Reset();
@@ -243,6 +249,46 @@ void BattleState::DecideMonsterAttack(Monster &m) const {
        ts.Select(target);
 }
 
+void BattleState::DecideCapsuleAttack() {
+       AttackChoice &ac(capsule.GetAttackChoice());
+       TargetSelection &ts(ac.Selection());
+       ac.Reset();
+       int target(rand() % monsters.size());
+       while (!MonsterPositionOccupied(target)) {
+               target = rand() % monsters.size();
+       }
+       ac.SetType(AttackChoice::SWORD);
+       ts.SelectMonsters();
+       ts.SetSingle();
+       ts.Select(target);
+}
+
+AttackChoice &BattleState::Order::GetAttackChoice(BattleState &b) const {
+       switch (by) {
+               case HERO:
+                       return b.HeroAt(index).GetAttackChoice();
+               case CAPSULE:
+                       return b.GetCapsule().GetAttackChoice();
+               case MONSTER:
+                       return b.MonsterAt(index).GetAttackChoice();
+               default:
+                       throw std::runtime_error("invalid case in BttleStats::Order::GetAttackChoice()");
+       }
+}
+
+Stats &BattleState::Order::GetStats(BattleState &b) const {
+       switch (by) {
+               case HERO:
+                       return b.HeroAt(index).GetStats();
+               case CAPSULE:
+                       return b.GetCapsule().GetStats();
+               case MONSTER:
+                       return b.MonsterAt(index).GetStats();
+               default:
+                       throw std::runtime_error("invalid case in BttleStats::Order::GetAttackChoice()");
+       }
+}
+
 void BattleState::CalculateDamage(const Stats &attackerStats, TargetSelection &ts) const {
        bool hitSome(false);
        if (ts.TargetsMonsters()) {
@@ -298,7 +344,7 @@ Uint16 BattleState::CalculateDamage(const Stats &attacker, const Stats &defender
 
 void BattleState::ApplyDamage() {
        if (attackCursor < 0) return;
-       AttackChoice &ac(CurrentAttack().isMonster ? MonsterAt(CurrentAttack().index).GetAttackChoice() : HeroAt(CurrentAttack().index).GetAttackChoice());
+       AttackChoice &ac = CurrentAttack().GetAttackChoice(*this);
        TargetSelection &ts(ac.Selection());
        if (ts.TargetsMonsters()) {
                for (int i(0); i < MaxMonsters(); ++i) {
@@ -322,11 +368,7 @@ void BattleState::ApplyDamage() {
 }
 
 AttackChoice &BattleState::CurrentAttackAttackChoice() {
-       if (CurrentAttack().isMonster) {
-               return MonsterAt(CurrentAttack().index).GetAttackChoice();
-       } else {
-               return HeroAt(CurrentAttack().index).GetAttackChoice();
-       }
+       return CurrentAttack().GetAttackChoice(*this);
 }
 
 void BattleState::ClearAllAttacks() {
@@ -338,6 +380,7 @@ void BattleState::ClearAllAttacks() {
        for (int i(0); i < MaxMonsters(); ++i) {
                MonsterAt(i).GetAttackChoice() = AttackChoice(this);
        }
+       capsule.GetAttackChoice() = AttackChoice(this);
        attackOrder.clear();
 }
 
@@ -394,6 +437,15 @@ void BattleState::RenderHeroes(SDL_Surface *screen, const Vector<int> &offset) {
        }
 }
 
+void BattleState::RenderCapsule(SDL_Surface *screen, const Vector<int> &offset) {
+       if (!capsule.Active() || capsule.Health() <= 0) return;
+       if (capsule.GetAnimation().Running()) {
+               capsule.GetAnimation().DrawCenter(screen, capsule.Position() + offset);
+       } else {
+               capsule.Sprite()->DrawCenter(screen, capsule.Position() + offset);
+       }
+}
+
 void BattleState::RenderHeroTags(SDL_Surface *screen, const Vector<int> &offset) {
        assert(screen);
        int tagHeight(attackTypeMenu.Height());
index 0f51f237cd2a47138ac222127f269a15f477aca8..1c994e4f88a664c2d572173fd79c156d1daf0687 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "fwd.h"
 #include "AttackTypeMenu.h"
+#include "Capsule.h"
 #include "Hero.h"
 #include "HeroTag.h"
 #include "Monster.h"
@@ -47,6 +48,7 @@ public:
 public:
        void AddMonster(const Monster &);
        void AddHero(const Hero &);
+       void SetCapsule(const Capsule &);
 
 public:
        virtual void HandleEvents(const app::Input &);
@@ -76,6 +78,8 @@ public:
        const HeroTag &HeroTagAt(int index) const { assert(index >= 0 && index < NumHeroes()); return heroTags[index]; }
        const geometry::Vector<int> &HeroTagPositionAt(int index) const { assert(index >= 0 && index < NumHeroes()); return heroTagPositions[index]; }
 
+       Capsule &GetCapsule() { return capsule; }
+
        bool HasChosenAttackType() const { return ActiveHero().GetAttackChoice().GetType() != AttackChoice::UNDECIDED; }
        bool AttackSelectionDone() const { return activeHero >= numHeroes; }
 
@@ -89,10 +93,20 @@ public:
        void SetRunaway() { ranAway = true; }
 
        struct Order {
-               Order(int index, bool isMonster)
-               : index(index), isMonster(isMonster) { }
+               enum Performer {
+                       HERO,
+                       CAPSULE,
+                       MONSTER,
+               };
+               Order(Performer by, int index = 0)
+               : index(index), by(by) { }
+               AttackChoice &GetAttackChoice(BattleState &) const;
+               common::Stats &GetStats(BattleState &) const;
+               bool IsHero() const { return by == HERO; }
+               bool IsCapsule() const { return by == CAPSULE; }
+               bool IsMonster() const { return by == MONSTER; }
                int index;
-               bool isMonster;
+               Performer by;
        };
 
        void CalculateAttackOrder();
@@ -120,6 +134,7 @@ public:
        void RenderBackground(SDL_Surface *screen, const geometry::Vector<int> &offset);
        void RenderMonsters(SDL_Surface *screen, const geometry::Vector<int> &offset);
        void RenderHeroes(SDL_Surface *screen, const geometry::Vector<int> &offset);
+       void RenderCapsule(SDL_Surface *screen, const geometry::Vector<int> &offset);
        void RenderHeroTags(SDL_Surface *screen, const geometry::Vector<int> &offset);
        void RenderSmallHeroTags(SDL_Surface *screen, const geometry::Vector<int> &offset);
 
@@ -134,7 +149,8 @@ private:
 private:
        void LoadInventory();
 
-       void DecideMonsterAttack(Monster &) const;
+       void DecideMonsterAttack(Monster &);
+       void DecideCapsuleAttack();
        void CalculateDamage(const common::Stats &attackerStats, TargetSelection &targets) const;
        Uint16 CalculateDamage(const common::Stats &attacker, const common::Stats &defender) const;
 
@@ -154,6 +170,7 @@ private:
        SmallHeroTag smallHeroTags[4];
        geometry::Vector<int> heroTagPositions[4];
        geometry::Vector<int> smallHeroTagPositions[4];
+       Capsule capsule;
        int numHeroes;
        int activeHero;
        int attackCursor;
diff --git a/src/battle/Capsule.cpp b/src/battle/Capsule.cpp
new file mode 100644 (file)
index 0000000..ef85ae1
--- /dev/null
@@ -0,0 +1,73 @@
+#include "Capsule.h"
+
+#include "../common/Capsule.h"
+
+#include <cassert>
+
+using graphics::Animation;
+using graphics::Sprite;
+
+namespace battle {
+
+Capsule::Capsule(common::Capsule *master)
+: master(master)
+, health(master ? master->MaxHealth() : 0) {
+       if (master) {
+               stats = master->GetStats();
+       }
+}
+
+
+const char *Capsule::Name() const {
+       assert(master);
+       return master->Name();
+}
+
+Uint8 Capsule::Level() const {
+       assert(master);
+       return master->Level();
+}
+
+const Sprite *Capsule::Sprite() {
+       assert(master);
+       return master->BattleSprite();
+}
+
+const Animation *Capsule::MeleeAnimation() const {
+       assert(master);
+       return master->MeleeAnimation();
+}
+
+const Animation *Capsule::AttackAnimation() const {
+       assert(master);
+       return master->AttackAnimation();
+}
+
+const Animation *Capsule::SpellAnimation() const {
+       assert(master);
+       return master->SpellAnimation();
+}
+
+
+Uint16 Capsule::MaxHealth() const {
+       assert(master);
+       return master->MaxHealth();
+}
+
+Uint16 Capsule::Health() const {
+       return health;
+}
+
+int Capsule::RelativeHealth(int max) const {
+       return Health() * max / MaxHealth();
+}
+
+void Capsule::SubtractHealth(int amount) {
+       if (amount > health) {
+               health = 0;
+       } else {
+               health -= amount;
+       }
+}
+
+}
diff --git a/src/battle/Capsule.h b/src/battle/Capsule.h
new file mode 100644 (file)
index 0000000..7438492
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef BATTLE_CAPSULE_H_
+#define BATTLE_CAPSULE_H_
+
+namespace common {
+       class Capsule;
+}
+
+#include "AttackChoice.h"
+#include "../common/Stats.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Animation.h"
+#include "../graphics/fwd.h"
+#include "../graphics/Menu.h"
+
+namespace battle {
+
+class Capsule {
+
+public:
+       Capsule(common::Capsule *master = 0);
+
+public:
+       bool Active() const { return master; }
+
+       const char *Name() const;
+       Uint8 Level() const;
+       const graphics::Sprite *Sprite();
+
+       Uint16 MaxHealth() const;
+       Uint16 Health() const;
+       int RelativeHealth(int max) const;
+       void SubtractHealth(int amount);
+
+       common::Stats &GetStats() { return stats; }
+       const common::Stats &GetStats() const { return stats; }
+
+       graphics::AnimationRunner &GetAnimation() { return animation; }
+       const graphics::AnimationRunner &GetAnimation() const { return animation; }
+       void SetAnimation(const graphics::AnimationRunner &a) { animation = a; }
+
+       const graphics::Animation *MeleeAnimation() const;
+       const graphics::Animation *AttackAnimation() const;
+       const graphics::Animation *SpellAnimation() const;
+
+       geometry::Vector<int> &Position() { return position; }
+       const geometry::Vector<int> &Position() const { return position; }
+
+       AttackChoice &GetAttackChoice() { return attackChoice; }
+       const AttackChoice &GetAttackChoice() const { return attackChoice; }
+
+private:
+       common::Capsule *master;
+
+       int health;
+
+       graphics::AnimationRunner animation;
+       geometry::Vector<int> position;
+       AttackChoice attackChoice;
+       common::Stats stats;
+
+};
+
+}
+
+#endif /* BATTLE_CAPSULE_H_ */
index 166ace69f411db14cda4d1ae7cbecdbb5cf51d1a..63d16562f1324822d8c8eac50aa6580b54e88611 100644 (file)
@@ -1,6 +1,7 @@
 #include "NumberAnimation.h"
 
 #include "../geometry/Vector.h"
+#include "../graphics/Sprite.h"
 
 using app::State;
 using geometry::Vector;
index 42a88e4673b0444129fac3587564f090a578ee55..961f57cf845cdf703014c83345dc569803a231f9 100644 (file)
@@ -67,6 +67,7 @@ void TargetSelection::MoveUp() {
 }
 
 void TargetSelection::MoveRight() {
+       assert(battle);
        if (TargetsMonsters()) {
                cursor = (cursor + 1) % battle->MaxMonsters();
                while (!battle->MonsterPositionOccupied(cursor)) {
@@ -78,6 +79,7 @@ void TargetSelection::MoveRight() {
 }
 
 void TargetSelection::MoveDown() {
+       assert(battle);
        if (TargetsMonsters()) {
                SelectHeroes();
                return;
@@ -89,6 +91,7 @@ void TargetSelection::MoveDown() {
 }
 
 void TargetSelection::MoveLeft() {
+       assert(battle);
        if (TargetsMonsters()) {
                cursor = (cursor + battle->MaxMonsters() - 1) % battle->MaxMonsters();
                FindNextEnemy();
@@ -98,6 +101,7 @@ void TargetSelection::MoveLeft() {
 }
 
 void TargetSelection::FindNextEnemy() {
+       assert(battle);
        int start(cursor);
        while (!battle->MonsterPositionOccupied(cursor)) {
                cursor = (cursor + battle->MaxMonsters() - 1) % battle->MaxMonsters();
index dc03285ced2c7884b8f67bdb412d1c896cbabe13..ba5317899cfeb6ef63196b9d61de74d5975da659 100644 (file)
@@ -1,13 +1,16 @@
 #ifndef BATTLE_TARGETSELECTION_H_
 #define BATTLE_TARGETSELECTION_H_
 
-#include "fwd.h"
-#include "../common/fwd.h"
+namespace common {
+       class TargetingMode;
+}
 
 #include <vector>
 
 namespace battle {
 
+class BattleState;
+
 class TargetSelection {
 
 public:
index 73827d891a4d234188a8eae427b0ed31a47bdee2..959b85650e8aa833f8592fd6a17a082c9aff7d36 100644 (file)
@@ -6,6 +6,7 @@ namespace battle {
 class AttackChoice;
 class AttackTypeMenu;
 class BattleState;
+class Capsule;
 class Hero;
 class HeroTag;
 class Monster;
index 665756fcf38d8639cbe2fcbf8216ab540f0fca95..43414eb89a60d86e7964ad2f63861da7818f5b8e 100644 (file)
@@ -10,6 +10,7 @@
 #include "../BattleState.h"
 #include "../Hero.h"
 #include "../Monster.h"
+#include "../TargetSelection.h"
 #include "../../app/Application.h"
 #include "../../app/Input.h"
 #include "../../common/Ikari.h"
@@ -66,13 +67,20 @@ void PerformAttacks::HandleEvents(const Input &input) {
 
        battle->CalculateDamage();
 
-       if (battle->CurrentAttack().isMonster) {
+       if (battle->CurrentAttack().IsMonster()) {
                Monster &monster(battle->MonsterAt(battle->CurrentAttack().index));
                titleBarText = monster.Name();
                targetAnimation = AnimationRunner(monster.MeleeAnimation());
                moveAnimation = AnimationRunner(monster.AttackAnimation());
                monster.SetAnimation(moveAnimation);
                AddNumberAnimations(battle->MonsterAt(battle->CurrentAttack().index).GetAttackChoice().Selection());
+       } else if (battle->CurrentAttack().IsCapsule()) {
+               Capsule &capsule(battle->GetCapsule());
+               titleBarText = capsule.Name();
+               targetAnimation = AnimationRunner(capsule.MeleeAnimation());
+               moveAnimation = AnimationRunner(capsule.AttackAnimation());
+               capsule.SetAnimation(moveAnimation);
+               AddNumberAnimations(capsule.GetAttackChoice().Selection());
        } else {
                Hero &hero(battle->HeroAt(battle->CurrentAttack().index));
                const AttackChoice &ac(battle->HeroAt(battle->CurrentAttack().index).GetAttackChoice());
@@ -121,10 +129,12 @@ void PerformAttacks::HandleEvents(const Input &input) {
        if (titleBarText) titleBarTimer = GraphicsTimers().StartCountdown(850);
        if (moveAnimation.Valid()) {
                moveAnimation.Start(*this);
-               if (battle->CurrentAttack().isMonster) {
+               if (battle->CurrentAttack().IsMonster()) {
                        battle->MonsterAt(battle->CurrentAttack().index).SetAnimation(moveAnimation);
-               } else {
+               } else if (battle->CurrentAttack().IsHero()) {
                        battle->HeroAt(battle->CurrentAttack().index).SetAnimation(moveAnimation);
+               } else {
+                       battle->GetCapsule().SetAnimation(moveAnimation);
                }
        }
        if (targetAnimation.Valid()) {
@@ -194,7 +204,7 @@ bool PerformAttacks::HasAnimationsRunning() const {
 void PerformAttacks::ResetAnimation() {
        if (moveAnimation.Valid()) {
                moveAnimation.Clear();
-               if (!battle->CurrentAttack().isMonster) {
+               if (!battle->CurrentAttack().IsMonster()) {
                        battle->HeroAt(battle->CurrentAttack().index).GetAnimation().Clear();
                }
        }
@@ -216,6 +226,7 @@ void PerformAttacks::Render(SDL_Surface *screen) {
        battle->RenderBackground(screen, offset);
        battle->RenderMonsters(screen, offset);
        battle->RenderHeroes(screen, offset);
+       battle->RenderCapsule(screen, offset);
        battle->RenderSmallHeroTags(screen, offset);
        RenderTitleBar(screen, offset);
        RenderNumbers(screen, offset);
index 06ce1b89cd93329719988b561b272fcf1c6982e9..b8623698f5734715b3818c0fe6d375fa9a1b437c 100644 (file)
@@ -10,7 +10,6 @@
 
 #include "../../app/State.h"
 
-#include "../BattleState.h"
 #include "../NumberAnimation.h"
 #include "../../geometry/Vector.h"
 #include "../../graphics/Animation.h"
@@ -19,6 +18,9 @@
 
 namespace battle {
 
+class BattleState;
+class TargetSelection;
+
 class PerformAttacks
 : public app::State {
 
diff --git a/src/common/Capsule.cpp b/src/common/Capsule.cpp
new file mode 100644 (file)
index 0000000..8fa1ca9
--- /dev/null
@@ -0,0 +1,187 @@
+#include "Capsule.h"
+
+#include "../common/Spell.h"
+#include "../common/Stats.h"
+#include "../graphics/Animation.h"
+#include "../graphics/Sprite.h"
+#include "../loader/Interpreter.h"
+#include "../loader/TypeDescription.h"
+
+#include <cassert>
+
+using common::Spell;
+using common::Stats;
+using graphics::Animation;
+using graphics::Sprite;
+using loader::FieldDescription;
+using loader::Interpreter;
+using loader::TypeDescription;
+
+namespace common {
+
+Capsule::Capsule()
+: name("")
+, alignment("")
+
+, maxHealth(0)
+
+, level(1)
+, experience(0)
+
+, levelLadder(0)
+, numLevels(0)
+
+, classes(0)
+, numClasses(0)
+, curClass(0)
+, maxClass(0) {
+
+}
+
+
+const char *Capsule::ClassName() const {
+       return GetClass().name;
+}
+
+const char *Capsule::Tribe() const {
+       return GetClass().tribe;
+}
+
+const Spell *Capsule::Attack1() const {
+       return GetClass().attacks[0];
+}
+
+const Spell *Capsule::Attack2() const {
+       return GetClass().attacks[1];
+}
+
+const Spell *Capsule::Attack3() const {
+       return GetClass().attacks[2];
+}
+
+
+Uint16 Capsule::MaxHealth() const {
+       return maxHealth + GetClass().healthBoost;
+}
+
+
+Stats Capsule::GetStats() const {
+       return stats + GetClass().statBoost;
+}
+
+int Capsule::NextLevel() const {
+       int levelOffset(Level() - 1);
+       if (levelOffset < numLevels) {
+               return levelLadder[levelOffset] - Experience();
+       } else {
+               return 0;
+       }
+}
+
+
+Sprite *Capsule::BattleSprite() {
+       return GetClass().battleSprite;
+}
+
+const Sprite *Capsule::BattleSprite() const {
+       return GetClass().battleSprite;
+}
+
+Animation *Capsule::MeleeAnimation() {
+       return GetClass().meleeAnimation;
+}
+
+Animation *Capsule::AttackAnimation() {
+       return GetClass().attackAnimation;
+}
+
+Animation *Capsule::SpellAnimation() {
+       return GetClass().spellAnimation;
+}
+
+
+Capsule::Class &Capsule::GetClass() {
+       assert(classes && curClass < numClasses);
+       return classes[curClass];
+}
+
+const Capsule::Class &Capsule::GetClass() const {
+       assert(classes && curClass < numClasses);
+       return classes[curClass];
+}
+
+
+Capsule::Class::Class()
+: name(0)
+, tribe(0)
+, battleSprite(0)
+, meleeAnimation(0)
+, attackAnimation(0)
+, spellAnimation(0)
+
+, healthBoost(0) {
+       attacks[0] = 0;
+       attacks[1] = 0;
+       attacks[2] = 0;
+}
+
+
+void Capsule::CreateTypeDescription() {
+       Capsule c;
+
+       TypeDescription &td(TypeDescription::Create(TYPE_ID, "Capsule"));
+       td.SetConstructor(&Construct);
+       td.SetSize(sizeof(Capsule));
+
+       td.AddField("name", FieldDescription(((char *)&c.name) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("alignment", FieldDescription(((char *)&c.alignment) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
+
+       td.AddField("maxHealth", FieldDescription(((char *)&c.maxHealth) - ((char *)&c), Interpreter::NUMBER_ID));
+
+       td.AddField("stats", FieldDescription(((char *)&c.stats) - ((char *)&c), Stats::TYPE_ID));
+
+       td.AddField("level", FieldDescription(((char *)&c.level) - ((char *)&c), Interpreter::NUMBER_ID));
+       td.AddField("experience", FieldDescription(((char *)&c.experience) - ((char *)&c), Interpreter::NUMBER_ID));
+
+       td.AddField("ladder", FieldDescription(((char *)&c.levelLadder) - ((char *)&c), Interpreter::NUMBER_ID).SetReferenced().SetAggregate());
+
+       td.AddField("classes", FieldDescription(((char *)&c.classes) - ((char *)&c), Class::TYPE_ID).SetReferenced().SetAggregate());
+       td.AddField("class", FieldDescription(((char *)&c.curClass) - ((char *)&c), Interpreter::NUMBER_ID));
+       td.AddField("maxClass", FieldDescription(((char *)&c.maxClass) - ((char *)&c), Interpreter::NUMBER_ID));
+
+       Class::CreateTypeDescription();
+}
+
+void Capsule::Construct(void *data) {
+       new (data) Capsule;
+}
+
+
+void Capsule::Class::CreateTypeDescription() {
+       Class c;
+
+       TypeDescription &td(TypeDescription::Create(TYPE_ID, "CapsuleClass"));
+       td.SetConstructor(&Construct);
+       td.SetSize(sizeof(Class));
+
+       td.AddField("name", FieldDescription(((char *)&c.name) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("tribe", FieldDescription(((char *)&c.tribe) - ((char *)&c), Interpreter::STRING_ID).SetReferenced());
+
+       td.AddField("attack1", FieldDescription(((char *)&c.attacks[0]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
+       td.AddField("attack2", FieldDescription(((char *)&c.attacks[1]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
+       td.AddField("attack3", FieldDescription(((char *)&c.attacks[2]) - ((char *)&c), Spell::TYPE_ID).SetReferenced());
+
+       td.AddField("battleSprite", FieldDescription(((char *)&c.battleSprite) - ((char *)&c), Sprite::TYPE_ID).SetReferenced());
+       td.AddField("meleeAnimation", FieldDescription(((char *)&c.meleeAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
+       td.AddField("attackAnimation", FieldDescription(((char *)&c.attackAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
+       td.AddField("spellAnimation", FieldDescription(((char *)&c.spellAnimation) - ((char *)&c), Animation::TYPE_ID).SetReferenced());
+
+       td.AddField("healthBoost", FieldDescription(((char *)&c.healthBoost) - ((char *)&c), Interpreter::NUMBER_ID));
+       td.AddField("statBoost", FieldDescription(((char *)&c.statBoost) - ((char *)&c), Stats::TYPE_ID));
+}
+
+void Capsule::Class::Construct(void *data) {
+       new (data) Capsule::Class;
+}
+
+}
diff --git a/src/common/Capsule.h b/src/common/Capsule.h
new file mode 100644 (file)
index 0000000..b1039fa
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef COMMON_CAPSULE_H_
+#define COMMON_CAPSULE_H_
+
+namespace graphics {
+       class Animation;
+       class Sprite;
+}
+
+#include "../common/Stats.h"
+
+#include <SDL.h>
+
+namespace common {
+
+class Spell;
+
+class Capsule {
+
+public:
+       static const int TYPE_ID = 307;
+
+public:
+       Capsule();
+
+       const char *Name() const { return name; }
+       const char *ClassName() const;
+       const char *Alignment() const { return alignment; }
+       const char *Tribe() const;
+       const Spell *Attack1() const;
+       const Spell *Attack2() const;
+       const Spell *Attack3() const;
+
+       Uint16 MaxHealth() const;
+
+       Stats GetStats() const;
+
+       Uint8 Level() const { return level; }
+       int Experience() const { return experience; }
+       int NextLevel() const;
+
+       graphics::Sprite *BattleSprite();
+       const graphics::Sprite *BattleSprite() const;
+       graphics::Animation *MeleeAnimation();
+       graphics::Animation *AttackAnimation();
+       graphics::Animation *SpellAnimation();
+
+       static void CreateTypeDescription();
+       static void Construct(void *);
+
+private:
+       struct Class {
+               static const int TYPE_ID = 308;
+
+               Class();
+
+               static void CreateTypeDescription();
+               static void Construct(void *);
+
+               const char *name;
+               const char *tribe;
+               Spell *attacks[3];
+               graphics::Sprite *battleSprite;
+               graphics::Animation *meleeAnimation;
+               graphics::Animation *attackAnimation;
+               graphics::Animation *spellAnimation;
+
+               int healthBoost;
+               Stats statBoost;
+       };
+
+       Class &GetClass();
+       const Class &GetClass() const;
+
+       const char *name;
+       const char *alignment;
+
+       int maxHealth;
+
+       Stats stats;
+
+       int level;
+       int experience;
+
+       int *levelLadder;
+       int numLevels;
+
+       Class *classes;
+       int numClasses, curClass, maxClass;
+
+};
+
+}
+
+#endif /* COMMON_CAPSULE_H_ */
index 2d9fd3e72ff6ac00f7a491d73dd165a44ec1ac8f..b08724bd8ee1f7048bbe66feded18afecba9a6c3 100644 (file)
@@ -4,6 +4,7 @@ namespace common {
 
 GameState::GameState()
 : partySize(1)
+, capsule(0)
 , money(0)
 , time(0)
 , messageSpeed(MESSAGE_SPEED_NORMAL)
index bcaea523ab497d3cc376a4e87cdea7b5010c37ed..4e2570d8fb8ea90c336169cb8e6a6b1c2ebf161e 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef COMMON_GAMESTATE_H_
 #define COMMON_GAMESTATE_H_
 
+#include "Capsule.h"
 #include "Hero.h"
 #include "Inventory.h"
 
@@ -16,6 +17,9 @@ struct GameState {
        Hero *party[4];
        int partySize;
 
+       Capsule capsules[7];
+       Capsule *capsule;
+
        Inventory inventory;
 
        Uint32 money;
index 3d813120381c5938d3e42bd5b4897bc7294f1775..6374c3540d5e43dc4861c1257f8966a27cf6d6e8 100644 (file)
@@ -45,6 +45,18 @@ private:
 
 };
 
+
+inline Stats operator +(const Stats &lhs, const Stats &rhs) {
+       return Stats(
+                       lhs.Attack() + rhs.Attack(),
+                       lhs.Defense() + rhs.Defense(),
+                       lhs.Strength() + rhs.Strength(),
+                       lhs.Agility() + rhs.Agility(),
+                       lhs.Intelligence() + rhs.Intelligence(),
+                       lhs.Gut() + rhs.Gut(),
+                       lhs.MagicResistance() + rhs.MagicResistance());
+}
+
 }
 
 #endif /* COMMON_STATS_H_ */
index 5b9be8200172f22cf6359fb37f433ae6b9b3bb7e..209eaa158b083d87fd0d4f77ae79716d077215b3 100644 (file)
@@ -3,6 +3,7 @@
 
 namespace common {
 
+class Capsule;
 struct GameConfig;
 struct GameState;
 class Hero;
index d4a17d950e127ed0f0316c37b0bd2ce8dba5bd58..f55a9aa9fc6520b7c46e1532f8c83fccd9dece55 100644 (file)
@@ -1,9 +1,13 @@
 #include "Animation.h"
 
 #include "Sprite.h"
+#include "../app/Application.h"
+#include "../app/State.h"
 #include "../loader/Interpreter.h"
 #include "../loader/TypeDescription.h"
 
+#include <cassert>
+
 using loader::FieldDescription;
 using loader::Interpreter;
 using loader::TypeDescription;
@@ -22,4 +26,69 @@ void Animation::AddFields(TypeDescription &td, const Animation &a, std::ptrdiff_
        td.AddField("repeat", FieldDescription(((char *)&a.repeat) - ((char *)&a) - offset, Interpreter::BOOLEAN_ID).SetDescription("whether the animation should start over at the beginning after reaching the last frame"));
 }
 
+
+void AnimationRunner::Start(app::State &ctrl) {
+       assert(animation);
+       timer = ctrl.GraphicsTimers().StartInterval(animation->FrameTime());
+}
+
+void AnimationRunner::Start(app::Application &ctrl) {
+       assert(animation);
+       timer = ctrl.GlobalTimers().StartInterval(animation->FrameTime());
+}
+
+void AnimationRunner::Stop() {
+       timer = app::Timer<Uint32>();
+}
+
+bool AnimationRunner::Started() const {
+       return timer.Started();
+}
+
+bool AnimationRunner::Running() const {
+       return animation
+                       && timer.Running()
+                       && (animation->Repeat()
+                                       || timer.Iteration() < animation->NumFrames());
+}
+
+bool AnimationRunner::Finished() const {
+       return Started() && !Running();
+}
+
+bool AnimationRunner::JustFinished() const {
+       return animation
+                       && timer.JustHit()
+                       && timer.Iteration() == animation->NumFrames();
+}
+
+
+void AnimationRunner::Draw(SDL_Surface *dest, geometry::Vector<int> position) const {
+       GetSprite()->Draw(dest,
+                       position + animation->Offset(Frame()),
+                       animation->Col(Frame()) + ColOffset(),
+                       animation->Row(Frame()) + RowOffset());
+}
+
+void AnimationRunner::DrawTopRight(SDL_Surface *dest, geometry::Vector<int> position) const {
+       geometry::Vector<int> offset(-GetSprite()->Width(), 0);
+       Draw(dest, position + offset);
+}
+
+void AnimationRunner::DrawCenter(SDL_Surface *dest, geometry::Vector<int> position) const {
+       Draw(dest, position - (GetSprite()->Size() / 2));
+}
+
+void AnimationRunner::DrawCenterBottom(SDL_Surface *dest, geometry::Vector<int> position) const {
+       geometry::Vector<int> offset(-GetSprite()->Width() / 2, -GetSprite()->Height());
+       Draw(dest, position + offset);
+}
+
+int AnimationRunner::Frame() const {
+       return Running()
+                       ? ((timer.Iteration() + frameShift) % animation->NumFrames())
+                       : 0;
+}
+
+
 }
index 50330957ab9d28412cb1314c70596f86d75ead1f..79bfa852b887f02316afad317a5bfdd912348eb5 100644 (file)
@@ -1,11 +1,15 @@
 #ifndef GRAPHICS_ANIMATION_H_
 #define GRAPHICS_ANIMATION_H_
 
-#include "Sprite.h"
-#include "../app/Application.h"
-#include "../app/State.h"
+namespace app {
+       class Application;
+       class State;
+}
+namespace loader {
+       class TypeDescription;
+}
+
 #include "../app/Timer.h"
-#include "../loader/fwd.h"
 #include "../geometry/Vector.h"
 
 #include <memory>
@@ -13,6 +17,8 @@
 
 namespace graphics {
 
+class Sprite;
+
 class Animation {
 
 public:
@@ -64,27 +70,13 @@ public:
        bool Valid() const { return animation; }
        void Clear() { animation = 0; timer = app::Timer<Uint32>(); }
 
-       void Start(app::State &ctrl) {
-               timer = ctrl.GraphicsTimers().StartInterval(animation->FrameTime());
-       }
-       void Start(app::Application &ctrl) {
-               timer = ctrl.GlobalTimers().StartInterval(animation->FrameTime());
-       }
-       void Stop() {
-               timer = app::Timer<Uint32>();
-       }
-       bool Started() const {
-               return timer.Started();
-       }
-       bool Running() const {
-               return timer.Running() && (animation->Repeat() || timer.Iteration() < animation->NumFrames());
-       }
-       bool Finished() const {
-               return Started() && !Running();
-       }
-       bool JustFinished() const {
-               return timer.JustHit() && timer.Iteration() == animation->NumFrames();
-       }
+       void Start(app::State &ctrl);
+       void Start(app::Application &ctrl);
+       void Stop();
+       bool Started() const;
+       bool Running() const;
+       bool Finished() const;
+       bool JustFinished() const;
 
        const app::Timer<Uint32> &GetTimer() { return timer; }
 
@@ -101,22 +93,12 @@ public:
        void ChangeSprite(const Sprite *s) { sprite = s; }
        const Sprite *GetSprite() const { return sprite ? sprite : animation->GetSprite(); }
 
-       void Draw(SDL_Surface *dest, geometry::Vector<int> position) const {
-               GetSprite()->Draw(dest, position + animation->Offset(Frame()), animation->Col(Frame()) + ColOffset(), animation->Row(Frame()) + RowOffset());
-       }
-       void DrawTopRight(SDL_Surface *dest, geometry::Vector<int> position) const {
-               geometry::Vector<int> offset(-GetSprite()->Width(), 0);
-               Draw(dest, position + offset);
-       }
-       void DrawCenter(SDL_Surface *dest, geometry::Vector<int> position) const {
-               Draw(dest, position - (GetSprite()->Size() / 2));
-       }
-       void DrawCenterBottom(SDL_Surface *dest, geometry::Vector<int> position) const {
-               geometry::Vector<int> offset(-GetSprite()->Width() / 2, -GetSprite()->Height());
-               Draw(dest, position + offset);
-       }
-
-       int Frame() const { return Running() ? ((timer.Iteration() + frameShift) % animation->NumFrames()) : 0; }
+       void Draw(SDL_Surface *dest, geometry::Vector<int> position) const;
+       void DrawTopRight(SDL_Surface *dest, geometry::Vector<int> position) const;
+       void DrawCenter(SDL_Surface *dest, geometry::Vector<int> position) const;
+       void DrawCenterBottom(SDL_Surface *dest, geometry::Vector<int> position) const;
+
+       int Frame() const;
 
 private:
        const Animation *animation;
index f999c4af18f748d7129e71056074aa40b49e586b..bd2eaf8732b7044b28a1d770d87539301a4f474a 100644 (file)
@@ -3,12 +3,47 @@
 #include "../loader/Interpreter.h"
 #include "../loader/TypeDescription.h"
 
+using geometry::Vector;
 using loader::FieldDescription;
 using loader::Interpreter;
 using loader::TypeDescription;
 
 namespace graphics {
 
+ComplexAnimation::ComplexAnimation()
+: frames(0)
+, numFrames(0) {
+
+}
+
+ComplexAnimation::ComplexAnimation(
+               const Sprite *sprite,
+               int frameTime,
+               bool repeat)
+: Animation(sprite, frameTime, repeat)
+, frames(0)
+, numFrames(0) {
+
+}
+
+
+int ComplexAnimation::NumFrames() const {
+       return numFrames;
+}
+
+int ComplexAnimation::Col(int frame) const {
+       return frames[frame].col;
+}
+
+int ComplexAnimation::Row(int frame) const {
+       return frames[frame].row;
+}
+
+Vector<int> ComplexAnimation::Offset(int frame) const {
+       return frames[frame].disposition;
+}
+
+
 void ComplexAnimation::CreateTypeDescription() {
        ComplexAnimation ca;
        Animation *a(&ca);
index f4a5db575d8f657809ffeaf3684b0f7fd2d6f12c..eeeef680d37b558a8a06ebaa226c2b0d9d85ed4d 100644 (file)
@@ -12,9 +12,8 @@ public:
        static const int TYPE_ID = 402;
 
 public:
-       ComplexAnimation() : frames(0), numFrames(0) { }
-       ComplexAnimation(const Sprite *sprite, int frameTime, bool repeat = false)
-       : Animation(sprite, frameTime, repeat), frames(0), numFrames(0) { }
+       ComplexAnimation();
+       ComplexAnimation(const Sprite *sprite, int frameTime, bool repeat = false);
 
 public:
        struct FrameProp {
@@ -32,10 +31,10 @@ public:
        static void Construct(void *);
 
 protected:
-       virtual int NumFrames() const { return numFrames; };
-       virtual int Col(int frame) const { return frames[frame].col; }
-       virtual int Row(int frame) const { return frames[frame].row; }
-       virtual geometry::Vector<int> Offset(int frame) const { return frames[frame].disposition; }
+       virtual int NumFrames() const;
+       virtual int Col(int frame) const;
+       virtual int Row(int frame) const;
+       virtual geometry::Vector<int> Offset(int frame) const;
 
 private:
        const FrameProp *frames;
index ba5c64d4dbdcf29d79fc671464269d33bdc7cdc8..069d0325f90ffd124bfd9b9d9eb63ad621d528ac 100644 (file)
@@ -4,6 +4,7 @@
 #include "../loader/TypeDescription.h"
 
 #include <cmath>
+#include <cstring>
 #include <iostream>
 
 using geometry::Vector;
@@ -76,8 +77,12 @@ void Font::DrawStringRight(const char *s, SDL_Surface *dest, const Vector<int> &
        if (!sprite) return;
 
        int length(0);
-       while (length < maxWidth && s[length] != '\0') {
-               ++length;
+       if (maxWidth > 0) {
+               while (length < maxWidth && s[length] != '\0') {
+                       ++length;
+               }
+       } else {
+               length = std::strlen(s);
        }
        Vector<int> position(positionIn.X() - length * CharWidth(), positionIn.Y());
 
@@ -124,7 +129,16 @@ void Font::DrawNumber(int numberIn, SDL_Surface *dest, const Vector<int> &positi
 void Font::DrawNumberRight(int number, SDL_Surface *dest, const Vector<int> &positionIn, int digits) const {
        if (!sprite) return;
 
-       Vector<int> position(positionIn.X() - digits * CharWidth(), positionIn.Y());
+       Vector<int> position(positionIn);
+       if (digits > 0) {
+               position.X() -= digits * CharWidth();
+       } else if (number == 0) {
+               position.X() -= CharWidth();
+       } else {
+               for (int i = number; i > 0; i /= 10) {
+                       position.X() -= CharWidth();
+               }
+       }
 
        DrawNumber(number, dest, position, digits);
 }
index 6527e3e2c7325a8ed8baa087a270b87af1bcee4a..1b81f85a2d731ec7e88c4ed4a1be4926f8f8a0d9 100644 (file)
@@ -32,6 +32,7 @@ void MenuProperties::CreateTypeDescription() {
        td.AddField("additionalTextGap", FieldDescription(((char *)&p.additionalTextGap) - ((char *)&p), Interpreter::NUMBER_ID).SetDescription("space between normal and additional text in pixels"));
        td.AddField("wrapX", FieldDescription(((char *)&p.wrapX) - ((char *)&p), Interpreter::BOOLEAN_ID).SetDescription("horizontally wrap cursor movement"));
        td.AddField("wrapY", FieldDescription(((char *)&p.wrapY) - ((char *)&p), Interpreter::BOOLEAN_ID).SetDescription("vertically wrap cursor movement"));
+       td.AddField("thirdColumnHack", FieldDescription(((char *)&p.thirdColumnHack) - ((char *)&p), Interpreter::NUMBER_ID).SetDescription("offset the third column by this many characters"));
 }
 
 void MenuProperties::Construct(void *data) {
index 886e2fd07af5a7bacb4d0c04566bc9824719231f..d83b2a5e9b540801b88128b77f4d41002bc36521 100644 (file)
@@ -28,6 +28,7 @@ struct MenuProperties {
        int charsPerNumber;
        int charsPerAdditionalText;
        int additionalTextGap;
+       int thirdColumnHack;
        char delimiter;
        bool wrapX;
        bool wrapY;
@@ -37,7 +38,7 @@ struct MenuProperties {
        , charsPerEntry(0), rows(1), rowGap(0)
        , iconSpace(0), cols(1), colGap(0)
        , charsPerNumber(0), charsPerAdditionalText(0)
-       , additionalTextGap(0), delimiter(':')
+       , additionalTextGap(0), thirdColumnHack(0), delimiter(':')
        , wrapX(false), wrapY(false) { }
 
        static void CreateTypeDescription();
@@ -241,10 +242,9 @@ void Menu<T>::Draw(SDL_Surface *dest, const geometry::Vector<int> &position) con
                                (i % cols) * (ColWidth() + colGap),
                                (i / cols) * RowHeight());
 
-               // Third column hack!
-               // This fixes the position of the "DROP" item in the inventory menu.
-               if (i % cols == 2) {
-                       iconOffset += geometry::Vector<int>(font->CharWidth(), 0);
+               // This fixes the position of the third column of the inventory and capsule menus.
+               if (thirdColumnHack && i % cols == 2) {
+                       iconOffset += geometry::Vector<int>(font->CharWidth() * thirdColumnHack, 0);
                }
 
                if (entries[start + i].icon) {
@@ -273,10 +273,9 @@ void Menu<T>::Draw(SDL_Surface *dest, const geometry::Vector<int> &position) con
        geometry::Vector<int> cursorOffset(
                        (selected % cols) * (ColWidth() + colGap) - cursor->Width(),
                        ((selected - start) / cols) * RowHeight());
-       // Third column hack!
-       // This fixes the position of the "DROP" item in the inventory menu.
-       if (selected % cols == 2) {
-               cursorOffset += geometry::Vector<int>(font->CharWidth(), 0);
+       // This fixes the position of the third column of the inventory and capsule menus.
+       if (thirdColumnHack && selected % cols == 2) {
+               cursorOffset += geometry::Vector<int>(font->CharWidth() * thirdColumnHack, 0);
        }
        switch (state) {
                case STATE_INACTIVE:
index baed3419188b2f393e0e27ade3d3b56f7e38f0f3..24985f91ebb12e5db89143389f29a29a71f2d4d8 100644 (file)
@@ -9,6 +9,41 @@ using loader::TypeDescription;
 
 namespace graphics {
 
+SimpleAnimation::SimpleAnimation()
+: numFrames(0)
+, col(0)
+, row(0) {
+
+}
+
+SimpleAnimation::SimpleAnimation(
+               const Sprite *sprite,
+               int frameTime,
+               int numFrames,
+               int col,
+               int row,
+               bool repeat)
+: Animation(sprite, frameTime, repeat)
+, numFrames(numFrames)
+, col(col)
+, row(row) {
+
+}
+
+
+int SimpleAnimation::NumFrames() const {
+       return numFrames;
+}
+
+int SimpleAnimation::Col(int frame) const {
+       return col;
+}
+
+int SimpleAnimation::Row(int frame) const {
+       return row + frame;
+}
+
+
 void SimpleAnimation::CreateTypeDescription() {
        SimpleAnimation sa;
        Animation *a(&sa);
index 49eff9a79bc5c5385cc8c2456fc912538c94691d..88a41c5ba52e859137549e5d68737beacf340264 100644 (file)
@@ -12,10 +12,9 @@ public:
        static const int TYPE_ID = 408;
 
 public:
-       SimpleAnimation()
-       : numFrames(0), col(0), row(0) { }
-       SimpleAnimation(const Sprite *sprite, int frameTime, int numFrames, int col = 0, int row = 0, bool repeat = false)
-       : Animation(sprite, frameTime, repeat), numFrames(numFrames), col(col), row(row) { }
+       SimpleAnimation();
+       SimpleAnimation(const Sprite *sprite, int frameTime, int numFrames,
+                       int col = 0, int row = 0, bool repeat = false);
 
 public:
        void SetNumFrames(int n) { numFrames = n; }
@@ -26,9 +25,9 @@ public:
        static void Construct(void *);
 
 protected:
-       virtual int NumFrames() const { return numFrames; };
-       virtual int Col(int frame) const { return col; }
-       virtual int Row(int frame) const { return row + frame; }
+       virtual int NumFrames() const;
+       virtual int Col(int frame) const;
+       virtual int Row(int frame) const;
 
 private:
        int numFrames;
index 78a31b548db4737e0cd4cba08ee104fd73a9313f..050ac930e9ef956d90bb16763fd94a47e02697b5 100644 (file)
@@ -4,6 +4,7 @@
 #include "../battle/Resources.h"
 #include "../battle/Monster.h"
 #include "../battle/PartyLayout.h"
+#include "../common/Capsule.h"
 #include "../common/Hero.h"
 #include "../common/Item.h"
 #include "../common/Spell.h"
@@ -12,6 +13,7 @@
 
 using battle::Monster;
 using battle::PartyLayout;
+using common::Capsule;
 using common::Hero;
 using common::Item;
 using common::Spell;
@@ -32,6 +34,10 @@ battle::Resources *Caster::GetBattleResources(const string &ident) {
                        intp.GetObject(battle::Resources::TYPE_ID, ident));
 }
 
+Capsule *Caster::GetCapsule(const string &ident) {
+       return reinterpret_cast<Capsule *>(intp.GetObject(Capsule::TYPE_ID, ident));
+}
+
 Hero *Caster::GetHero(const string &ident) {
        return reinterpret_cast<Hero *>(intp.GetObject(Hero::TYPE_ID, ident));
 }
index 2aa6be09ed5762d8dae481bf321813d10f94e851..31ce61226677f40f8d32645bbf1d861e6680f3bf 100644 (file)
@@ -22,6 +22,7 @@ private:
 
 public:
        battle::Resources *GetBattleResources(const std::string &identifier);
+       common::Capsule *GetCapsule(const std::string &identifier);
        common::Hero *GetHero(const std::string &identifier);
        common::Item *GetItem(const std::string &identifier);
        map::Map *GetMap(const std::string &identifier);
index 31724d5b22acd42f67b0222f8a954234c77981ad..2611a722aeba9b20ebf2431e33606e846be645e8 100644 (file)
@@ -2,10 +2,12 @@
 #include "app/Arguments.h"
 #include "app/Input.h"
 #include "battle/BattleState.h"
+#include "battle/Capsule.h"
 #include "battle/Hero.h"
 #include "battle/Monster.h"
 #include "battle/PartyLayout.h"
 #include "battle/Resources.h"
+#include "common/Capsule.h"
 #include "common/GameConfig.h"
 #include "common/GameState.h"
 #include "common/Hero.h"
@@ -55,6 +57,7 @@ using app::Input;
 using battle::BattleState;
 using battle::Monster;
 using battle::PartyLayout;
+using common::Capsule;
 using common::GameConfig;
 using common::GameState;
 using common::Hero;
@@ -99,6 +102,7 @@ int main(int argc, char **argv) {
                battle::Monster::CreateTypeDescription();
                battle::PartyLayout::CreateTypeDescription();
 
+               common::Capsule::CreateTypeDescription();
                common::Hero::CreateTypeDescription();
                common::Ikari::CreateTypeDescription();
                common::Item::CreateTypeDescription();
@@ -190,6 +194,9 @@ int main(int argc, char **argv) {
                gameState.party[3] = &gameState.heroes[3];
                gameState.partySize = 4;
 
+               gameState.capsules[0] = *caster.GetCapsule("flash");
+               gameState.capsule = gameState.capsules;
+
                GameConfig gameConfig;
                gameConfig.state = &gameState;
                gameConfig.heroesLayout = caster.GetPartyLayout("heroesLayout");
@@ -287,6 +294,7 @@ int main(int argc, char **argv) {
                        battleState->AddMonster(monster);
                        battleState->AddMonster(monster);
                        battleState->AddMonster(monster);
+                       battleState->SetCapsule(caster.GetCapsule("flash"));
                        battleState->AddHero(gameState.heroes[0]);
                        battleState->AddHero(gameState.heroes[1]);
                        battleState->AddHero(gameState.heroes[2]);
index d678dab965d573c7722a963a9cc5936ac57af5c6..35c0c5c76f9a09a53b38e68ac5f8228d524c8449 100644 (file)
@@ -296,6 +296,9 @@ bool MapState::CheckMonster() {
                                                battleState->AddHero(*game->state->party[i]);
                                        }
                                }
+                               if (game->state->capsule) {
+                                       battleState->SetCapsule(game->state->capsule);
+                               }
                                for (battle::Monster **monster((*e)->MonstersBegin()); monster != (*e)->MonstersEnd(); ++monster) {
                                        battleState->AddMonster(**monster);
                                }
@@ -311,9 +314,6 @@ bool MapState::CheckMonster() {
                                // TODO: move entity erase to happen after the transition or battle
                                entities.erase(e);
                                return true;
-                               // needed information here:
-                               //  - battle background (from tile/area/map)
-                               //  - monsters + layout (from entity)
                        }
                }
        }
diff --git a/src/menu/CapsuleChangeMenu.cpp b/src/menu/CapsuleChangeMenu.cpp
new file mode 100644 (file)
index 0000000..3b161ad
--- /dev/null
@@ -0,0 +1,97 @@
+#include "CapsuleChangeMenu.h"
+
+#include "CapsuleMenu.h"
+#include "Resources.h"
+#include "../app/Application.h"
+#include "../app/Input.h"
+#include "../common/Inventory.h"
+#include "../common/Item.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+
+using app::Input;
+using common::Capsule;
+using common::Inventory;
+using common::Item;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+CapsuleChangeMenu::CapsuleChangeMenu(CapsuleMenu *parent)
+: parent(parent) {
+
+}
+
+
+void CapsuleChangeMenu::OnEnterState(SDL_Surface *) {
+
+}
+
+void CapsuleChangeMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void CapsuleChangeMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void CapsuleChangeMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void CapsuleChangeMenu::OnResize(int width, int height) {
+
+}
+
+
+void CapsuleChangeMenu::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::ACTION_B)) {
+               Ctrl().PopState();
+       }
+}
+
+void CapsuleChangeMenu::UpdateWorld(float deltaT) {
+
+}
+
+void CapsuleChangeMenu::Render(SDL_Surface *screen) {
+       const Font &font(*parent->Res().statusFont);
+       const Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+       const Vector<int> capsuleOffset(
+                       6 * font.CharWidth(),
+                       12 * font.CharHeight());
+       const Vector<int> infoOffset(
+                       12 * font.CharWidth(),
+                       2 * font.CharHeight() - font.CharHeight() / 8);
+       // TODO: wheel offset: top left, center, or center bottom?
+       const Vector<int> wheelOffset;
+       const Vector<int> menuOffset(
+                               font.CharWidth(),
+                               24 * font.CharHeight() - font.CharHeight() / 8);
+
+       parent->RenderBackground(screen);
+       parent->RenderCapsule(screen, offset + capsuleOffset);
+       parent->RenderInfo(screen, offset + infoOffset);
+       parent->RenderWheel(screen, offset + wheelOffset);
+       parent->RenderMenu(screen, offset + menuOffset);
+}
+
+
+int CapsuleChangeMenu::Width() const {
+       return parent->Width();
+}
+
+int CapsuleChangeMenu::Height() const {
+       return parent->Height();
+}
+
+const Capsule &CapsuleChangeMenu::GetCapsule() const {
+       return parent->GetCapsule();
+}
+
+}
diff --git a/src/menu/CapsuleChangeMenu.h b/src/menu/CapsuleChangeMenu.h
new file mode 100644 (file)
index 0000000..5ac40fb
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef MENU_CAPSULECHANGEMENU_H_
+#define MENU_CAPSULECHANGEMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+
+namespace menu {
+
+class CapsuleMenu;
+
+class CapsuleChangeMenu
+: public app::State {
+
+public:
+       explicit CapsuleChangeMenu(CapsuleMenu *parent);
+
+public:
+       virtual void HandleEvents(const app::Input &);
+       virtual void UpdateWorld(float deltaT);
+       virtual void Render(SDL_Surface *);
+
+public:
+       int Width() const;
+       int Height() const;
+
+private:
+       virtual void OnEnterState(SDL_Surface *screen);
+       virtual void OnExitState(SDL_Surface *screen);
+       virtual void OnResumeState(SDL_Surface *screen);
+       virtual void OnPauseState(SDL_Surface *screen);
+
+       virtual void OnResize(int width, int height);
+
+       const common::Capsule &GetCapsule() const;
+
+private:
+       CapsuleMenu *parent;
+
+};
+
+}
+
+#endif /* MENU_CAPSULECHANGEMENU_H_ */
diff --git a/src/menu/CapsuleFeedMenu.cpp b/src/menu/CapsuleFeedMenu.cpp
new file mode 100644 (file)
index 0000000..184212d
--- /dev/null
@@ -0,0 +1,224 @@
+#include "CapsuleFeedMenu.h"
+
+#include "CapsuleMenu.h"
+#include "Resources.h"
+#include "../app/Application.h"
+#include "../app/Input.h"
+#include "../common/Inventory.h"
+#include "../common/Item.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+
+using app::Input;
+using common::Capsule;
+using common::Inventory;
+using common::Item;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+CapsuleFeedMenu::CapsuleFeedMenu(CapsuleMenu *parent)
+: parent(parent)
+, menu(*parent->Res().capsuleFeedMenuProperties)
+, itemMenu(*parent->Res().inventoryMenuProperties) {
+       menu.Add(parent->Res().itemMenuSelectText, CHOICE_SELECT);
+       menu.Add(parent->Res().itemMenuSortText, CHOICE_SORT);
+       LoadInventory();
+}
+
+
+void CapsuleFeedMenu::OnEnterState(SDL_Surface *) {
+       menu.SetSelected();
+       itemMenu.SetActive();
+}
+
+void CapsuleFeedMenu::LoadInventory() {
+       const Inventory &inv(parent->Game().state->inventory);
+       itemMenu.Clear();
+       itemMenu.Reserve(inv.MaxItems());
+       for (int i(0); i < inv.MaxItems(); ++i) {
+               const Item *item(inv.ItemAt(i));
+               if (item) {
+                       // TODO: find out which items are impossible to feed to a capsule
+                       itemMenu.Add(item->Name(), item, true, item->MenuIcon(), inv.ItemCountAt(i));
+               } else {
+                       itemMenu.AddEmptyEntry();
+               }
+       }
+}
+
+void CapsuleFeedMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void CapsuleFeedMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void CapsuleFeedMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void CapsuleFeedMenu::OnResize(int width, int height) {
+
+}
+
+
+void CapsuleFeedMenu::HandleEvents(const Input &input) {
+       if (menu.IsActive()) {
+               if (input.JustPressed(Input::PAD_LEFT)) {
+                       menu.PreviousItem();
+               }
+               if (input.JustPressed(Input::PAD_RIGHT)) {
+                       menu.NextItem();
+               }
+       } else {
+               if (input.JustPressed(Input::PAD_UP)) {
+                       itemMenu.PreviousItem();
+               }
+               if (input.JustPressed(Input::PAD_DOWN)) {
+                       itemMenu.NextItem();
+               }
+       }
+
+       if (input.JustPressed(Input::ACTION_A)) {
+               if (menu.IsActive()) {
+                       if (menu.Selected() == CHOICE_SORT) {
+                               parent->Game().state->inventory.Sort();
+                               LoadInventory();
+                       } else {
+                               menu.SetSelected();
+                               itemMenu.SetActive();
+                       }
+               } else if (itemMenu.IsActive()) {
+                       itemMenu.SetDualSelection();
+               } else if (itemMenu.SelectedIndex() == itemMenu.SecondaryIndex()) {
+                       switch (menu.Selected()) {
+                               case CHOICE_SELECT:
+                                       if (true /* can feed */) {
+                                               // TODO: implement capsule feeding
+                                       }
+                                       itemMenu.SetActive();
+                                       break;
+                               case CHOICE_SORT:
+                                       // invalid state, recover
+                                       menu.SetActive();
+                                       itemMenu.SetInactive();
+                                       break;
+                       }
+               } else {
+                       parent->Game().state->inventory.SwapEntriesAt(
+                                       itemMenu.SelectedIndex(),
+                                       itemMenu.SecondaryIndex());
+                       itemMenu.SwapSelected();
+                       itemMenu.SetActive();
+               }
+       }
+       if (input.JustPressed(Input::ACTION_B)) {
+               if (menu.IsActive()) {
+                       Ctrl().PopState();
+               } else if (itemMenu.IsActive()) {
+                       menu.SetActive();
+                       itemMenu.SetInactive();
+               } else {
+                       itemMenu.SetActive();
+               }
+       }
+}
+
+void CapsuleFeedMenu::UpdateWorld(float deltaT) {
+
+}
+
+void CapsuleFeedMenu::Render(SDL_Surface *screen) {
+       const Font &font(*parent->Res().statusFont);
+       const Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+       const Vector<int> nameOffset(
+                       font.CharWidth(),
+                       2 * font.CharHeight() - font.CharHeight() / 8);
+       const Vector<int> spriteOffset(
+                               3 * font.CharWidth() + font.CharWidth() * 3 / 4,
+                               4 * font.CharHeight() + font.CharHeight() / 4);
+       const Vector<int> hungerOffset(
+                       13 * font.CharWidth(),
+                       9 * font.CharHeight() + font.CharHeight() / 8);
+       const Vector<int> menuOffset(
+                       font.CharWidth(),
+                       13 * font.CharHeight() + font.CharHeight() / 8);
+       const Vector<int> itemsOffset(
+                       font.CharWidth(),
+                       16 * font.CharHeight() + font.CharHeight() / 8);
+
+       parent->RenderBackground(screen);
+       RenderName(screen, offset + nameOffset);
+       RenderSprite(screen, offset + spriteOffset);
+       RenderHunger(screen, offset + hungerOffset);
+       RenderMenu(screen, offset + menuOffset);
+       RenderItems(screen, offset + itemsOffset);
+}
+
+void CapsuleFeedMenu::RenderName(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Font &font(*parent->Res().statusFont);
+       const Vector<int> separatorOffset(5 * font.CharWidth(), 0);
+       const Vector<int> nameOffset(6 * font.CharWidth(), 0);
+
+       font.DrawString(parent->Res().capsuleNameLabel, screen, offset, 5);
+       font.DrawChar(':', screen, offset + separatorOffset);
+       font.DrawString(GetCapsule().Name(), screen, offset + nameOffset);
+}
+
+void CapsuleFeedMenu::RenderSprite(SDL_Surface *screen, const Vector<int> &offset) const {
+       // TODO: sitting ground
+       GetCapsule().BattleSprite()->Draw(screen, offset);
+}
+
+void CapsuleFeedMenu::RenderHunger(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Font &font(*parent->Res().normalFont);
+       const Frame &frame(*parent->Res().statusFrame);
+       const Vector<int> textOffset(2 * font.CharWidth(), font.CharHeight());
+
+       frame.Draw(screen, offset, 18 * font.CharWidth(), 3 * font.CharHeight());
+       font.DrawString(parent->Res().capsuleNotHungryText, screen, offset + textOffset, 15);
+}
+
+void CapsuleFeedMenu::RenderMenu(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Font &font(*parent->Res().normalFont);
+       const Frame &frame(*parent->Res().statusFrame);
+       const Vector<int> labelOffset(2 * font.CharWidth(), font.CharHeight());
+       const Vector<int> menubgOffset(8 * font.CharWidth(), 0);
+       const Vector<int> menuOffset(11 * font.CharWidth(), font.CharHeight());
+
+       frame.Draw(screen, offset, 8 * font.CharWidth(), 3 * font.CharHeight());
+       font.DrawString(parent->Res().capsuleFeedLabel, screen, offset + labelOffset);
+       frame.Draw(screen, offset + menubgOffset, 22 * font.CharWidth(), 3 * font.CharHeight());
+       menu.Draw(screen, offset + menuOffset);
+}
+
+void CapsuleFeedMenu::RenderItems(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Font &font(*parent->Res().normalFont);
+       const Frame &frame(*parent->Res().statusFrame);
+       const Vector<int> menuOffset(3 * font.CharWidth(), font.CharHeight() * 5 / 4);
+
+       frame.Draw(screen, offset, 30 * font.CharWidth(), 11 * font.CharHeight());
+       itemMenu.Draw(screen, offset + menuOffset);
+}
+
+
+int CapsuleFeedMenu::Width() const {
+       return parent->Width();
+}
+
+int CapsuleFeedMenu::Height() const {
+       return parent->Height();
+}
+
+const Capsule &CapsuleFeedMenu::GetCapsule() const {
+       return parent->GetCapsule();
+}
+
+}
diff --git a/src/menu/CapsuleFeedMenu.h b/src/menu/CapsuleFeedMenu.h
new file mode 100644 (file)
index 0000000..8c75edd
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef MENU_CAPSULEFEEDMENU_H_
+#define MENU_CAPSULEFEEDMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class CapsuleMenu;
+
+class CapsuleFeedMenu
+: public app::State {
+
+public:
+       explicit CapsuleFeedMenu(CapsuleMenu *parent);
+
+public:
+       virtual void HandleEvents(const app::Input &);
+       virtual void UpdateWorld(float deltaT);
+       virtual void Render(SDL_Surface *);
+
+public:
+       int Width() const;
+       int Height() const;
+
+private:
+       virtual void OnEnterState(SDL_Surface *screen);
+       virtual void OnExitState(SDL_Surface *screen);
+       virtual void OnResumeState(SDL_Surface *screen);
+       virtual void OnPauseState(SDL_Surface *screen);
+
+       virtual void OnResize(int width, int height);
+
+       const common::Capsule &GetCapsule() const;
+
+       void LoadInventory();
+
+       void RenderName(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderSprite(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderHunger(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderItems(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+       CapsuleMenu *parent;
+       enum Choice {
+               CHOICE_SELECT,
+               CHOICE_SORT,
+       };
+       graphics::Menu<Choice> menu;
+       graphics::Menu<const common::Item *> itemMenu;
+
+};
+
+}
+
+#endif /* MENU_CAPSULEFEEDMENU_H_ */
diff --git a/src/menu/CapsuleMenu.cpp b/src/menu/CapsuleMenu.cpp
new file mode 100644 (file)
index 0000000..ab32a1b
--- /dev/null
@@ -0,0 +1,267 @@
+#include "CapsuleMenu.h"
+
+#include "CapsuleChangeMenu.h"
+#include "CapsuleFeedMenu.h"
+#include "CapsuleNameMenu.h"
+#include "PartyMenu.h"
+#include "Resources.h"
+#include "../app/Application.h"
+#include "../app/Input.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../common/Spell.h"
+#include "../common/Stats.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+#include "../graphics/Texture.h"
+
+using app::Input;
+using common::Capsule;
+using common::Stats;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+CapsuleMenu::CapsuleMenu(PartyMenu *parent)
+: parent(parent)
+, menu(*Res().capsuleMenuProperties) {
+       menu.Add(Res().capsuleFeedLabel, CHOICE_FEED);
+       menu.Add(Res().capsuleChangeLabel, CHOICE_CHANGE);
+       menu.Add(Res().capsuleNameLabel, CHOICE_NAME);
+}
+
+
+void CapsuleMenu::OnEnterState(SDL_Surface *) {
+
+}
+
+void CapsuleMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void CapsuleMenu::OnResumeState(SDL_Surface *) {
+       menu.SetActive();
+}
+
+void CapsuleMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void CapsuleMenu::OnResize(int width, int height) {
+
+}
+
+
+void CapsuleMenu::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::PAD_LEFT)) {
+               menu.PreviousItem();
+       }
+       if (input.JustPressed(Input::PAD_RIGHT)) {
+               menu.NextItem();
+       }
+
+       if (input.JustPressed(Input::ACTION_A)) {
+               switch (menu.Selected()) {
+                       case CHOICE_FEED:
+                               Ctrl().PushState(new CapsuleFeedMenu(this));
+                               menu.SetSelected();
+                               break;
+                       case CHOICE_CHANGE:
+                               Ctrl().PushState(new CapsuleChangeMenu(this));
+                               menu.SetSelected();
+                               break;
+                       case CHOICE_NAME:
+                               Ctrl().PushState(new CapsuleNameMenu(this));
+                               menu.SetSelected();
+                               break;
+               }
+       } else if (input.JustPressed(Input::ACTION_B)) {
+               Ctrl().PopState();
+       }
+}
+
+void CapsuleMenu::UpdateWorld(float deltaT) {
+
+}
+
+void CapsuleMenu::Render(SDL_Surface *screen) {
+       const Font &font(*Res().statusFont);
+       const Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+       const Vector<int> capsuleOffset(
+                       6 * font.CharWidth(),
+                       12 * font.CharHeight());
+       const Vector<int> infoOffset(
+                       12 * font.CharWidth(),
+                       2 * font.CharHeight() - font.CharHeight() / 8);
+       // TODO: wheel offset: top left, center, or center bottom?
+       const Vector<int> wheelOffset;
+       const Vector<int> statsOffset(
+                       12 * font.CharWidth(),
+                       15 * font.CharHeight() - font.CharHeight() / 8);
+       const Vector<int> menuOffset(
+                               font.CharWidth(),
+                               24 * font.CharHeight() - font.CharHeight() / 8);
+
+       RenderBackground(screen);
+       RenderCapsule(screen, offset + capsuleOffset);
+       RenderInfo(screen, offset + infoOffset);
+       RenderWheel(screen, offset + wheelOffset);
+       RenderStats(screen, offset + statsOffset);
+       RenderMenu(screen, offset + menuOffset);
+}
+
+void CapsuleMenu::RenderBackground(SDL_Surface *screen) const {
+       Res().capsulebg->Render(screen, Vector<int>(), Vector<int>(screen->w, screen->h));
+}
+
+void CapsuleMenu::RenderCapsule(SDL_Surface *screen, const Vector<int> &offset) const {
+       GetCapsule().BattleSprite()->DrawCenterBottom(screen, offset);
+}
+
+void CapsuleMenu::RenderInfo(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Capsule &capsule(GetCapsule());
+       const Font &font(*Res().statusFont);
+       const Vector<int> delimiterOffset(5 * font.CharWidth(), 0);
+       const Vector<int> valueOffset(6 * font.CharWidth(), 0);
+       const Vector<int> lineBreak(0, font.CharHeight() + font.CharHeight() / 2);
+       Vector<int> lineHead(offset);
+
+       font.DrawString(Res().capsuleNameLabel, screen, lineHead, 5);
+       font.DrawChar(':', screen, lineHead + delimiterOffset);
+       font.DrawString(capsule.Name(), screen, lineHead + valueOffset);
+
+       lineHead += lineBreak;
+       font.DrawString(Res().capsuleClassLabel, screen, lineHead, 5);
+       font.DrawChar(':', screen, lineHead + delimiterOffset);
+       font.DrawString(capsule.ClassName(), screen, lineHead + valueOffset);
+
+       lineHead += lineBreak;
+       font.DrawString(Res().capsuleAlignmentLabel, screen, lineHead, 5);
+       font.DrawChar(':', screen, lineHead + delimiterOffset);
+       font.DrawString(capsule.Alignment(), screen, lineHead + valueOffset);
+
+       lineHead += lineBreak;
+       font.DrawString(Res().capsuleTribeLabel, screen, lineHead, 5);
+       font.DrawChar(':', screen, lineHead + delimiterOffset);
+       font.DrawString(capsule.Tribe(), screen, lineHead + valueOffset);
+
+       lineHead += lineBreak;
+       font.DrawString(Res().capsuleAttack1Label, screen, lineHead, 5);
+       font.DrawChar(':', screen, lineHead + delimiterOffset);
+       if (capsule.Attack1()) {
+               font.DrawString(capsule.Attack1()->Name(), screen, lineHead + valueOffset);
+       } else {
+               font.DrawString(Res().capsuleNoAttackText, screen, lineHead + valueOffset);
+       }
+
+       lineHead += lineBreak;
+       font.DrawString(Res().capsuleAttack1Label, screen, lineHead, 5);
+       font.DrawChar(':', screen, lineHead + delimiterOffset);
+       if (capsule.Attack2()) {
+               font.DrawString(capsule.Attack2()->Name(), screen, lineHead + valueOffset);
+       } else {
+               font.DrawString(Res().capsuleNoAttackText, screen, lineHead + valueOffset);
+       }
+
+       lineHead += lineBreak;
+       font.DrawString(Res().capsuleAttack1Label, screen, lineHead, 5);
+       font.DrawChar(':', screen, lineHead + delimiterOffset);
+       if (capsule.Attack3()) {
+               font.DrawString(capsule.Attack3()->Name(), screen, lineHead + valueOffset);
+       } else {
+               font.DrawString(Res().capsuleNoAttackText, screen, lineHead + valueOffset);
+       }
+}
+
+void CapsuleMenu::RenderWheel(SDL_Surface *screen, const Vector<int> &offset) const {
+       // later
+}
+
+void CapsuleMenu::RenderStats(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Capsule &capsule(GetCapsule());
+       Stats stats(capsule.GetStats());
+       const Font &font(*Res().statusFont);
+       const Vector<int> lineBreak(0, font.CharHeight());
+       Vector<int> lineHead(offset);
+
+       RenderStatsLine(screen, lineHead, Res().hpLabel, capsule.MaxHealth());
+       lineHead += lineBreak;
+       RenderStatsLine(screen, lineHead, Res().atpLabel, stats.Attack());
+       lineHead += lineBreak;
+       RenderStatsLine(screen, lineHead, Res().dfpLabel, stats.Defense());
+       lineHead += lineBreak;
+       RenderStatsLine(screen, lineHead, Res().strLabel, stats.Strength());
+       lineHead += lineBreak;
+       RenderStatsLine(screen, lineHead, Res().aglLabel, stats.Agility());
+       lineHead += lineBreak;
+       RenderStatsLine(screen, lineHead, Res().intLabel, stats.Intelligence());
+       lineHead += lineBreak;
+       RenderStatsLine(screen, lineHead, Res().gutLabel, stats.Gut());
+       lineHead += lineBreak;
+       RenderStatsLine(screen, lineHead, Res().mgrLabel, stats.MagicResistance());
+
+       lineHead = offset + Vector<int>(18 * font.CharWidth(), 0);
+       font.DrawStringRight(Res().levelLabel, screen, lineHead);
+       lineHead += lineBreak;
+       font.DrawNumberRight(capsule.Level(), screen, lineHead);
+       lineHead += 2 * lineBreak;
+       font.DrawStringRight(Res().experienceLabel, screen, lineHead);
+       lineHead += lineBreak;
+       font.DrawNumberRight(capsule.Experience(), screen, lineHead);
+       lineHead += 2 * lineBreak;
+       font.DrawStringRight(Res().nextLevelLabel, screen, lineHead);
+       lineHead += lineBreak;
+       font.DrawNumberRight(capsule.NextLevel(), screen, lineHead);
+}
+
+void CapsuleMenu::RenderStatsLine(SDL_Surface *screen, const geometry::Vector<int> &offset, const char *name, int value) const {
+       const Font &font(*Res().statusFont);
+       const Vector<int> numberOffset(4 * font.CharWidth(), 0);
+
+       font.DrawString(name, screen, offset, 4);
+       font.DrawNumber(value, screen, offset + numberOffset, 3);
+}
+
+void CapsuleMenu::RenderMenu(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Font &font(*Res().normalFont);
+       const Frame &frame(*Res().statusFrame);
+       const Vector<int> menuOffset(3 * font.CharWidth(), font.CharHeight());
+
+       frame.Draw(screen, offset, 30 * font.CharWidth(), 3 * font.CharHeight());
+       menu.Draw(screen, offset + menuOffset);
+}
+
+
+common::GameConfig &CapsuleMenu::Game() {
+       return parent->Game();
+}
+
+const common::GameConfig &CapsuleMenu::Game() const {
+       return parent->Game();
+}
+
+Resources &CapsuleMenu::Res() {
+       return parent->Res();
+}
+
+const Resources &CapsuleMenu::Res() const {
+       return parent->Res();
+}
+
+
+int CapsuleMenu::Width() const {
+       return parent->Width();
+}
+
+int CapsuleMenu::Height() const {
+       return parent->Height();
+}
+
+const Capsule &CapsuleMenu::GetCapsule() const {
+       return *Game().state->capsule;
+}
+
+}
diff --git a/src/menu/CapsuleMenu.h b/src/menu/CapsuleMenu.h
new file mode 100644 (file)
index 0000000..1491f39
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef MENU_CAPSULEMENU_H_
+#define MENU_CAPSULEMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class CapsuleMenu
+: public app::State {
+
+public:
+       explicit CapsuleMenu(PartyMenu *parent);
+
+public:
+       virtual void HandleEvents(const app::Input &);
+       virtual void UpdateWorld(float deltaT);
+       virtual void Render(SDL_Surface *);
+
+       void RenderBackground(SDL_Surface *screen) const;
+       void RenderCapsule(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderInfo(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderWheel(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderStats(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderStatsLine(SDL_Surface *screen, const geometry::Vector<int> &offset, const char *name, int value) const;
+       void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+public:
+       common::GameConfig &Game();
+       const common::GameConfig &Game() const;
+       Resources &Res();
+       const Resources &Res() const;
+       const common::Capsule &GetCapsule() const;
+
+       int Width() const;
+       int Height() const;
+
+private:
+       virtual void OnEnterState(SDL_Surface *screen);
+       virtual void OnExitState(SDL_Surface *screen);
+       virtual void OnResumeState(SDL_Surface *screen);
+       virtual void OnPauseState(SDL_Surface *screen);
+
+       virtual void OnResize(int width, int height);
+
+private:
+       PartyMenu *parent;
+       enum Choice {
+               CHOICE_FEED,
+               CHOICE_CHANGE,
+               CHOICE_NAME,
+       };
+       graphics::Menu<Choice> menu;
+
+};
+
+}
+
+#endif /* MENU_CAPSULEMENU_H_ */
diff --git a/src/menu/CapsuleNameMenu.cpp b/src/menu/CapsuleNameMenu.cpp
new file mode 100644 (file)
index 0000000..14acd46
--- /dev/null
@@ -0,0 +1,114 @@
+#include "CapsuleNameMenu.h"
+
+#include "CapsuleMenu.h"
+#include "Resources.h"
+#include "../app/Application.h"
+#include "../app/Input.h"
+#include "../common/Inventory.h"
+#include "../common/Item.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+
+#include <cstring>
+
+using app::Input;
+using common::Capsule;
+using common::Inventory;
+using common::Item;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+CapsuleNameMenu::CapsuleNameMenu(CapsuleMenu *parent)
+: parent(parent)
+, cursor(5) {
+       std::strncpy(buffer, GetCapsule().Name(), 6);
+       buffer[5] = '\0';
+}
+
+
+void CapsuleNameMenu::OnEnterState(SDL_Surface *) {
+
+}
+
+void CapsuleNameMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void CapsuleNameMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void CapsuleNameMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void CapsuleNameMenu::OnResize(int width, int height) {
+
+}
+
+
+void CapsuleNameMenu::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::START)) {
+               Ctrl().PopState();
+       }
+}
+
+void CapsuleNameMenu::UpdateWorld(float deltaT) {
+
+}
+
+void CapsuleNameMenu::Render(SDL_Surface *screen) {
+       const Font &font(*parent->Res().statusFont);
+       const Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+       const Vector<int> nameOffset(
+                       4 * font.CharWidth(),
+                       4 * font.CharHeight() - font.CharHeight() / 8);
+       const Vector<int> alphaOffset(
+                       4 * font.CharWidth(),
+                       7 * font.CharHeight() - font.CharHeight() / 8);
+
+       parent->RenderBackground(screen);
+       RenderName(screen, offset + nameOffset);
+       RenderAlphabet(screen, offset + alphaOffset);
+}
+
+void CapsuleNameMenu::RenderName(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Font &font(*parent->Res().normalFont);
+       const Frame &frame(*parent->Res().statusFrame);
+       const Vector<int> labelOffset(2 * font.CharWidth(), font.CharHeight());
+       const Vector<int> namebgOffset(8 * font.CharWidth(), 0);
+       const Vector<int> nameOffset(13 * font.CharWidth(), font.CharHeight());
+
+       frame.Draw(screen, offset, 8 * font.CharWidth(), 3 * font.CharHeight());
+       font.DrawString(parent->Res().capsuleNameLabel, screen, offset + labelOffset, 5);
+       frame.Draw(screen, offset + namebgOffset, 16 * font.CharWidth(), 3 * font.CharHeight());
+       font.DrawString(buffer, screen, offset + nameOffset, 5);
+}
+
+void CapsuleNameMenu::RenderAlphabet(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Font &font(*parent->Res().normalFont);
+       const Frame &frame(*parent->Res().statusFrame);
+
+       frame.Draw(screen, offset, 24 * font.CharWidth(), 17 * font.CharHeight());
+}
+
+
+int CapsuleNameMenu::Width() const {
+       return parent->Width();
+}
+
+int CapsuleNameMenu::Height() const {
+       return parent->Height();
+}
+
+const Capsule &CapsuleNameMenu::GetCapsule() const {
+       return parent->GetCapsule();
+}
+
+}
diff --git a/src/menu/CapsuleNameMenu.h b/src/menu/CapsuleNameMenu.h
new file mode 100644 (file)
index 0000000..0021da4
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef MENU_CAPSULENAMEMENU_H_
+#define MENU_CAPSULENAMEMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+
+namespace menu {
+
+class CapsuleMenu;
+
+class CapsuleNameMenu
+: public app::State {
+
+public:
+       explicit CapsuleNameMenu(CapsuleMenu *parent);
+
+public:
+       virtual void HandleEvents(const app::Input &);
+       virtual void UpdateWorld(float deltaT);
+       virtual void Render(SDL_Surface *);
+
+public:
+       int Width() const;
+       int Height() const;
+
+private:
+       virtual void OnEnterState(SDL_Surface *screen);
+       virtual void OnExitState(SDL_Surface *screen);
+       virtual void OnResumeState(SDL_Surface *screen);
+       virtual void OnPauseState(SDL_Surface *screen);
+
+       virtual void OnResize(int width, int height);
+
+       const common::Capsule &GetCapsule() const;
+
+       void LoadInventory();
+
+       void RenderName(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderAlphabet(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+       CapsuleMenu *parent;
+       int cursor;
+       char buffer[6];
+
+};
+
+}
+
+#endif /* MENU_CAPSULENAMEMENU_H_ */
index 9c903eb607ee3893b50032313050f312ae6d19c0..6d6e2d12543e51a8e47f644aa064d85b7da02df7 100644 (file)
@@ -2,6 +2,8 @@
 
 #include "PartyMenu.h"
 #include "Resources.h"
+#include "../app/Application.h"
+#include "../app/Input.h"
 #include "../common/GameConfig.h"
 #include "../common/GameState.h"
 #include "../graphics/Font.h"
index eb74ab8b5ea899a5220c2e959a5c37f92c3666c1..c980f9719a3c120e0097f5a8c19bcb63cbdced90 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "PartyMenu.h"
 #include "Resources.h"
+#include "../app/Application.h"
 #include "../app/Input.h"
 #include "../common/GameConfig.h"
 #include "../common/GameState.h"
index 20a2a8ee567dd74b37734699f1577a71d42ca6d9..f3176b3f70981aa4fe66c942b3d4ea4bd9d6aa8c 100644 (file)
@@ -1,5 +1,6 @@
 #include "PartyMenu.h"
 
+#include "CapsuleMenu.h"
 #include "ChangeHero.h"
 #include "ConfigMenu.h"
 #include "EquipMenu.h"
@@ -40,7 +41,7 @@ PartyMenu::PartyMenu(GameConfig *game)
        mainMenu.Add(Res().mainMenuStatusText, 4);
        mainMenu.Add(Res().mainMenuSpellText, 1);
        mainMenu.Add(Res().mainMenuChangeText, 5);
-       mainMenu.Add(Res().mainMenuCapsuleText, 2);
+       mainMenu.Add(Res().mainMenuCapsuleText, 2, game->state->capsule);
        mainMenu.Add(Res().mainMenuConfigText, 6);
        mainMenu.Add(Res().mainMenuEquipmentText, 3);
        mainMenu.Add(Res().mainMenuScenarioText, 7);
@@ -98,6 +99,11 @@ void PartyMenu::HandleEvents(const Input &input) {
                                Ctrl().PushState(new SelectHero(this, this, this, OnSpellSelect));
                                break;
                        case MENU_ITEM_CAPSULE:
+                               if (game->state->capsule) {
+                                       Ctrl().PushState(new CapsuleMenu(this));
+                               } else {
+                                       // noise and blur
+                               }
                                break;
                        case MENU_ITEM_EQUIP:
                                Ctrl().PushState(new SelectHero(this, this, this, OnEquipSelect));
index 79aecf6ea1f424df934a2118cf87631f46f908fa..a355909d87b1412bba23871fdd8102a0b060e1a6 100644 (file)
@@ -56,7 +56,9 @@ Resources::Resources()
 , gutLabel(0)
 , mgrLabel(0)
 
+, hpLabel(0)
 , ipLabel(0)
+, levelLabel(0)
 , experienceLabel(0)
 , nextLevelLabel(0)
 
@@ -69,6 +71,7 @@ Resources::Resources()
 , itemMenuUseText(0)
 , itemMenuSortText(0)
 , itemMenuDropText(0)
+, itemMenuSelectText(0)
 
 , inventoryMenuProperties(0)
 
@@ -98,6 +101,23 @@ Resources::Resources()
 , scenarioMenuProperties(0)
 , scenarioMenuHeadline(0)
 
+, capsulebg(0)
+
+, capsuleMenuProperties(0)
+, capsuleFeedMenuProperties(0)
+
+, capsuleFeedLabel(0)
+, capsuleChangeLabel(0)
+, capsuleNameLabel(0)
+, capsuleClassLabel(0)
+, capsuleAlignmentLabel(0)
+, capsuleTribeLabel(0)
+, capsuleAttack1Label(0)
+, capsuleAttack2Label(0)
+, capsuleAttack3Label(0)
+, capsuleNoAttackText(0)
+, capsuleNotHungryText(0)
+
 { }
 
 
@@ -145,7 +165,9 @@ void Resources::CreateTypeDescription() {
        td.AddField("gutLabel", FieldDescription(((char *)&r.gutLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
        td.AddField("mgrLabel", FieldDescription(((char *)&r.mgrLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
 
+       td.AddField("hpLabel", FieldDescription(((char *)&r.hpLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
        td.AddField("ipLabel", FieldDescription(((char *)&r.ipLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("levelLabel", FieldDescription(((char *)&r.levelLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
        td.AddField("experienceLabel", FieldDescription(((char *)&r.experienceLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
        td.AddField("nextLevelLabel", FieldDescription(((char *)&r.nextLevelLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
 
@@ -158,6 +180,7 @@ void Resources::CreateTypeDescription() {
        td.AddField("itemMenuUseText", FieldDescription(((char *)&r.itemMenuUseText) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
        td.AddField("itemMenuSortText", FieldDescription(((char *)&r.itemMenuSortText) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
        td.AddField("itemMenuDropText", FieldDescription(((char *)&r.itemMenuDropText) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("itemMenuSelectText", FieldDescription(((char *)&r.itemMenuSelectText) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
 
        td.AddField("inventoryMenu", FieldDescription(((char *)&r.inventoryMenuProperties) - ((char *)&r), MenuProperties::TYPE_ID).SetReferenced().SetDescription("properties of the inventory menu"));
        td.AddField("spellMenu", FieldDescription(((char *)&r.spellMenuProperties) - ((char *)&r), MenuProperties::TYPE_ID).SetReferenced().SetDescription("properties of the spell menu"));
@@ -185,6 +208,23 @@ void Resources::CreateTypeDescription() {
 
        td.AddField("scenarioMenu", FieldDescription(((char *)&r.scenarioMenuProperties) - ((char *)&r), MenuProperties::TYPE_ID).SetReferenced().SetDescription("properties of the scenario menu"));
        td.AddField("scenarioMenuHeadline", FieldDescription(((char *)&r.scenarioMenuHeadline) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+
+       td.AddField("capsulebg", FieldDescription(((char *)&r.capsulebg) - ((char *)&r), Texture::TYPE_ID).SetReferenced().SetDescription("background texture for the capsule menus"));
+
+       td.AddField("capsuleMenu", FieldDescription(((char *)&r.capsuleMenuProperties) - ((char *)&r), MenuProperties::TYPE_ID).SetReferenced().SetDescription("properties of the capsule main menu (the bottom bar)"));
+       td.AddField("capsuleFeedMenu", FieldDescription(((char *)&r.capsuleFeedMenuProperties) - ((char *)&r), MenuProperties::TYPE_ID).SetReferenced().SetDescription("properties of the capsule feed menu (above the inventory)"));
+
+       td.AddField("capsuleFeedLabel", FieldDescription(((char *)&r.capsuleFeedLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleChangeLabel", FieldDescription(((char *)&r.capsuleChangeLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleNameLabel", FieldDescription(((char *)&r.capsuleNameLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleClassLabel", FieldDescription(((char *)&r.capsuleClassLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleAlignmentLabel", FieldDescription(((char *)&r.capsuleAlignmentLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleTribeLabel", FieldDescription(((char *)&r.capsuleTribeLabel) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleAttack1Label", FieldDescription(((char *)&r.capsuleAttack1Label) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleAttack2Label", FieldDescription(((char *)&r.capsuleAttack2Label) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleAttack3Label", FieldDescription(((char *)&r.capsuleAttack3Label) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleNoAttackText", FieldDescription(((char *)&r.capsuleNoAttackText) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
+       td.AddField("capsuleNotHungryText", FieldDescription(((char *)&r.capsuleNotHungryText) - ((char *)&r), Interpreter::STRING_ID).SetReferenced());
 }
 
 void Resources::Construct(void *data) {
index 9ea26e665000270d0b024e7ef5eaa550cd9b07b3..be2fb2559284568a753346e6404d221710be49c1 100644 (file)
@@ -46,7 +46,9 @@ struct Resources {
        const char *gutLabel;
        const char *mgrLabel;
 
+       const char *hpLabel;
        const char *ipLabel;
+       const char *levelLabel;
        const char *experienceLabel;
        const char *nextLevelLabel;
 
@@ -59,6 +61,7 @@ struct Resources {
        const char *itemMenuUseText;
        const char *itemMenuSortText;
        const char *itemMenuDropText;
+       const char *itemMenuSelectText;
 
        graphics::MenuProperties *inventoryMenuProperties;
 
@@ -88,6 +91,23 @@ struct Resources {
        graphics::MenuProperties *scenarioMenuProperties;
        const char *scenarioMenuHeadline;
 
+       graphics::Texture *capsulebg;
+
+       graphics::MenuProperties *capsuleMenuProperties;
+       graphics::MenuProperties *capsuleFeedMenuProperties;
+
+       const char *capsuleFeedLabel;
+       const char *capsuleChangeLabel;
+       const char *capsuleNameLabel;
+       const char *capsuleClassLabel;
+       const char *capsuleAlignmentLabel;
+       const char *capsuleTribeLabel;
+       const char *capsuleAttack1Label;
+       const char *capsuleAttack2Label;
+       const char *capsuleAttack3Label;
+       const char *capsuleNoAttackText;
+       const char *capsuleNotHungryText;
+
        Resources();
 
        static void CreateTypeDescription();
index 9896d8605ee3b55019e449cb09be3a680344bceb..2c317bb29c158eaf77daeec8a61607830ba8eb84 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "PartyMenu.h"
 #include "Resources.h"
+#include "../app/Application.h"
 #include "../app/Input.h"
 #include "../common/GameConfig.h"
 #include "../common/GameState.h"
index b42a39afa04d4724a3385282fe7d02545a5c9dd6..bb66d3c6fcbddff09d6ae5187a0c2b72e3b540fa 100644 (file)
@@ -3,6 +3,7 @@
 #include "HeroStatus.h"
 #include "PartyMenu.h"
 #include "Resources.h"
+#include "../app/Application.h"
 #include "../app/Input.h"
 #include "../common/GameConfig.h"
 #include "../common/GameState.h"
index 466e34b846ddddc7da6961d947adfef8b7d5070a..59322d1a68287f14b6abbd461462b635ca05488b 100644 (file)
@@ -3,6 +3,10 @@
 
 namespace menu {
 
+class CapsuleChangeMenu;
+class CapsuleFeedMenu;
+class CapsuleMenu;
+class CapsuleNameMenu;
 class ChangeHero;
 class ConfigMenu;
 class EquipMenu;
diff --git a/test-data/capsulebg.png b/test-data/capsulebg.png
new file mode 100644 (file)
index 0000000..884e33b
Binary files /dev/null and b/test-data/capsulebg.png differ
diff --git a/test-data/capsules.l2h b/test-data/capsules.l2h
new file mode 100644 (file)
index 0000000..e996696
--- /dev/null
@@ -0,0 +1 @@
+Capsule flash
diff --git a/test-data/capsules.l2s b/test-data/capsules.l2s
new file mode 100644 (file)
index 0000000..a4f525e
--- /dev/null
@@ -0,0 +1,56 @@
+Sprite flashSprite {
+       image: :"flash.png",
+       size: <96, 96>
+}
+
+export Capsule flash {
+       name: "Flash",
+       alignment: "LIGHT",
+       maxHealth: 5,
+       stats: Stats {
+               atp: 12,
+               dfp: 18,
+               str:  2,
+               agl: 11,
+               int: 16,
+               gut: 23,
+               mgr: 11
+       },
+       classes: [ CapsuleClass
+               {
+                       name: "4",
+                       tribe: "Twinkle",
+                       battleSprite: flashSprite,
+                       meleeAnimation: SimpleAnimation {
+                               sprite: Sprite {
+                                       image: :"melee-maxim.png",
+                                       size: <96,96>
+                               },
+                               frametime: 66, // two "frames"
+                               framecount: 4
+                       },
+                       attackAnimation: ComplexAnimation {
+                               sprite: flashSprite,
+                               frametime: fourFramesTime,
+                               repeat: false,
+                               frames:
+                               [ ComplexAnimationFrame
+                                       { column: 0, row: 1, disposition: < 0, -16> },
+                                       { column: 0, row: 0, disposition: < 0, -16> },
+                                       { column: 0, row: 1, disposition: < 0, -16> },
+                                       { column: 0, row: 0, disposition: < 0, -16> }
+                               ]
+                       },
+                       healthBoost: 208,
+                       statBoost: Stats {
+                               atp:  38,
+                               dfp:  71,
+                               str:  24,
+                               agl:  78,
+                               int: 195,
+                               gut:  12, // TODO: this is probably higher, but clipped at 199
+                               mgr: 135
+                       }
+               }
+       ]
+}
diff --git a/test-data/flash.png b/test-data/flash.png
new file mode 100644 (file)
index 0000000..85fd123
Binary files /dev/null and b/test-data/flash.png differ
index 8491b37316fa9867848ba3cae311a35fa826ff14..722043d1a8cf73e1089b32885eaa11d62eb9ee20 100644 (file)
@@ -20,7 +20,8 @@ export PartyLayout heroesLayout {
                < 48,136>,
                <128,136>,
                < 80,152>,
-               <160,152>
+               <160,152>,
+               <216,144>
        ]
 }
 
@@ -697,6 +698,7 @@ export MenuResources menuResources {
                colGap: 32,
                cursor: menuCursor,
                font: menuFont,
+               disabledFont: menuInactiveFont,
                wrapX: true,
                wrapY: true
        },
@@ -727,7 +729,9 @@ export MenuResources menuResources {
        intLabel: "INT",
        gutLabel: "GUT",
        mgrLabel: "MGR",
+       hpLabel: "HP",
        ipLabel: "IP",
+       levelLabel: "LEVEL",
        experienceLabel: "NOW EXP",
        nextLevelLabel: "NEXT LEVEL",
        statusMenu: MenuProperties {
@@ -756,6 +760,7 @@ export MenuResources menuResources {
        itemMenuUseText: "USE",
        itemMenuSortText: "SORT",
        itemMenuDropText: "DROP",
+       itemMenuSelectText: "SELECT",
        inventoryMenu: MenuProperties {
                cols: 1,
                rows: 6,
@@ -767,7 +772,8 @@ export MenuResources menuResources {
                disabledFont: menuInactiveFont,
                iconSpace: 16,
                charsPerNumber: 2,
-               delimiter: ":"
+               delimiter: ":",
+               thirdColumnHack: 1
        },
        spellMenu: MenuProperties {
                cols: 2,
@@ -835,5 +841,38 @@ export MenuResources menuResources {
                cursor: menuCursor,
                font: menuFont
        },
-       scenarioMenuHeadline: "SCENARIO ITEM"
+       scenarioMenuHeadline: "SCENARIO ITEM",
+       capsulebg: Texture {
+               image: :"capsulebg.png",
+               size: <64, 64>
+       },
+       capsuleMenu: MenuProperties {
+               cols: 3,
+               rows: 1,
+               charsPerEntry: 7,
+               cursor: menuCursor,
+               selectedCursor: menuActiveCursor,
+               font: menuFont,
+               thirdColumnHack: 2
+       },
+       capsuleFeedMenu: MenuProperties {
+               cols: 2,
+               rows: 1,
+               charsPerEntry: 7,
+               colGap: 32,
+               cursor: menuCursor,
+               selectedCursor: menuActiveCursor,
+               font: menuFont
+       },
+       capsuleFeedLabel: "FEED",
+       capsuleChangeLabel: "CHANGE",
+       capsuleNameLabel: "NAME",
+       capsuleClassLabel: "CLASS",
+       capsuleAlignmentLabel: "ALI.",
+       capsuleTribeLabel: "TRIBE",
+       capsuleAttack1Label: "SP.1",
+       capsuleAttack2Label: "SP.2",
+       capsuleAttack3Label: "SP.3",
+       capsuleNoAttackText: "Nothing",
+       capsuleNotHungryText: "I'm not hungry."
 }