Application::Application(sdl::InitScreen *screen, State *initialState)
: screen(screen)
, states()
-, last(SDL_GetTicks())
-, toPop(0) {
+, last(SDL_GetTicks()) {
assert(screen && "cannot create application without screen");
assert(initialState && "cannot create application without initial state");
RealPushState(initialState);
}
void Application::UpdateState() {
- while (toPop > 0) {
- RealPopState();
- --toPop;
- }
- while (!toPush.empty()) {
- State *s(toPush.front());
- toPush.pop();
- RealPushState(s);
+ while (!stateChanges.empty()) {
+ switch (stateChanges.front().type) {
+ case StateCommand::PUSH:
+ RealPushState(stateChanges.front().state);
+ break;
+ case StateCommand::POP:
+ RealPopState();
+ break;
+ case StateCommand::CHANGE:
+ RealChangeState(stateChanges.front().state);
+ break;
+ }
+ stateChanges.pop();
}
}
void Application::ChangeState(State *s) {
- PopState();
- PushState(s);
+ StateCommand cmd;
+ cmd.type = StateCommand::CHANGE;
+ cmd.state = s;
+ stateChanges.push(cmd);
}
void Application::PushState(State *s) {
- toPush.push(s);
+ StateCommand cmd;
+ cmd.type = StateCommand::PUSH;
+ cmd.state = s;
+ stateChanges.push(cmd);
}
-void Application::RealPushState(State *s) {
+void Application::PopState() {
+ StateCommand cmd;
+ cmd.type = StateCommand::POP;
+ cmd.state = 0;
+ stateChanges.push(cmd);
+}
+
+void Application::RealChangeState(State *s) {
+ if (!states.empty()) {
+ states.top()->PauseState(*this, screen->Screen());
+ states.top()->ExitState(*this, screen->Screen());
+ states.pop();
+ }
states.push(s);
s->EnterState(*this, screen->Screen());
+ s->ResumeState(*this, screen->Screen());
}
-void Application::PopState() {
- ++toPop;
+void Application::RealPushState(State *s) {
+ if (!states.empty()) {
+ states.top()->PauseState(*this, screen->Screen());
+ }
+ states.push(s);
+ s->EnterState(*this, screen->Screen());
+ s->ResumeState(*this, screen->Screen());
}
void Application::RealPopState() {
if (states.empty()) return;
- states.top()->ExitState();
+ states.top()->PauseState(*this, screen->Screen());
+ states.top()->ExitState(*this, screen->Screen());
delete states.top();
states.pop();
+ if (!states.empty()) {
+ states.top()->ResumeState(*this, screen->Screen());
+ }
}
void Application::Quit() {
Input &Buttons() { return input; }
const Input &Buttons() const { return input; }
+private:
+ struct StateCommand {
+ enum Type {
+ PUSH, POP, CHANGE
+ } type;
+ State *state;
+ };
+
private:
State *CurrentState();
void UpdateState();
+ void RealChangeState(State *);
void RealPushState(State *);
void RealPopState();
void PopAllStates();
private:
sdl::InitScreen *screen;
std::stack<State *> states;
- std::queue<State *> toPush;
+ std::queue<StateCommand> stateChanges;
Input input;
Uint32 last;
- int toPop;
};
public:
/// do some setup
+ /// called when the state first enters the stack
/// @param ctrl the Application running the state
virtual void EnterState(Application &ctrl, SDL_Surface *screen) = 0;
- virtual void ExitState() = 0;
+ /// do some cleanup
+ /// called when the state is popped from the stack
+ virtual void ExitState(Application &ctrl, SDL_Surface *screen) = 0;
+ /// called when the state becomes the active one
+ virtual void ResumeState(Application &ctrl, SDL_Surface *screen) = 0;
+ /// called when the state becomes inactive
+ virtual void PauseState(Application &ctrl, SDL_Surface *screen) = 0;
/// adapt the state's graphics to given dimensions
virtual void Resize(int width, int height) = 0;
for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
heroTags.push_back(HeroTag(&heroes[i], HeroTag::Alignment((i + 1) % 2)));
}
+}
+
+void BattleState::ExitState(Application &ctrl, SDL_Surface *screen) {
+
+}
+
+void BattleState::ResumeState(Application &ctrl, SDL_Surface *screen) {
+ // reset attack choices
+ activeHero = -1;
+ attackChoices.clear();
+ attackChoices.resize(heroes.size());
ctrl.PushState(new SelectMoveAction(this));
}
-void BattleState::ExitState() {
+void BattleState::PauseState(Application &ctrl, SDL_Surface *screen) {
}
RenderMonsters(screen, offset);
// RenderHeroes(screen, offset);
RenderHeroTags(screen, offset);
- RenderAttackTypeMenu(screen, offset);
}
void BattleState::RenderBackground(SDL_Surface *screen, const Vector<int> &offset) {
tagPosition[3] = Point<int>(tagWidth + attackTypeMenu.IconWidth(), uiOffset + tagHeight + attackTypeMenu.IconHeight());
for (vector<HeroTag>::size_type i(0), end(heroTags.size()); i < end; ++i) {
- heroTags[i].Render(screen, tagWidth, tagHeight, tagPosition[i] + offset, i == activeHero);
+ heroTags[i].Render(screen, tagWidth, tagHeight, tagPosition[i] + offset, (int)i == activeHero);
}
}
-void BattleState::RenderAttackTypeMenu(SDL_Surface *screen, const Vector<int> &offset) {
- Point<int> position(
- (BackgroundWidth() - attackTypeMenu.Width()) / 2,
- (BackgroundHeight() * 3 / 4) - (attackTypeMenu.Height() / 2));
- attackTypeMenu.Render(screen, position + offset);
-}
-
}
#ifndef BATTLE_BATTLESTATE_H_
#define BATTLE_BATTLESTATE_H_
+#include "AttackChoice.h"
#include "AttackTypeMenu.h"
#include "Hero.h"
#include "HeroTag.h"
public:
virtual void EnterState(app::Application &ctrl, SDL_Surface *screen);
- virtual void ExitState();
+ virtual void ExitState(app::Application &ctrl, SDL_Surface *screen);
+ virtual void ResumeState(app::Application &ctrl, SDL_Surface *screen);
+ virtual void PauseState(app::Application &ctrl, SDL_Surface *screen);
virtual void Resize(int width, int height);
bool HasMoreHeroes() const { return activeHero < (int) heroes.size(); }
void NextHero() { ++activeHero; }
+ bool HasChosenAttackType() const { return attackChoices[activeHero].GetType() != AttackChoice::UNDECIDED; }
+ void SetAttackType(AttackChoice::Type t) { attackChoices[activeHero].SetType(t); }
+ bool AttackSelectionDone() const { return activeHero >= (int) heroes.size(); }
public:
geometry::Vector<int> CalculateScreenOffset(SDL_Surface *screen) const {
void RenderMonsters(SDL_Surface *screen, const geometry::Vector<int> &offset);
void RenderHeroes(SDL_Surface *screen, const geometry::Vector<int> &offset);
void RenderHeroTags(SDL_Surface *screen, const geometry::Vector<int> &offset);
- void RenderAttackTypeMenu(SDL_Surface *screen, const geometry::Vector<int> &offset);
private:
SDL_Surface *background;
std::vector<Monster> monsters;
std::vector<Hero> heroes;
std::vector<HeroTag> heroTags;
+ std::vector<AttackChoice> attackChoices;
int activeHero;
};
#include "../AttackChoice.h"
#include "../BattleState.h"
+#include "../../app/Application.h"
#include "../../app/Input.h"
#include "../../geometry/operators.h"
#include <stdexcept>
+using app::Application;
using app::Input;
using geometry::Point;
using geometry::Vector;
namespace battle {
-void SelectAttackType::EnterState(app::Application &c, SDL_Surface *screen) {
+void SelectAttackType::EnterState(Application &c, SDL_Surface *screen) {
ctrl = &c;
}
-void SelectAttackType::ExitState() {
+void SelectAttackType::ExitState(Application &c, SDL_Surface *screen) {
ctrl = 0;
}
+void SelectAttackType::ResumeState(Application &ctrl, SDL_Surface *screen) {
+
+}
+
+void SelectAttackType::PauseState(Application &ctrl, SDL_Surface *screen) {
+
+}
+
void SelectAttackType::Resize(int width, int height) {
}
if (input.JustPressed(Input::ACTION_A)) {
+ battle->SetAttackType(battle->GetAttackTypeMenu().Selected());
switch (battle->GetAttackTypeMenu().Selected()) {
case AttackChoice::SWORD:
- // TODO: switch to next character
+ battle->NextHero();
break;
case AttackChoice::MAGIC:
// TODO: switch to spell select
break;
case AttackChoice::DEFEND:
- // TODO: switch to next character
+ battle->NextHero();
break;
case AttackChoice::IKARI:
// TODO: switch to ikari attack select
throw std::logic_error("selected invalid attack type");
}
}
+
+ if (battle->AttackSelectionDone()) {
+ // TODO: switch to battle animation instead
+ ctrl->PopState();
+ }
}
void SelectAttackType::UpdateWorld(float deltaT) {
public:
virtual void EnterState(app::Application &ctrl, SDL_Surface *screen);
- virtual void ExitState();
+ virtual void ExitState(app::Application &ctrl, SDL_Surface *screen);
+ virtual void ResumeState(app::Application &ctrl, SDL_Surface *screen);
+ virtual void PauseState(app::Application &ctrl, SDL_Surface *screen);
virtual void Resize(int width, int height);
#include "../../app/Input.h"
#include "../../geometry/operators.h"
+using app::Application;
using app::Input;
using geometry::Point;
using geometry::Vector;
namespace battle {
-void SelectMoveAction::EnterState(app::Application &c, SDL_Surface *screen) {
+void SelectMoveAction::EnterState(Application &c, SDL_Surface *screen) {
ctrl = &c;
}
-void SelectMoveAction::ExitState() {
+void SelectMoveAction::ExitState(Application &c, SDL_Surface *screen) {
ctrl = 0;
}
+void SelectMoveAction::ResumeState(Application &ctrl, SDL_Surface *screen) {
+
+}
+
+void SelectMoveAction::PauseState(Application &ctrl, SDL_Surface *screen) {
+
+}
+
void SelectMoveAction::Resize(int width, int height) {
public:
virtual void EnterState(app::Application &ctrl, SDL_Surface *screen);
- virtual void ExitState();
+ virtual void ExitState(app::Application &ctrl, SDL_Surface *screen);
+ virtual void ResumeState(app::Application &ctrl, SDL_Surface *screen);
+ virtual void PauseState(app::Application &ctrl, SDL_Surface *screen);
virtual void Resize(int width, int height);