#include "State.h"
+#include <stdexcept>
+
+using std::domain_error;
+
namespace app {
+State::State()
+: ctrl(0) {
+
+}
+
State::~State() {
}
-void State::EnterState(Application &ctrl, SDL_Surface *screen) {
- OnEnterState(ctrl, screen);
+void State::EnterState(Application &c, SDL_Surface *screen) {
+ ctrl = &c;
+ OnEnterState(c, screen);
}
-void State::ExitState(Application &ctrl, SDL_Surface *screen) {
- OnExitState(ctrl, screen);
+void State::ExitState(Application &c, SDL_Surface *screen) {
+ OnExitState(c, screen);
+ ctrl = 0;
}
void State::ResumeState(Application &ctrl, SDL_Surface *screen) {
OnResize(width, height);
}
+
+Application &State::Ctrl() {
+ if (ctrl) {
+ return *ctrl;
+ } else {
+ throw domain_error("call to app::State::Ctrl() without application context");
+ }
+}
+
+const Application &State::Ctrl() const {
+ if (ctrl) {
+ return *ctrl;
+ } else {
+ throw domain_error("call to app::State::Ctrl() without application context");
+ }
+}
+
}
class State {
public:
+ State();
virtual ~State();
public:
/// Draw a picture of the world.
virtual void Render(SDL_Surface *) = 0;
+protected:
+ /// Get a handle to the application this state is running on.
+ /// Do not call this while the state is off the stack (e.g. in c'tor/d'tor)
+ /// or you'll get a std::domain_error (potentially evil in d'tor)!
+ Application &Ctrl();
+ const Application &Ctrl() const;
+
private:
/// Do some setup that needs an application and/or screen handle and thus
/// can not be done by the constructor.
Timers<float> &PhysicsTimers() { return physicsTimers; }
private:
+ Application *ctrl;
Timers<Uint32> graphicsTimers;
Timers<float> physicsTimers;
namespace battle {
void PerformAttacks::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
battle->CalculateAttackOrder();
numberAnimation.reserve(battle->MaxMonsters() > battle->NumHeroes() + 1 ? battle->MaxMonsters() : battle->NumHeroes() + 1);
numberPosition.reserve(numberAnimation.size());
void PerformAttacks::OnExitState(Application &c, SDL_Surface *screen) {
battle->ClearAllAttacks();
- ctrl = 0;
}
void PerformAttacks::OnResumeState(Application &ctrl, SDL_Surface *screen) {
battle->ApplyDamage();
battle->NextAttack();
if (battle->AttacksFinished()) {
- ctrl->PopState();
+ Ctrl().PopState();
return;
}
public:
explicit PerformAttacks(BattleState *battle)
- : ctrl(0), battle(battle), moveAnimation(0), targetAnimation(0), titleBarText(0), cursor(-1) { }
+ : battle(battle), moveAnimation(0), targetAnimation(0), titleBarText(0), cursor(-1) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderTargetAnimation(SDL_Surface *screen, const geometry::Vector<int> &offset) const;
private:
- app::Application *ctrl;
BattleState *battle;
graphics::AnimationRunner moveAnimation;
graphics::AnimationRunner targetAnimation;
namespace battle {
void RunState::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void RunState::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void RunState::OnResumeState(Application &ctrl, SDL_Surface *screen) {
void RunState::HandleEvents(const Input &input) {
if (timer.Finished()) {
battle->SetRunaway();
- ctrl->PopState(); // pop self
+ Ctrl().PopState(); // pop self
}
}
public:
explicit RunState(BattleState *battle)
- : ctrl(0), battle(battle){ }
+ : battle(battle){ }
public:
void RenderTitleBar(SDL_Surface *screen, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
app::Timer<Uint32> timer;
namespace battle {
void SelectAttackType::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void SelectAttackType::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void SelectAttackType::OnResumeState(Application &ctrl, SDL_Surface *screen) {
ac.Selection().SetSingle();
}
ac.Selection().Reset();
- ctrl->PushState(new SelectTarget(battle, this, &ac.Selection(), battle->Res().weaponTargetCursor));
+ Ctrl().PushState(new SelectTarget(battle, this, &ac.Selection(), battle->Res().weaponTargetCursor));
break;
case AttackChoice::MAGIC:
if (battle->ActiveHero().CanUseMagic()) {
- ctrl->PushState(new SelectSpell(battle, this));
+ Ctrl().PushState(new SelectSpell(battle, this));
}
break;
case AttackChoice::DEFEND:
battle->NextHero();
break;
case AttackChoice::IKARI:
- ctrl->PushState(new SelectIkari(battle, this));
+ Ctrl().PushState(new SelectIkari(battle, this));
break;
case AttackChoice::ITEM:
- ctrl->PushState(new SelectItem(battle, this));
+ Ctrl().PushState(new SelectItem(battle, this));
break;
default:
throw std::logic_error("selected invalid attack type");
ac.Reset();
battle->PreviousHero();
if (battle->BeforeFirstHero()) {
- ctrl->ChangeState(new SelectMoveAction(battle));
+ Ctrl().ChangeState(new SelectMoveAction(battle));
} else {
battle->ActiveHero().GetAttackChoice().Reset();
}
}
if (battle->AttackSelectionDone()) {
- ctrl->PopState();
+ Ctrl().PopState();
}
}
public:
explicit SelectAttackType(BattleState *battle)
- : ctrl(0), battle(battle) { }
+ : battle(battle) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
};
namespace battle {
void SelectIkari::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void SelectIkari::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void SelectIkari::OnResumeState(Application &ctrl, SDL_Surface *screen) {
ac.SetType(AttackChoice::IKARI);
ac.SetItem(battle->ActiveHero().IkariMenu().Selected());
battle->NextHero();
- ctrl->PopState();
+ Ctrl().PopState();
} else {
if (ikari->GetTargetingMode().TargetsSingle()) {
ac.Selection().SetSingle();
} else {
ac.Selection().SetMultiple();
}
- ctrl->PushState(new SelectTarget(battle, parent, &ac.Selection(), ikari->IsMagical() ? battle->Res().magicTargetCursor : battle->Res().weaponTargetCursor));
+ Ctrl().PushState(new SelectTarget(battle, parent, &ac.Selection(), ikari->IsMagical() ? battle->Res().magicTargetCursor : battle->Res().weaponTargetCursor));
}
}
}
if (input.JustPressed(Input::ACTION_B)) {
- ctrl->PopState(); // return control to parent
+ Ctrl().PopState(); // return control to parent
}
if (input.JustPressed(Input::PAD_UP)) {
battle->ActiveHero().IkariMenu().PreviousRow();
public:
SelectIkari(BattleState *battle, SelectAttackType *parent)
- : ctrl(0), battle(battle), parent(parent) { }
+ : battle(battle), parent(parent) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderMenu(SDL_Surface *, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
SelectAttackType *parent;
namespace battle {
void SelectItem::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void SelectItem::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void SelectItem::OnResumeState(Application &ctrl, SDL_Surface *screen) {
ac.SetType(AttackChoice::ITEM);
ac.SetItem(item);
battle->NextHero();
- ctrl->PopState();
+ Ctrl().PopState();
} else {
if (item->GetTargetingMode().TargetsSingle()) {
ac.Selection().SetSingle();
} else {
ac.Selection().SetMultiple();
}
- ctrl->PushState(new SelectTarget(battle, parent, &ac.Selection(), battle->Res().itemTargetCursor));
+ Ctrl().PushState(new SelectTarget(battle, parent, &ac.Selection(), battle->Res().itemTargetCursor));
}
}
}
if (input.JustPressed(Input::ACTION_B)) {
- ctrl->PopState(); // return control to parent
+ Ctrl().PopState(); // return control to parent
}
if (input.JustPressed(Input::PAD_UP)) {
battle->ItemMenu().PreviousRow();
public:
SelectItem(BattleState *battle, SelectAttackType *parent)
- : ctrl(0), battle(battle), parent(parent) { }
+ : battle(battle), parent(parent) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderMenu(SDL_Surface *, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
SelectAttackType *parent;
namespace battle {
void SelectMoveAction::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void SelectMoveAction::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void SelectMoveAction::OnResumeState(Application &ctrl, SDL_Surface *screen) {
if (input.JustPressed(Input::ACTION_A)) {
switch (battle->GetMoveMenu().Selected()) {
case MoveMenu::ATTACK:
- ctrl->ChangeState(new SelectAttackType(battle));
+ Ctrl().ChangeState(new SelectAttackType(battle));
battle->NextHero();
break;
case MoveMenu::CHANGE:
- ctrl->PushState(new SwapHeroes(battle, this));
+ Ctrl().PushState(new SwapHeroes(battle, this));
break;
case MoveMenu::RUN:
- ctrl->ChangeState(new RunState(battle));
+ Ctrl().ChangeState(new RunState(battle));
break;
}
}
public:
explicit SelectMoveAction(BattleState *battle)
- : ctrl(0), battle(battle) { }
+ : battle(battle) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderMenu(SDL_Surface *screen, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
};
namespace battle {
void SelectSpell::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void SelectSpell::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void SelectSpell::OnResumeState(Application &ctrl, SDL_Surface *screen) {
ac.SetType(AttackChoice::MAGIC);
ac.SetSpell(spell);
battle->NextHero();
- ctrl->PopState();
+ Ctrl().PopState();
} else {
if (spell->GetTargetingMode().TargetsSingle()) {
ac.Selection().SetSingle();
} else {
ac.Selection().SetMultiple();
}
- ctrl->PushState(new SelectTarget(battle, parent, &ac.Selection(), battle->Res().magicTargetCursor));
+ Ctrl().PushState(new SelectTarget(battle, parent, &ac.Selection(), battle->Res().magicTargetCursor));
}
}
}
if (input.JustPressed(Input::ACTION_B)) {
- ctrl->PopState(); // return control to parent
+ Ctrl().PopState(); // return control to parent
}
if (input.JustPressed(Input::PAD_UP)) {
battle->ActiveHero().SpellMenu().PreviousRow();
public:
SelectSpell(BattleState *battle, SelectAttackType *parent)
- : ctrl(0), battle(battle), parent(parent) { }
+ : battle(battle), parent(parent) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderMenu(SDL_Surface *, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
SelectAttackType *parent;
namespace battle {
void SelectTarget::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void SelectTarget::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void SelectTarget::OnResumeState(Application &ctrl, SDL_Surface *screen) {
void SelectTarget::HandleEvents(const Input &input) {
if (input.JustPressed(Input::ACTION_A)) {
if (selection->CurrentIsSelected()) {
- ctrl->PopState(); // return control to parent
+ Ctrl().PopState(); // return control to parent
} else {
selection->Select();
if (selection->SelectSingle()) {
- ctrl->PopState(); // return control to parent
+ Ctrl().PopState(); // return control to parent
}
}
}
selection->Unselect();
} else {
selection->UnselectAll();
- ctrl->PopState(); // return control to parent
+ Ctrl().PopState(); // return control to parent
}
}
public:
SelectTarget(BattleState *battle, SelectAttackType *parent, TargetSelection *selection, const graphics::Sprite *cursorIcon)
- : ctrl(0), battle(battle), parent(parent), selection(selection), cursorIcon(cursorIcon), flipFlop(true) { }
+ : battle(battle), parent(parent), selection(selection), cursorIcon(cursorIcon), flipFlop(true) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderCursors(SDL_Surface *screen, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
SelectAttackType *parent;
TargetSelection *selection;
namespace battle {
void SwapHeroes::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void SwapHeroes::OnExitState(Application &c, SDL_Surface *screen) {
- ctrl = 0;
+
}
void SwapHeroes::OnResumeState(Application &ctrl, SDL_Surface *screen) {
if (cursor == selected) {
selected = -1;
} else {
- ctrl->PopState();
+ Ctrl().PopState();
}
}
public:
SwapHeroes(BattleState *battle, SelectMoveAction *parent)
- : ctrl(0), battle(battle), parent(parent), cursor(0), selected(-1), flipFlop(true) { }
+ : battle(battle), parent(parent), cursor(0), selected(-1), flipFlop(true) { }
public:
virtual void HandleEvents(const app::Input &);
void RenderCursors(SDL_Surface *screen, const geometry::Vector<int> &offset);
private:
- app::Application *ctrl;
BattleState *battle;
SelectMoveAction *parent;
int cursor;
namespace graphics {
ColorFade::ColorFade(State *slave, Uint32 color, int duration, bool in, bool interactive)
-: ctrl(0)
-, slave(slave)
+: slave(slave)
, blinds(0)
, color(color)
, duration(duration)
}
void ColorFade::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
if (leadIn > 0) {
timer = GraphicsTimers().StartCountdown(leadIn);
} else {
if (leadOut > 0) {
timer = GraphicsTimers().StartCountdown(leadOut);
} else {
- ctrl->PopState();
+ Ctrl().PopState();
}
} else {
- ctrl->PopState();
+ Ctrl().PopState();
}
}
}
private:
app::Timer<Uint32> timer;
- app::Application *ctrl;
app::State *slave;
SDL_Surface *blinds;
Uint32 color;
MapState::MapState(GameConfig *g, Map *map)
: game(g)
-, ctrl(0)
, map(map)
, controlled(0)
, pushed(0)
void MapState::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
camera.Resize(screen->w, screen->h);
LoadMap(map);
}
ColorFade *fadeOut(new ColorFade(this, 0, 500));
fadeOut->SetLeadOutTime(500);
- ctrl->PushState(fadeIn);
- ctrl->PushState(battleState);
- ctrl->PushState(fadeOut);
+ Ctrl().PushState(fadeIn);
+ Ctrl().PushState(battleState);
+ Ctrl().PushState(fadeOut);
// TODO: move entity erase to happen after the transition or battle
entities.erase(e);
return true;
void MapState::HandleSyscall(common::ScriptRunner &r) {
switch (r.Integer0()) {
case TRANSITION: {
- ctrl->PushState(new ColorFade(this, 0, 500, true));
- ctrl->PushState(new TransitionState(this, reinterpret_cast<Map *>(r.Address0()), r.Vector0()));
+ Ctrl().PushState(new ColorFade(this, 0, 500, true));
+ Ctrl().PushState(new TransitionState(this, reinterpret_cast<Map *>(r.Address0()), r.Vector0()));
ColorFade *fadeOut(new ColorFade(this, 0, 500, false));
fadeOut->SetLeadOutTime(500);
- ctrl->PushState(fadeOut);
+ Ctrl().PushState(fadeOut);
break;
}
}
private:
common::GameConfig *game;
- app::Application *ctrl;
Map *map;
Entity *controlled;
Entity *pushed;
namespace map {
TransitionState::TransitionState(MapState *ms, Map *map, const Vector<int> &coordinates)
-: ctrl(0)
-, ms(ms)
+: ms(ms)
, map(map)
, coordinates(coordinates) {
}
void TransitionState::OnEnterState(Application &c, SDL_Surface *screen) {
- ctrl = &c;
+
}
void TransitionState::OnExitState(Application &, SDL_Surface *screen) {
void TransitionState::HandleEvents(const Input &input) {
ms->Transition(map, coordinates);
- ctrl->PopState();
+ Ctrl().PopState();
}
virtual void OnResize(int width, int height);
private:
- app::Application *ctrl;
MapState *ms;
Map *map;
const geometry::Vector<int> &coordinates;