#include "Map.h"
#include "Tile.h"
+#include "TransitionState.h"
+#include "Trigger.h"
#include "../app/Application.h"
#include "../app/Input.h"
+#include "../battle/BattleState.h"
+#include "../common/GameConfig.h"
+#include "../common/GameState.h"
+#include "../graphics/ColorFade.h"
#include <algorithm>
using app::Application;
using app::Input;
+using battle::BattleState;
+using common::GameConfig;
using geometry::Vector;
+using graphics::ColorFade;
namespace map {
-MapState::MapState(Map *map)
-: map(map)
+MapState::MapState(GameConfig *g, Map *map)
+: game(g)
+, ctrl(0)
+, map(map)
, controlled(0)
, tempTarget(20, 20)
, camera(100, 100, &tempTarget)
, walkingSpeed(64)
, nextDirection(-1)
, afterLock(false)
+, skipLock(false)
, debug(false) {
}
-void MapState::EnterState(Application &ctrl, SDL_Surface *screen) {
+void MapState::EnterState(Application &c, SDL_Surface *screen) {
+ ctrl = &c;
camera.Resize(screen->w, screen->h);
+ LoadMap(map);
}
void MapState::ExitState(Application &ctrl, SDL_Surface *screen) {
if (moveTimer.Running() && !moveTimer.JustHit()) return;
Vector<int> nowLock(controlled->Position());
+ bool event(false);
if (nowLock != lastLock) {
- OnGridLock();
+ event = OnGridLock();
afterLock = true;
moveTimer.Clear();
} else if (moveTimer.JustHit()) {
- OnGridLock();
+ event = OnGridLock();
afterLock = true;
}
- // TODO: halt all activity if lock caused a state/map transition
+ if (event) {
+ return;
+ }
if (nextDirection >= 0) {
bool blocked(CheckBlocking());
}
bool MapState::CheckBlocking() const {
- const Tile &tile(map->TileAt(controlled->Position()));
+ const Tile *tile(map->TileAt(controlled->Position()));
+ if (!tile) {
+ return false;
+ }
Vector<int> nextPosition;
switch (nextDirection) {
case Entity::ORIENTATION_NORTH:
- if (tile.BlocksNorth()) {
+ if (tile->BlocksNorth()) {
return true;
} else {
nextPosition = Vector<int>(
}
break;
case Entity::ORIENTATION_EAST:
- if (tile.BlocksEast()) {
+ if (tile->BlocksEast()) {
return true;
} else {
nextPosition = Vector<int>(
}
break;
case Entity::ORIENTATION_SOUTH:
- if (tile.BlocksSouth()) {
+ if (tile->BlocksSouth()) {
return true;
} else {
nextPosition = Vector<int>(
}
break;
case Entity::ORIENTATION_WEST:
- if (tile.BlocksWest()) {
+ if (tile->BlocksWest()) {
return true;
} else {
nextPosition = Vector<int>(
return false;
}
-void MapState::OnGridLock() {
- LockEntities();
- CheckMonster();
- CheckTrigger();
+bool MapState::OnGridLock() {
+ if (skipLock) {
+ skipLock = false;
+ return false;
+ } else {
+ LockEntities();
+ return CheckMonster() || CheckTrigger();
+ }
}
void MapState::LockEntities() {
}
}
-void MapState::CheckMonster() {
+bool MapState::CheckMonster() {
Vector<int> coords(map->TileCoordinates(controlled->Position()));
Vector<int> neighbor[4];
neighbor[0] = Vector<int>(coords.X(), coords.Y() - 1); // N
for (std::vector<Entity *>::iterator e(entities.begin()), end(entities.end()); e != end; ++e) {
if ((*e)->Hostile() && map->TileCoordinates((*e)->Position()) == neighbor[i]) {
// TODO: check for turn advantage, see #26
- // TODO: remove entity, push battle state and transition and halt all other activity
+ // TODO: other transition
+ BattleState *battleState(new BattleState(game, map->BattleBackgroundAt((*e)->Position()), (*e)->PartyLayout()));
+ for (int i(0); i < 4; ++i) {
+ if (game->state->party[i]) {
+ battleState->AddHero(*game->state->party[i]);
+ }
+ }
+ for (battle::Monster *monster((*e)->MonstersBegin()); monster != (*e)->MonstersEnd(); ++monster) {
+ battleState->AddMonster(*monster);
+ }
+
+ ColorFade *fadeIn(new ColorFade(this, 0, 500, true));
+ fadeIn->SetLeadInTime(500);
+ ColorFade *fadeOut(new ColorFade(this, 0, 500));
+ fadeOut->SetLeadOutTime(500);
+
+ 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;
// needed information here:
- // - battle background (from tile?)
+ // - battle background (from tile/area/map)
// - monsters + layout (from entity)
- // - battle resources (from global resources)
}
}
}
+ return false;
}
-void MapState::CheckTrigger() {
+bool MapState::CheckTrigger() {
Trigger *trigger(map->TriggerAt(Vector<int>(controlled->Position())));
if (trigger) {
- // TODO: run trigger
+ // TODO: run trigger script
+ if (trigger->map) {
+ ctrl->PushState(new ColorFade(this, 0, 500, true));
+ ctrl->PushState(new TransitionState(this, trigger->map, trigger->target));
+ ColorFade *fadeOut(new ColorFade(this, 0, 500, false));
+ fadeOut->SetLeadOutTime(500);
+ ctrl->PushState(fadeOut);
+ return true;
+ }
}
-
+ return false;
}
void MapState::OnMove(bool realMove) {
}
+void MapState::Transition(Map *newMap, const Vector<int> &coordinates) {
+ UnloadMap();
+ Vector<int> position(coordinates * map->Tileset()->Size());
+ for (Entity *e(controlled); e; e = e->Follower()) {
+ e->Position() = position;
+ e->SetOrientation(controlled->GetOrientation());
+ }
+ LoadMap(newMap);
+ skipLock = true;
+}
+
+void MapState::UnloadMap() {
+ entities.clear();
+}
+
+void MapState::LoadMap(Map *m) {
+ map = m;
+ entities.insert(entities.end(), m->EntitiesBegin(), m->EntitiesEnd());
+ for (Entity *e(controlled); e; e = e->Follower()) {
+ entities.push_back(e);
+ }
+}
+
+
void MapState::Render(SDL_Surface *screen) {
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));