*.o
*.d
*.l2o
-build/*/l2e
+/build/*/l2e
+/build/*/local.mk
shots/
bin/*
l2e.depend
<Unit filename="src\common\GameState.h" />
<Unit filename="src\common\Hero.cpp" />
<Unit filename="src\common\Hero.h" />
- <Unit filename="src\common\HeroGroup.h" />
<Unit filename="src\common\Ikari.cpp" />
<Unit filename="src\common\Ikari.h" />
<Unit filename="src\common\Inventory.cpp" />
<Unit filename="src\map\Trigger.cpp" />
<Unit filename="src\map\Trigger.h" />
<Unit filename="src\map\fwd.h" />
+ <Unit filename="src\menu\ChangeHero.cpp" />
+ <Unit filename="src\menu\ChangeHero.h" />
+ <Unit filename="src\menu\ConfigMenu.cpp" />
+ <Unit filename="src\menu\ConfigMenu.h" />
+ <Unit filename="src\menu\EquipMenu.cpp" />
+ <Unit filename="src\menu\EquipMenu.h" />
+ <Unit filename="src\menu\fwd.h" />
+ <Unit filename="src\menu\HeroStatus.cpp" />
+ <Unit filename="src\menu\HeroStatus.h" />
+ <Unit filename="src\menu\InventoryMenu.cpp" />
+ <Unit filename="src\menu\InventoryMenu.h" />
+ <Unit filename="src\menu\PartyMenu.cpp" />
+ <Unit filename="src\menu\PartyMenu.h" />
+ <Unit filename="src\menu\Resources.cpp" />
+ <Unit filename="src\menu\Resources.h" />
+ <Unit filename="src\menu\ScenarioMenu.cpp" />
+ <Unit filename="src\menu\ScenarioMenu.h" />
+ <Unit filename="src\menu\SelectHero.cpp" />
+ <Unit filename="src\menu\SelectHero.h" />
+ <Unit filename="src\menu\SpellMenu.cpp" />
+ <Unit filename="src\menu\SpellMenu.h" />
+ <Unit filename="src\menu\StatusMenu.cpp" />
+ <Unit filename="src\menu\StatusMenu.h" />
<Unit filename="src\sdl\InitImage.cpp" />
<Unit filename="src\sdl\InitImage.h" />
<Unit filename="src\sdl\InitSDL.cpp" />
common::Stats &GetStats() { return stats; }
const common::Stats &GetStats() const { return stats; }
- common::Item *Weapon() { return master->Weapon(); }
- common::Item *Armor() { return master->Armor(); }
- common::Item *Shield() { return master->Shield(); }
- common::Item *Helmet() { return master->Helmet(); }
- common::Item *Ring() { return master->Ring(); }
- common::Item *Jewel() { return master->Jewel(); }
-
- const common::Item *Weapon() const { return master->Weapon(); }
- const common::Item *Armor() const { return master->Armor(); }
- const common::Item *Shield() const { return master->Shield(); }
- const common::Item *Helmet() const { return master->Helmet(); }
- const common::Item *Ring() const { return master->Ring(); }
- const common::Item *Jewel() const { return master->Jewel(); }
-
- bool HasWeapon() const { return master->HasWeapon(); }
- bool HasArmor() const { return master->HasArmor(); }
- bool HasShield() const { return master->HasShield(); }
- bool HasHelmet() const { return master->HasHelmet(); }
- bool HasRing() const { return master->HasRing(); }
- bool HasJewel() const { return master->HasJewel(); }
+ const common::Item *Weapon() const { return master->Equipment(common::Hero::EQUIP_WEAPON); }
+ const common::Item *Armor() const { return master->Equipment(common::Hero::EQUIP_ARMOR); }
+ const common::Item *Shield() const { return master->Equipment(common::Hero::EQUIP_SHIELD); }
+ const common::Item *Helmet() const { return master->Equipment(common::Hero::EQUIP_HELMET); }
+ const common::Item *Ring() const { return master->Equipment(common::Hero::EQUIP_RING); }
+ const common::Item *Jewel() const { return master->Equipment(common::Hero::EQUIP_JEWEL); }
+
+ bool HasWeapon() const { return master->Equipped(common::Hero::EQUIP_WEAPON); }
+ bool HasArmor() const { return master->Equipped(common::Hero::EQUIP_ARMOR); }
+ bool HasShield() const { return master->Equipped(common::Hero::EQUIP_SHIELD); }
+ bool HasHelmet() const { return master->Equipped(common::Hero::EQUIP_HELMET); }
+ bool HasRing() const { return master->Equipped(common::Hero::EQUIP_RING); }
+ bool HasJewel() const { return master->Equipped(common::Hero::EQUIP_JEWEL); }
graphics::AnimationRunner &GetAnimation() { return animation; }
const graphics::AnimationRunner &GetAnimation() const { return animation; }
GameConfig::GameConfig()
: state(0)
, battleResources(0)
-, heroesLayout(0) {
+, heroesLayout(0)
+, menuResources(0) {
}
#include "fwd.h"
#include "../battle/fwd.h"
+#include "../menu/fwd.h"
namespace common {
battle::Resources *battleResources;
battle::PartyLayout *heroesLayout;
+ menu::Resources *menuResources;
+
};
}
namespace common {
GameState::GameState()
-: money(0) {
+: partySize(1)
+, money(0)
+, time(0)
+, messageSpeed(MESSAGE_SPEED_NORMAL)
+, battleCursor(CURSOR_CLEAR)
+, statusCursor(CURSOR_CLEAR)
+, music(MUSIC_STEREO) {
party[0] = heroes;
party[1] = 0;
party[2] = 0;
Hero heroes[7];
Hero *party[4];
+ int partySize;
Inventory inventory;
Uint32 money;
+ Uint32 time;
+
+ enum MessageSpeed {
+ MESSAGE_SPEED_FAST,
+ MESSAGE_SPEED_NORMAL,
+ MESSAGE_SPEED_SLOW,
+ };
+ enum Cursor {
+ CURSOR_CLEAR,
+ CURSOR_MEMORY,
+ };
+ enum Music {
+ MUSIC_STEREO,
+ MUSIC_MONO,
+ };
+ int messageSpeed;
+ int battleCursor;
+ int statusCursor;
+ int music;
};
#include "Hero.h"
+#include "Item.h"
+#include "Spell.h"
#include "../graphics/Animation.h"
#include "../graphics/Sprite.h"
#include "../loader/Interpreter.h"
#include "../loader/TypeDescription.h"
#include "../map/Entity.h"
+#include <cstring>
+
using graphics::Animation;
using graphics::Sprite;
using loader::FieldDescription;
using loader::Interpreter;
using loader::TypeDescription;
using map::Entity;
+using std::memset;
+
namespace common {
, ip(0)
, level(0)
+, experience(0)
+, levelLadder(0)
+, numLevels(0)
-, weapon(0)
-, armor(0)
-, shield(0)
-, helmet(0)
-, ring(0)
-, jewel(0)
+, useMask(0)
, battleSprite(0)
, meleeAnimation(0)
, attackAnimation(0)
, spellAnimation(0) {
-
+ memset(equipment, 0, sizeof(equipment));
}
}
+int Hero::NextLevel() const {
+ int levelOffset(Level() - 1);
+ if (levelOffset < numLevels) {
+ return levelLadder[levelOffset] - Experience();
+ } else {
+ return 0;
+ }
+}
+
+
+bool Hero::CanEquip(const Item &item) const {
+ return useMask & item.HeroMask();
+}
+
+bool Hero::CanInvoke(const Spell &spell) const {
+ return useMask & spell.HeroMask();
+}
+
+
void Hero::CreateTypeDescription() {
Hero h;
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("useMask", FieldDescription(((char *)&h.useMask) - ((char *)&h), Interpreter::NUMBER_ID));
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"));
~Hero() { }
public:
+ enum EquipSlot {
+ EQUIP_WEAPON,
+ EQUIP_ARMOR,
+ EQUIP_SHIELD,
+ EQUIP_HELMET,
+ EQUIP_RING,
+ EQUIP_JEWEL,
+ EQUIP_COUNT,
+ };
+
const char *Name() const { return name; }
Uint16 MaxHealth() const { return maxHealth; }
const Stats &GetStats() const { return stats; }
Uint8 Level() const { return level; }
+ int Experience() const { return experience; }
+ int NextLevel() const;
+
+ bool CanEquip(const Item &) const;
+ bool CanInvoke(const Spell &) const;
- Item *Weapon() { return weapon; }
- Item *Armor() { return armor; }
- Item *Shield() { return shield; }
- Item *Helmet() { return helmet; }
- Item *Ring() { return ring; }
- Item *Jewel() { return jewel; }
-
- const Item *Weapon() const { return weapon; }
- const Item *Armor() const { return armor; }
- const Item *Shield() const { return shield; }
- const Item *Helmet() const { return helmet; }
- const Item *Ring() const { return ring; }
- const Item *Jewel() const { return jewel; }
-
- bool HasWeapon() const { return weapon; }
- bool HasArmor() const { return armor; }
- bool HasShield() const { return shield; }
- bool HasHelmet() const { return helmet; }
- bool HasRing() const { return ring; }
- bool HasJewel() const { return jewel; }
+ const Item *Equipment(EquipSlot i) const { return equipment[i]; }
+ bool Equipped(EquipSlot i) const { return equipment[i]; }
+ void RemoveEquipment(EquipSlot i) { equipment[i] = 0; }
+ void SetEquipment(EquipSlot i, const Item *item) { equipment[i] = item; }
+ std::vector<const Spell *> &Spells() { return spells; }
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; }
// temporary setters
public:
- void SetWeapon(common::Item *i) { weapon = i; }
- void SetArmor(common::Item *i) { armor = i; }
- void SetShield(common::Item *i) { shield = i; }
- void SetHelmet(common::Item *i) { helmet = i; }
- void SetRing(common::Item *i) { ring = i; }
- void SetJewel(common::Item *i) { jewel = i; }
-
void AddSpell(Spell *s) { spells.push_back(s); }
private:
Stats stats;
int level;
+ int experience;
+
+ int *levelLadder;
+ int numLevels;
+
+ int useMask;
- Item *weapon;
- Item *armor;
- Item *shield;
- Item *helmet;
- Item *ring;
- Item *jewel;
+ const Item *equipment[EQUIP_COUNT];
// TODO: vector does not seem to be a good choice
std::vector<const Spell *> spells;
+++ /dev/null
-/*
- * HeroGroup.h
- *
- * Created on: Aug 10, 2012
- * Author: holy
- */
-
-#ifndef COMMON_HEROGROUP_H_
-#define COMMON_HEROGROUP_H_
-
-#include <SDL.h>
-
-namespace common {
-
-class HeroGroup {
-
-public:
- HeroGroup() : members(NOBODY) { }
-
-public:
- bool HasMaxim() const { return members & MAXIM; }
- bool HasSelan() const { return members & SELAN; }
- bool HasGuy() const { return members & GUY; }
- bool HasArtea() const { return members & ARTEA; }
- bool HasTia() const { return members & TIA; }
- bool HasDekar() const { return members & DEKAR; }
- bool HasLexis() const { return members & LEXIS; }
-
- void AddMaxim() { members |= MAXIM; }
- void AddSelan() { members |= SELAN; }
- void AddGuy() { members |= GUY; }
- void AddArtea() { members |= ARTEA; }
- void AddTia() { members |= TIA; }
- void AddDekar() { members |= DEKAR; }
- void AddLexis() { members |= LEXIS; }
- void AddAll() { members = (MAXIM | SELAN | GUY | ARTEA | TIA | DEKAR | LEXIS); }
-
- void RemoveMaxim() { members &= ~MAXIM; }
- void RemoveSelan() { members &= ~SELAN; }
- void RemoveGuy() { members &= ~GUY; }
- void RemoveArtea() { members &= ~ARTEA; }
- void RemoveTia() { members &= ~TIA; }
- void RemoveDekar() { members &= ~DEKAR; }
- void RemoveLexis() { members &= ~LEXIS; }
- void RemoveAll() { members = NOBODY; }
-
-public:
- enum {
- NOBODY = 0,
- MAXIM = 1,
- SELAN = 2,
- GUY = 4,
- ARTEA = 8,
- TIA = 16,
- DEKAR = 32,
- LEXIS = 64,
- };
- Uint8 members;
-
-};
-
-}
-
-#endif /* COMMON_HEROGROUP_H_ */
#include "Inventory.h"
+#include "Item.h"
+
+#include <algorithm>
+
+
namespace common {
-Inventory::Inventory() {
+Inventory::Inventory()
+: scenarioEnd(0) {
}
}
}
+void Inventory::RemoveAll(const Item *item) {
+ Remove(item, 255);
+}
+
Inventory::Entry *Inventory::FindItem(const Item *item) {
for (int i(0); i < MaxItems(); ++i) {
if (item == ItemAt(i)) {
return !ItemAt(offset);
}
+
+bool Inventory::AddScenarioItem(const Item *i) {
+ if (scenarioEnd < MaxScenarioItems()) {
+ scenario[scenarioEnd] = i;
+ ++scenarioEnd;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+void Inventory::Sort() {
+ std::sort(entries, entries + 96, Entry::Less);
+}
+
+bool Inventory::Entry::Less(const Entry &lhs, const Entry &rhs) {
+ if (lhs.item) {
+ if (rhs.item) {
+ return Item::Less(*lhs.item, *rhs.item);
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+}
+
+void Inventory::SwapEntriesAt(int lhs, int rhs) {
+ std::swap(entries[lhs], entries[rhs]);
+}
+
}
public:
bool Add(const Item *, int count = 1);
void Remove(const Item *, int count = 1);
+ void RemoveAll(const Item *);
int MaxItems() const { return 96; }
+ bool AddScenarioItem(const Item *);
+ const Item *ScenarioItemAt(int offset) const { return scenario[offset]; }
+ int NumScenarioItems() const { return scenarioEnd; }
+ int MaxScenarioItems() const { return 64; }
+
const Item *ItemAt(int offset) const { return entries[offset].item; }
int ItemCountAt(int offset) const { return entries[offset].count; }
+ void Sort();
+ void SwapEntriesAt(int lhs, int rhs);
+
private:
struct Entry {
Entry() : item(0), count(0) { }
const Item *item;
Uint8 count;
+ static bool Less(const Entry &, const Entry &);
};
private:
private:
Entry entries[96];
+ const Item *scenario[64];
+ int scenarioEnd;
};
, properties(0)
, equipability(0)
+, heroMask(0)
, mostUseful(false)
-, equipable(false)
, cursed(false)
, fruit(false)
, scenario(false)
td.AddField("menuicon", FieldDescription(((char *)&i.menuIcon) - ((char *)&i), Sprite::TYPE_ID).SetReferenced().SetDescription("icon that is displayed in menus"));
td.AddField("mostUseful", FieldDescription(((char *)&i.mostUseful) - ((char *)&i), Interpreter::BOOLEAN_ID));
- td.AddField("equipable", FieldDescription(((char *)&i.equipable) - ((char *)&i), Interpreter::BOOLEAN_ID));
td.AddField("cursed", FieldDescription(((char *)&i.cursed) - ((char *)&i), Interpreter::BOOLEAN_ID));
td.AddField("fruit", FieldDescription(((char *)&i.fruit) - ((char *)&i), Interpreter::BOOLEAN_ID));
td.AddField("scenario", FieldDescription(((char *)&i.scenario) - ((char *)&i), Interpreter::BOOLEAN_ID));
td.AddField("targets", FieldDescription(((char *)&i.targettingMode) - ((char *)&i), TargetingMode::TYPE_ID).SetDescription("how target selection is to be performed"));
td.AddField("ikari", FieldDescription(((char *)&i.ikari) - ((char *)&i), Ikari::TYPE_ID).SetReferenced().SetDescription("ikari attack of the item (sensible only for equipment)"));
td.AddField("attackanimation", FieldDescription(((char *)&i.attackAnimation) - ((char *)&i), Animation::TYPE_ID).SetReferenced().SetDescription("animation that is run when the item is used for attacking"));
+ td.AddField("equipability", FieldDescription(((char *)&i.equipability) - ((char *)&i), Interpreter::NUMBER_ID).SetDescription("how this item can be equipped"));
+ td.AddField("heroMask", FieldDescription(((char *)&i.heroMask) - ((char *)&i), Interpreter::NUMBER_ID).SetDescription("which heroes may equip this item"));
}
void Item::Construct(void *data) {
new (data) Item;
}
+
+bool Item::Less(const Item &lhs, const Item &rhs) {
+ if (lhs.IsMostUseful()) {
+ return !rhs.IsMostUseful();
+ }
+ if (lhs.IsEquipable()) {
+ if (rhs.IsMostUseful()) {
+ return false;
+ }
+ if (!rhs.IsEquipable()) {
+ return true;
+ }
+ return lhs.equipability < rhs.equipability;
+ }
+ if (lhs.IsFruit()) {
+ if (rhs.IsMostUseful() || rhs.IsEquipable()) {
+ return true;
+ }
+ return !rhs.IsFruit();
+ }
+ return false;
+}
+
}
#define COMMON_ITEM_H_
#include "fwd.h"
-#include "HeroGroup.h"
+#include "Hero.h"
#include "TargetingMode.h"
#include "../graphics/fwd.h"
const char *Name() const { return name; }
bool IsMostUseful() const { return mostUseful; }
- bool IsEquipable() const { return equipable; }
+ bool IsEquipable() const { return equipability; }
bool IsCursed() const { return cursed; }
bool IsFruit() const { return fruit; }
bool IsScenario() const { return scenario; }
Uint16 Value() const { return value; }
- bool CanEquipWeapon() const { return equipability & EQUIPPABLE_WEAPON; }
- bool CanEquipArmor() const { return equipability & EQUIPPABLE_ARMOR; }
- bool CanEquipShield() const { return equipability & EQUIPPABLE_SHIELD; }
- bool CanEquipHelmet() const { return equipability & EQUIPPABLE_HELMET; }
- bool CanEquipRing() const { return equipability & EQUIPPABLE_RING; }
- bool CanEquipJewel() const { return equipability & EQUIPPABLE_JEWEL; }
+ bool EquipableAt(Hero::EquipSlot slot) const { return equipability & (1 << slot); }
- HeroGroup &EquipableBy() { return equipableBy; }
- const HeroGroup &EquipableBy() const { return equipableBy; }
+ int HeroMask() const { return heroMask; }
bool HasEffectOnStatusScreen() const { return properties & PROPERTY_HAS_EFFECT_STATUS; }
bool HasEffectInBattle() const { return properties & PROPERTY_HAS_EFFECT_BATTLE; }
bool HasBattleAnimation() const { return properties & PROPERTY_HAS_BATTLE_ANIMATION; }
bool HasIkariEffect() const { return properties & PROPERTY_HAS_IKARI_EFFECT; }
+ static bool Less(const Item &, const Item &);
+
// temporary setters
public:
void SetName(const char *n) { name = n; }
static void Construct(void *);
private:
- enum Equipable {
- EQUIPPABLE_NONE = 0,
- EQUIPPABLE_WEAPON = 1,
- EQUIPPABLE_ARMOR = 2,
- EQUIPPABLE_SHIELD = 4,
- EQUIPPABLE_HELMET = 8,
- EQUIPPABLE_RING = 16,
- EQUIPPABLE_JEWEL = 32,
- };
enum Property {
PROPERTY_HAS_EFFECT_STATUS = 1,
PROPERTY_HAS_EFFECT_BATTLE = 2,
Uint16 properties;
TargetingMode targettingMode;
- Uint8 equipability;
- HeroGroup equipableBy;
+ int equipability;
+ int heroMask;
// TODO: turn these back into bits as soon as fields are implemented in the loader
bool mostUseful;
- bool equipable;
bool cursed;
bool fruit;
bool scenario;
namespace common {
Spell::Spell()
-: name(""), value(0), cost(0), status(false), battle(false) {
+: name("")
+, value(0)
+, cost(0)
+, heroMask(0)
+, status(false)
+, battle(false) {
}
+bool Spell::Less(const Spell *lhs, const Spell *rhs) {
+ // TODO: find out real spell sorting order
+ return lhs->Cost() < rhs->Cost();
+}
+
+
void Spell::CreateTypeDescription() {
Spell s;
td.SetSize(sizeof(Spell));
td.AddField("name", FieldDescription(((char *)&s.name) - ((char *)&s), Interpreter::STRING_ID).SetReferenced().SetDescription("the spell's name"));
- td.AddField("cost", FieldDescription(((char *)&s.cost) - ((char *)&s), Interpreter::NUMBER_ID).SetDescription("Amount of magic points needed and deducted for invocation"));
+ td.AddField("cost", FieldDescription(((char *)&s.cost) - ((char *)&s), Interpreter::NUMBER_ID).SetDescription("amount of magic points needed and deducted for invocation"));
td.AddField("targets", FieldDescription(((char *)&s.targetingMode) - ((char *)&s), TargetingMode::TYPE_ID).SetDescription("how target selection is to be performed"));
+ td.AddField("heroMask", FieldDescription(((char *)&s.heroMask) - ((char *)&s), Interpreter::NUMBER_ID).SetDescription("which heroes can invoke this spell"));
td.AddField("status", FieldDescription(((char *)&s.status) - ((char *)&s), Interpreter::BOOLEAN_ID).SetDescription("if the spell can be used at the status screen"));
td.AddField("battle", FieldDescription(((char *)&s.battle) - ((char *)&s), Interpreter::BOOLEAN_ID).SetDescription("if the spell can be used in battle"));
}
#ifndef COMMON_SPELL_H_
#define COMMON_SPELL_H_
-#include "HeroGroup.h"
#include "TargetingMode.h"
namespace common {
TargetingMode &GetTargetingMode() { return targetingMode; }
const TargetingMode &GetTargetingMode() const { return targetingMode; }
- HeroGroup &UsableBy() { return usableBy; }
- const HeroGroup &UsableBy() const { return usableBy; }
+ int HeroMask() const { return heroMask; }
+
+ static bool Less(const Spell *, const Spell *);
// temporary setters
public:
int cost;
TargetingMode targetingMode;
- HeroGroup usableBy;
+ int heroMask;
bool status;
bool battle;
struct GameConfig;
struct GameState;
class Hero;
-class HeroGroup;
class Ikari;
class Inventory;
class Item;
Scalar X() const { return x; }
Scalar Y() const { return y; }
+ Scalar &X() { return x; }
+ Scalar &Y() { return y; }
+
Scalar Index(Scalar lineLength) const { return Y() * lineLength + X(); }
static Vector<Scalar> FromIndex(Scalar index, Scalar lineLength) {
return Vector<Scalar>(index % lineLength, index / lineLength);
namespace graphics {
+int Font::StringWidth(const char *s) const {
+ int width(0), col(0);
+ for (int i(0); s[i]; ++i) {
+ if (s[i] == '\n') {
+ if (width < col) {
+ width = col;
+ }
+ col = 0;
+ } else {
+ ++col;
+ }
+ }
+ return (width < col ? col : width) * CharWidth();
+}
+
+int Font::StringHeight(const char *s) const {
+ if (*s == '\0') {
+ return 0;
+ }
+ int height(1);
+ for (; *s; ++s) {
+ if (*s == '\n') {
+ ++height;
+ }
+ }
+ return height * CharHeight();
+}
+
+
void Font::DrawChar(char c, SDL_Surface *dest, const Vector<int> &position) const {
if (!sprite) return;
sprite->Draw(dest, position, col, row);
}
-void Font::DrawString(const char *s, SDL_Surface *dest, const Vector<int> &positionIn, int maxChars) const {
+void Font::DrawString(const char *s, SDL_Surface *dest, const Vector<int> &positionIn, int maxWidth) const {
if (!sprite) return;
Vector<int> position(positionIn);
+ Vector<int> lineHead(positionIn);
Vector<int> step(CharWidth(), 0);
- for (int i(0); s[i] && (maxChars <= 0 || i < maxChars); ++i, position += step) {
- DrawChar(s[i], dest, position);
+ Vector<int> lineBreak(0, CharHeight());
+ for (int i(0), col(0); s[i] && (maxWidth <= 0 || col < maxWidth); ++i) {
+ if (s[i] == '\n') {
+ lineHead += lineBreak;
+ position = lineHead;
+ col = 0;
+ } else {
+ DrawChar(s[i], dest, position);
+ position += step;
+ ++col;
+ }
}
}
+void Font::DrawStringRight(const char *s, SDL_Surface *dest, const Vector<int> &positionIn, int maxWidth) const {
+ // NOTE: this does not handle line breaks
+ if (!sprite) return;
+
+ int length(0);
+ while (length < maxWidth && 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;
}
}
+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;
public:
int CharWidth() const { return sprite->Width(); }
int CharHeight() const { return sprite->Height(); }
+ int StringWidth(const char *) const;
+ int StringHeight(const char *) const;
+
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 DrawString(const char *s, SDL_Surface *dest, const geometry::Vector<int> &position, int maxWidth = 0) const;
+ void DrawStringRight(const char *s, SDL_Surface *dest, const geometry::Vector<int> &position, int maxWidth = 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; }
#include "Frame.h"
+#include "Texture.h"
#include "../loader/Interpreter.h"
#include "../loader/TypeDescription.h"
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();
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);
}
#include "Sprite.h"
#include "../geometry/Vector.h"
+#include <algorithm>
#include <vector>
#include <SDL.h>
const Font *font;
const Font *disabledFont;
const Sprite *cursor;
+ const Sprite *selectedCursor;
int charsPerEntry;
int rows;
int rowGap;
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)
+ : font(0), disabledFont(0), cursor(0), selectedCursor(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 *);
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:
+ void SetInactive() { state = STATE_INACTIVE; }
+ void SetActive() { state = STATE_ACTIVE; }
+ void SetSelected() { state = STATE_SELECTED; }
+ void SetDualSelection() { state = STATE_DUAL; secondarySelection = selected; }
+ bool IsActive() const { return state == STATE_ACTIVE; }
+ bool HasSelected() const { return state == STATE_SELECTED; }
+ bool InDualMode() const { return state == STATE_DUAL; }
+
int Width() const;
int Height() const;
int ColWidth() const;
int SelectedNumber() const { return entries[selected].number; }
bool SelectedIsEnabled() const { return entries[selected].enabled; }
+ T &SecondarySelection() { return entries[secondarySelection].value; }
+ const T &SecondarySelection() const { return entries[secondarySelection].value; }
+ const char *SecondaryTitle() const { return entries[secondarySelection].title; }
+ int SecondaryNumber() const { return entries[secondarySelection].number; }
+ bool SecondaryIsEnabled() const { return entries[secondarySelection].enabled; }
+
+ void SwapSelected() { SwapEntriesAt(selected, secondarySelection); }
+ void SwapEntriesAt(int lhs, int rhs) { std::swap(entries[lhs], entries[rhs]); }
+
void NextItem();
void PreviousItem();
void NextRow();
void PreviousRow();
void SelectIndex(int index);
int SelectedIndex() const { return selected; }
+ int SecondaryIndex() const { return secondarySelection; }
bool IsSelected(int index) const { return index == selected; }
int EntryCount() const { return entries.size(); }
void Enable(int index) { entries[index].enabled = true; }
void Reserve(int n) { entries.reserve(n); }
void Clear() { entries.clear(); }
+ void ClearEntry(int at) { entries[at] = Entry(0, T(), false); }
void Draw(SDL_Surface *dest, const geometry::Vector<int> &position) const;
};
std::vector<Entry> entries;
int selected;
+ int secondarySelection;
int topRow;
+ enum State {
+ STATE_INACTIVE,
+ STATE_ACTIVE,
+ STATE_SELECTED,
+ STATE_DUAL,
+ };
+ State state;
};
Menu<T>::Menu()
: MenuProperties()
, selected(0)
-, topRow(0) {
+, secondarySelection(0)
+, topRow(0)
+, state(STATE_ACTIVE) {
}
Menu<T>::Menu(const MenuProperties &p)
: MenuProperties(p)
, selected(0)
-, topRow(0) {
-
-}
-
-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) {
+, secondarySelection(0)
+, topRow(0)
+, state(STATE_ACTIVE) {
}
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>
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);
}
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(
(selected % cols) * (ColWidth() + colGap) - cursor->Width(),
((selected - start) / cols) * RowHeight());
- cursor->Draw(dest, position + cursorOffset);
+ // 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);
+ }
+ switch (state) {
+ case STATE_INACTIVE:
+ break;
+ case STATE_ACTIVE:
+ cursor->Draw(dest, position + cursorOffset);
+ break;
+ case STATE_SELECTED:
+ selectedCursor->Draw(dest, position + cursorOffset);
+ break;
+ case STATE_DUAL:
+ cursor->Draw(dest, position + cursorOffset
+ - geometry::Vector<int>(selectedCursor->Width(), 0));
+ if (secondarySelection >= start && secondarySelection <= end) {
+ geometry::Vector<int> secondaryOffset(
+ (secondarySelection % cols) * (ColWidth() + colGap) - cursor->Width(),
+ ((secondarySelection - start) / cols) * RowHeight());
+ selectedCursor->Draw(dest, position + secondaryOffset);
+ }
+ break;
+ }
}
}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
+
+}
--- /dev/null
+/*
+ * 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_ */
struct MenuProperties;
class SimpleAnimation;
class Sprite;
+class Texture;
}
#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"
#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"
using battle::PartyLayout;
using common::GameConfig;
using common::GameState;
+using common::Hero;
using common::Spell;
using geometry::Vector;
+using graphics::Texture;
using loader::Caster;
using loader::Interpreter;
using loader::ParsedSource;
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;
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;
gameState.heroes[0].AddSpell(valorSpell);
gameState.heroes[1].AddSpell(valorSpell);
+ gameState.inventory.Add(caster.GetItem("zirconPlateItem"));
gameState.inventory.Add(caster.GetItem("antidoteItem"), 9);
+ gameState.inventory.Add(caster.GetItem("powerRingItem"));
gameState.inventory.Add(caster.GetItem("magicJarItem"), 4);
+ gameState.inventory.Add(caster.GetItem("sProRingItem"));
gameState.inventory.Add(caster.GetItem("hiPotionItem"), 4);
+ gameState.inventory.Add(caster.GetItem("powerRingItem"));
gameState.inventory.Add(caster.GetItem("powerPotionItem"), 4);
+ gameState.inventory.Add(caster.GetItem("zircoSwordItem"));
gameState.inventory.Add(caster.GetItem("escapeItem"), 2);
+ gameState.inventory.Add(caster.GetItem("zircoHelmetItem"));
gameState.inventory.Add(caster.GetItem("sleepBallItem"), 1);
-
- gameState.heroes[0].SetWeapon(caster.GetItem("zircoSwordItem"));
- gameState.heroes[0].SetArmor(caster.GetItem("zirconArmorItem"));
- gameState.heroes[0].SetShield(caster.GetItem("holyShieldItem"));
- gameState.heroes[0].SetHelmet(caster.GetItem("legendHelmItem"));
- gameState.heroes[0].SetRing(caster.GetItem("sProRingItem"));
- gameState.heroes[0].SetJewel(caster.GetItem("evilJewelItem"));
-
-// gameState.heroes[1].SetWeapon(cst.GetItem("zircoWhipItem"));
- gameState.heroes[1].SetArmor(caster.GetItem("zirconPlateItem"));
- gameState.heroes[1].SetShield(caster.GetItem("zircoGlovesItem"));
- gameState.heroes[1].SetHelmet(caster.GetItem("holyCapItem"));
- gameState.heroes[1].SetRing(caster.GetItem("ghostRingItem"));
- gameState.heroes[1].SetJewel(caster.GetItem("eagleRockItem"));
-
-// gameState.heroes[2].SetWeapon(cst.GetItem("zircoAxItem"));
- gameState.heroes[2].SetArmor(caster.GetItem("zirconArmorItem"));
- gameState.heroes[2].SetShield(caster.GetItem("megaShieldItem"));
- gameState.heroes[2].SetHelmet(caster.GetItem("zircoHelmetItem"));
- gameState.heroes[2].SetRing(caster.GetItem("powerRingItem"));
- gameState.heroes[2].SetJewel(caster.GetItem("evilJewelItem"));
+ gameState.inventory.Add(caster.GetItem("zirconPlateItem"));
+
+ gameState.heroes[0].SetEquipment(Hero::EQUIP_WEAPON, caster.GetItem("zircoSwordItem"));
+ gameState.heroes[0].SetEquipment(Hero::EQUIP_ARMOR, caster.GetItem("zirconArmorItem"));
+ gameState.heroes[0].SetEquipment(Hero::EQUIP_SHIELD, caster.GetItem("holyShieldItem"));
+ gameState.heroes[0].SetEquipment(Hero::EQUIP_HELMET, caster.GetItem("legendHelmItem"));
+ gameState.heroes[0].SetEquipment(Hero::EQUIP_RING, caster.GetItem("sProRingItem"));
+ gameState.heroes[0].SetEquipment(Hero::EQUIP_JEWEL, caster.GetItem("evilJewelItem"));
+
+// gameState.heroes[1].SetEquipment(Hero::EQUIP_WEAPON, caster.GetItem("zircoWhipItem"));
+ gameState.heroes[1].SetEquipment(Hero::EQUIP_ARMOR, caster.GetItem("zirconPlateItem"));
+ gameState.heroes[1].SetEquipment(Hero::EQUIP_SHIELD, caster.GetItem("zircoGlovesItem"));
+ gameState.heroes[1].SetEquipment(Hero::EQUIP_HELMET, caster.GetItem("holyCapItem"));
+ gameState.heroes[1].SetEquipment(Hero::EQUIP_RING, caster.GetItem("ghostRingItem"));
+ gameState.heroes[1].SetEquipment(Hero::EQUIP_JEWEL, caster.GetItem("eagleRockItem"));
+
+// gameState.heroes[2].SetEquipment(Hero::EQUIP_WEAPON, caster.GetItem("zircoAxItem"));
+ gameState.heroes[2].SetEquipment(Hero::EQUIP_ARMOR, caster.GetItem("zirconArmorItem"));
+ gameState.heroes[2].SetEquipment(Hero::EQUIP_SHIELD, caster.GetItem("megaShieldItem"));
+ gameState.heroes[2].SetEquipment(Hero::EQUIP_HELMET, caster.GetItem("zircoHelmetItem"));
+ gameState.heroes[2].SetEquipment(Hero::EQUIP_RING, caster.GetItem("powerRingItem"));
+ gameState.heroes[2].SetEquipment(Hero::EQUIP_JEWEL, caster.GetItem("evilJewelItem"));
// NOTE: this is actually Artea equipment
-// gameState.heroes[3].SetWeapon(cst.GetItem("lizardBlowItem"));
- gameState.heroes[3].SetArmor(caster.GetItem("holyRobeItem"));
- gameState.heroes[3].SetShield(caster.GetItem("zircoGlovesItem"));
- gameState.heroes[3].SetHelmet(caster.GetItem("holyCapItem"));
- gameState.heroes[3].SetRing(caster.GetItem("rocketRingItem"));
- gameState.heroes[3].SetJewel(caster.GetItem("krakenRockItem"));
+// gameState.heroes[3].SetEquipment(Hero::EQUIP_WEAPON, caster.GetItem("lizardBlowItem"));
+ gameState.heroes[3].SetEquipment(Hero::EQUIP_ARMOR, caster.GetItem("holyRobeItem"));
+ gameState.heroes[3].SetEquipment(Hero::EQUIP_SHIELD, caster.GetItem("zircoGlovesItem"));
+ gameState.heroes[3].SetEquipment(Hero::EQUIP_HELMET, caster.GetItem("holyCapItem"));
+ gameState.heroes[3].SetEquipment(Hero::EQUIP_RING, caster.GetItem("rocketRingItem"));
+ gameState.heroes[3].SetEquipment(Hero::EQUIP_JEWEL, caster.GetItem("krakenRockItem"));
gameState.heroes[0].MapEntity().Position() = Vector<float>(64, 128);
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);
+ graphics::Sprite menuInactiveFontSprite(IMG_Load("test-data/menu-font-inactive.png"), 16, 16);
+ graphics::Font menuInactiveFont(&menuInactiveFontSprite, 0, -2);
+
+ menuResources.normalFont = &menuFont;
+ menuResources.inactiveFont = &menuInactiveFont;
+
+ 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.selectedCursor = &menuActiveCursor;
+ 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.selectedCursor = &menuActiveCursor;
+ inventoryMenuProperties.font = &menuFont;
+ inventoryMenuProperties.disabledFont = &menuInactiveFont;
+ inventoryMenuProperties.iconSpace = 16;
+ inventoryMenuProperties.charsPerNumber = 2;
+ inventoryMenuProperties.delimiter = ':';
+ menuResources.inventoryMenuProperties = &inventoryMenuProperties;
+
+ graphics::MenuProperties spellMenuProperties;
+ spellMenuProperties.cols = 2;
+ spellMenuProperties.rows = 6;
+ spellMenuProperties.charsPerEntry = 8;
+ spellMenuProperties.rowGap = 8;
+ spellMenuProperties.colGap = 48;
+ spellMenuProperties.cursor = &menuCursor;
+ spellMenuProperties.selectedCursor = &menuActiveCursor;
+ spellMenuProperties.font = &menuFont;
+ spellMenuProperties.disabledFont = &menuInactiveFont;
+ spellMenuProperties.iconSpace = 0;
+ spellMenuProperties.charsPerNumber = 2;
+ spellMenuProperties.delimiter = ':';
+ menuResources.spellMenuProperties = &spellMenuProperties;
+
+ graphics::MenuProperties equipmentActionMenuProperties;
+ equipmentActionMenuProperties.cols = 1;
+ equipmentActionMenuProperties.rows = 5;
+ equipmentActionMenuProperties.charsPerEntry = 10;
+ equipmentActionMenuProperties.rowGap = 8;
+ equipmentActionMenuProperties.cursor = &menuCursor;
+ equipmentActionMenuProperties.selectedCursor = &menuActiveCursor;
+ equipmentActionMenuProperties.font = &menuFont;
+ equipmentActionMenuProperties.iconSpace = 0;
+ menuResources.equipmentActionMenuProperties = &equipmentActionMenuProperties;
+
+ graphics::MenuProperties equipmentMenuProperties;
+ equipmentMenuProperties.cols = 1;
+ equipmentMenuProperties.rows = 6;
+ equipmentMenuProperties.charsPerEntry = 12;
+ equipmentMenuProperties.rowGap = 16;
+ equipmentMenuProperties.cursor = &menuCursor;
+ equipmentMenuProperties.selectedCursor = &menuActiveCursor;
+ equipmentMenuProperties.font = menuResources.statusFont;
+ equipmentMenuProperties.iconSpace = 16;
+ equipmentMenuProperties.wrapY = true;
+ menuResources.equipmentMenuProperties = &equipmentMenuProperties;
+
+ menuResources.equipMenuEquipLabel = "EQUIP";
+ menuResources.equipMenuStrongestLabel = "STRONGEST";
+ menuResources.equipMenuRemoveLabel = "REMOVE";
+ menuResources.equipMenuRemoveAllLabel = "REMOVE ALL";
+ menuResources.equipMenuDropLabel = "DROP";
+
+ graphics::MenuProperties configMenuProperties;
+ configMenuProperties.cols = 1;
+ configMenuProperties.rows = 4;
+ configMenuProperties.charsPerEntry = 8;
+ configMenuProperties.rowGap = 32;
+ configMenuProperties.cursor = &menuCursor;
+ configMenuProperties.font = &menuFont;
+ configMenuProperties.wrapY = true;
+ menuResources.configMenuProperties = &configMenuProperties;
+
+ menuResources.configMessageSpeedLabel = "MESSAGE\n SPEED";
+ menuResources.configMessageSpeedFast = "FAST";
+ menuResources.configMessageSpeedNormal = "NORMAL";
+ menuResources.configMessageSpeedSlow = "SLOW";
+ menuResources.configBattleCursorLabel = "BATTLE\n CURSOR";
+ menuResources.configStatusCursorLabel = "STATUS\n CURSOR";
+ menuResources.configCursorClear = "CLEAR";
+ menuResources.configCursorMemory = "MEMORY";
+ menuResources.configMusicLabel = "MUSIC";
+ menuResources.configMusicStereo = "STEREO";
+ menuResources.configMusicMono = "MONO";
+
+ graphics::MenuProperties scenarioMenuProperties;
+ scenarioMenuProperties.cols = 1;
+ scenarioMenuProperties.rows = 6;
+ scenarioMenuProperties.charsPerEntry = 14;
+ scenarioMenuProperties.rowGap = 8;
+ scenarioMenuProperties.cursor = &menuCursor;
+ scenarioMenuProperties.font = &menuFont;
+ menuResources.scenarioMenuProperties = &scenarioMenuProperties;
+ menuResources.scenarioMenuHeadline = "SCENARIO ITEM";
+
InitScreen screen(width, height);
app::State *state(0);
#include "../common/GameConfig.h"
#include "../common/GameState.h"
#include "../graphics/ColorFade.h"
+#include "../menu/PartyMenu.h"
#include <algorithm>
using common::GameConfig;
using geometry::Vector;
using graphics::ColorFade;
+using menu::PartyMenu;
namespace map {
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)) {
--- /dev/null
+/*
+ * 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;
+ }
+}
+
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * ConfigMenu.cpp
+ *
+ * Created on: Nov 29, 2012
+ * Author: holy
+ */
+
+#include "ConfigMenu.h"
+
+#include "PartyMenu.h"
+#include "Resources.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+
+using app::Input;
+using common::GameState;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+ConfigMenu::ConfigMenu(PartyMenu *parent)
+: parent(parent)
+, configMenu(*parent->Res().configMenuProperties) {
+ configMenu.Add(parent->Res().configMessageSpeedLabel, 0);
+ configMenu.Add(parent->Res().configBattleCursorLabel, 1);
+ configMenu.Add(parent->Res().configStatusCursorLabel, 2);
+ configMenu.Add(parent->Res().configMusicLabel, 3);
+}
+
+
+void ConfigMenu::OnEnterState(SDL_Surface *) {
+
+}
+
+void ConfigMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void ConfigMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void ConfigMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void ConfigMenu::OnResize(int width, int height) {
+
+}
+
+
+int ConfigMenu::Width() const {
+ return parent->Width();
+}
+
+int ConfigMenu::Height() const {
+ return parent->Height();
+}
+
+
+void ConfigMenu::HandleEvents(const Input &input) {
+ if (input.JustPressed(Input::ACTION_B)) {
+ Ctrl().PopState();
+ }
+ if (input.JustPressed(Input::PAD_DOWN)) {
+ configMenu.NextRow();
+ }
+ if (input.JustPressed(Input::PAD_UP)) {
+ configMenu.PreviousRow();
+ }
+
+ GameState &state(*parent->Game().state);
+ int *property(0);
+ int mod(0);
+ switch (configMenu.Selected()) {
+ case 0:
+ property = &state.messageSpeed;
+ mod = 3;
+ break;
+ case 1:
+ property = &state.battleCursor;
+ mod = 2;
+ break;
+ case 2:
+ property = &state.statusCursor;
+ mod = 2;
+ break;
+ case 3:
+ property = &state.music;
+ mod = 2;
+ break;
+ }
+ if (input.JustPressed(Input::ACTION_A) || input.JustPressed(Input::PAD_RIGHT)) {
+ *property = (*property + 1) % mod;
+ }
+ if (input.JustPressed(Input::PAD_LEFT)) {
+ *property = (*property + mod - 1) % mod;
+ }
+}
+
+void ConfigMenu::UpdateWorld(float deltaT) {
+
+}
+
+void ConfigMenu::Render(SDL_Surface *screen) {
+ const Font &font(*parent->Res().normalFont);
+ const Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+ const Vector<int> headlineOffset(
+ font.CharWidth(), 2 * font.CharHeight() - font.CharHeight() / 8);
+ const Vector<int> menuOffset(
+ font.CharWidth(), 5 * font.CharHeight() - font.CharHeight() / 8);
+
+ parent->RenderBackground(screen);
+ RenderHeadline(screen, offset + headlineOffset);
+ RenderMenu(screen, offset + menuOffset);
+}
+
+void ConfigMenu::RenderHeadline(SDL_Surface *screen, const geometry::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, 10 * font.CharWidth(), 3 * font.CharHeight());
+ font.DrawString(parent->Res().mainMenuConfigText, screen, offset + textOffset, 6);
+}
+
+void ConfigMenu::RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const {
+ const Resources &res(parent->Res());
+ const Font &font(*res.normalFont);
+ const Font &inactiveFont(*res.inactiveFont);
+ const Frame &frame(*res.statusFrame);
+ const GameState &state(*parent->Game().state);
+ const Vector<int> menuOffset(
+ 3 * font.CharWidth(), 2 * font.CharHeight());
+
+ frame.Draw(screen, offset, 30 * font.CharWidth(), 14 * font.CharHeight());
+ configMenu.Draw(screen, offset + menuOffset);
+
+ Vector<int> lineOffset(
+ menuOffset.X() + configMenu.Width() + 2 * font.CharWidth(),
+ menuOffset.Y());
+ Vector<int> colOffset(lineOffset);
+
+ if (state.messageSpeed == GameState::MESSAGE_SPEED_FAST) {
+ font.DrawString(res.configMessageSpeedFast, screen, offset + colOffset);
+ colOffset.X() += font.StringWidth(res.configMessageSpeedFast) + font.CharWidth();
+ } else {
+ inactiveFont.DrawString(res.configMessageSpeedFast, screen, offset + colOffset);
+ colOffset.X() += inactiveFont.StringWidth(res.configMessageSpeedFast) + inactiveFont.CharWidth();
+ }
+ if (state.messageSpeed == GameState::MESSAGE_SPEED_NORMAL) {
+ font.DrawString(res.configMessageSpeedNormal, screen, offset + colOffset);
+ colOffset.X() += font.StringWidth(res.configMessageSpeedNormal) + font.CharWidth();
+ } else {
+ inactiveFont.DrawString(res.configMessageSpeedNormal, screen, offset + colOffset);
+ colOffset.X() += inactiveFont.StringWidth(res.configMessageSpeedNormal) + inactiveFont.CharWidth();
+ }
+ if (state.messageSpeed == GameState::MESSAGE_SPEED_SLOW) {
+ font.DrawString(res.configMessageSpeedSlow, screen, offset + colOffset);
+ } else {
+ inactiveFont.DrawString(res.configMessageSpeedSlow, screen, offset + colOffset);
+ }
+
+ lineOffset.Y() += configMenu.RowHeight();
+ colOffset = lineOffset;
+
+ if (state.battleCursor == GameState::CURSOR_CLEAR) {
+ font.DrawString(res.configCursorClear, screen, offset + colOffset);
+ colOffset.X() += font.StringWidth(res.configCursorClear) + 2 * font.CharWidth();
+ } else {
+ inactiveFont.DrawString(res.configCursorClear, screen, offset + colOffset);
+ colOffset.X() += inactiveFont.StringWidth(res.configCursorClear) + 2 * inactiveFont.CharWidth();
+ }
+ if (state.battleCursor == GameState::CURSOR_MEMORY) {
+ font.DrawString(res.configCursorMemory, screen, offset + colOffset);
+ } else {
+ inactiveFont.DrawString(res.configCursorMemory, screen, offset + colOffset);
+ }
+
+ lineOffset.Y() += configMenu.RowHeight();
+ colOffset = lineOffset;
+
+ if (state.statusCursor == GameState::CURSOR_CLEAR) {
+ font.DrawString(res.configCursorClear, screen, offset + colOffset);
+ colOffset.X() += font.StringWidth(res.configCursorClear) + 2 * font.CharWidth();
+ } else {
+ inactiveFont.DrawString(res.configCursorClear, screen, offset + colOffset);
+ colOffset.X() += inactiveFont.StringWidth(res.configCursorClear) + 2 * inactiveFont.CharWidth();
+ }
+ if (state.statusCursor == GameState::CURSOR_MEMORY) {
+ font.DrawString(res.configCursorMemory, screen, offset + colOffset);
+ } else {
+ inactiveFont.DrawString(res.configCursorMemory, screen, offset + colOffset);
+ }
+
+ lineOffset.Y() += configMenu.RowHeight();
+ colOffset = lineOffset;
+
+ if (state.music == GameState::MUSIC_STEREO) {
+ font.DrawString(res.configMusicStereo, screen, offset + colOffset);
+ colOffset.X() += font.StringWidth(res.configMusicStereo) + font.CharWidth();
+ } else {
+ inactiveFont.DrawString(res.configMusicStereo, screen, offset + colOffset);
+ colOffset.X() += inactiveFont.StringWidth(res.configMusicStereo) + inactiveFont.CharWidth();
+ }
+ if (state.music == GameState::MUSIC_MONO) {
+ font.DrawString(res.configMusicMono, screen, offset + colOffset);
+ } else {
+ inactiveFont.DrawString(res.configMusicMono, screen, offset + colOffset);
+ }
+}
+
+}
--- /dev/null
+/*
+ * ConfigMenu.h
+ *
+ * Created on: Nov 29, 2012
+ * Author: holy
+ */
+
+#ifndef MENU_CONFIGMENU_H_
+#define MENU_CONFIGMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class ConfigMenu
+: public app::State {
+
+public:
+ explicit ConfigMenu(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 RenderHeadline(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+ void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+ PartyMenu *parent;
+ graphics::Menu<int> configMenu;
+
+};
+
+}
+
+#endif /* MENU_CONFIGMENU_H_ */
--- /dev/null
+/*
+ * EquipMenu.cpp
+ *
+ * Created on: Nov 18, 2012
+ * Author: holy
+ */
+
+#include "EquipMenu.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/Inventory.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::Inventory;
+using common::Item;
+using common::Stats;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+
+namespace menu {
+
+EquipMenu::EquipMenu(PartyMenu *parent, int cursor)
+: parent(parent)
+, cursor(cursor)
+, actionMenu(*parent->Res().equipmentActionMenuProperties)
+, equipmentMenu(*parent->Res().equipmentMenuProperties)
+, inventoryMenu(*parent->Res().inventoryMenuProperties) {
+ actionMenu.Add(parent->Res().equipMenuEquipLabel, CHOICE_EQUIP);
+ actionMenu.Add(parent->Res().equipMenuStrongestLabel, CHOICE_STRONGEST);
+ actionMenu.Add(parent->Res().equipMenuRemoveLabel, CHOICE_REMOVE);
+ actionMenu.Add(parent->Res().equipMenuRemoveAllLabel, CHOICE_REMOVE_ALL);
+ actionMenu.Add(parent->Res().equipMenuDropLabel, CHOICE_DROP);
+
+ LoadEquipment();
+}
+
+
+void EquipMenu::OnEnterState(SDL_Surface *) {
+ equipmentMenu.SetInactive();
+ inventoryMenu.SetInactive();
+}
+
+void EquipMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void EquipMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void EquipMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void EquipMenu::OnResize(int width, int height) {
+
+}
+
+
+void EquipMenu::HandleEvents(const Input &input) {
+ if (input.JustPressed(Input::SHOULDER_LEFT)) {
+ PreviousHero();
+ }
+ if (input.JustPressed(Input::SHOULDER_RIGHT)) {
+ NextHero();
+ }
+ if (actionMenu.IsActive()) {
+ if (input.JustPressed(Input::PAD_UP)) {
+ actionMenu.PreviousRow();
+ }
+ if (input.JustPressed(Input::PAD_DOWN)) {
+ actionMenu.NextRow();
+ }
+ if (input.JustPressed(Input::ACTION_A)) {
+ switch (actionMenu.Selected()) {
+ case CHOICE_EQUIP:
+ LoadEquipment();
+ actionMenu.SetSelected();
+ equipmentMenu.SetActive();
+ break;
+ case CHOICE_STRONGEST:
+ // TODO: implement "equip strongest" when items' stat effects are done
+ break;
+ case CHOICE_REMOVE:
+ actionMenu.SetSelected();
+ equipmentMenu.SetActive();
+ break;
+ case CHOICE_REMOVE_ALL:
+ RemoveAllEquipment();
+ break;
+ case CHOICE_DROP:
+ actionMenu.SetSelected();
+ equipmentMenu.SetActive();
+ break;
+ }
+ } else if (input.JustPressed(Input::ACTION_B)) {
+ Ctrl().PopState();
+ }
+ } else if (equipmentMenu.IsActive()) {
+ if (input.JustPressed(Input::PAD_UP)) {
+ equipmentMenu.PreviousRow();
+ if (InventoryVisible()) {
+ LoadInventory();
+ }
+ }
+ if (input.JustPressed(Input::PAD_DOWN)) {
+ equipmentMenu.NextRow();
+ if (InventoryVisible()) {
+ LoadInventory();
+ }
+ }
+ if (input.JustPressed(Input::ACTION_B)) {
+ equipmentMenu.SetInactive();
+ actionMenu.SetActive();
+ } else if (input.JustPressed(Input::ACTION_A)) {
+ switch (actionMenu.Selected()) {
+ case CHOICE_EQUIP:
+ equipmentMenu.SetSelected();
+ inventoryMenu.SetActive();
+ break;
+ case CHOICE_STRONGEST:
+ case CHOICE_REMOVE_ALL:
+ // invalid state, recover
+ equipmentMenu.SetInactive();
+ actionMenu.SetActive();
+ break;
+ case CHOICE_REMOVE:
+ RemoveItem();
+ break;
+ case CHOICE_DROP:
+ DropItem();
+ break;
+ }
+ }
+ } else {
+ if (input.JustPressed(Input::PAD_UP)) {
+ inventoryMenu.PreviousRow();
+ }
+ if (input.JustPressed(Input::PAD_DOWN)) {
+ inventoryMenu.NextRow();
+ }
+ if (input.JustPressed(Input::ACTION_A)) {
+ EquipSelected();
+ inventoryMenu.SetInactive();
+ equipmentMenu.SetActive();
+ } else if (input.JustPressed(Input::ACTION_B)) {
+ inventoryMenu.SetInactive();
+ equipmentMenu.SetActive();
+ }
+ }
+}
+
+void EquipMenu::UpdateWorld(float deltaT) {
+
+}
+
+void EquipMenu::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);
+
+ parent->RenderBackground(screen);
+ parent->Res().shoulderNav->Draw(screen, offset + shoulderNavOffset);
+ RenderStatus(screen, offset + parent->StatusOffset(0));
+ RenderStats(screen, offset + statsOffset);
+ RenderEquipmentMenu(screen, offset + equipOffset);
+ if (InventoryVisible()) {
+ Vector<int> inventoryOffset(
+ parent->Res().statusFont->CharWidth(),
+ 17 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+ RenderInventoryMenu(screen, offset + inventoryOffset);
+ } else {
+ Vector<int> menuOffset(
+ 15 * parent->Res().statusFont->CharWidth(),
+ 17 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
+ RenderActionMenu(screen, offset + menuOffset);
+ }
+}
+
+int EquipMenu::Width() const {
+ return parent->Width();
+}
+
+int EquipMenu::Height() const {
+ return parent->Height();
+}
+
+void EquipMenu::RenderStatus(SDL_Surface *screen, const Vector<int> &offset) const {
+ parent->GetHeroStatus(cursor).Render(screen, offset);
+}
+
+void EquipMenu::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 EquipMenu::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 EquipMenu::RenderEquipmentMenu(SDL_Surface *screen, const Vector<int> &offset) const {
+ equipmentMenu.Draw(screen, offset);
+}
+
+void EquipMenu::RenderActionMenu(SDL_Surface *screen, const Vector<int> &offset) const {
+ const Font &font(*parent->Res().statusFont);
+ const Frame &frame(*parent->Res().statusFrame);
+ const Vector<int> menuOffset(3 * font.CharWidth(), font.CharHeight() + font.CharHeight() / 2);
+
+ frame.Draw(screen, offset, 15 * font.CharWidth(), 10 * font.CharHeight());
+ actionMenu.Draw(screen, offset + menuOffset);
+}
+
+void EquipMenu::RenderInventoryMenu(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());
+ inventoryMenu.Draw(screen, offset + menuOffset);
+}
+
+
+void EquipMenu::NextHero() {
+ cursor = (cursor + 1) % parent->Game().state->partySize;
+ LoadEquipment();
+ if (InventoryVisible()) {
+ LoadInventory();
+ }
+}
+
+void EquipMenu::PreviousHero() {
+ cursor = (cursor + parent->Game().state->partySize - 1) % parent->Game().state->partySize;
+ LoadEquipment();
+ if (InventoryVisible()) {
+ LoadInventory();
+ }
+}
+
+Hero &EquipMenu::GetHero() {
+ return *parent->Game().state->party[cursor];
+}
+
+const Hero &EquipMenu::GetHero() const {
+ return *parent->Game().state->party[cursor];
+}
+
+
+void EquipMenu::LoadEquipment() {
+ equipmentMenu.Clear();
+ for (int i = 0; i < Hero::EQUIP_COUNT; ++i) {
+ if (GetHero().Equipped(Hero::EquipSlot(i))) {
+ const Item *item(GetHero().Equipment(Hero::EquipSlot(i)));
+ equipmentMenu.Add(item->Name(), item, true, item->MenuIcon());
+ } else {
+ equipmentMenu.Add(parent->Res().noEquipmentText, 0);
+ }
+ }
+}
+
+void EquipMenu::RemoveAllEquipment() {
+ Inventory &inv(parent->Game().state->inventory);
+ for (int i = 0; i < Hero::EQUIP_COUNT; ++i) {
+ if (GetHero().Equipped(Hero::EquipSlot(i))
+ && inv.Add(GetHero().Equipment(Hero::EquipSlot(i)), 1)) {
+ GetHero().RemoveEquipment(Hero::EquipSlot(i));
+ }
+ }
+ LoadEquipment();
+}
+
+void EquipMenu::RemoveItem() {
+ Inventory &inv(parent->Game().state->inventory);
+ Hero::EquipSlot slot = Hero::EquipSlot(equipmentMenu.SelectedIndex());
+
+ if (GetHero().Equipped(slot) && inv.Add(GetHero().Equipment(slot), 1)) {
+ GetHero().RemoveEquipment(slot);
+ }
+
+ LoadEquipment();
+}
+
+void EquipMenu::DropItem() {
+ GetHero().RemoveEquipment(Hero::EquipSlot(equipmentMenu.SelectedIndex()));
+ LoadEquipment();
+}
+
+
+bool EquipMenu::InventoryVisible() const {
+ return !actionMenu.IsActive() && actionMenu.Selected() == CHOICE_EQUIP;
+}
+
+void EquipMenu::LoadInventory() {
+ const Inventory &inv = parent->Game().state->inventory;
+ const Hero &hero = GetHero();
+ const Hero::EquipSlot slot = Hero::EquipSlot(equipmentMenu.SelectedIndex());
+
+ inventoryMenu.Clear();
+ for (int i = 0; i < inv.MaxItems(); ++i) {
+ const Item *item = inv.ItemAt(i);
+ if (item && item->EquipableAt(slot)) {
+ inventoryMenu.Add(item->Name(), item, hero.CanEquip(*item),
+ item->MenuIcon(), inv.ItemCountAt(i));
+ }
+ }
+}
+
+void EquipMenu::EquipSelected() {
+ Inventory &inv = parent->Game().state->inventory;
+ Hero &hero = GetHero();
+ const Hero::EquipSlot slot = Hero::EquipSlot(equipmentMenu.SelectedIndex());
+
+ const Item *selected = inventoryMenu.Selected();
+ const Item *equipped = equipmentMenu.Selected();
+
+ if (!hero.CanEquip(*selected)) {
+ // TODO: error noise and blur
+ return;
+ }
+
+ inv.Remove(selected, 1);
+ if (!inv.Add(equipped, 1)) {
+ // roll back
+ inv.Add(selected, 1);
+ // TODO: error noise, blur, message?
+ return;
+ }
+
+ hero.SetEquipment(slot, selected);
+ LoadEquipment();
+ LoadInventory();
+}
+
+}
--- /dev/null
+/*
+ * EquipMenu.h
+ *
+ * Created on: Nov 18, 2012
+ * Author: holy
+ */
+
+#ifndef MENU_EQUIPMENU_H_
+#define MENU_EQUIPMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class EquipMenu
+: public app::State {
+
+public:
+ EquipMenu(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();
+
+ common::Hero &GetHero();
+ const common::Hero &GetHero() const;
+
+ void LoadEquipment();
+ void RemoveAllEquipment();
+ void RemoveItem();
+ void DropItem();
+
+ bool InventoryVisible() const;
+ void LoadInventory();
+ void EquipSelected();
+
+ 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 RenderEquipmentMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+ void RenderActionMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+ void RenderInventoryMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+ PartyMenu *parent;
+ int cursor;
+ enum Choice {
+ CHOICE_EQUIP,
+ CHOICE_STRONGEST,
+ CHOICE_REMOVE,
+ CHOICE_REMOVE_ALL,
+ CHOICE_DROP,
+ };
+ graphics::Menu<Choice> actionMenu;
+ graphics::Menu<const common::Item *> equipmentMenu;
+ graphics::Menu<const common::Item *> inventoryMenu;
+
+};
+
+}
+
+#endif /* MENU_EQUIPMENU_H_ */
--- /dev/null
+/*
+ * 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);
+}
+
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+using std::swap;
+
+namespace menu {
+
+InventoryMenu::InventoryMenu(PartyMenu *parent)
+: parent(parent)
+, menu(*parent->Res().itemMenuProperties)
+, itemMenu(*parent->Res().inventoryMenuProperties) {
+ menu.Add(parent->Res().itemMenuUseText, CHOICE_USE);
+ menu.Add(parent->Res().itemMenuSortText, CHOICE_SORT);
+ menu.Add(parent->Res().itemMenuDropText, CHOICE_DROP);
+}
+
+
+void InventoryMenu::OnEnterState(SDL_Surface *) {
+ menu.SetSelected();
+ LoadInventory();
+}
+
+void InventoryMenu::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) {
+ 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 (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_USE:
+ if (itemMenu.Selected()->CanUseOnStatusScreen()) {
+ // TODO: implement item use
+ }
+ itemMenu.SetActive();
+ break;
+ case CHOICE_SORT:
+ // invalid state, recover
+ menu.SetActive();
+ itemMenu.SetInactive();
+ break;
+ case CHOICE_DROP:
+ if (itemMenu.Selected()->CanDrop()) {
+ parent->Game().state->inventory.RemoveAll(itemMenu.Selected());
+ itemMenu.ClearEntry(itemMenu.SelectedIndex());
+ }
+ itemMenu.SetActive();
+ 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 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);
+}
+
+}
--- /dev/null
+/*
+ * 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 LoadInventory();
+
+ 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;
+ enum Choice {
+ CHOICE_USE,
+ CHOICE_SORT,
+ CHOICE_DROP,
+ };
+ graphics::Menu<Choice> menu;
+ graphics::Menu<const common::Item *> itemMenu;
+
+};
+
+}
+
+#endif /* MENU_INVENTORYMENU_H_ */
--- /dev/null
+/*
+ * PartyMenu.cpp
+ *
+ * Created on: Oct 21, 2012
+ * Author: holy
+ */
+
+#include "PartyMenu.h"
+
+#include "ChangeHero.h"
+#include "ConfigMenu.h"
+#include "EquipMenu.h"
+#include "InventoryMenu.h"
+#include "Resources.h"
+#include "ScenarioMenu.h"
+#include "SelectHero.h"
+#include "SpellMenu.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:
+ Ctrl().PushState(new SelectHero(this, this, this, OnSpellSelect));
+ break;
+ case MENU_ITEM_CAPSULE:
+ break;
+ case MENU_ITEM_EQUIP:
+ Ctrl().PushState(new SelectHero(this, this, this, OnEquipSelect));
+ 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:
+ Ctrl().PushState(new ConfigMenu(this));
+ break;
+ case MENU_ITEM_SCENARIO:
+ Ctrl().PushState(new ScenarioMenu(this));
+ 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::OnEquipSelect(void *ref, int index) {
+ PartyMenu *self(reinterpret_cast<PartyMenu *>(ref));
+ self->Ctrl().ChangeState(
+ new EquipMenu(self, index));
+}
+
+void PartyMenu::OnSpellSelect(void *ref, int index) {
+ PartyMenu *self(reinterpret_cast<PartyMenu *>(ref));
+ self->Ctrl().ChangeState(
+ new SpellMenu(self, index));
+}
+
+void PartyMenu::OnStatusSelect(void *ref, int index) {
+ PartyMenu *self(reinterpret_cast<PartyMenu *>(ref));
+ self->Ctrl().ChangeState(
+ new StatusMenu(self, index));
+}
+
+}
--- /dev/null
+/*
+ * 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 OnEquipSelect(void *, int);
+ static void OnSpellSelect(void *, int);
+ 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_ */
--- /dev/null
+/*
+ * Resources.cpp
+ *
+ * Created on: Oct 21, 2012
+ * Author: holy
+ */
+
+#include "Resources.h"
+
+namespace menu {
+
+Resources::Resources()
+: menubg(0)
+, normalFont(0)
+, inactiveFont(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)
+
+, spellMenuProperties(0)
+
+, equipmentActionMenuProperties(0)
+, equipmentMenuProperties(0)
+, equipMenuEquipLabel(0)
+, equipMenuStrongestLabel(0)
+, equipMenuRemoveLabel(0)
+, equipMenuRemoveAllLabel(0)
+, equipMenuDropLabel(0)
+
+, configMenuProperties(0)
+, configMessageSpeedLabel(0)
+, configMessageSpeedFast(0)
+, configMessageSpeedNormal(0)
+, configMessageSpeedSlow(0)
+, configBattleCursorLabel(0)
+, configStatusCursorLabel(0)
+, configCursorClear(0)
+, configCursorMemory(0)
+, configMusicLabel(0)
+, configMusicStereo(0)
+, configMusicMono(0)
+
+, scenarioMenuProperties(0)
+, scenarioMenuHeadline(0) {
+
+}
+
+}
--- /dev/null
+/*
+ * 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 *inactiveFont;
+ 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;
+
+ graphics::MenuProperties *spellMenuProperties;
+
+ graphics::MenuProperties *equipmentActionMenuProperties;
+ graphics::MenuProperties *equipmentMenuProperties;
+ const char *equipMenuEquipLabel;
+ const char *equipMenuStrongestLabel;
+ const char *equipMenuRemoveLabel;
+ const char *equipMenuRemoveAllLabel;
+ const char *equipMenuDropLabel;
+
+ graphics::MenuProperties *configMenuProperties;
+ const char *configMessageSpeedLabel;
+ const char *configMessageSpeedFast;
+ const char *configMessageSpeedNormal;
+ const char *configMessageSpeedSlow;
+ const char *configBattleCursorLabel;
+ const char *configStatusCursorLabel;
+ const char *configCursorClear;
+ const char *configCursorMemory;
+ const char *configMusicLabel;
+ const char *configMusicStereo;
+ const char *configMusicMono;
+
+ graphics::MenuProperties *scenarioMenuProperties;
+ const char *scenarioMenuHeadline;
+
+ Resources();
+
+};
+
+}
+
+#endif /* MENU_RESOURCES_H_ */
--- /dev/null
+/*
+ * ScenarioMenu.cpp
+ *
+ * Created on: Nov 30, 2012
+ * Author: holy
+ */
+
+#include "ScenarioMenu.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 {
+
+ScenarioMenu::ScenarioMenu(PartyMenu *parent)
+: parent(parent)
+, itemMenu(*parent->Res().scenarioMenuProperties) {
+
+}
+
+
+void ScenarioMenu::OnEnterState(SDL_Surface *) {
+ LoadItems();
+}
+
+void ScenarioMenu::LoadItems() {
+ const Inventory &inv(parent->Game().state->inventory);
+ itemMenu.Clear();
+ itemMenu.Reserve(inv.MaxScenarioItems());
+ int i = 0;
+ for (; i < inv.NumScenarioItems(); ++i) {
+ const Item *item(inv.ScenarioItemAt(i));
+ itemMenu.Add(item->Name(), item, item->CanUseOnStatusScreen(), item->MenuIcon(), inv.ItemCountAt(i));
+ }
+ for (; i < inv.MaxScenarioItems(); ++i) {
+ itemMenu.AddEmptyEntry();
+ }
+}
+
+void ScenarioMenu::OnExitState(SDL_Surface *) {
+
+}
+
+void ScenarioMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void ScenarioMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void ScenarioMenu::OnResize(int width, int height) {
+
+}
+
+
+void ScenarioMenu::HandleEvents(const Input &input) {
+ if (input.JustPressed(Input::PAD_DOWN)) {
+ itemMenu.NextRow();
+ }
+ if (input.JustPressed(Input::PAD_UP)) {
+ itemMenu.PreviousRow();
+ }
+ if (input.JustPressed(Input::ACTION_B)) {
+ Ctrl().PopState();
+ }
+}
+
+void ScenarioMenu::UpdateWorld(float deltaT) {
+
+}
+
+
+void ScenarioMenu::Render(SDL_Surface *screen) {
+ const Font &font(*parent->Res().normalFont);
+ Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
+ Vector<int> headlineOffset(font.CharWidth(), 13 * font.CharHeight() + font.CharHeight() / 8);
+ Vector<int> itemsOffset(font.CharWidth(), 16 * font.CharHeight() + font.CharHeight() / 8);
+
+ parent->RenderBackground(screen);
+ parent->RenderHeros(screen, offset);
+ RenderHeadline(screen, offset + headlineOffset);
+ RenderItems(screen, offset + itemsOffset);
+}
+
+int ScenarioMenu::Width() const {
+ return parent->Width();
+}
+
+int ScenarioMenu::Height() const {
+ return parent->Height();
+}
+
+void ScenarioMenu::RenderHeadline(SDL_Surface *screen, const geometry::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());
+
+ int width = font.StringWidth(parent->Res().scenarioMenuHeadline) + 4 * font.CharWidth();
+ frame.Draw(screen, offset, width, 3 * font.CharHeight());
+ font.DrawString(parent->Res().scenarioMenuHeadline, screen, offset + textOffset);
+}
+
+void ScenarioMenu::RenderItems(SDL_Surface *screen, const geometry::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);
+}
+
+}
--- /dev/null
+/*
+ * ScenarioMenu.h
+ *
+ * Created on: Nov 30, 2012
+ * Author: holy
+ */
+
+#ifndef MENU_SCENARIOMENU_H_
+#define MENU_SCENARIOMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class ScenarioMenu
+: public app::State {
+
+public:
+ explicit ScenarioMenu(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 LoadItems();
+
+ void RenderHeadline(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+ void RenderItems(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+ PartyMenu *parent;
+ graphics::Menu<const common::Item *> itemMenu;
+
+};
+
+}
+
+#endif /* MENU_SCENARIOMENU_H_ */
--- /dev/null
+/*
+ * 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);
+}
+
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * SpellMenu.cpp
+ *
+ * Created on: Nov 18, 2012
+ * Author: holy
+ */
+
+#include "SpellMenu.h"
+
+#include "HeroStatus.h"
+#include "PartyMenu.h"
+#include "Resources.h"
+#include "../app/Input.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../common/Hero.h"
+#include "../common/Spell.h"
+#include "../graphics/Font.h"
+#include "../graphics/Frame.h"
+
+#include <algorithm>
+#include <SDL.h>
+#include <vector>
+
+using app::Input;
+using common::Hero;
+using common::Spell;
+using geometry::Vector;
+using graphics::Font;
+using graphics::Frame;
+using std::vector;
+
+namespace menu {
+
+SpellMenu::SpellMenu(PartyMenu *parent, int cursor)
+: parent(parent)
+, highlight(0)
+, cursor(cursor)
+, actionMenu(*parent->Res().itemMenuProperties)
+, spellMenu(*parent->Res().spellMenuProperties) {
+ actionMenu.Add(parent->Res().itemMenuUseText, CHOICE_USE);
+ actionMenu.Add(parent->Res().itemMenuSortText, CHOICE_SORT);
+}
+
+
+void SpellMenu::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);
+
+ actionMenu.SetSelected();
+ LoadSpells();
+}
+
+void SpellMenu::LoadSpells() {
+ spellMenu.Clear();
+ // TODO: set to max spells once implementation is changed
+ spellMenu.Reserve(GetHero().Spells().size());
+ for (vector<const Spell *>::const_iterator
+ i = GetHero().Spells().begin(), end = GetHero().Spells().end();
+ i != end; ++i) {
+ const Spell *spell = *i;
+ spellMenu.Add(spell->Name(), spell, spell->CanUseOnStatusScreen(), 0, spell->Cost());
+ }
+}
+
+const Hero &SpellMenu::GetHero() const {
+ return *parent->Game().state->party[cursor];
+}
+
+Hero &SpellMenu::GetHero() {
+ return *parent->Game().state->party[cursor];
+}
+
+void SpellMenu::OnExitState(SDL_Surface *) {
+ SDL_FreeSurface(highlight);
+}
+
+void SpellMenu::OnResumeState(SDL_Surface *) {
+
+}
+
+void SpellMenu::OnPauseState(SDL_Surface *) {
+
+}
+
+
+void SpellMenu::OnResize(int width, int height) {
+
+}
+
+
+void SpellMenu::HandleEvents(const Input &input) {
+ if (actionMenu.IsActive()) {
+ if (input.JustPressed(Input::PAD_LEFT)) {
+ actionMenu.PreviousItem();
+ }
+ if (input.JustPressed(Input::PAD_RIGHT)) {
+ actionMenu.NextItem();
+ }
+ } else {
+ if (input.JustPressed(Input::PAD_UP)) {
+ spellMenu.PreviousRow();
+ }
+ if (input.JustPressed(Input::PAD_RIGHT)) {
+ spellMenu.NextItem();
+ }
+ if (input.JustPressed(Input::PAD_DOWN)) {
+ spellMenu.NextRow();
+ }
+ if (input.JustPressed(Input::PAD_LEFT)) {
+ spellMenu.PreviousItem();
+ }
+ }
+
+ if (input.JustPressed(Input::ACTION_A)) {
+ if (actionMenu.IsActive()) {
+ if (actionMenu.Selected() == CHOICE_SORT) {
+ std::sort(GetHero().Spells().begin(),
+ GetHero().Spells().end(),
+ Spell::Less);
+ LoadSpells();
+ } else {
+ actionMenu.SetSelected();
+ spellMenu.SetActive();
+ }
+ } else if (spellMenu.IsActive()) {
+ spellMenu.SetDualSelection();
+ } else if (spellMenu.SelectedIndex() == spellMenu.SecondaryIndex()) {
+ if (spellMenu.Selected()->CanUseOnStatusScreen()) {
+ // TODO: use spell
+ }
+ } else {
+ std::swap(GetHero().Spells().at(spellMenu.SelectedIndex()),
+ GetHero().Spells().at(spellMenu.SecondaryIndex()));
+ spellMenu.SwapSelected();
+ spellMenu.SetActive();
+ }
+ }
+
+ if (input.JustPressed(Input::ACTION_B)) {
+ if (actionMenu.IsActive()) {
+ Ctrl().PopState();
+ } else if (spellMenu.IsActive()) {
+ actionMenu.SetActive();
+ spellMenu.SetInactive();
+ } else {
+ spellMenu.SetActive();
+ }
+ }
+}
+
+void SpellMenu::UpdateWorld(float deltaT) {
+
+}
+
+void SpellMenu::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> spellsOffset(font.CharWidth(), 16 * font.CharHeight() + font.CharHeight() / 8);
+
+ parent->RenderBackground(screen);
+ RenderHighlight(screen, offset);
+ parent->RenderHeros(screen, offset);
+ RenderMenu(screen, menuOffset + offset);
+ RenderSpells(screen, spellsOffset + offset);
+}
+
+int SpellMenu::Width() const {
+ return parent->Width();
+}
+
+int SpellMenu::Height() const {
+ return parent->Height();
+}
+
+void SpellMenu::RenderHighlight(SDL_Surface *screen, const Vector<int> &offset) const {
+ if (cursor < 0) return;
+ Vector<int> statusOffset(parent->StatusOffset(cursor));
+ 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 SpellMenu::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() + 9 * font.CharWidth(), offset.Y());
+ const Vector<int> menuOffset(menuFrameOffset.X() + 3 * font.CharWidth(), menuFrameOffset.Y() + font.CharHeight());
+
+ frame.Draw(screen, offset, 9 * font.CharWidth(), 3 * font.CharHeight());
+ font.DrawString(parent->Res().mainMenuSpellText, screen, labelOffset + offset);
+ frame.Draw(screen, menuFrameOffset, 21 * font.CharWidth(), 3 * font.CharHeight());
+ actionMenu.Draw(screen, menuOffset);
+}
+
+void SpellMenu::RenderSpells(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());
+ spellMenu.Draw(screen, offset + menuOffset);
+}
+
+}
--- /dev/null
+/*
+ * SpellMenu.h
+ *
+ * Created on: Nov 18, 2012
+ * Author: holy
+ */
+
+#ifndef MENU_SPELLMENU_H_
+#define MENU_SPELLMENU_H_
+
+#include "fwd.h"
+#include "../app/State.h"
+#include "../common/fwd.h"
+#include "../geometry/Vector.h"
+#include "../graphics/Menu.h"
+
+namespace menu {
+
+class SpellMenu
+: public app::State {
+
+public:
+ SpellMenu(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);
+
+ common::Hero &GetHero();
+ const common::Hero &GetHero() const;
+
+ void LoadSpells();
+
+ void RenderHighlight(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+ void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+ void RenderSpells(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
+
+private:
+ PartyMenu *parent;
+ SDL_Surface *highlight;
+ int cursor;
+ enum Choice {
+ CHOICE_USE,
+ CHOICE_SORT,
+ };
+ graphics::Menu<Choice> actionMenu;
+ graphics::Menu<const common::Spell *> spellMenu;
+
+};
+
+}
+
+#endif /* MENU_SPELLMENU_H_ */
--- /dev/null
+/*
+ * 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);
+ for (int i = 0; i < Hero::EQUIP_COUNT; ++i) {
+ RenderEquipmentLine(hero.Equipment(Hero::EquipSlot(i)), screen, position);
+ position += lineBreak;
+ }
+}
+
+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];
+}
+
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * fwd.h
+ *
+ * Created on: Oct 21, 2012
+ * Author: holy
+ */
+
+#ifndef MENU_FWD_H_
+#define MENU_FWD_H_
+
+namespace menu {
+
+class ChangeHero;
+class ConfigMenu;
+class EquipMenu;
+class HeroStatus;
+class InventoryMenu;
+class PartyMenu;
+struct Resources;
+class ScenarioMenu;
+class SelectHero;
+class SpellMenu;
+class StatusMenu;
+
+}
+
+#endif /* MENU_FWD_H_ */
Number single
Number multiple
+// Hero masks
+Number maskMaxim
+Number maskSelan
+Number maskGuy
+Number maskArtea
+Number maskDekar
+Number maskTia
+Number maskLexis
+Number maskAll
+
// Ikari
Boolean magical
Boolean physical
+// Items
+Number weapon
+Number armor
+Number shield
+Number helmet
+Number ring
+Number jewel
+
// Trigger type
Number triggerNorth
Number triggerEast
export Number multiple 1
export Number single 2
+// Hero masks
+export Number maskMaxim 1
+export Number maskSelan 2
+export Number maskGuy 4
+export Number maskArtea 8
+export Number maskDekar 16
+export Number maskTia 32
+export Number maskLexis 64
+export Number maskAll 127
+
// Ikari
export Boolean magical false
export Boolean physical true
+// Items
+export Number weapon 1
+export Number armor 2
+export Number shield 4
+export Number helmet 8
+export Number ring 16
+export Number jewel 32
+
// Trigger type
export Number triggerNorth 0
export Number triggerEast 1
targets: TargetingMode {
faction: ally,
mode: single
- }
+ },
+ mostUseful: true
}
export Item eagleRockItem {
name: "Eagle rock",
menuicon: jewelIcon,
- ikari: diveIkari
+ ikari: diveIkari,
+ equipability: jewel,
+ heroMask: maskAll
}
export Item escapeItem {
name: "Escape",
- battle: false
+ battle: false,
+ mostUseful: true
}
export Item evilJewelItem {
name: "Evil jewel",
menuicon: jewelIcon,
- ikari: gloomyIkari
+ ikari: gloomyIkari,
+ equipability: jewel,
+ heroMask: maskAll
}
export Item ghostRingItem {
name: "Ghost ring",
menuicon: ringIcon,
- ikari: destroyIkari
+ ikari: destroyIkari,
+ equipability: ring,
+ heroMask: maskAll
}
export Item hiPotionItem {
name: "Hi-Potion",
targets: TargetingMode {
faction: ally,
mode: single
- }
+ },
+ mostUseful: true
}
export Item holyCapItem {
name: "Holy cap",
menuicon: helmetIcon,
- ikari: vulnerableIkari
+ ikari: vulnerableIkari,
+ equipability: helmet,
+ heroMask: 42 // Selan, Artea, Tia
}
export Item holyRobeItem {
name: "Holy robe",
menuicon: armorIcon,
- ikari: crisisCureIkari
+ ikari: crisisCureIkari,
+ equipability: armor,
+ heroMask: 42 // Selan, Artea, Tia
}
export Item holyShieldItem {
name: "Holy shield",
menuicon: shieldIcon,
- ikari: lightGuardIkari
+ ikari: lightGuardIkari,
+ equipability: shield,
+ heroMask: 21 // Maxim, Guy, Dekar
}
export Item krakenRockItem {
name: "Kraken rock",
menuicon: jewelIcon,
- ikari: tenLeggerIkari
+ ikari: tenLeggerIkari,
+ equipability: jewel,
+ heroMask: maskAll
}
export Item legendHelmItem {
name: "Legend helm",
menuicon: helmetIcon,
- ikari: boomerangIkari
+ ikari: boomerangIkari,
+ equipability: helmet,
+ heroMask: 21 // Maxim, Guy, Dekar
}
export Item lizardBlowItem {
name: "Lizard blow",
targets: TargetingMode {
faction: enemy,
mode: single
- }
+ },
+ equipability: weapon,
+ heroMask: maskAll
}
export Item magicJarItem {
name: "Magic jar",
targets: TargetingMode {
faction: ally,
mode: single
- }
+ },
+ mostUseful: true
}
export Item megaShieldItem {
name: "Mega shield",
menuicon: shieldIcon,
- ikari: ironBarrierIkari
+ ikari: ironBarrierIkari,
+ equipability: shield,
+ heroMask: 20 // Guy, Dekar
}
export Item powerPotionItem {
name: "Power potion",
menuicon: potionIcon,
- battle: false
+ battle: false,
+ mostUseful: true
}
export Item powerRingItem {
name: "Power ring",
menuicon: ringIcon,
- ikari: trickIkari
+ ikari: trickIkari,
+ equipability: ring,
+ heroMask: maskAll
}
export Item rocketRingItem {
name: "Rocket ring",
menuicon: ringIcon,
- ikari: fakeIkari
+ ikari: fakeIkari,
+ equipability: ring,
+ heroMask: maskAll
}
export Item sleepBallItem {
name: "Sleep ball",
targets: TargetingMode {
faction: enemy,
mode: single
- }
+ },
+ mostUseful: true
}
export Item sProRingItem {
name: "S-pro ring",
menuicon: ringIcon,
- ikari: courageIkari
+ ikari: courageIkari,
+ equipability: ring,
+ heroMask: maskAll
}
export Item zircoAxItem {
name: "Zirco ax",
targets: TargetingMode {
faction: enemy,
mode: single
- }
+ },
+ equipability: weapon,
+ heroMask: 20 // Guy, Dekar
}
export Item zircoGlovesItem {
name: "Zirco gloves",
menuicon: shieldIcon,
- ikari: forcefieldIkari
+ ikari: forcefieldIkari,
+ equipability: shield,
+ heroMask: 106 // Selan, Artea, Tia, Lexis
}
export Item zircoHelmetItem {
name: "Zirco helmet",
menuicon: helmetIcon,
- ikari: slowIkari
+ ikari: slowIkari,
+ equipability: helmet,
+ heroMask: 21 // Maxim, Guy, Dekar
}
export Item zirconArmorItem {
name: "Zircon armor",
menuicon: armorIcon,
battle: false,
- ikari: magicCureIkari
+ ikari: magicCureIkari,
+ equipability: armor,
+ heroMask: 21 // Maxim, Guy, Dekar
}
export Item zirconPlateItem {
name: "Zircon plate",
menuicon: armorIcon,
- ikari: suddenCureIkari
+ ikari: suddenCureIkari,
+ equipability: armor,
+ heroMask: 74 // Selan, Artea, Lexis
}
export Item zircoSwordItem {
name: "Zirco sword",
mode: single
},
ikari: firestormIkari,
- attackanimation: swordAttackAnimation
+ attackanimation: swordAttackAnimation,
+ equipability: weapon,
+ heroMask: maskMaxim
}
export Item zircoWhipItem {
name: "Zirco whip",
faction: enemy,
mode: single
},
- ikari: thundershriekIkari
+ ikari: thundershriekIkari,
+ equipability: weapon,
+ heroMask: 34 // Selan, Tia
}
gut: 100,
mgr: 10
},
+ ladder: [
+ 10
+ ],
+ useMask: maskMaxim,
attackAnimation: ComplexAnimation {
sprite: maximSprite,
frametime: frameTime,
gut: 80,
mgr: 13
},
+ useMask: maskSelan,
attackAnimation: ComplexAnimation {
sprite: selanSprite,
frametime: frameTime,
gut: 90,
mgr: 8
},
+ useMask: maskGuy,
attackAnimation: ComplexAnimation {
sprite: guySprite,
frametime: frameTime,
gut: 100,
mgr: 5
},
+ useMask: maskDekar,
attackAnimation: ComplexAnimation {
sprite: dekarSprite,
frametime: frameTime,