4 * Created on: Sep 29, 2012
12 #include "TransitionState.h"
14 #include "../app/Application.h"
15 #include "../app/Input.h"
16 #include "../battle/BattleState.h"
17 #include "../common/GameConfig.h"
18 #include "../common/GameState.h"
19 #include "../graphics/ColorFade.h"
23 using app::Application;
25 using battle::BattleState;
26 using common::GameConfig;
27 using geometry::Vector;
28 using graphics::ColorFade;
32 MapState::MapState(GameConfig *g, Map *map)
38 , camera(100, 100, &tempTarget)
48 void MapState::EnterState(Application &c, SDL_Surface *screen) {
50 camera.Resize(screen->w, screen->h);
54 void MapState::ExitState(Application &ctrl, SDL_Surface *screen) {
58 void MapState::ResumeState(Application &ctrl, SDL_Surface *screen) {
59 camera.Resize(screen->w, screen->h);
62 void MapState::PauseState(Application &ctrl, SDL_Surface *screen) {
66 void MapState::Resize(int width, int height) {
67 camera.Resize(width, height);
71 void MapState::HandleEvents(const Input &input) {
72 if (!controlled) return;
74 if (input.IsDown(Input::PAD_UP)) {
75 nextDirection = Entity::ORIENTATION_NORTH;
76 } else if (input.IsDown(Input::PAD_RIGHT)) {
77 nextDirection = Entity::ORIENTATION_EAST;
78 } else if (input.IsDown(Input::PAD_DOWN)) {
79 nextDirection = Entity::ORIENTATION_SOUTH;
80 } else if (input.IsDown(Input::PAD_LEFT)) {
81 nextDirection = Entity::ORIENTATION_WEST;
86 if (input.JustPressed(Input::DEBUG_1)) {
91 void MapState::UpdateWorld(float deltaT) {
92 if (controlled && controlled->TileLock(map->Tileset()->Size())) {
95 for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
100 void MapState::OnTileLock() {
101 if (moveTimer.Running() && !moveTimer.JustHit()) return;
103 Vector<int> nowLock(controlled->Position());
105 if (nowLock != lastLock) {
106 event = OnGridLock();
109 } else if (moveTimer.JustHit()) {
110 event = OnGridLock();
118 if (nextDirection >= 0) {
119 bool blocked(CheckBlocking());
124 controlled->SetOrientation(Entity::Orientation(nextDirection));
126 controlled->SetSpeed(walkingSpeed);
129 controlled->SetSpeed(0.0f);
130 StopFollowers(*controlled);
131 if (!moveTimer.Running()) {
132 int tileSize((controlled->GetOrientation() % 2) ? map->Tileset()->Width() : map->Tileset()->Height());
133 moveTimer = PhysicsTimers().StartInterval(tileSize/walkingSpeed);
136 if (!controlled->AnimationRunning()) {
137 controlled->StartAnimation(*this);
140 controlled->SetSpeed(0.0f);
141 StopFollowers(*controlled);
142 controlled->StopAnimation();
149 bool MapState::CheckBlocking() const {
150 const Tile *tile(map->TileAt(controlled->Position()));
154 Vector<int> nextPosition;
155 switch (nextDirection) {
156 case Entity::ORIENTATION_NORTH:
157 if (tile->BlocksNorth()) {
160 nextPosition = Vector<int>(
161 controlled->Position().X(),
162 controlled->Position().Y() - map->Tileset()->Height());
165 case Entity::ORIENTATION_EAST:
166 if (tile->BlocksEast()) {
169 nextPosition = Vector<int>(
170 controlled->Position().X() + map->Tileset()->Width(),
171 controlled->Position().Y());
174 case Entity::ORIENTATION_SOUTH:
175 if (tile->BlocksSouth()) {
178 nextPosition = Vector<int>(
179 controlled->Position().X(),
180 controlled->Position().Y() + map->Tileset()->Height());
183 case Entity::ORIENTATION_WEST:
184 if (tile->BlocksWest()) {
187 nextPosition = Vector<int>(
188 controlled->Position().X() - map->Tileset()->Width(),
189 controlled->Position().Y());
195 Vector<int> nextTileCoords(map->TileCoordinates(nextPosition));
196 for (std::vector<Entity *>::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
197 const Entity &e(**i);
198 if (map->TileCoordinates(e.Position()) == nextTileCoords && e.Blocking()) {
205 bool MapState::OnGridLock() {
211 return CheckMonster() || CheckTrigger();
215 void MapState::LockEntities() {
216 for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
217 if (*i == controlled) {
221 (*i)->Position().Lock(map->Tileset()->Size());
225 bool MapState::CheckMonster() {
226 Vector<int> coords(map->TileCoordinates(controlled->Position()));
227 Vector<int> neighbor[4];
228 neighbor[0] = Vector<int>(coords.X(), coords.Y() - 1); // N
229 neighbor[1] = Vector<int>(coords.X() + 1, coords.Y()); // E
230 neighbor[2] = Vector<int>(coords.X(), coords.Y() + 1); // S
231 neighbor[3] = Vector<int>(coords.X() - 1, coords.Y()); // W
233 for (int i(0); i < 4; ++i) {
234 for (std::vector<Entity *>::iterator e(entities.begin()), end(entities.end()); e != end; ++e) {
235 if ((*e)->Hostile() && map->TileCoordinates((*e)->Position()) == neighbor[i]) {
236 // TODO: check for turn advantage, see #26
237 // TODO: other transition
238 BattleState *battleState(new BattleState(game, map->BattleBackgroundAt((*e)->Position()), (*e)->PartyLayout()));
239 for (int i(0); i < 4; ++i) {
240 if (game->state->party[i]) {
241 battleState->AddHero(*game->state->party[i]);
244 for (battle::Monster *monster((*e)->MonstersBegin()); monster != (*e)->MonstersEnd(); ++monster) {
245 battleState->AddMonster(*monster);
248 ColorFade *fadeIn(new ColorFade(this, 0, 500, true));
249 fadeIn->SetLeadInTime(500);
250 ColorFade *fadeOut(new ColorFade(this, 0, 500));
251 fadeOut->SetLeadOutTime(500);
253 ctrl->PushState(fadeIn);
254 ctrl->PushState(battleState);
255 ctrl->PushState(fadeOut);
256 // TODO: move entity erase to happen after the transition or battle
259 // needed information here:
260 // - battle background (from tile/area/map)
261 // - monsters + layout (from entity)
268 bool MapState::CheckTrigger() {
269 Trigger *trigger(map->TriggerAt(Vector<int>(controlled->Position())));
271 // TODO: run trigger script
273 ctrl->PushState(new ColorFade(this, 0, 500, true));
274 ctrl->PushState(new TransitionState(this, trigger->map, trigger->target));
275 ColorFade *fadeOut(new ColorFade(this, 0, 500, false));
276 fadeOut->SetLeadOutTime(500);
277 ctrl->PushState(fadeOut);
284 void MapState::OnMove(bool realMove) {
285 // TODO: evaluate monster movements
287 UpdateFollower(*controlled);
289 StopFollowers(*controlled);
293 void MapState::UpdateFollower(Entity &e) {
294 if (!e.Follower()) return;
296 Entity &f(*e.Follower());
299 Vector<int> coords(map->TileCoordinates(e.Position()));
300 Vector<int> fCoords(map->TileCoordinates(f.Position()));
301 Vector<int> direction(coords - fCoords);
303 if (direction.Y() < 0) {
304 f.SetOrientation(Entity::ORIENTATION_NORTH);
305 f.SetSpeed(walkingSpeed);
306 f.StartAnimation(*this);
307 } else if (direction.X() > 0) {
308 f.SetOrientation(Entity::ORIENTATION_EAST);
309 f.SetSpeed(walkingSpeed);
310 f.StartAnimation(*this);
311 } else if (direction.Y() > 0) {
312 f.SetOrientation(Entity::ORIENTATION_SOUTH);
313 f.SetSpeed(walkingSpeed);
314 f.StartAnimation(*this);
315 } else if (direction.X() < 0) {
316 f.SetOrientation(Entity::ORIENTATION_WEST);
317 f.SetSpeed(walkingSpeed);
318 f.StartAnimation(*this);
325 void MapState::StopFollowers(Entity &e) {
326 for (Entity *f(e.Follower()); f; f = f->Follower()) {
333 void MapState::Transition(Map *newMap, const Vector<int> &coordinates) {
335 Vector<int> position(coordinates * map->Tileset()->Size());
336 for (Entity *e(controlled); e; e = e->Follower()) {
337 e->Position() = position;
338 e->SetOrientation(controlled->GetOrientation());
344 void MapState::UnloadMap() {
348 void MapState::LoadMap(Map *m) {
350 entities.insert(entities.end(), m->EntitiesBegin(), m->EntitiesEnd());
351 for (Entity *e(controlled); e; e = e->Follower()) {
352 entities.push_back(e);
357 void MapState::Render(SDL_Surface *screen) {
358 SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
360 Vector<int> offset(camera.CalculateOffset());
361 map->Render(screen, offset);
364 map->RenderDebug(screen, offset);
367 std::sort(entities.begin(), entities.end(), ZCompare);
368 for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
369 (*i)->Render(screen, offset);
374 bool MapState::ZCompare(const Entity *lhs, const Entity *rhs) {
375 return lhs->Position().Y() < rhs->Position().Y();