]> git.localhorst.tv Git - l2e.git/blob - src/map/MapState.cpp
350a1f48f8be2813585fef2fbc8233b5f4f06000
[l2e.git] / src / map / MapState.cpp
1 /*
2  * MapState.cpp
3  *
4  *  Created on: Sep 29, 2012
5  *      Author: holy
6  */
7
8 #include "MapState.h"
9
10 #include "Map.h"
11 #include "Tile.h"
12 #include "../app/Application.h"
13 #include "../app/Input.h"
14
15 #include <algorithm>
16
17 using app::Application;
18 using app::Input;
19 using geometry::Vector;
20
21 namespace map {
22
23 MapState::MapState(Map *map)
24 : map(map)
25 , controlled(0)
26 , tempTarget(20, 20)
27 , camera(100, 100, &tempTarget)
28 , walkingSpeed(64)
29 , nextDirection(-1)
30 , afterLock(false)
31 , debug(false) {
32
33 }
34
35
36 void MapState::EnterState(Application &ctrl, SDL_Surface *screen) {
37         camera.Resize(screen->w, screen->h);
38 }
39
40 void MapState::ExitState(Application &ctrl, SDL_Surface *screen) {
41
42 }
43
44 void MapState::ResumeState(Application &ctrl, SDL_Surface *screen) {
45         camera.Resize(screen->w, screen->h);
46 }
47
48 void MapState::PauseState(Application &ctrl, SDL_Surface *screen) {
49
50 }
51
52 void MapState::Resize(int width, int height) {
53         camera.Resize(width, height);
54 }
55
56
57 void MapState::HandleEvents(const Input &input) {
58         if (!controlled) return;
59
60         if (input.IsDown(Input::PAD_UP)) {
61                 nextDirection = Entity::ORIENTATION_NORTH;
62         } else if (input.IsDown(Input::PAD_RIGHT)) {
63                 nextDirection = Entity::ORIENTATION_EAST;
64         } else if (input.IsDown(Input::PAD_DOWN)) {
65                 nextDirection = Entity::ORIENTATION_SOUTH;
66         } else if (input.IsDown(Input::PAD_LEFT)) {
67                 nextDirection = Entity::ORIENTATION_WEST;
68         } else {
69                 nextDirection = -1;
70         }
71
72         if (input.JustPressed(Input::DEBUG_1)) {
73                 debug = !debug;
74         }
75 }
76
77 void MapState::UpdateWorld(float deltaT) {
78         if (controlled && controlled->TileLock(map->Tileset()->Size())) {
79                 OnTileLock();
80         }
81         for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
82                 (*i)->Update(deltaT);
83         }
84 }
85
86 void MapState::OnTileLock() {
87         if (moveTimer.Running() && !moveTimer.JustHit()) return;
88
89         Vector<int> nowLock(controlled->Position());
90         if (nowLock != lastLock) {
91                 OnGridLock();
92                 afterLock = true;
93                 moveTimer.Clear();
94         } else if (moveTimer.JustHit()) {
95                 OnGridLock();
96                 afterLock = true;
97         }
98
99         // TODO: halt all activity if lock caused a state/map transition
100
101         if (nextDirection >= 0) {
102                 bool blocked(CheckBlocking());
103                 if (afterLock) {
104                         OnMove(!blocked);
105                         afterLock = false;
106                 }
107                 controlled->SetOrientation(Entity::Orientation(nextDirection));
108                 if (!blocked) {
109                         controlled->SetSpeed(walkingSpeed);
110                         moveTimer.Clear();
111                 } else {
112                         controlled->SetSpeed(0.0f);
113                         StopFollowers(*controlled);
114                         if (!moveTimer.Running()) {
115                                 int tileSize((controlled->GetOrientation() % 2) ? map->Tileset()->Width() : map->Tileset()->Height());
116                                 moveTimer = PhysicsTimers().StartInterval(tileSize/walkingSpeed);
117                         }
118                 }
119                 if (!controlled->AnimationRunning()) {
120                         controlled->StartAnimation(*this);
121                 }
122         } else {
123                 controlled->SetSpeed(0.0f);
124                 StopFollowers(*controlled);
125                 controlled->StopAnimation();
126                 moveTimer.Clear();
127         }
128
129         lastLock = nowLock;
130 }
131
132 bool MapState::CheckBlocking() const {
133         const Tile &tile(map->TileAt(controlled->Position()));
134         Vector<int> nextPosition;
135         switch (nextDirection) {
136                 case Entity::ORIENTATION_NORTH:
137                         if (tile.BlocksNorth()) {
138                                 return true;
139                         } else {
140                                 nextPosition = Vector<int>(
141                                                 controlled->Position().X(),
142                                                 controlled->Position().Y() - map->Tileset()->Height());
143                         }
144                         break;
145                 case Entity::ORIENTATION_EAST:
146                         if (tile.BlocksEast()) {
147                                 return true;
148                         } else {
149                                 nextPosition = Vector<int>(
150                                                 controlled->Position().X() + map->Tileset()->Width(),
151                                                 controlled->Position().Y());
152                         }
153                         break;
154                 case Entity::ORIENTATION_SOUTH:
155                         if (tile.BlocksSouth()) {
156                                 return true;
157                         } else {
158                                 nextPosition = Vector<int>(
159                                                 controlled->Position().X(),
160                                                 controlled->Position().Y() + map->Tileset()->Height());
161                         }
162                         break;
163                 case Entity::ORIENTATION_WEST:
164                         if (tile.BlocksWest()) {
165                                 return true;
166                         } else {
167                                 nextPosition = Vector<int>(
168                                                 controlled->Position().X() - map->Tileset()->Width(),
169                                                 controlled->Position().Y());
170                         }
171                         break;
172                 default:
173                         return false;
174         }
175         Vector<int> nextTileCoords(map->TileCoordinates(nextPosition));
176         for (std::vector<Entity *>::const_iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
177                 const Entity &e(**i);
178                 if (map->TileCoordinates(e.Position()) == nextTileCoords && e.Blocking()) {
179                         return true;
180                 }
181         }
182         return false;
183 }
184
185 void MapState::OnGridLock() {
186         LockEntities();
187         CheckMonster();
188         CheckTrigger();
189 }
190
191 void MapState::LockEntities() {
192         for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
193                 if (*i == controlled) {
194                         // don't lock player
195                         continue;
196                 }
197                 (*i)->Position().Lock(map->Tileset()->Size());
198         }
199 }
200
201 void MapState::CheckMonster() {
202         Vector<int> coords(map->TileCoordinates(controlled->Position()));
203         Vector<int> neighbor[4];
204         neighbor[0] = Vector<int>(coords.X(), coords.Y() - 1); // N
205         neighbor[1] = Vector<int>(coords.X() + 1, coords.Y()); // E
206         neighbor[2] = Vector<int>(coords.X(), coords.Y() + 1); // S
207         neighbor[3] = Vector<int>(coords.X() - 1, coords.Y()); // W
208
209         for (int i(0); i < 4; ++i) {
210                 for (std::vector<Entity *>::iterator e(entities.begin()), end(entities.end()); e != end; ++e) {
211                         if ((*e)->Hostile() && map->TileCoordinates((*e)->Position()) == neighbor[i]) {
212                                 // TODO: check for turn advantage, see #26
213                                 // TODO: remove entity, push battle state and transition and halt all other activity
214                                 // needed information here:
215                                 //  - battle background (from tile?)
216                                 //  - monsters + layout (from entity)
217                                 //  - battle resources (from global resources)
218                         }
219                 }
220         }
221 }
222
223 void MapState::CheckTrigger() {
224         Trigger *trigger(map->TriggerAt(Vector<int>(controlled->Position())));
225         if (trigger) {
226                 // TODO: run trigger
227         }
228
229 }
230
231 void MapState::OnMove(bool realMove) {
232         // TODO: evaluate monster movements
233         if (realMove) {
234                 UpdateFollower(*controlled);
235         } else {
236                 StopFollowers(*controlled);
237         }
238 }
239
240 void MapState::UpdateFollower(Entity &e) {
241         if (!e.Follower()) return;
242
243         Entity &f(*e.Follower());
244         UpdateFollower(f);
245
246         Vector<int> coords(map->TileCoordinates(e.Position()));
247         Vector<int> fCoords(map->TileCoordinates(f.Position()));
248         Vector<int> direction(coords - fCoords);
249
250         if (direction.Y() < 0) {
251                 f.SetOrientation(Entity::ORIENTATION_NORTH);
252                 f.SetSpeed(walkingSpeed);
253                 f.StartAnimation(*this);
254         } else if (direction.X() > 0) {
255                 f.SetOrientation(Entity::ORIENTATION_EAST);
256                 f.SetSpeed(walkingSpeed);
257                 f.StartAnimation(*this);
258         } else if (direction.Y() > 0) {
259                 f.SetOrientation(Entity::ORIENTATION_SOUTH);
260                 f.SetSpeed(walkingSpeed);
261                 f.StartAnimation(*this);
262         } else if (direction.X() < 0) {
263                 f.SetOrientation(Entity::ORIENTATION_WEST);
264                 f.SetSpeed(walkingSpeed);
265                 f.StartAnimation(*this);
266         } else {
267                 f.SetSpeed(0.0f);
268                 f.StopAnimation();
269         }
270 }
271
272 void MapState::StopFollowers(Entity &e) {
273         for (Entity *f(e.Follower()); f; f = f->Follower()) {
274                 f->SetSpeed(0.0f);
275                 f->StopAnimation();
276         }
277 }
278
279
280 void MapState::Render(SDL_Surface *screen) {
281         SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
282
283         Vector<int> offset(camera.CalculateOffset());
284         map->Render(screen, offset);
285
286         if (debug) {
287                 map->RenderDebug(screen, offset);
288         }
289
290         std::sort(entities.begin(), entities.end(), ZCompare);
291         for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
292                 (*i)->Render(screen, offset);
293         }
294 }
295
296
297 bool MapState::ZCompare(const Entity *lhs, const Entity *rhs) {
298         return lhs->Position().Y() < rhs->Position().Y();
299 }
300
301 }