]> git.localhorst.tv Git - l2e.git/blob - src/map/MapState.cpp
don't lock player character onto its tile
[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
32 }
33
34
35 void MapState::EnterState(Application &ctrl, SDL_Surface *screen) {
36         camera.Resize(screen->w, screen->h);
37 }
38
39 void MapState::ExitState(Application &ctrl, SDL_Surface *screen) {
40
41 }
42
43 void MapState::ResumeState(Application &ctrl, SDL_Surface *screen) {
44         camera.Resize(screen->w, screen->h);
45 }
46
47 void MapState::PauseState(Application &ctrl, SDL_Surface *screen) {
48
49 }
50
51 void MapState::Resize(int width, int height) {
52         camera.Resize(width, height);
53 }
54
55
56 void MapState::HandleEvents(const Input &input) {
57         if (!controlled) return;
58
59         if (input.IsDown(Input::PAD_UP)) {
60                 nextDirection = Entity::ORIENTATION_NORTH;
61         } else if (input.IsDown(Input::PAD_RIGHT)) {
62                 nextDirection = Entity::ORIENTATION_EAST;
63         } else if (input.IsDown(Input::PAD_DOWN)) {
64                 nextDirection = Entity::ORIENTATION_SOUTH;
65         } else if (input.IsDown(Input::PAD_LEFT)) {
66                 nextDirection = Entity::ORIENTATION_WEST;
67         } else {
68                 nextDirection = -1;
69         }
70 }
71
72 void MapState::UpdateWorld(float deltaT) {
73         if (controlled && controlled->TileLock(map->Tileset()->Size())) {
74                 OnTileLock();
75         }
76         for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
77                 (*i)->Update(deltaT);
78         }
79 }
80
81 void MapState::OnTileLock() {
82         if (moveTimer.Running() && !moveTimer.JustHit()) return;
83
84         Vector<int> nowLock(controlled->Position());
85         if (nowLock != lastLock) {
86                 OnGridLock();
87                 afterLock = true;
88                 moveTimer.Clear();
89         } else if (moveTimer.JustHit()) {
90                 OnGridLock();
91                 afterLock = true;
92         }
93
94         // TODO: halt all activity if lock caused a state/map transition
95
96         if (nextDirection >= 0) {
97                 const Tile &tile(map->TileAt(controlled->Position()));
98                 bool blocked(false);
99                 switch (nextDirection) {
100                         case Entity::ORIENTATION_NORTH:
101                                 blocked = tile.BlocksNorth();
102                                 break;
103                         case Entity::ORIENTATION_EAST:
104                                 blocked = tile.BlocksEast();
105                                 break;
106                         case Entity::ORIENTATION_SOUTH:
107                                 blocked = tile.BlocksSouth();
108                                 break;
109                         case Entity::ORIENTATION_WEST:
110                                 blocked = tile.BlocksWest();
111                                 break;
112                 }
113                 if (afterLock) {
114                         OnMove(!blocked);
115                         afterLock = false;
116                 }
117                 controlled->SetOrientation(Entity::Orientation(nextDirection));
118                 if (!blocked) {
119                         controlled->SetSpeed(walkingSpeed);
120                         moveTimer.Clear();
121                 } else {
122                         controlled->SetSpeed(0.0f);
123                         StopFollowers(*controlled);
124                         if (!moveTimer.Running()) {
125                                 int tileSize((controlled->GetOrientation() % 2) ? map->Tileset()->Width() : map->Tileset()->Height());
126                                 moveTimer = PhysicsTimers().StartInterval(tileSize/walkingSpeed);
127                         }
128                 }
129                 if (!controlled->AnimationRunning()) {
130                         controlled->StartAnimation(*this);
131                 }
132         } else {
133                 controlled->SetSpeed(0.0f);
134                 StopFollowers(*controlled);
135                 controlled->StopAnimation();
136                 moveTimer.Clear();
137         }
138
139         lastLock = nowLock;
140 }
141
142 void MapState::OnGridLock() {
143         LockEntities();
144         Trigger *trigger(map->TriggerAt(Vector<int>(controlled->Position())));
145         if (trigger) {
146                 // TODO: run trigger
147         }
148         // TODO: check for adjacent monsters
149         // TODO: force all entities into their grid positions?
150 }
151
152 void MapState::LockEntities() {
153         for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
154                 if (*i == controlled) {
155                         // don't lock player
156                         continue;
157                 }
158                 (*i)->Position().Lock(map->Tileset()->Size());
159         }
160 }
161
162 void MapState::OnMove(bool realMove) {
163         // TODO: evaluate monster movements
164         if (realMove) {
165                 UpdateFollower(*controlled);
166         } else {
167                 StopFollowers(*controlled);
168         }
169 }
170
171 void MapState::UpdateFollower(Entity &e) {
172         if (!e.Follower()) return;
173
174         Entity &f(*e.Follower());
175         UpdateFollower(f);
176
177         Vector<int> coords(map->TileCoordinates(e.Position()));
178         Vector<int> fCoords(map->TileCoordinates(f.Position()));
179         Vector<int> direction(coords - fCoords);
180
181         if (direction.Y() < 0) {
182                 f.SetOrientation(Entity::ORIENTATION_NORTH);
183                 f.SetSpeed(walkingSpeed);
184                 f.StartAnimation(*this);
185         } else if (direction.X() > 0) {
186                 f.SetOrientation(Entity::ORIENTATION_EAST);
187                 f.SetSpeed(walkingSpeed);
188                 f.StartAnimation(*this);
189         } else if (direction.Y() > 0) {
190                 f.SetOrientation(Entity::ORIENTATION_SOUTH);
191                 f.SetSpeed(walkingSpeed);
192                 f.StartAnimation(*this);
193         } else if (direction.X() < 0) {
194                 f.SetOrientation(Entity::ORIENTATION_WEST);
195                 f.SetSpeed(walkingSpeed);
196                 f.StartAnimation(*this);
197         } else {
198                 f.SetSpeed(0.0f);
199                 f.StopAnimation();
200         }
201 }
202
203 void MapState::StopFollowers(Entity &e) {
204         for (Entity *f(e.Follower()); f; f = f->Follower()) {
205                 f->SetSpeed(0.0f);
206                 f->StopAnimation();
207         }
208 }
209
210
211 void MapState::Render(SDL_Surface *screen) {
212         SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
213
214         Vector<int> offset(camera.CalculateOffset());
215         map->Render(screen, offset);
216
217         std::sort(entities.begin(), entities.end(), ZCompare);
218         for (std::vector<Entity *>::iterator i(entities.begin()), end(entities.end()); i != end; ++i) {
219                 (*i)->Render(screen, offset);
220         }
221 }
222
223
224 bool MapState::ZCompare(const Entity *lhs, const Entity *rhs) {
225         return lhs->Position().Y() < rhs->Position().Y();
226 }
227
228 }