]> git.localhorst.tv Git - l2e.git/commitdiff
Merge branch 'master' into menus
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 11 Nov 2012 15:36:25 +0000 (16:36 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Sun, 11 Nov 2012 15:36:25 +0000 (16:36 +0100)
I'm not putting up with changing build settings on every checkout

Conflicts:
Debug/makefile
Debug/sources.mk
Debug/src/graphics/subdir.mk
Release/makefile
Release/sources.mk
Release/src/graphics/subdir.mk

42 files changed:
Debug/src/menu/subdir.mk [new file with mode: 0644]
Release/src/menu/subdir.mk [new file with mode: 0644]
src/common/GameConfig.cpp
src/common/GameConfig.h
src/common/GameState.cpp
src/common/GameState.h
src/common/Hero.cpp
src/common/Hero.h
src/graphics/Font.cpp
src/graphics/Font.h
src/graphics/Frame.cpp
src/graphics/Menu.h
src/graphics/Texture.cpp [new file with mode: 0644]
src/graphics/Texture.h [new file with mode: 0644]
src/graphics/fwd.h
src/main.cpp
src/map/MapState.cpp
src/menu/ChangeHero.cpp [new file with mode: 0644]
src/menu/ChangeHero.h [new file with mode: 0644]
src/menu/HeroStatus.cpp [new file with mode: 0644]
src/menu/HeroStatus.h [new file with mode: 0644]
src/menu/InventoryMenu.cpp [new file with mode: 0644]
src/menu/InventoryMenu.h [new file with mode: 0644]
src/menu/PartyMenu.cpp [new file with mode: 0644]
src/menu/PartyMenu.h [new file with mode: 0644]
src/menu/Resources.cpp [new file with mode: 0644]
src/menu/Resources.h [new file with mode: 0644]
src/menu/SelectHero.cpp [new file with mode: 0644]
src/menu/SelectHero.h [new file with mode: 0644]
src/menu/StatusMenu.cpp [new file with mode: 0644]
src/menu/StatusMenu.h [new file with mode: 0644]
src/menu/fwd.h [new file with mode: 0644]
test-data/hero-cursor.png [new file with mode: 0644]
test-data/menu-cursor-active.png [new file with mode: 0644]
test-data/menu-cursor.png [new file with mode: 0644]
test-data/menu-font.png [new file with mode: 0644]
test-data/menubg.png [new file with mode: 0644]
test-data/normal-font.png
test-data/shoulder-nav.png [new file with mode: 0644]
test-data/status-frame.png [new file with mode: 0644]
test-data/status-labels.png [new file with mode: 0644]
test-data/test.l2s

diff --git a/Debug/src/menu/subdir.mk b/Debug/src/menu/subdir.mk
new file mode 100644 (file)
index 0000000..49f3428
--- /dev/null
@@ -0,0 +1,42 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables 
+CPP_SRCS += \
+../src/menu/ChangeHero.cpp \
+../src/menu/HeroStatus.cpp \
+../src/menu/InventoryMenu.cpp \
+../src/menu/PartyMenu.cpp \
+../src/menu/Resources.cpp \
+../src/menu/SelectHero.cpp \
+../src/menu/StatusMenu.cpp 
+
+OBJS += \
+./src/menu/ChangeHero.o \
+./src/menu/HeroStatus.o \
+./src/menu/InventoryMenu.o \
+./src/menu/PartyMenu.o \
+./src/menu/Resources.o \
+./src/menu/SelectHero.o \
+./src/menu/StatusMenu.o 
+
+CPP_DEPS += \
+./src/menu/ChangeHero.d \
+./src/menu/HeroStatus.d \
+./src/menu/InventoryMenu.d \
+./src/menu/PartyMenu.d \
+./src/menu/Resources.d \
+./src/menu/SelectHero.d \
+./src/menu/StatusMenu.d 
+
+
+# Each subdirectory must supply rules for building sources it contributes
+src/menu/%.o: ../src/menu/%.cpp
+       @echo 'Building file: $<'
+       @echo 'Invoking: GCC C++ Compiler'
+       g++ -I/usr/include/SDL -O0 -g3 -Wall -Werror -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
+       @echo 'Finished building: $<'
+       @echo ' '
+
+
diff --git a/Release/src/menu/subdir.mk b/Release/src/menu/subdir.mk
new file mode 100644 (file)
index 0000000..bfcd29c
--- /dev/null
@@ -0,0 +1,42 @@
+################################################################################
+# Automatically-generated file. Do not edit!
+################################################################################
+
+# Add inputs and outputs from these tool invocations to the build variables 
+CPP_SRCS += \
+../src/menu/ChangeHero.cpp \
+../src/menu/HeroStatus.cpp \
+../src/menu/InventoryMenu.cpp \
+../src/menu/PartyMenu.cpp \
+../src/menu/Resources.cpp \
+../src/menu/SelectHero.cpp \
+../src/menu/StatusMenu.cpp 
+
+OBJS += \
+./src/menu/ChangeHero.o \
+./src/menu/HeroStatus.o \
+./src/menu/InventoryMenu.o \
+./src/menu/PartyMenu.o \
+./src/menu/Resources.o \
+./src/menu/SelectHero.o \
+./src/menu/StatusMenu.o 
+
+CPP_DEPS += \
+./src/menu/ChangeHero.d \
+./src/menu/HeroStatus.d \
+./src/menu/InventoryMenu.d \
+./src/menu/PartyMenu.d \
+./src/menu/Resources.d \
+./src/menu/SelectHero.d \
+./src/menu/StatusMenu.d 
+
+
+# Each subdirectory must supply rules for building sources it contributes
+src/menu/%.o: ../src/menu/%.cpp
+       @echo 'Building file: $<'
+       @echo 'Invoking: GCC C++ Compiler'
+       g++ -DNDEBUG -I/usr/include/SDL -O3 -Wall -Werror -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
+       @echo 'Finished building: $<'
+       @echo ' '
+
+
index b35e99161d437b19ff05c2888e97831be641d3c3..6673a326686a90200ae10f9c370add18233dc0c2 100644 (file)
@@ -12,7 +12,8 @@ namespace common {
 GameConfig::GameConfig()
 : state(0)
 , battleResources(0)
-, heroesLayout(0) {
+, heroesLayout(0)
+, menuResources(0) {
 
 }
 
index 16b0142b426e058aca16564c648bd61f7f06b619..c13b4ab3efc60609684c9af47499ca45bdf3196d 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "fwd.h"
 #include "../battle/fwd.h"
+#include "../menu/fwd.h"
 
 namespace common {
 
@@ -22,6 +23,8 @@ struct GameConfig {
        battle::Resources *battleResources;
        battle::PartyLayout *heroesLayout;
 
+       menu::Resources *menuResources;
+
 };
 
 }
index 7992d43980e0a9888835e3c7dba8793079e8b4ed..ee7b1b2b51fda40a979b8ead46526a0aadd0ae7c 100644 (file)
@@ -10,7 +10,9 @@
 namespace common {
 
 GameState::GameState()
-: money(0) {
+: partySize(1)
+, money(0)
+, time(0) {
        party[0] = heroes;
        party[1] = 0;
        party[2] = 0;
index fca50c1f846138168edd40cba990363ad49b6ea8..078da1a3738cba03eeae82eadbe2c8d0711eca54 100644 (file)
@@ -21,10 +21,12 @@ struct GameState {
 
        Hero heroes[7];
        Hero *party[4];
+       int partySize;
 
        Inventory inventory;
 
        Uint32 money;
+       Uint32 time;
 
 };
 
index 02c4dcc05b8e4fc8807f0d266e31d9652d539c14..8222e124ce8e81686a876fbc94c23dd25c99a95f 100644 (file)
@@ -32,6 +32,9 @@ Hero::Hero()
 , ip(0)
 
 , level(0)
+, experience(0)
+, levelLadder(0)
+, numLevels(0)
 
 , weapon(0)
 , armor(0)
@@ -63,6 +66,16 @@ void Hero::SubtractHealth(int amount) {
 }
 
 
+int Hero::NextLevel() const {
+       int levelOffset(Level() - 1);
+       if (levelOffset < numLevels) {
+               return levelLadder[levelOffset] - Experience();
+       } else {
+               return 0;
+       }
+}
+
+
 void Hero::CreateTypeDescription() {
        Hero h;
 
@@ -81,6 +94,7 @@ void Hero::CreateTypeDescription() {
        td.AddField("stats", FieldDescription(((char *)&h.stats) - ((char *)&h), Stats::TYPE_ID));
 
        td.AddField("level", FieldDescription(((char *)&h.level) - ((char *)&h), Interpreter::NUMBER_ID));
+       td.AddField("ladder", FieldDescription(((char *)&h.levelLadder) - ((char *)&h), Interpreter::NUMBER_ID).SetReferenced().SetAggregate());
 
        td.AddField("battleSprite", FieldDescription(((char *)&h.battleSprite) - ((char *)&h), Sprite::TYPE_ID).SetReferenced().SetDescription("the sprite used for battle scenes"));
        td.AddField("attackAnimation", FieldDescription(((char *)&h.attackAnimation) - ((char *)&h), Animation::TYPE_ID).SetReferenced().SetDescription("the animation played for physical attacks"));
index ca4651c947d66003583879145d4b44b4c304b9c7..77269c6b25572415a43c32da5e83cbd15c001f47 100644 (file)
@@ -47,6 +47,8 @@ public:
        const Stats &GetStats() const { return stats; }
 
        Uint8 Level() const { return level; }
+       int Experience() const { return experience; }
+       int NextLevel() const;
 
        Item *Weapon() { return weapon; }
        Item *Armor() { return armor; }
@@ -72,6 +74,7 @@ public:
        const std::vector<const Spell *> &Spells() const { return spells; }
 
        graphics::Sprite *BattleSprite() { return battleSprite; }
+       const graphics::Sprite *BattleSprite() const { return battleSprite; }
        graphics::Animation *MeleeAnimation() { return meleeAnimation; }
        graphics::Animation *AttackAnimation() { return attackAnimation; }
        graphics::Animation *SpellAnimation() { return spellAnimation; }
@@ -103,6 +106,10 @@ private:
        Stats stats;
 
        int level;
+       int experience;
+
+       int *levelLadder;
+       int numLevels;
 
        Item *weapon;
        Item *armor;
index be96a2c104b860f0e9dda819388c92c0fa206d81..59059e07436d1893da0a9fc7dc73612fe5c79a92 100644 (file)
@@ -39,6 +39,18 @@ void Font::DrawString(const char *s, SDL_Surface *dest, const Vector<int> &posit
        }
 }
 
+void Font::DrawStringRight(const char *s, SDL_Surface *dest, const Vector<int> &positionIn, int maxChars) const {
+       if (!sprite) return;
+
+       int length(0);
+       while (length < maxChars && s[length] != '\0') {
+               ++length;
+       }
+       Vector<int> position(positionIn.X() - length * CharWidth(), positionIn.Y());
+
+       DrawString(s, dest, position, length);
+}
+
 void Font::DrawDigit(int digit, SDL_Surface *dest, const Vector<int> &position) const {
        if (!sprite) return;
 
@@ -76,6 +88,14 @@ 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());
+
+       DrawNumber(number, dest, position, digits);
+}
+
 
 void Font::CreateTypeDescription() {
        Font f;
index 07cd35f0a5f32867e33487fbb082b578d589478d..b981946642925a10980d48532a89d9d3065afb05 100644 (file)
@@ -31,8 +31,10 @@ public:
        int CharHeight() const { return sprite->Height(); }
        void DrawChar(char c, SDL_Surface *dest, const geometry::Vector<int> &position) const;
        void DrawString(const char *s, SDL_Surface *dest, const geometry::Vector<int> &position, int maxChars = 0) const;
+       void DrawStringRight(const char *s, SDL_Surface *dest, const geometry::Vector<int> &position, int maxChars = 0) const;
        void DrawDigit(int d, SDL_Surface *dest, const geometry::Vector<int> &position) const;
        void DrawNumber(int n, SDL_Surface *dest, const geometry::Vector<int> &position, int digits = 0) const;
+       void DrawNumberRight(int n, SDL_Surface *dest, const geometry::Vector<int> &position, int digits = 0) const;
 
 public:
        void SetSprite(const Sprite *s) { sprite = s; }
index 46fa1b59db7c799255c282f90e9fe92c654a509d..86b9cd25d5d7b5d06c0213aea81ef303db945b96 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "Frame.h"
 
+#include "Texture.h"
 #include "../loader/Interpreter.h"
 #include "../loader/TypeDescription.h"
 
@@ -40,55 +41,26 @@ void Frame::Draw(SDL_Surface *dest, const Vector<int> &position, int width, int
        SDL_BlitSurface(surface, &srcRect, dest, &destRect);
 
        // top border
-       srcRect.x += BorderWidth();
-       srcRect.w = RepeatWidth();
-       destRect.x += BorderWidth();
-       int fullRepeatWidth(width - (2 * BorderWidth()));
-       int repeatCursor(0);
-       while (repeatCursor < fullRepeatWidth) {
-               SDL_BlitSurface(surface, &srcRect, dest, &destRect);
-               destRect.x += RepeatWidth();
-               repeatCursor += RepeatWidth();
-       }
+       Texture(surface, Vector<int>(RepeatWidth(), BorderHeight()), Vector<int>(offset.X() + BorderWidth(), offset.Y()))
+       .Render(dest, Vector<int>(position.X() + BorderWidth(), position.Y()), Vector<int>(position.X() + width - BorderWidth(), position.Y() + BorderHeight()));
 
        // top-right corner
-       srcRect.x += RepeatWidth();
+       srcRect.x = offset.X() + RepeatWidth() + BorderWidth();
        srcRect.w = BorderWidth();
+       destRect.x = position.X() + width - BorderWidth();
        SDL_BlitSurface(surface, &srcRect, dest, &destRect);
 
-       // middle
-       destRect.y += BorderHeight();
-       int fullRepeatHeight(height - (2 * BorderHeight()));
-       int hRepeatCursor(0);
-       while (hRepeatCursor < fullRepeatHeight) {
-
-               // left border
-               srcRect.x = offset.X();
-               srcRect.y = offset.Y() + BorderHeight();
-               srcRect.w = BorderWidth();
-               srcRect.h = RepeatHeight();
-               destRect.x = position.X();
-               SDL_BlitSurface(surface, &srcRect, dest, &destRect);
-
-               // fill
-               repeatCursor = 0;
-               srcRect.x += BorderWidth();
-               srcRect.w = RepeatWidth();
-               destRect.x += BorderWidth();
-               while (repeatCursor < fullRepeatWidth) {
-                       SDL_BlitSurface(surface, &srcRect, dest, &destRect);
-                       destRect.x += RepeatWidth();
-                       repeatCursor += RepeatWidth();
-               }
-
-               // right border
-               srcRect.x += RepeatWidth();
-               srcRect.w = BorderWidth();
-               SDL_BlitSurface(surface, &srcRect, dest, &destRect);
-
-               destRect.y += RepeatHeight();
-               hRepeatCursor += RepeatHeight();
-       }
+       // left border
+       Texture(surface, Vector<int>(BorderWidth(), RepeatHeight()), Vector<int>(offset.X(), offset.Y() + BorderHeight()))
+       .Render(dest, Vector<int>(position.X(), position.Y() + BorderHeight()), Vector<int>(position.X() + BorderWidth(), position.Y() + height - BorderHeight()));
+
+       // center fill
+       Texture(surface, RepeatSize(), Vector<int>(offset.X() + BorderWidth(), offset.Y() + BorderHeight()))
+       .Render(dest, position + BorderSize(), position + Vector<int>(width, height) - BorderSize());
+
+       // right border
+       Texture(surface, Vector<int>(BorderWidth(), RepeatHeight()), Vector<int>(offset.X() + BorderWidth() + RepeatWidth(), offset.Y() + BorderHeight()))
+       .Render(dest, Vector<int>(position.X() + width - BorderWidth(), position.Y() + BorderHeight()), Vector<int>(position.X() + width, position.Y() + height - BorderHeight()));
 
        // bottom-left corner
        srcRect.x = offset.X();
@@ -96,27 +68,17 @@ void Frame::Draw(SDL_Surface *dest, const Vector<int> &position, int width, int
        srcRect.w = BorderWidth();
        srcRect.h = BorderHeight();
        destRect.x = position.X();
+       destRect.y = position.Y() + height - BorderHeight();
        SDL_BlitSurface(surface, &srcRect, dest, &destRect);
 
        // bottom border
-       srcRect.x += BorderWidth();
-       srcRect.w = RepeatWidth();
-       destRect.x += BorderWidth();
-       repeatCursor = 0;
-       while (repeatCursor < fullRepeatWidth) {
-               SDL_BlitSurface(surface, &srcRect, dest, &destRect);
-               destRect.x += RepeatWidth();
-               repeatCursor += RepeatWidth();
-       }
-       if (fullRepeatWidth < fullRepeatWidth) {
-               srcRect.w = fullRepeatWidth - fullRepeatWidth;
-               SDL_BlitSurface(surface, &srcRect, dest, &destRect);
-               destRect.x += fullRepeatWidth - fullRepeatWidth;
-       }
+       Texture(surface, Vector<int>(RepeatWidth(), BorderHeight()), Vector<int>(offset.X() + BorderWidth(), offset.Y() + BorderHeight() + RepeatHeight()))
+       .Render(dest, Vector<int>(position.X() + BorderWidth(), position.Y() + height - BorderHeight()), Vector<int>(position.X() + width - BorderWidth(), position.Y() + height));
 
        // bottom-right corner
-       srcRect.x += RepeatWidth();
+       srcRect.x = offset.X() + BorderWidth() + RepeatWidth();
        srcRect.w = BorderWidth();
+       destRect.x = position.X() + width - BorderWidth();
        SDL_BlitSurface(surface, &srcRect, dest, &destRect);
 }
 
index 4dc60323571cbeb37134fe51d2bf6f911a231a70..e42f24e0cfcf7334777f99616aaa6fa34c44b990 100644 (file)
@@ -34,16 +34,16 @@ struct MenuProperties {
        int charsPerAdditionalText;
        int additionalTextGap;
        char delimiter;
+       bool wrapX;
+       bool wrapY;
 
        MenuProperties()
        : font(0), disabledFont(0), cursor(0)
-       , charsPerEntry(0), rows(0), rowGap(0)
-       , iconSpace(0), cols(0), colGap(0)
+       , charsPerEntry(0), rows(1), rowGap(0)
+       , iconSpace(0), cols(1), colGap(0)
        , charsPerNumber(0), charsPerAdditionalText(0)
-       , additionalTextGap(0), delimiter(':') { }
-
-       MenuProperties(const Font *font, const Font *disabledFont, const Sprite *cursor, int charsPerEntry, int rows, int rowGap, int iconSpace, int cols, int colGap, int charsPerNumber, char delimiter, int charsPerAdditionalText, int additionalTextGap)
-       : font(font), disabledFont(disabledFont), cursor(cursor), charsPerEntry(charsPerEntry), rows(rows), rowGap(rowGap), iconSpace(iconSpace), cols(cols), colGap(colGap), charsPerNumber(charsPerNumber), charsPerAdditionalText(charsPerAdditionalText), additionalTextGap(additionalTextGap), delimiter(delimiter) { }
+       , additionalTextGap(0), delimiter(':')
+       , wrapX(false), wrapY(false) { }
 
        static void CreateTypeDescription();
        static void Construct(void *);
@@ -57,7 +57,6 @@ class Menu
 public:
        Menu();
        Menu(const MenuProperties &);
-       Menu(const Font *font, const Font *disabledFont, const Sprite *cursor, int charsPerEntry, int rows, int rowGap = 0, int iconSpace = 0, int cols = 1, int colGap = 0, int charsPerNumber = 0, char delimiter = ':', int charsPerAdditionalText = 0, int additionalTextGap = 0);
 
 public:
        int Width() const;
@@ -131,21 +130,6 @@ Menu<T>::Menu(const MenuProperties &p)
 
 }
 
-template<class T>
-Menu<T>::Menu(const Font *font, const Font *disabledFont, const Sprite *cursor, int charsPerEntry, int rows, int rowGap, int iconSpace, int cols, int colGap, int charsPerNumber, char delimiter, int charsPerAdditionalText, int additionalTextGap)
-: MenuProperties(
-               font, disabledFont ? disabledFont : font,
-               cursor, charsPerEntry,
-               rows, rowGap, iconSpace,
-               cols, colGap, charsPerNumber,
-               delimiter,
-               charsPerAdditionalText,
-               additionalTextGap)
-, selected(0)
-, topRow(0) {
-
-}
-
 
 template<class T>
 int Menu<T>::ColWidth() const {
@@ -173,22 +157,38 @@ int Menu<T>::Height() const {
 
 template<class T>
 void Menu<T>::NextItem() {
-       SelectIndex(selected + 1);
+       int index(selected + 1);
+       if (wrapX && index % cols == 0) {
+               index -= cols;
+       }
+       SelectIndex(index);
 }
 
 template<class T>
 void Menu<T>::PreviousItem() {
-       SelectIndex(selected - 1);
+       int index(selected - 1);
+       if (wrapX && selected % cols == 0) {
+               index += cols;
+       }
+       SelectIndex(index);
 }
 
 template<class T>
 void Menu<T>::NextRow() {
-       SelectIndex(selected + cols);
+       int index(selected + cols);
+       if (wrapY && index >= int(entries.size())) {
+               index -= entries.size();
+       }
+       SelectIndex(index);
 }
 
 template<class T>
 void Menu<T>::PreviousRow() {
-       SelectIndex(selected - cols);
+       int index(selected - cols);
+       if (wrapY && index < 0) {
+               index += entries.size();
+       }
+       SelectIndex(index);
 }
 
 template<class T>
@@ -214,6 +214,13 @@ void Menu<T>::Draw(SDL_Surface *dest, const geometry::Vector<int> &position) con
                geometry::Vector<int> iconOffset(
                                (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);
+               }
+
                if (entries[start + i].icon) {
                        entries[start + i].icon->Draw(dest, position + iconOffset);
                }
@@ -234,7 +241,7 @@ void Menu<T>::Draw(SDL_Surface *dest, const geometry::Vector<int> &position) con
                if (charsPerNumber) {
                        usedFont->DrawChar(delimiter, dest, position + textOffset);
                        textOffset += geometry::Vector<int>(usedFont->CharWidth(), 0);
-                       usedFont->DrawNumber(entries[start + i].number, dest, position + textOffset);
+                       usedFont->DrawNumber(entries[start + i].number, dest, position + textOffset, charsPerNumber);
                }
        }
        geometry::Vector<int> cursorOffset(
diff --git a/src/graphics/Texture.cpp b/src/graphics/Texture.cpp
new file mode 100644 (file)
index 0000000..2bb0e97
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Texture.cpp
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#include "Texture.h"
+
+#include "../sdl/utility.h"
+
+using geometry::Vector;
+
+namespace graphics {
+
+Texture::Texture(
+               SDL_Surface *surface,
+               const Vector<int> &size,
+               const Vector<int> &offset)
+: surface(surface)
+, size(size)
+, offset(offset) {
+
+}
+
+Texture::~Texture() {
+
+}
+
+
+void Texture::Render(SDL_Surface *dest, const Vector<int> &from, const Vector<int> &to) const {
+       SDL_Rect destRect;
+       destRect.x = from.X();
+       destRect.y = from.Y();
+       if (!surface || size == Vector<int>()) {
+               destRect.w = to.X() - from.X();
+               destRect.h = to.Y() - from.Y();
+               SDL_FillRect(dest, &destRect, SDL_MapRGB(dest->format, 0xFF, 0x00, 0x00));
+               return;
+       }
+
+       SDL_Rect srcRect;
+       srcRect.x = offset.X();
+       srcRect.y = offset.Y();
+
+       for (destRect.y = from.Y(); destRect.y < to.Y(); destRect.y += size.Y()) {
+               srcRect.h = size.Y();
+               destRect.h = size.Y();
+               if (destRect.y + destRect.h > to.Y()) {
+                       srcRect.h = to.Y() - destRect.y;
+                       destRect.h = to.Y() - destRect.y;
+               }
+               for (destRect.x = from.X(); destRect.x < to.X(); destRect.x += size.X()) {
+                       srcRect.w = size.X();
+                       destRect.w = size.X();
+                       if (destRect.x + destRect.w > to.X()) {
+                               srcRect.w = to.X() - destRect.x;
+                               destRect.w = to.X() - destRect.x;
+                       }
+                       SDL_BlitSurface(surface, &srcRect, dest, &destRect);
+               }
+       }
+}
+
+}
diff --git a/src/graphics/Texture.h b/src/graphics/Texture.h
new file mode 100644 (file)
index 0000000..ecb516a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Texture.h
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#ifndef GRAPHICS_TEXTURE_H_
+#define GRAPHICS_TEXTURE_H_
+
+#include "../geometry/Vector.h"
+
+#include <SDL.h>
+
+namespace graphics {
+
+class Texture {
+
+public:
+       explicit Texture(
+                       SDL_Surface *surface = 0,
+                       const geometry::Vector<int> &size = geometry::Vector<int>(),
+                       const geometry::Vector<int> &offset = geometry::Vector<int>());
+       ~Texture();
+
+public:
+       void Render(SDL_Surface *dest, const geometry::Vector<int> &from, const geometry::Vector<int> &to) const;
+
+public:
+       void SetSurface(SDL_Surface *s) { surface = s; }
+       void SetSize(const geometry::Vector<int> &s) { size = s; }
+       void SetOffset(const geometry::Vector<int> &o) { offset = o; }
+
+private:
+       SDL_Surface *surface;
+       geometry::Vector<int> size;
+       geometry::Vector<int> offset;
+
+};
+
+}
+
+#endif /* GRAPHICS_TEXTURE_H_ */
index 31dbf27f8bace3d9fc9815a83aa1b245969e079a..961890b3471981b6237744f42bd6c231bdc0900e 100644 (file)
@@ -24,6 +24,7 @@ class Menu;
 struct MenuProperties;
 class SimpleAnimation;
 class Sprite;
+class Texture;
 
 }
 
index f70103a0dd411da6755c9cd85240f320855a5ee8..d76eca5c6b1e44be8037810ca842f89ea7060115 100644 (file)
@@ -30,6 +30,7 @@
 #include "graphics/Menu.h"
 #include "graphics/SimpleAnimation.h"
 #include "graphics/Sprite.h"
+#include "graphics/Texture.h"
 #include "loader/Caster.h"
 #include "loader/Interpreter.h"
 #include "loader/ParsedSource.h"
@@ -41,6 +42,7 @@
 #include "map/MapState.h"
 #include "map/Tile.h"
 #include "map/Trigger.h"
+#include "menu/Resources.h"
 #include "sdl/InitImage.h"
 #include "sdl/InitScreen.h"
 #include "sdl/InitSDL.h"
@@ -64,6 +66,7 @@ using common::GameConfig;
 using common::GameState;
 using common::Spell;
 using geometry::Vector;
+using graphics::Texture;
 using loader::Caster;
 using loader::Interpreter;
 using loader::ParsedSource;
@@ -83,8 +86,8 @@ using std::string;
 using std::vector;
 
 int main(int argc, char **argv) {
-       const int width = 800;
-       const int height = 480;
+       const int width = 512;
+       const int height = 448;
 
        const float walkSpeed = 128.0f;
 
@@ -188,6 +191,7 @@ int main(int argc, char **argv) {
                gameState.party[1] = &gameState.heroes[1];
                gameState.party[2] = &gameState.heroes[2];
                gameState.party[3] = &gameState.heroes[3];
+               gameState.partySize = 4;
 
                GameConfig gameConfig;
                gameConfig.state = &gameState;
@@ -268,6 +272,120 @@ int main(int argc, char **argv) {
                gameState.heroes[3].MapEntity().SetFlags(Entity::FLAG_NONBLOCKING);
                gameState.heroes[2].MapEntity().AddFollower(&gameState.heroes[3].MapEntity());
 
+               menu::Resources menuResources;
+               gameConfig.menuResources = &menuResources;
+
+               Texture menubg;
+               menubg.SetSurface(IMG_Load("test-data/menubg.png"));
+               menubg.SetSize(Vector<int>(64, 64));
+               menuResources.menubg = &menubg;
+
+               menuResources.statusFont = gameConfig.battleResources->normalFont;
+
+               graphics::Sprite statusLabels(IMG_Load("test-data/status-labels.png"), 32, 16);
+               menuResources.statusLabels = &statusLabels;
+
+               graphics::Frame statusFrame(IMG_Load("test-data/status-frame.png"), 32, 32, 32, 32);
+               menuResources.statusFrame = &statusFrame;
+
+               graphics::Sprite menuFontSprite(IMG_Load("test-data/menu-font.png"), 16, 16);
+               graphics::Font menuFont(&menuFontSprite, 0, -2);
+
+               menuResources.normalFont = &menuFont;
+
+               graphics::Sprite menuCursor(IMG_Load("test-data/menu-cursor.png"), 32, 16);
+               menuResources.menuCursor = &menuCursor;
+               graphics::Sprite menuActiveCursor(IMG_Load("test-data/menu-cursor-active.png"), 32, 18);
+               menuResources.menuActiveCursor = &menuActiveCursor;
+
+               graphics::MenuProperties mainMenuProperties;
+               mainMenuProperties.cols = 2;
+               mainMenuProperties.rows = 4;
+               mainMenuProperties.charsPerEntry = 8;
+               mainMenuProperties.rowGap = 8;
+               mainMenuProperties.colGap = 32;
+               mainMenuProperties.cursor = &menuCursor;
+               mainMenuProperties.font = &menuFont;
+               mainMenuProperties.wrapX = true;
+               mainMenuProperties.wrapY = true;
+               menuResources.mainMenuProperties = &mainMenuProperties;
+
+               menuResources.mainMenuItemText = "ITEM";
+               menuResources.mainMenuSpellText = "SPELL";
+               menuResources.mainMenuCapsuleText = "CAPSULE";
+               menuResources.mainMenuEquipmentText = "EQUIP";
+               menuResources.mainMenuStatusText = "STATUS";
+               menuResources.mainMenuChangeText = "CHANGE";
+               menuResources.mainMenuConfigText = "CONFIG";
+               menuResources.mainMenuScenarioText = "SCENARIO";
+
+               menuResources.mainMenuTimeText = "TIME";
+               menuResources.mainMenuGoldText = "GOLD";
+
+               graphics::Sprite heroCursor(IMG_Load("test-data/hero-cursor.png"), 64, 16);
+               menuResources.heroCursor = &heroCursor;
+               menuResources.heroCursorBlinkTime = 532;
+
+               menuResources.noEquipmentText = "No equip";
+
+               graphics::Sprite shoulderNav(IMG_Load("test-data/shoulder-nav.png"), 160, 16);
+               menuResources.shoulderNav = &shoulderNav;
+
+               menuResources.atpLabel = "ATP";
+               menuResources.dfpLabel = "DFP";
+               menuResources.strLabel = "STR";
+               menuResources.aglLabel = "AGL";
+               menuResources.intLabel = "INT";
+               menuResources.gutLabel = "GUT";
+               menuResources.mgrLabel = "MGR";
+
+               menuResources.ipLabel = "IP";
+               menuResources.experienceLabel = "NOW EXP";
+               menuResources.nextLevelLabel = "NEXT LEVEL";
+
+               graphics::MenuProperties statusMenuProperties;
+               statusMenuProperties.cols = 2;
+               statusMenuProperties.rows = 1;
+               statusMenuProperties.charsPerEntry = 6;
+               statusMenuProperties.rowGap = 0;
+               statusMenuProperties.colGap = 16;
+               statusMenuProperties.cursor = &menuCursor;
+               statusMenuProperties.font = &menuFont;
+               statusMenuProperties.wrapX = true;
+               menuResources.statusMenuProperties = &statusMenuProperties;
+
+               menuResources.nextLabel = "NEXT";
+               menuResources.returnLabel = "RETURN";
+
+               graphics::MenuProperties itemMenuProperties;
+               itemMenuProperties.cols = 3;
+               itemMenuProperties.rows = 1;
+               itemMenuProperties.charsPerEntry = 5;
+               itemMenuProperties.rowGap = 8;
+               itemMenuProperties.colGap = 16;
+               itemMenuProperties.cursor = &menuCursor;
+               itemMenuProperties.font = &menuFont;
+               itemMenuProperties.wrapX = true;
+               itemMenuProperties.wrapY = true;
+               menuResources.itemMenuProperties = &itemMenuProperties;
+               menuResources.itemMenuUseText = "USE";
+               menuResources.itemMenuSortText = "SORT";
+               menuResources.itemMenuDropText = "DROP";
+
+               graphics::MenuProperties inventoryMenuProperties;
+               inventoryMenuProperties.cols = 1;
+               inventoryMenuProperties.rows = 6;
+               inventoryMenuProperties.charsPerEntry = 13;
+               inventoryMenuProperties.rowGap = 8;
+               inventoryMenuProperties.cursor = &menuCursor;
+               inventoryMenuProperties.font = &menuFont;
+               // TODO: disabled font
+               inventoryMenuProperties.disabledFont = &menuFont;
+               inventoryMenuProperties.iconSpace = 16;
+               inventoryMenuProperties.charsPerNumber = 2;
+               inventoryMenuProperties.delimiter = ':';
+               menuResources.inventoryMenuProperties = &inventoryMenuProperties;
+
                InitScreen screen(width, height);
 
                app::State *state(0);
index 5ec95071963cbfccac3f3920b3ffc0c1ca56343d..af156304b9412c6523e7aec39f7b0547e6fadd3f 100644 (file)
@@ -17,6 +17,7 @@
 #include "../common/GameConfig.h"
 #include "../common/GameState.h"
 #include "../graphics/ColorFade.h"
+#include "../menu/PartyMenu.h"
 
 #include <algorithm>
 
@@ -26,6 +27,7 @@ using battle::BattleState;
 using common::GameConfig;
 using geometry::Vector;
 using graphics::ColorFade;
+using menu::PartyMenu;
 
 namespace map {
 
@@ -69,6 +71,11 @@ void MapState::OnResize(int width, int height) {
 
 
 void MapState::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::ACTION_X)) {
+               Ctrl().PushState(new PartyMenu(game));
+               return;
+       }
+
        if (!controlled) return;
 
        if (input.IsDown(Input::PAD_UP)) {
diff --git a/src/menu/ChangeHero.cpp b/src/menu/ChangeHero.cpp
new file mode 100644 (file)
index 0000000..f1d871d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * ChangeHero.cpp
+ *
+ *  Created on: Nov 4, 2012
+ *      Author: holy
+ */
+
+#include "ChangeHero.h"
+
+#include "HeroStatus.h"
+#include "PartyMenu.h"
+#include "Resources.h"
+#include "SelectHero.h"
+#include "../app/Application.h"
+#include "../app/Input.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+
+#include <algorithm>
+
+using app::Input;
+using geometry::Vector;
+using std::swap;
+
+namespace menu {
+
+ChangeHero::ChangeHero(PartyMenu *parent)
+: parent(parent)
+, highlight(0)
+, selection(0) {
+
+}
+
+
+void ChangeHero::OnEnterState(SDL_Surface *) {
+       const HeroStatus &status(parent->GetHeroStatus(0));
+       highlight = SDL_CreateRGBSurface(0, status.Width(), status.Height(), 32, 0xFF000000, 0xFF0000, 0xFF00, 0);
+       SDL_FillRect(highlight, 0, SDL_MapRGB(highlight->format, 0xFF, 0xFF, 0xFF));
+       SDL_SetAlpha(highlight, SDL_SRCALPHA|SDL_RLEACCEL, 0x20);
+}
+
+void ChangeHero::OnExitState(SDL_Surface *) {
+       SDL_FreeSurface(highlight);
+}
+
+void ChangeHero::OnResumeState(SDL_Surface *) {
+       if (selection < 0) {
+               Ctrl().PopState();
+       } else {
+               selection = -1;
+               Ctrl().PushState(new SelectHero(this, parent, this, OnHeroSelected));
+       }
+}
+
+void ChangeHero::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void ChangeHero::OnResize(int width, int height) {
+
+}
+
+
+int ChangeHero::Width() const {
+       return parent->Width();
+}
+
+int ChangeHero::Height() const {
+       return parent->Height();
+}
+
+
+void ChangeHero::HandleEvents(const Input &input) {
+
+}
+
+void ChangeHero::UpdateWorld(float deltaT) {
+
+}
+
+void ChangeHero::Render(SDL_Surface *screen) {
+       Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+
+       parent->RenderBackground(screen);
+       RenderHighlight(screen, offset);
+       parent->RenderHeros(screen, offset);
+       parent->RenderMenu(screen, offset + Vector<int>(8 * parent->Res().normalFont->CharWidth(), 13 * parent->Res().normalFont->CharHeight() + parent->Res().normalFont->CharHeight() / 8));
+       parent->RenderInfo(screen, offset + Vector<int>(14 * parent->Res().normalFont->CharWidth(), 21 * parent->Res().normalFont->CharHeight() + parent->Res().normalFont->CharHeight() / 8));
+}
+
+void ChangeHero::RenderHighlight(SDL_Surface *screen, const Vector<int> &offset) const {
+       if (selection < 0) return;
+       Vector<int> statusOffset(parent->StatusOffset(selection));
+       statusOffset -= Vector<int>(0, parent->Res().normalFont->CharHeight() / 8);
+       SDL_Rect rect;
+       rect.x = statusOffset.X();
+       rect.y = statusOffset.Y();
+       SDL_BlitSurface(highlight, 0, screen, &rect);
+}
+
+
+void ChangeHero::OnHeroSelected(void *ref, int index) {
+       ChangeHero *self(reinterpret_cast<ChangeHero *>(ref));
+       self->SelectedHero(index);
+}
+
+void ChangeHero::SelectedHero(int index) {
+       if (selection < 0) {
+               selection = index;
+       } else {
+               if (index != selection) {
+                       swap(parent->Game().state->party[selection],
+                                       parent->Game().state->party[index]);
+               }
+               selection = -1;
+       }
+}
+
+}
diff --git a/src/menu/ChangeHero.h b/src/menu/ChangeHero.h
new file mode 100644 (file)
index 0000000..6bb5f31
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * ChangeHero.h
+ *
+ *  Created on: Nov 4, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_CHANGEHERO_H_
+#define MENU_CHANGEHERO_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../geometry/Vector.h"
+
+#include <SDL.h>
+
+namespace menu {
+
+class ChangeHero
+: public app::State {
+
+public:
+       explicit ChangeHero(PartyMenu *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);
+
+       void SelectedHero(int index);
+
+       void RenderHighlight(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+       static void OnHeroSelected(void *, int);
+
+private:
+       PartyMenu *parent;
+       SDL_Surface *highlight;
+       int selection;
+
+};
+
+}
+
+#endif /* MENU_CHANGEHERO_H_ */
diff --git a/src/menu/HeroStatus.cpp b/src/menu/HeroStatus.cpp
new file mode 100644 (file)
index 0000000..5bc0c3b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * HeroStatus.cpp
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#include "HeroStatus.h"
+
+#include "Resources.h"
+#include "../common/Hero.h"
+#include "../graphics/Font.h"
+#include "../graphics/Sprite.h"
+
+using geometry::Vector;
+
+namespace menu {
+
+HeroStatus::HeroStatus()
+: res(0)
+, party(0)
+, hero(0) {
+
+}
+
+HeroStatus::~HeroStatus() {
+
+}
+
+
+int HeroStatus::Width() const {
+       return party[hero]->BattleSprite()->Width() + res->statusFont->CharWidth() * 11;
+}
+
+int HeroStatus::Height() const {
+       return party[hero]->BattleSprite()->Height() + res->statusFont->CharWidth();
+}
+
+
+void HeroStatus::Render(SDL_Surface *screen, const Vector<int> &offset) const {
+       if (!party) return;
+
+       party[hero]->BattleSprite()->Draw(screen, offset, 0, 0);
+
+       // for some reason, fonts are shifted by one pixel in the original
+       Vector<int> nameOffset(
+                       party[hero]->BattleSprite()->Width(),
+                       res->statusFont->CharHeight() * 7 / 8);
+       nameOffset += offset;
+       res->statusFont->DrawString(party[hero]->Name(), screen, nameOffset, 5);
+
+       Vector<int> levelLabelOffset(nameOffset.X() + 6 * res->statusFont->CharWidth(), nameOffset.Y());
+       res->statusLabels->Draw(screen, levelLabelOffset, 0, 0);
+
+       Vector<int> levelOffset(levelLabelOffset.X() + 2 * res->statusFont->CharWidth(), levelLabelOffset.Y());
+       res->statusFont->DrawNumber(party[hero]->Level(), screen, levelOffset, 2);
+
+       Vector<int> healthLabelOffset(nameOffset.X(), nameOffset.Y() + res->statusFont->CharHeight());
+       res->statusLabels->Draw(screen, healthLabelOffset, 0, 1);
+
+       Vector<int> healthOffset(nameOffset.X() + 3 * res->statusFont->CharWidth(), nameOffset.Y() + res->statusFont->CharHeight());
+       res->statusFont->DrawNumber(party[hero]->Health(), screen, healthOffset, 3);
+
+       Vector<int> healthSeparatorOffset(healthOffset.X() + 3 * res->statusFont->CharWidth(), healthOffset.Y());
+       res->statusFont->DrawChar('/', screen, healthSeparatorOffset);
+
+       Vector<int> maxHealthOffset(healthSeparatorOffset.X() + res->statusFont->CharWidth(), healthOffset.Y());
+       res->statusFont->DrawNumber(party[hero]->MaxHealth(), screen, maxHealthOffset, 3);
+
+       Vector<int> manaLabelOffset(healthLabelOffset.X(), healthLabelOffset.Y() + res->statusFont->CharHeight());
+       res->statusLabels->Draw(screen, manaLabelOffset, 0, 2);
+
+       Vector<int> manaOffset(healthOffset.X(), healthOffset.Y() + res->statusFont->CharHeight());
+       res->statusFont->DrawNumber(party[hero]->Mana(), screen, manaOffset, 3);
+
+       Vector<int> manaSeparatorOffset(healthSeparatorOffset.X(), manaOffset.Y());
+       res->statusFont->DrawChar('/', screen, manaSeparatorOffset);
+
+       Vector<int> maxManaOffset(maxHealthOffset.X(), manaOffset.Y());
+       res->statusFont->DrawNumber(party[hero]->MaxMana(), screen, maxManaOffset, 3);
+}
+
+}
diff --git a/src/menu/HeroStatus.h b/src/menu/HeroStatus.h
new file mode 100644 (file)
index 0000000..27c048e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * HeroStatus.h
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_HEROSTATUS_H_
+#define MENU_HEROSTATUS_H_
+
+#include "fwd.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+
+#include <SDL.h>
+
+namespace menu {
+
+class HeroStatus {
+
+public:
+       HeroStatus();
+       ~HeroStatus();
+
+public:
+       void SetResources(const Resources *r) { res = r; }
+       void SetHero(common::Hero **p, int h) { party = p; hero = h; }
+
+       int Width() const;
+       int Height() const;
+       geometry::Vector<int> Size() const { return geometry::Vector<int>(Width(), Height()); }
+
+       void Render(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+       const Resources *res;
+       common::Hero **party;
+       int hero;
+
+};
+
+}
+
+#endif /* MENU_HEROSTATUS_H_ */
diff --git a/src/menu/InventoryMenu.cpp b/src/menu/InventoryMenu.cpp
new file mode 100644 (file)
index 0000000..2ea7fb3
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * InventoryMenu.cpp
+ *
+ *  Created on: Nov 4, 2012
+ *      Author: holy
+ */
+
+#include "InventoryMenu.h"
+
+#include "PartyMenu.h"
+#include "Resources.h"
+#include "../app/Input.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../common/Inventory.h"
+#include "../common/Item.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+
+using app::Input;
+using common::Inventory;
+using common::Item;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+InventoryMenu::InventoryMenu(PartyMenu *parent)
+: parent(parent)
+, menu(*parent->Res().itemMenuProperties)
+, itemMenu(*parent->Res().inventoryMenuProperties) {
+       menu.Add(parent->Res().itemMenuUseText, 0);
+       menu.Add(parent->Res().itemMenuSortText, 1);
+       menu.Add(parent->Res().itemMenuDropText, 2);
+}
+
+
+void InventoryMenu::OnEnterState(SDL_Surface *) {
+       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) {
+                       itemMenu.Add(item->Name(), item, item->CanUseOnStatusScreen(), item->MenuIcon(), inv.ItemCountAt(i));
+               } else {
+                       itemMenu.AddEmptyEntry();
+               }
+       }
+}
+
+void InventoryMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void InventoryMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void InventoryMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void InventoryMenu::OnResize(int width, int height) {
+
+}
+
+
+void InventoryMenu::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::PAD_LEFT)) {
+               menu.PreviousItem();
+       }
+       if (input.JustPressed(Input::PAD_RIGHT)) {
+               menu.NextItem();
+       }
+
+       if (input.JustPressed(Input::PAD_UP)) {
+               itemMenu.PreviousItem();
+       }
+       if (input.JustPressed(Input::PAD_DOWN)) {
+               itemMenu.NextItem();
+       }
+}
+
+void InventoryMenu::UpdateWorld(float deltaT) {
+
+}
+
+
+void InventoryMenu::Render(SDL_Surface *screen) {
+       const Font &font(*parent->Res().normalFont);
+       Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+       Vector<int> menuOffset(font.CharWidth(), 13 * font.CharHeight() + font.CharHeight() / 8);
+       Vector<int> inventoryOffset(font.CharWidth(), 16 * font.CharHeight() + font.CharHeight() / 8);
+
+       parent->RenderBackground(screen);
+       parent->RenderHeros(screen, offset);
+       RenderMenu(screen, menuOffset + offset);
+       RenderInventory(screen, inventoryOffset + offset);
+}
+
+int InventoryMenu::Width() const {
+       return parent->Width();
+}
+
+int InventoryMenu::Height() const {
+       return parent->Height();
+}
+
+void InventoryMenu::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> menuFrameOffset(offset.X() + 8 * font.CharWidth(), offset.Y());
+       const Vector<int> menuOffset(menuFrameOffset.X() + 3 * font.CharWidth(), menuFrameOffset.Y() + font.CharHeight());
+
+       frame.Draw(screen, offset, 8 * font.CharWidth(), 3 * font.CharHeight());
+       font.DrawString(parent->Res().mainMenuItemText, screen, labelOffset + offset);
+       frame.Draw(screen, menuFrameOffset, 22 * font.CharWidth(), 3 * font.CharHeight());
+       menu.Draw(screen, menuOffset);
+}
+
+void InventoryMenu::RenderInventory(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() + font.CharHeight() / 4);
+
+       frame.Draw(screen, offset, 30 * font.CharWidth(), 11 * font.CharHeight());
+       itemMenu.Draw(screen, offset + menuOffset);
+}
+
+}
diff --git a/src/menu/InventoryMenu.h b/src/menu/InventoryMenu.h
new file mode 100644 (file)
index 0000000..20cbe17
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * InventoryMenu.h
+ *
+ *  Created on: Nov 4, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_INVENTORYMENU_H_
+#define MENU_INVENTORYMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class InventoryMenu
+: public app::State {
+
+public:
+       explicit InventoryMenu(PartyMenu *parent);
+
+public:
+       virtual void HandleEvents(const app::Input &);
+       virtual void UpdateWorld(float deltaT);
+       virtual void Render(SDL_Surface *);
+
+       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);
+
+       void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderInventory(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+       PartyMenu *parent;
+       graphics::Menu<int> menu;
+       graphics::Menu<const common::Item *> itemMenu;
+
+};
+
+}
+
+#endif /* MENU_INVENTORYMENU_H_ */
diff --git a/src/menu/PartyMenu.cpp b/src/menu/PartyMenu.cpp
new file mode 100644 (file)
index 0000000..07b7770
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * PartyMenu.cpp
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#include "PartyMenu.h"
+
+#include "ChangeHero.h"
+#include "InventoryMenu.h"
+#include "Resources.h"
+#include "SelectHero.h"
+#include "StatusMenu.h"
+#include "../app/Application.h"
+#include "../app/Input.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+#include "../graphics/Texture.h"
+
+using app::Input;
+using common::GameConfig;
+using geometry::Vector;
+
+namespace menu {
+
+PartyMenu::PartyMenu(GameConfig *game)
+: game(game)
+, mainMenu(*game->menuResources->mainMenuProperties) {
+       for (int i(0); i < 4; ++i) {
+               status[i].SetHero(game->state->party, i);
+               status[i].SetResources(game->menuResources);
+       }
+       statusPositions[0] = Vector<int>(0, 0);
+       statusPositions[1] = Vector<int>(status[0].Width(), 0);
+       statusPositions[2] = Vector<int>(0, status[0].Height());
+       statusPositions[3] = Vector<int>(status[0].Width(), status[0].Height());
+
+       mainMenu.Add(Res().mainMenuItemText, 0);
+       mainMenu.Add(Res().mainMenuStatusText, 4);
+       mainMenu.Add(Res().mainMenuSpellText, 1);
+       mainMenu.Add(Res().mainMenuChangeText, 5);
+       mainMenu.Add(Res().mainMenuCapsuleText, 2);
+       mainMenu.Add(Res().mainMenuConfigText, 6);
+       mainMenu.Add(Res().mainMenuEquipmentText, 3);
+       mainMenu.Add(Res().mainMenuScenarioText, 7);
+}
+
+PartyMenu::~PartyMenu() {
+
+}
+
+
+void PartyMenu::OnEnterState(SDL_Surface *) {
+
+}
+
+void PartyMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void PartyMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void PartyMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void PartyMenu::OnResize(int width, int height) {
+
+}
+
+
+void PartyMenu::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::ACTION_B)) {
+               Ctrl().PopState();
+               return;
+       }
+
+       if (input.JustPressed(Input::PAD_UP)) {
+               mainMenu.PreviousRow();
+       } else if (input.JustPressed(Input::PAD_RIGHT)) {
+               mainMenu.NextItem();
+       } else if (input.JustPressed(Input::PAD_DOWN)) {
+               mainMenu.NextRow();
+       } else if (input.JustPressed(Input::PAD_LEFT)) {
+               mainMenu.PreviousItem();
+       }
+
+       if (input.JustPressed(Input::ACTION_A)) {
+               switch (mainMenu.Selected()) {
+                       case MENU_ITEM_ITEM:
+                               Ctrl().PushState(new InventoryMenu(this));
+                               break;
+                       case MENU_ITEM_SPELL:
+                               break;
+                       case MENU_ITEM_CAPSULE:
+                               break;
+                       case MENU_ITEM_EQUIP:
+                               break;
+                       case MENU_ITEM_STATUS:
+                               Ctrl().PushState(new SelectHero(this, this, this, OnStatusSelect));
+                               break;
+                       case MENU_ITEM_CHANGE:
+                               Ctrl().PushState(new ChangeHero(this));
+                               break;
+                       case MENU_ITEM_CONFIG:
+                               break;
+                       case MENU_ITEM_SCENARIO:
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
+void PartyMenu::UpdateWorld(float deltaT) {
+
+}
+
+void PartyMenu::Render(SDL_Surface *screen) {
+       Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+
+       RenderBackground(screen);
+       RenderHeros(screen, offset);
+       RenderMenu(screen, offset + Vector<int>(8 * Res().normalFont->CharWidth(), 13 * Res().normalFont->CharHeight() + Res().normalFont->CharHeight() / 8));
+       RenderInfo(screen, offset + Vector<int>(14 * Res().normalFont->CharWidth(), 21 * Res().normalFont->CharHeight() + Res().normalFont->CharHeight() / 8));
+}
+
+int PartyMenu::Width() const {
+       return 2 * (status[0].Width() + Res().normalFont->CharWidth());
+}
+
+int PartyMenu::Height() const {
+       return 2 * Res().normalFont->CharHeight()
+                       + 2 * status[0].Height()
+                       + Res().normalFont->CharHeight()
+                       + 8 * Res().normalFont->CharHeight()
+                       + 5 * Res().normalFont->CharHeight()
+                       + 2 * Res().normalFont->CharHeight();
+}
+
+void PartyMenu::RenderBackground(SDL_Surface *screen) const {
+       Res().menubg->Render(screen, Vector<int>(), Vector<int>(screen->w, screen->h));
+}
+
+void PartyMenu::RenderHeros(SDL_Surface *screen, const Vector<int> &offset) const {
+       for (int i(0); i < 4; ++i) {
+               status[i].Render(screen, offset + StatusOffset(i));
+       }
+}
+
+Vector<int> PartyMenu::StatusOffset(int index) const {
+       return statusPositions[index] + Vector<int>(Res().normalFont->CharWidth(), 2 * Res().normalFont->CharHeight());
+}
+
+void PartyMenu::RenderMenu(SDL_Surface *screen, const Vector<int> &offset) const {
+       Vector<int> menuOffset(3 * Res().normalFont->CharWidth(), Res().normalFont->CharHeight() + Res().normalFont->CharHeight() / 4);
+
+       Res().statusFrame->Draw(screen, offset, 23 * Res().normalFont->CharWidth(), 8 * Res().normalFont->CharHeight());
+       mainMenu.Draw(screen, offset + menuOffset);
+}
+
+void PartyMenu::RenderInfo(SDL_Surface *screen, const Vector<int> &offset) const {
+       Res().statusFrame->Draw(screen, offset, 17 * Res().normalFont->CharWidth(), 5 * Res().normalFont->CharHeight());
+
+       Vector<int> timeLabelOffset(2 * Res().normalFont->CharWidth(), Res().normalFont->CharHeight() + Res().normalFont->CharHeight() / 4);
+       Res().normalFont->DrawString(Res().mainMenuTimeText, screen, offset + timeLabelOffset);
+
+       Vector<int> hoursOffset(timeLabelOffset.X() + 6 * Res().normalFont->CharWidth(), timeLabelOffset.Y());
+       Res().normalFont->DrawNumber(game->state->time / 60 / 60, screen, offset + hoursOffset, 4);
+
+       Vector<int> timeSeparatorOffset(hoursOffset.X() + 4 * Res().normalFont->CharWidth(), hoursOffset.Y());
+       Res().normalFont->DrawChar(':', screen, offset + timeSeparatorOffset);
+
+       Vector<int> minutesOffset(timeSeparatorOffset.X() + Res().normalFont->CharWidth(), timeSeparatorOffset.Y());
+       Res().normalFont->DrawNumber(game->state->time / 60, screen, offset + minutesOffset, 2);
+       if (game->state->time / 60 < 10) {
+               Res().normalFont->DrawChar('0', screen, offset + minutesOffset);
+       }
+
+       Vector<int> goldLabelOffset(2 * Res().normalFont->CharWidth(), 2 * Res().normalFont->CharHeight() + Res().normalFont->CharHeight() * 3 / 4);
+       Res().normalFont->DrawString(Res().mainMenuGoldText, screen, offset + goldLabelOffset);
+
+       Vector<int> goldOffset(goldLabelOffset.X() + 6 * Res().normalFont->CharWidth(), goldLabelOffset.Y());
+       Res().normalFont->DrawNumber(game->state->money, screen, offset + goldOffset, 7);
+}
+
+
+Resources &PartyMenu::Res() {
+       return *game->menuResources;
+}
+
+const Resources &PartyMenu::Res() const {
+       return *game->menuResources;
+}
+
+void PartyMenu::OnStatusSelect(void *ref, int index) {
+       PartyMenu *self(reinterpret_cast<PartyMenu *>(ref));
+       self->Ctrl().ChangeState(
+                       new StatusMenu(self, index));
+}
+
+}
diff --git a/src/menu/PartyMenu.h b/src/menu/PartyMenu.h
new file mode 100644 (file)
index 0000000..fa1b92f
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * PartyMenu.h
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_PARTYMENU_H_
+#define MENU_PARTYMENU_H_
+
+#include "fwd.h"
+#include "HeroStatus.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class PartyMenu
+: public app::State {
+
+public:
+       explicit PartyMenu(common::GameConfig *);
+       virtual ~PartyMenu();
+
+public:
+       virtual void HandleEvents(const app::Input &);
+       virtual void UpdateWorld(float deltaT);
+       virtual void Render(SDL_Surface *);
+
+public:
+       common::GameConfig &Game() { return *game; }
+       const common::GameConfig &Game() const { return *game; }
+       Resources &Res();
+       const Resources &Res() const;
+
+       int Width() const;
+       int Height() const;
+
+public:
+       void RenderBackground(SDL_Surface *screen) const;
+       void RenderHeros(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderInfo(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+       geometry::Vector<int> StatusOffset(int index) const;
+       const HeroStatus &GetHeroStatus(int index) const { return status[index]; }
+
+       static void OnStatusSelect(void *, int);
+
+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:
+       enum MenuItem {
+               MENU_ITEM_ITEM,
+               MENU_ITEM_SPELL,
+               MENU_ITEM_CAPSULE,
+               MENU_ITEM_EQUIP,
+               MENU_ITEM_STATUS,
+               MENU_ITEM_CHANGE,
+               MENU_ITEM_CONFIG,
+               MENU_ITEM_SCENARIO,
+       };
+
+private:
+       HeroStatus status[4];
+       geometry::Vector<int> statusPositions[4];
+       common::GameConfig *game;
+       graphics::Menu<int> mainMenu;
+
+};
+
+}
+
+#endif /* MENU_PARTYMENU_H_ */
diff --git a/src/menu/Resources.cpp b/src/menu/Resources.cpp
new file mode 100644 (file)
index 0000000..28f5cb6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Resources.cpp
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#include "Resources.h"
+
+namespace menu {
+
+Resources::Resources()
+: menubg(0)
+, normalFont(0)
+, statusFont(0)
+
+, menuCursor(0)
+, menuActiveCursor(0)
+
+, statusLabels(0)
+, statusFrame(0)
+
+, mainMenuProperties(0)
+, mainMenuItemText(0)
+, mainMenuSpellText(0)
+, mainMenuCapsuleText(0)
+, mainMenuEquipmentText(0)
+, mainMenuStatusText(0)
+, mainMenuChangeText(0)
+, mainMenuConfigText(0)
+, mainMenuScenarioText(0)
+
+, mainMenuTimeText(0)
+, mainMenuGoldText(0)
+
+, heroCursor(0)
+, heroCursorBlinkTime(0)
+
+, noEquipmentText(0)
+
+, shoulderNav(0)
+
+, atpLabel(0)
+, dfpLabel(0)
+, strLabel(0)
+, aglLabel(0)
+, intLabel(0)
+, gutLabel(0)
+, mgrLabel(0)
+
+, ipLabel(0)
+, experienceLabel(0)
+, nextLevelLabel(0)
+
+, statusMenuProperties(0)
+
+, nextLabel(0)
+, returnLabel(0)
+
+, itemMenuProperties(0)
+, itemMenuUseText(0)
+, itemMenuSortText(0)
+, itemMenuDropText(0)
+
+, inventoryMenuProperties(0) {
+
+}
+
+}
diff --git a/src/menu/Resources.h b/src/menu/Resources.h
new file mode 100644 (file)
index 0000000..05ceaf3
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Resources.h
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_RESOURCES_H_
+#define MENU_RESOURCES_H_
+
+#include "../graphics/fwd.h"
+
+namespace menu {
+
+struct Resources {
+
+       graphics::Texture *menubg;
+
+       graphics::Font *normalFont;
+       graphics::Font *statusFont;
+
+       graphics::Sprite *menuCursor;
+       graphics::Sprite *menuActiveCursor;
+
+       graphics::Sprite *statusLabels;
+       graphics::Frame *statusFrame;
+
+       graphics::MenuProperties *mainMenuProperties;
+       const char *mainMenuItemText;
+       const char *mainMenuSpellText;
+       const char *mainMenuCapsuleText;
+       const char *mainMenuEquipmentText;
+       const char *mainMenuStatusText;
+       const char *mainMenuChangeText;
+       const char *mainMenuConfigText;
+       const char *mainMenuScenarioText;
+
+       const char *mainMenuTimeText;
+       const char *mainMenuGoldText;
+
+       graphics::Sprite *heroCursor;
+       int heroCursorBlinkTime;
+
+       const char *noEquipmentText;
+
+       graphics::Sprite *shoulderNav;
+
+       const char *atpLabel;
+       const char *dfpLabel;
+       const char *strLabel;
+       const char *aglLabel;
+       const char *intLabel;
+       const char *gutLabel;
+       const char *mgrLabel;
+
+       const char *ipLabel;
+       const char *experienceLabel;
+       const char *nextLevelLabel;
+
+       graphics::MenuProperties *statusMenuProperties;
+
+       const char *nextLabel;
+       const char *returnLabel;
+
+       graphics::MenuProperties *itemMenuProperties;
+       const char *itemMenuUseText;
+       const char *itemMenuSortText;
+       const char *itemMenuDropText;
+
+       graphics::MenuProperties *inventoryMenuProperties;
+
+       Resources();
+
+};
+
+}
+
+#endif /* MENU_RESOURCES_H_ */
diff --git a/src/menu/SelectHero.cpp b/src/menu/SelectHero.cpp
new file mode 100644 (file)
index 0000000..12690db
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * SelectHero.cpp
+ *
+ *  Created on: Oct 22, 2012
+ *      Author: holy
+ */
+
+#include "SelectHero.h"
+
+#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"
+#include "../common/Hero.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Sprite.h"
+
+using app::Input;
+using geometry::Vector;
+
+namespace menu {
+
+SelectHero::SelectHero(app::State *parent, PartyMenu *pm, void *ref, Callback cb, int cursor)
+: parent(parent)
+, partyMenu(pm)
+, ref(ref)
+, callback(cb)
+, cursor(cursor) {
+
+}
+
+
+void SelectHero::OnEnterState(SDL_Surface *) {
+       cursorBlink = GraphicsTimers().StartInterval(Res().heroCursorBlinkTime);
+}
+
+void SelectHero::OnExitState(SDL_Surface *) {
+
+}
+
+void SelectHero::OnResumeState(SDL_Surface *) {
+
+}
+
+void SelectHero::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void SelectHero::OnResize(int width, int height) {
+
+}
+
+
+void SelectHero::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::ACTION_A)) {
+               callback(ref, cursor);
+       }
+       if (input.JustPressed(Input::ACTION_B)) {
+               Ctrl().PopState();
+       }
+
+       if (input.JustPressed(Input::PAD_UP)) {
+               SelectUp();
+       } else if (input.JustPressed(Input::PAD_RIGHT)) {
+               SelectRight();
+       } else if (input.JustPressed(Input::PAD_DOWN)) {
+               SelectDown();
+       } else if (input.JustPressed(Input::PAD_LEFT)) {
+               SelectLeft();
+       }
+}
+
+void SelectHero::SelectUp() {
+       cursor = (cursor + 2) % partyMenu->Game().state->partySize;
+       cursorBlink.Restart();
+}
+
+void SelectHero::SelectRight() {
+       cursor = (cursor + 1) % partyMenu->Game().state->partySize;
+       cursorBlink.Restart();
+}
+
+void SelectHero::SelectDown() {
+       cursor = (cursor + 2) % partyMenu->Game().state->partySize;
+       cursorBlink.Restart();
+}
+
+void SelectHero::SelectLeft() {
+       cursor = (cursor + 3) % partyMenu->Game().state->partySize;
+       cursorBlink.Restart();
+}
+
+
+common::GameConfig &SelectHero::Game() {
+       return partyMenu->Game();
+}
+
+const common::GameConfig &SelectHero::Game() const {
+       return partyMenu->Game();
+}
+
+Resources &SelectHero::Res() {
+       return partyMenu->Res();
+}
+
+const Resources &SelectHero::Res() const {
+       return partyMenu->Res();
+}
+
+
+void SelectHero::UpdateWorld(float deltaT) {
+
+}
+
+
+void SelectHero::Render(SDL_Surface *screen) {
+       parent->Render(screen);
+       if (cursorBlink.Iteration() % 2 == 0) {
+               RenderCursor(screen);
+       }
+}
+
+void SelectHero::RenderCursor(SDL_Surface *screen) const {
+       Vector<int> position(
+                       0, Game().state->party[cursor]->BattleSprite()->Height());
+       position += partyMenu->StatusOffset(cursor);
+       Res().heroCursor->Draw(screen, position);
+}
+
+}
diff --git a/src/menu/SelectHero.h b/src/menu/SelectHero.h
new file mode 100644 (file)
index 0000000..5e67152
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SelectHero.h
+ *
+ *  Created on: Oct 22, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_SELECTHERO_H_
+#define MENU_SELECTHERO_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../app/Timer.h"
+#include "../common/fwd.h"
+
+#include <SDL.h>
+
+namespace menu {
+
+class SelectHero
+: public app::State {
+
+public:
+       typedef void (*Callback)(void *, int selection);
+
+public:
+       SelectHero(app::State *parent, PartyMenu *partyMenu, void *ref, Callback, int initialHero = 0);
+
+public:
+       virtual void HandleEvents(const app::Input &);
+       virtual void UpdateWorld(float deltaT);
+       virtual void Render(SDL_Surface *);
+
+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:
+       common::GameConfig &Game();
+       const common::GameConfig &Game() const;
+       Resources &Res();
+       const Resources &Res() const;
+
+       void SelectUp();
+       void SelectRight();
+       void SelectDown();
+       void SelectLeft();
+
+       void RenderCursor(SDL_Surface *screen) const;
+
+private:
+       app::State *parent;
+       PartyMenu *partyMenu;
+       void *ref;
+       Callback callback;
+       app::Timer<Uint32> cursorBlink;
+       int cursor;
+
+};
+
+}
+
+#endif /* MENU_SELECTHERO_H_ */
diff --git a/src/menu/StatusMenu.cpp b/src/menu/StatusMenu.cpp
new file mode 100644 (file)
index 0000000..3a9b38f
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * StatusMenu.cpp
+ *
+ *  Created on: Oct 22, 2012
+ *      Author: holy
+ */
+
+#include "StatusMenu.h"
+
+#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"
+#include "../common/Hero.h"
+#include "../common/Item.h"
+#include "../common/Stats.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+
+using app::Input;
+using common::Hero;
+using common::Item;
+using common::Stats;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+StatusMenu::StatusMenu(PartyMenu *parent, int cursor)
+: parent(parent)
+, cursor(cursor)
+, menu(*parent->Res().statusMenuProperties) {
+       menu.Add(parent->Res().nextLabel, 0);
+       menu.Add(parent->Res().returnLabel, 1);
+}
+
+
+void StatusMenu::OnEnterState(SDL_Surface *) {
+
+}
+
+void StatusMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void StatusMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void StatusMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void StatusMenu::OnResize(int width, int height) {
+
+}
+
+
+void StatusMenu::HandleEvents(const Input &input) {
+       if (input.JustPressed(Input::SHOULDER_RIGHT)) {
+               NextHero();
+       }
+       if (input.JustPressed(Input::SHOULDER_LEFT)) {
+               PreviousHero();
+       }
+
+       if (input.JustPressed(Input::PAD_LEFT)) {
+               menu.PreviousItem();
+       }
+       if (input.JustPressed(Input::PAD_RIGHT)) {
+               menu.NextItem();
+       }
+
+       if (input.JustPressed(Input::ACTION_A)) {
+               if (menu.Selected() == 0) {
+                       NextHero();
+               } else if (menu.Selected() == 1) {
+                       Ctrl().PopState();
+               }
+       }
+       if (input.JustPressed(Input::ACTION_B)) {
+               Ctrl().PopState();
+       }
+}
+
+void StatusMenu::UpdateWorld(float deltaT) {
+
+}
+
+void StatusMenu::Render(SDL_Surface *screen) {
+       Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+       Vector<int> shoulderNavOffset(
+                       5 * parent->Res().statusFont->CharWidth(),
+                       parent->Res().statusFont->CharHeight());
+       Vector<int> statsOffset(
+                       4 * parent->Res().statusFont->CharWidth(),
+                       8 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+       Vector<int> equipOffset(
+                       17 * parent->Res().statusFont->CharWidth(),
+                       4 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+       Vector<int> experienceOffset(
+                       11 * parent->Res().statusFont->CharWidth(),
+                       17 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+       Vector<int> nextLevelOffset(
+                       11 * parent->Res().statusFont->CharWidth(),
+                       20 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+       Vector<int> ikariOffset(
+                       17 * parent->Res().statusFont->CharWidth(),
+                       17 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+       Vector<int> menuOffset(
+                       parent->Res().statusFont->CharWidth(),
+                       23 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+
+       parent->RenderBackground(screen);
+       parent->Res().shoulderNav->Draw(screen, offset + shoulderNavOffset);
+       RenderStatus(screen, offset + parent->StatusOffset(0));
+       RenderStats(screen, offset + statsOffset);
+       RenderEquipment(screen, offset + equipOffset);
+       RenderExperience(screen, experienceOffset);
+       RenderNextLevel(screen, nextLevelOffset);
+       RenderIkari(screen, ikariOffset);
+       RenderMenu(screen, menuOffset);
+}
+
+int StatusMenu::Width() const {
+       return parent->Width();
+}
+
+int StatusMenu::Height() const {
+       return parent->Height();
+}
+
+void StatusMenu::RenderStatus(SDL_Surface *screen, const Vector<int> &offset) const {
+       parent->GetHeroStatus(cursor).Render(screen, offset);
+}
+
+void StatusMenu::RenderStats(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Stats &stats(GetHero().GetStats());
+       Vector<int> lineBreak(0, parent->Res().statusFont->CharHeight());
+
+       Vector<int> position(offset);
+       RenderStatsLine(parent->Res().atpLabel, stats.Attack(), screen, position);
+
+       position += lineBreak;
+       RenderStatsLine(parent->Res().dfpLabel, stats.Defense(), screen, position);
+
+       position += lineBreak;
+       RenderStatsLine(parent->Res().strLabel, stats.Strength(), screen, position);
+
+       position += lineBreak;
+       RenderStatsLine(parent->Res().aglLabel, stats.Agility(), screen, position);
+
+       position += lineBreak;
+       RenderStatsLine(parent->Res().intLabel, stats.Intelligence(), screen, position);
+
+       position += lineBreak;
+       RenderStatsLine(parent->Res().gutLabel, stats.Gut(), screen, position);
+
+       position += lineBreak;
+       RenderStatsLine(parent->Res().mgrLabel, stats.MagicResistance(), screen, position);
+}
+
+void StatusMenu::RenderStatsLine(const char *label, int number, SDL_Surface *screen, const Vector<int> &position) const {
+       const Font &font(*parent->Res().statusFont);
+       const Vector<int> numberOffset(4 * font.CharWidth(), 0);
+
+       font.DrawString(label, screen, position, 3);
+       font.DrawNumber(number, screen, position + numberOffset, 3);
+}
+
+void StatusMenu::RenderEquipment(SDL_Surface *screen, const Vector<int> &offset) const {
+       const Hero &hero(GetHero());
+       Vector<int> lineBreak(0, 2 * parent->Res().statusFont->CharHeight());
+
+       Vector<int> position(offset);
+       RenderEquipmentLine(hero.Weapon(), screen, position);
+
+       position += lineBreak;
+       RenderEquipmentLine(hero.Armor(), screen, position);
+
+       position += lineBreak;
+       RenderEquipmentLine(hero.Shield(), screen, position);
+
+       position += lineBreak;
+       RenderEquipmentLine(hero.Helmet(), screen, position);
+
+       position += lineBreak;
+       RenderEquipmentLine(hero.Ring(), screen, position);
+
+       position += lineBreak;
+       RenderEquipmentLine(hero.Jewel(), screen, position);
+}
+
+void StatusMenu::RenderEquipmentLine(const Item *item, SDL_Surface *screen, const Vector<int> &position) const {
+       const Font &font(*parent->Res().statusFont);
+       const Vector<int> textOffset(font.CharWidth(), 0);
+       if (item) {
+               if (item->MenuIcon()) {
+                       item->MenuIcon()->Draw(screen, position);
+               }
+               font.DrawString(item->Name(), screen, position + textOffset);
+       } else {
+               font.DrawString(parent->Res().noEquipmentText, screen, position + textOffset);
+       }
+}
+
+void StatusMenu::RenderExperience(SDL_Surface *screen, const geometry::Vector<int> &offset) const {
+       const Font &font(*parent->Res().statusFont);
+       font.DrawStringRight(parent->Res().experienceLabel, screen, offset, 10);
+
+       Vector<int> numberOffset(offset.X(), offset.Y() + font.CharHeight());
+       font.DrawNumberRight(GetHero().Experience(), screen, numberOffset, 7);
+}
+
+void StatusMenu::RenderNextLevel(SDL_Surface *screen, const geometry::Vector<int> &offset) const {
+       const Font &font(*parent->Res().statusFont);
+       font.DrawStringRight(parent->Res().nextLevelLabel, screen, offset, 10);
+
+       Vector<int> numberOffset(offset.X(), offset.Y() + font.CharHeight());
+       font.DrawNumberRight(GetHero().NextLevel(), screen, numberOffset, 7);
+}
+
+void StatusMenu::RenderIkari(SDL_Surface *screen, const geometry::Vector<int> &offset) const {
+       const Font &font(*parent->Res().statusFont);
+       font.DrawString(parent->Res().ipLabel, screen, offset, 5);
+
+       Vector<int> numberOffset(offset.X() + 5 * font.CharWidth(), offset.Y());
+       font.DrawNumber(GetHero().RelativeIP(100), screen, numberOffset, 3);
+
+       Vector<int> percentOffset(offset.X() + 8 * font.CharWidth(), offset.Y());
+       font.DrawChar('%', screen, percentOffset);
+}
+
+void StatusMenu::RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const {
+       const Font &font(*parent->Res().normalFont);
+       const Frame &frame(*parent->Res().statusFrame);
+
+       Vector<int> labelOffset(2 * font.CharWidth(), font.CharHeight());
+       frame.Draw(screen, offset, 10 * font.CharWidth(), 3 * font.CharHeight());
+       font.DrawString(parent->Res().mainMenuStatusText, screen, offset + labelOffset);
+
+       Vector<int> menuFrameOffset(10 * font.CharWidth(), 0);
+       Vector<int> menuOffset(13 * font.CharWidth(), font.CharHeight());
+       frame.Draw(screen, offset + menuFrameOffset, 20 * font.CharWidth(), 3 * font.CharHeight());
+       menu.Draw(screen, offset + menuOffset);
+}
+
+
+void StatusMenu::NextHero() {
+       cursor = (cursor + 1) % parent->Game().state->partySize;
+}
+
+void StatusMenu::PreviousHero() {
+       cursor = (cursor + parent->Game().state->partySize - 1) % parent->Game().state->partySize;
+}
+
+const Hero &StatusMenu::GetHero() const {
+       return *parent->Game().state->party[cursor];
+}
+
+}
diff --git a/src/menu/StatusMenu.h b/src/menu/StatusMenu.h
new file mode 100644 (file)
index 0000000..5f6f986
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * StatusMenu.h
+ *
+ *  Created on: Oct 22, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_STATUSMENU_H_
+#define MENU_STATUSMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class StatusMenu
+: public app::State {
+
+public:
+       StatusMenu(PartyMenu *parent, int heroIndex);
+
+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);
+
+       void NextHero();
+       void PreviousHero();
+
+       const common::Hero &GetHero() const;
+
+       void RenderStatus(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderStats(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderStatsLine(const char *label, int number, SDL_Surface *screen, const geometry::Vector<int> &position) const;
+       void RenderEquipment(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderEquipmentLine(const common::Item *, SDL_Surface *screen, const geometry::Vector<int> &position) const;
+       /// @param offset the top right corner!
+       void RenderExperience(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       /// @param offset the top right corner!
+       void RenderNextLevel(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderIkari(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+       void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+       PartyMenu *parent;
+       int cursor;
+       graphics::Menu<int> menu;
+
+};
+
+}
+
+#endif /* MENU_STATUSMENU_H_ */
diff --git a/src/menu/fwd.h b/src/menu/fwd.h
new file mode 100644 (file)
index 0000000..5e08e00
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * fwd.h
+ *
+ *  Created on: Oct 21, 2012
+ *      Author: holy
+ */
+
+#ifndef MENU_FWD_H_
+#define MENU_FWD_H_
+
+namespace menu {
+
+class ChangeHero;
+class HeroStatus;
+class InventoryMenu;
+class PartyMenu;
+struct Resources;
+class SelectHero;
+class StatusMenu;
+
+}
+
+#endif /* MENU_FWD_H_ */
diff --git a/test-data/hero-cursor.png b/test-data/hero-cursor.png
new file mode 100644 (file)
index 0000000..0496815
Binary files /dev/null and b/test-data/hero-cursor.png differ
diff --git a/test-data/menu-cursor-active.png b/test-data/menu-cursor-active.png
new file mode 100644 (file)
index 0000000..bee2487
Binary files /dev/null and b/test-data/menu-cursor-active.png differ
diff --git a/test-data/menu-cursor.png b/test-data/menu-cursor.png
new file mode 100644 (file)
index 0000000..b5743f1
Binary files /dev/null and b/test-data/menu-cursor.png differ
diff --git a/test-data/menu-font.png b/test-data/menu-font.png
new file mode 100644 (file)
index 0000000..a8122a8
Binary files /dev/null and b/test-data/menu-font.png differ
diff --git a/test-data/menubg.png b/test-data/menubg.png
new file mode 100644 (file)
index 0000000..1b42927
Binary files /dev/null and b/test-data/menubg.png differ
index 8a1532b71e4b679183ffd0079da7f2890df107b4..0c49e2c35f597457411e5ea6b566a0e3f584b252 100644 (file)
Binary files a/test-data/normal-font.png and b/test-data/normal-font.png differ
diff --git a/test-data/shoulder-nav.png b/test-data/shoulder-nav.png
new file mode 100644 (file)
index 0000000..54edbe6
Binary files /dev/null and b/test-data/shoulder-nav.png differ
diff --git a/test-data/status-frame.png b/test-data/status-frame.png
new file mode 100644 (file)
index 0000000..c6ea569
Binary files /dev/null and b/test-data/status-frame.png differ
diff --git a/test-data/status-labels.png b/test-data/status-labels.png
new file mode 100644 (file)
index 0000000..93fcebc
Binary files /dev/null and b/test-data/status-labels.png differ
index 4a4bb059b16dc9de5e1d57922bad2d2224354121..1267b9f9854ffcd979177574d6331d78c0e85250 100644 (file)
@@ -88,6 +88,9 @@ export Hero maxim {
                gut: 100,
                mgr:  10
        },
+       ladder: [
+               10
+       ],
        attackAnimation: ComplexAnimation {
                sprite: maximSprite,
                frametime: frameTime,