diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/game.cpp | 885 | ||||
-rw-r--r-- | src/game.h | 56 | ||||
-rw-r--r-- | src/main.cpp | 920 | ||||
-rw-r--r-- | src/renderer.cpp | 2 | ||||
-rw-r--r-- | src/renderer.h | 2 | ||||
-rw-r--r-- | src/timer.h | 2 |
7 files changed, 942 insertions, 926 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 360d4a2..5f07e97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -33,6 +33,7 @@ add_executable(Ether | |||
33 | src/renderer.cpp | 33 | src/renderer.cpp |
34 | src/muxer.cpp | 34 | src/muxer.cpp |
35 | src/animation.cpp | 35 | src/animation.cpp |
36 | src/game.cpp | ||
36 | vendor/fov.c | 37 | vendor/fov.c |
37 | ) | 38 | ) |
38 | 39 | ||
diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..8de9b7b --- /dev/null +++ b/src/game.cpp | |||
@@ -0,0 +1,885 @@ | |||
1 | #include "game.h" | ||
2 | #include <vector> | ||
3 | #include <fov.h> | ||
4 | #include <iostream> | ||
5 | #include "util.h" | ||
6 | #include "renderer.h" | ||
7 | |||
8 | Game::Game(std::mt19937& rng, Muxer& muxer) : | ||
9 | rng(rng), | ||
10 | muxer(muxer), | ||
11 | map( | ||
12 | -INIT_ZOOM * ZOOM_X_FACTOR / 2, | ||
13 | -INIT_ZOOM * ZOOM_Y_FACTOR / 2, | ||
14 | INIT_ZOOM * ZOOM_X_FACTOR, | ||
15 | INIT_ZOOM * ZOOM_Y_FACTOR) | ||
16 | { | ||
17 | losePopLampTimer.accumulate(losePopLampTimer.getDt()); | ||
18 | |||
19 | for (MapData& md : map.data()) | ||
20 | { | ||
21 | if (std::bernoulli_distribution(0.5)(rng)) | ||
22 | { | ||
23 | md.tile = Tile::Wall; | ||
24 | } | ||
25 | } | ||
26 | |||
27 | tick(); | ||
28 | tick(); | ||
29 | |||
30 | for (int y = -1; y <= 1; y++) | ||
31 | { | ||
32 | for (int x = -1; x <= 1; x++) | ||
33 | { | ||
34 | map.at(x,y).tile = Tile::Floor; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | tick(); | ||
39 | } | ||
40 | |||
41 | inline bool isTileSetOrNotLit(const Map<MapData>& map, int x, int y) | ||
42 | { | ||
43 | return (map.inBounds(x, y) && (map.at(x,y).tile == Tile::Wall || !map.at(x,y).lit)); | ||
44 | } | ||
45 | |||
46 | inline bool isTileSet(const Map<MapData>& map, int x, int y, Tile val = Tile::Wall) | ||
47 | { | ||
48 | return (map.inBounds(x, y) && map.at(x,y).tile == val); | ||
49 | } | ||
50 | |||
51 | inline void incrementIfSet(const Game& game, int& count, int x, int y, Tile val = Tile::Wall) | ||
52 | { | ||
53 | if (isTileSet(game.map, x, y, val)) | ||
54 | { | ||
55 | count++; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | inline int getZoomLevel(const Game& game) { | ||
60 | return game.curZoom - INIT_ZOOM; | ||
61 | } | ||
62 | |||
63 | void Game::tick( | ||
64 | int x1, | ||
65 | int y1, | ||
66 | int x2, | ||
67 | int y2, | ||
68 | bool invert, | ||
69 | bool onlyDark) | ||
70 | { | ||
71 | Map<MapData> temp(map); | ||
72 | |||
73 | for (int y = map.getTop(); y < map.getBottom(); y++) | ||
74 | { | ||
75 | for (int x = map.getLeft(); x < map.getRight(); x++) | ||
76 | { | ||
77 | if (invert == (x >= x1 && x < x2 && y >= y1 && y < y2)) | ||
78 | { | ||
79 | continue; | ||
80 | } | ||
81 | |||
82 | if (onlyDark && map.at(x,y).lit) | ||
83 | { | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | if (map.at(x,y).tile == Tile::Lamp) | ||
88 | { | ||
89 | continue; | ||
90 | } | ||
91 | |||
92 | int count = 0; | ||
93 | |||
94 | incrementIfSet(*this, count, x-1, y-1); | ||
95 | incrementIfSet(*this, count, x-1, y ); | ||
96 | incrementIfSet(*this, count, x-1, y+1); | ||
97 | incrementIfSet(*this, count, x , y-1); | ||
98 | incrementIfSet(*this, count, x , y ); | ||
99 | incrementIfSet(*this, count, x , y+1); | ||
100 | incrementIfSet(*this, count, x+1, y-1); | ||
101 | incrementIfSet(*this, count, x+1, y ); | ||
102 | incrementIfSet(*this, count, x+1, y+1); | ||
103 | |||
104 | if (count >= 5) | ||
105 | { | ||
106 | temp.at(x,y).tile = Tile::Wall; | ||
107 | } else { | ||
108 | temp.at(x,y).tile = Tile::Floor; | ||
109 | } | ||
110 | |||
111 | if (temp.at(x,y).tile != map.at(x,y).tile) { | ||
112 | temp.at(x,y).dirtyRender = true; | ||
113 | dirtyRender = true; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | map = std::move(temp); | ||
119 | } | ||
120 | |||
121 | void Game::tick(bool onlyDark) | ||
122 | { | ||
123 | tick( | ||
124 | map.getLeft(), | ||
125 | map.getTop(), | ||
126 | map.getRight(), | ||
127 | map.getBottom(), | ||
128 | false, | ||
129 | onlyDark); | ||
130 | } | ||
131 | |||
132 | bool Game::movePlayer(int x, int y) | ||
133 | { | ||
134 | if (x >= curBoundX && | ||
135 | y >= curBoundY && | ||
136 | x < curBoundX + curZoom * ZOOM_X_FACTOR && | ||
137 | y < curBoundY + curZoom * ZOOM_Y_FACTOR && | ||
138 | map.at(x,y).tile == Tile::Floor) | ||
139 | { | ||
140 | if (map.at(player_x, player_y).tile == Tile::Floor) | ||
141 | { | ||
142 | map.at(player_x, player_y).tile = Tile::Dust; | ||
143 | map.at(player_x, player_y).dustLife = 1; | ||
144 | numDust++; | ||
145 | } | ||
146 | |||
147 | player_oldx = player_x; | ||
148 | player_oldy = player_y; | ||
149 | player_x = x; | ||
150 | player_y = y; | ||
151 | muxer.setPlayerLoc(x, y); | ||
152 | moving = true; | ||
153 | moveProgress.start(66); | ||
154 | dirtyLighting = true; | ||
155 | |||
156 | return true; | ||
157 | } else { | ||
158 | if (!alreadyBumped) { | ||
159 | muxer.playSoundAtPosition("bump", x, y); | ||
160 | alreadyBumped = true; | ||
161 | bumpCooldown.reset(); | ||
162 | } | ||
163 | |||
164 | return false; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void Game::recalculateLighting() | ||
169 | { | ||
170 | litSpots = 0; | ||
171 | dirtyRender = true; | ||
172 | |||
173 | for (MapData& md : map.data()) | ||
174 | { | ||
175 | md.wasLit = md.lit; | ||
176 | md.lit = false; | ||
177 | md.litTiles.clear(); | ||
178 | |||
179 | if (md.tile == Tile::Wall) { | ||
180 | md.dirtyRender = true; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | fov_settings_type fov; | ||
185 | fov_settings_init(&fov); | ||
186 | |||
187 | fov_settings_set_opacity_test_function( | ||
188 | &fov, | ||
189 | [] (void* data, int x, int y) { | ||
190 | Game& game = *static_cast<Game*>(data); | ||
191 | |||
192 | return game.map.inBounds(x,y) && game.map.at(x,y).tile == Tile::Wall; | ||
193 | }); | ||
194 | |||
195 | fov_settings_set_apply_lighting_function( | ||
196 | &fov, | ||
197 | [] (void* data, int x, int y, int dx, int dy, void* source) { | ||
198 | Game& game = *static_cast<Game*>(data); | ||
199 | |||
200 | if (game.map.inBounds(x, y)) | ||
201 | { | ||
202 | MapData& sourceData = *static_cast<MapData*>(source); | ||
203 | double lightRadius = static_cast<double>(sourceData.lightRadius); | ||
204 | |||
205 | if (!game.map.at(x,y).lit) | ||
206 | { | ||
207 | game.litSpots++; | ||
208 | } | ||
209 | |||
210 | game.map.at(x,y).lit = true; | ||
211 | |||
212 | sourceData.litTiles.emplace(x,y); | ||
213 | } | ||
214 | }); | ||
215 | |||
216 | for (int y = map.getTop(); y < map.getBottom(); y++) | ||
217 | { | ||
218 | for (int x = map.getLeft(); x < map.getRight(); x++) | ||
219 | { | ||
220 | Source ls = Source::None; | ||
221 | int lightRadius; | ||
222 | |||
223 | if (renderPlayer && player_x == x && player_y == y) | ||
224 | { | ||
225 | ls = Source::Player; | ||
226 | lightRadius = RADIUS; | ||
227 | } else if (map.at(x,y).tile == Tile::Dust) | ||
228 | { | ||
229 | ls = Source::Dust; | ||
230 | lightRadius = 2; | ||
231 | } else if (map.at(x,y).tile == Tile::Lamp) | ||
232 | { | ||
233 | ls = Source::Lamp; | ||
234 | lightRadius = RADIUS; | ||
235 | } | ||
236 | |||
237 | map.at(x,y).lightType = ls; | ||
238 | |||
239 | if (ls != Source::None) | ||
240 | { | ||
241 | map.at(x,y).lightRadius = lightRadius; | ||
242 | map.at(x,y).litTiles.emplace(x,y); | ||
243 | |||
244 | fov_circle( | ||
245 | &fov, | ||
246 | static_cast<void*>(this), | ||
247 | static_cast<void*>(&map.at(x,y)), | ||
248 | x, | ||
249 | y, | ||
250 | lightRadius); | ||
251 | |||
252 | map.at(x,y).lit = true; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | dirtyLighting = false; | ||
258 | } | ||
259 | |||
260 | void Game::recalculateRender() { | ||
261 | for (int y = map.getTop(); y < map.getBottom(); y++) | ||
262 | { | ||
263 | for (int x = map.getLeft(); x < map.getRight(); x++) | ||
264 | { | ||
265 | if (map.at(x,y).dirtyRender) { | ||
266 | map.at(x,y).dirtyRender = false; | ||
267 | |||
268 | if (map.at(x,y).tile == Tile::Floor) { | ||
269 | if (std::bernoulli_distribution(0.05)(rng)) { | ||
270 | static const std::vector<int> furnishings { | ||
271 | TilesetIndex(20, 16), | ||
272 | TilesetIndex(21, 2), | ||
273 | TilesetIndex(22, 2), | ||
274 | TilesetIndex(21, 3), | ||
275 | TilesetIndex(22, 3)}; | ||
276 | map.at(x,y).renderId = furnishings.at(std::uniform_int_distribution<int>(0, furnishings.size()-1)(rng)); | ||
277 | } else { | ||
278 | map.at(x,y).renderId = -1; | ||
279 | } | ||
280 | } else if (map.at(x,y).tile == Tile::Wall) { | ||
281 | static bool initWalls = false; | ||
282 | static std::vector<int> wallRenders(256, TilesetIndex(0, 0)); | ||
283 | if (!initWalls) { | ||
284 | initWalls = true; | ||
285 | |||
286 | // Start in top left and go clockwise. | ||
287 | wallRenders[0b00011100] = TilesetIndex(16, 14); | ||
288 | wallRenders[0b00111100] = TilesetIndex(16, 14); | ||
289 | wallRenders[0b00011110] = TilesetIndex(16, 14); | ||
290 | wallRenders[0b00111110] = TilesetIndex(16, 14); | ||
291 | |||
292 | wallRenders[0b00011111] = TilesetIndex(17, 14); | ||
293 | wallRenders[0b10011111] = TilesetIndex(17, 14); | ||
294 | wallRenders[0b00111111] = TilesetIndex(17, 14); | ||
295 | wallRenders[0b10111111] = TilesetIndex(17, 14); | ||
296 | |||
297 | wallRenders[0b00000111] = TilesetIndex(18, 14); | ||
298 | wallRenders[0b00001111] = TilesetIndex(18, 14); | ||
299 | wallRenders[0b10000111] = TilesetIndex(18, 14); | ||
300 | wallRenders[0b10001111] = TilesetIndex(18, 14); | ||
301 | |||
302 | wallRenders[0b01111100] = TilesetIndex(16, 15); | ||
303 | wallRenders[0b11111100] = TilesetIndex(16, 15); | ||
304 | wallRenders[0b01111110] = TilesetIndex(16, 15); | ||
305 | wallRenders[0b11111110] = TilesetIndex(16, 15); | ||
306 | |||
307 | wallRenders[0b11000111] = TilesetIndex(18, 15); | ||
308 | wallRenders[0b11001111] = TilesetIndex(18, 15); | ||
309 | wallRenders[0b11100111] = TilesetIndex(18, 15); | ||
310 | wallRenders[0b11101111] = TilesetIndex(18, 15); | ||
311 | |||
312 | wallRenders[0b01110000] = TilesetIndex(16, 16); | ||
313 | wallRenders[0b01111000] = TilesetIndex(16, 16); | ||
314 | wallRenders[0b11110000] = TilesetIndex(16, 16); | ||
315 | wallRenders[0b11111000] = TilesetIndex(16, 16); | ||
316 | |||
317 | wallRenders[0b11110001] = TilesetIndex(17, 16); | ||
318 | wallRenders[0b11110011] = TilesetIndex(17, 16); | ||
319 | wallRenders[0b11111001] = TilesetIndex(17, 16); | ||
320 | wallRenders[0b11111011] = TilesetIndex(17, 16); | ||
321 | |||
322 | wallRenders[0b11000001] = TilesetIndex(18, 16); | ||
323 | wallRenders[0b11000011] = TilesetIndex(18, 16); | ||
324 | wallRenders[0b11100001] = TilesetIndex(18, 16); | ||
325 | wallRenders[0b11100011] = TilesetIndex(18, 16); | ||
326 | |||
327 | |||
328 | wallRenders[0b11110111] = TilesetIndex(21, 14); | ||
329 | wallRenders[0b11111101] = TilesetIndex(22, 14); | ||
330 | wallRenders[0b11011111] = TilesetIndex(21, 15); | ||
331 | wallRenders[0b01111111] = TilesetIndex(22, 15); | ||
332 | } | ||
333 | |||
334 | int renderDesc = 0; | ||
335 | if (isTileSetOrNotLit(map, x-1, y-1)) renderDesc |= (1 << 7); | ||
336 | if (isTileSetOrNotLit(map, x , y-1)) renderDesc |= (1 << 6); | ||
337 | if (isTileSetOrNotLit(map, x+1, y-1)) renderDesc |= (1 << 5); | ||
338 | if (isTileSetOrNotLit(map, x+1, y )) renderDesc |= (1 << 4); | ||
339 | if (isTileSetOrNotLit(map, x+1, y+1)) renderDesc |= (1 << 3); | ||
340 | if (isTileSetOrNotLit(map, x , y+1)) renderDesc |= (1 << 2); | ||
341 | if (isTileSetOrNotLit(map, x-1, y+1)) renderDesc |= (1 << 1); | ||
342 | if (isTileSetOrNotLit(map, x-1, y )) renderDesc |= (1 << 0); | ||
343 | |||
344 | map.at(x,y).renderId = wallRenders.at(renderDesc); | ||
345 | |||
346 | if (wallRenders.at(renderDesc) == 0 && renderDesc != 255) { | ||
347 | std::cout << renderDesc << std::endl; | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | |||
354 | dirtyRender = false; | ||
355 | } | ||
356 | |||
357 | bool Game::processKeys(const Input& keystate) | ||
358 | { | ||
359 | int px = player_x; | ||
360 | int py = player_y; | ||
361 | Direction dir = Direction::up; | ||
362 | |||
363 | if (keystate.up) | ||
364 | { | ||
365 | py--; | ||
366 | } | ||
367 | |||
368 | if (keystate.down) | ||
369 | { | ||
370 | py++; | ||
371 | dir = Direction::down; | ||
372 | } | ||
373 | |||
374 | if (keystate.left) | ||
375 | { | ||
376 | px--; | ||
377 | dir = Direction::left; | ||
378 | } | ||
379 | |||
380 | if (keystate.right) | ||
381 | { | ||
382 | px++; | ||
383 | dir = Direction::right; | ||
384 | } | ||
385 | |||
386 | if (!(player_x == px && player_y == py)) | ||
387 | { | ||
388 | playerAnim.setAnimation("walk"); | ||
389 | playerAnim.setDirection(dir); | ||
390 | |||
391 | bool succeeds = movePlayer(px, py); | ||
392 | if (!succeeds && px != player_x) { | ||
393 | succeeds = movePlayer(px, player_y); | ||
394 | } | ||
395 | if (!succeeds && py != player_y) { | ||
396 | succeeds = movePlayer(player_x, py); | ||
397 | } | ||
398 | return succeeds; | ||
399 | } else { | ||
400 | return false; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | void Game::kickUpDust(int x, int y, size_t chain) | ||
405 | { | ||
406 | Kickup dk; | ||
407 | dk.x = x; | ||
408 | dk.y = y; | ||
409 | dk.chain = chain; | ||
410 | dk.cur = 0; | ||
411 | dk.radius = RADIUS + (chain + 1) * (chain + 1); | ||
412 | dk.front.emplace(x, y); | ||
413 | dk.done.emplace(x, y); | ||
414 | |||
415 | kickups.push_back(dk); | ||
416 | } | ||
417 | |||
418 | void Game::popLamp(int x, int y, size_t chain) | ||
419 | { | ||
420 | muxer.playSoundAtPosition("pop", x, y); | ||
421 | |||
422 | if (map.at(x,y).tile == Tile::Lamp) | ||
423 | { | ||
424 | numLamps--; | ||
425 | } | ||
426 | |||
427 | map.at(x,y).tile = Tile::Dust; | ||
428 | map.at(x,y).dustLife = 2; | ||
429 | numDust++; | ||
430 | dirtyLighting = true; | ||
431 | |||
432 | kickUpDust(x, y, chain); | ||
433 | } | ||
434 | |||
435 | void Game::processKickup() | ||
436 | { | ||
437 | for (Kickup& kickup : kickups) | ||
438 | { | ||
439 | kickup.cur++; | ||
440 | |||
441 | std::set<coord> newFront; | ||
442 | for (const coord& xy : kickup.front) | ||
443 | { | ||
444 | auto processDir = [&] (int x, int y) { | ||
445 | coord c {x,y}; | ||
446 | |||
447 | if (map.inBounds(x,y) && | ||
448 | (map.at(x,y).tile == Tile::Floor || map.at(x,y).tile == Tile::Lamp) && | ||
449 | !kickup.done.count(c)) | ||
450 | { | ||
451 | newFront.insert(c); | ||
452 | kickup.done.insert(c); | ||
453 | |||
454 | if (map.at(x,y).tile == Tile::Floor) | ||
455 | { | ||
456 | map.at(x,y).tile = Tile::Dust; | ||
457 | map.at(x,y).dustLife = 2; | ||
458 | numDust++; | ||
459 | dirtyLighting = true; | ||
460 | } else if (map.at(x,y).tile == Tile::Lamp) | ||
461 | { | ||
462 | popLamp(x, y, kickup.chain + 1); | ||
463 | } | ||
464 | } | ||
465 | }; | ||
466 | |||
467 | processDir(std::get<0>(xy) - 1, std::get<1>(xy) ); | ||
468 | processDir(std::get<0>(xy) + 1, std::get<1>(xy) ); | ||
469 | processDir(std::get<0>(xy) , std::get<1>(xy) - 1); | ||
470 | processDir(std::get<0>(xy) , std::get<1>(xy) + 1); | ||
471 | |||
472 | if (std::bernoulli_distribution(0.5)(rng)) | ||
473 | { | ||
474 | processDir(std::get<0>(xy) - 1, std::get<1>(xy) - 1); | ||
475 | } | ||
476 | |||
477 | if (std::bernoulli_distribution(0.5)(rng)) | ||
478 | { | ||
479 | processDir(std::get<0>(xy) - 1, std::get<1>(xy) + 1); | ||
480 | } | ||
481 | |||
482 | if (std::bernoulli_distribution(0.5)(rng)) | ||
483 | { | ||
484 | processDir(std::get<0>(xy) + 1, std::get<1>(xy) - 1); | ||
485 | } | ||
486 | |||
487 | if (std::bernoulli_distribution(0.5)(rng)) | ||
488 | { | ||
489 | processDir(std::get<0>(xy) + 1, std::get<1>(xy) + 1); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | kickup.front.swap(newFront); | ||
494 | } | ||
495 | |||
496 | erase_if( | ||
497 | kickups, | ||
498 | [] (const Kickup& kickup) { | ||
499 | return kickup.cur == kickup.radius; | ||
500 | }); | ||
501 | } | ||
502 | |||
503 | void Game::growMap(size_t zoom) | ||
504 | { | ||
505 | int ol = map.getLeft(); | ||
506 | int ot = map.getTop(); | ||
507 | int ow = map.getWidth(); | ||
508 | int oh = map.getHeight(); | ||
509 | |||
510 | map.resize( | ||
511 | -zoom * ZOOM_X_FACTOR / 2, | ||
512 | -zoom * ZOOM_Y_FACTOR / 2, | ||
513 | zoom * ZOOM_X_FACTOR, | ||
514 | zoom * ZOOM_Y_FACTOR); | ||
515 | |||
516 | maxZoom = zoom; | ||
517 | |||
518 | for (int y = map.getTop(); y < map.getBottom(); y++) | ||
519 | { | ||
520 | for (int x = map.getLeft(); x < map.getRight(); x++) | ||
521 | { | ||
522 | if (!(x >= ol && x < (ol + ow) && y >= ot && y < (ot + oh))) | ||
523 | { | ||
524 | if (std::bernoulli_distribution(0.5)(rng)) | ||
525 | { | ||
526 | map.at(x,y).tile = Tile::Wall; | ||
527 | } | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | |||
532 | for (int i = 0; i < 3; i++) | ||
533 | { | ||
534 | tick(ol, ot, ol + ow, ot + oh, true); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | void Game::setZoom(size_t zoom) | ||
539 | { | ||
540 | if (zoom == curZoom) | ||
541 | { | ||
542 | return; | ||
543 | } | ||
544 | |||
545 | if (zoom > maxZoom) | ||
546 | { | ||
547 | growMap(zoom); | ||
548 | } | ||
549 | |||
550 | std::tie( | ||
551 | lastZoomLeft, | ||
552 | lastZoomTop, | ||
553 | lastZoomWidth, | ||
554 | lastZoomHeight) = | ||
555 | Renderer::calculateZoomRect(*this); | ||
556 | |||
557 | zoomProgress = 0; | ||
558 | zoomLength = std::abs(static_cast<long>(zoom - curZoom)) * TILE_WIDTH; | ||
559 | curZoom = zoom; | ||
560 | zooming = true; | ||
561 | |||
562 | curBoundX = player_x - zoom * ZOOM_X_FACTOR / 2; | ||
563 | if (curBoundX < map.getLeft()) | ||
564 | { | ||
565 | curBoundX = map.getLeft(); | ||
566 | } else if (curBoundX + zoom * ZOOM_X_FACTOR >= map.getRight()) | ||
567 | { | ||
568 | curBoundX = map.getRight() - zoom * ZOOM_X_FACTOR; | ||
569 | } | ||
570 | |||
571 | curBoundY = player_y - zoom * ZOOM_Y_FACTOR / 2; | ||
572 | if (curBoundY < map.getTop()) | ||
573 | { | ||
574 | curBoundY = map.getTop(); | ||
575 | } else if (curBoundY + zoom * ZOOM_Y_FACTOR >= map.getBottom()) | ||
576 | { | ||
577 | curBoundY = map.getBottom() - zoom * ZOOM_Y_FACTOR; | ||
578 | } | ||
579 | |||
580 | int zoomLevel = getZoomLevel(*this); | ||
581 | if (zoomLevel == 0) { | ||
582 | muxer.setMusicLevel(0); | ||
583 | } else if (zoomLevel < 3) { | ||
584 | muxer.setMusicLevel(1); | ||
585 | } else if (zoomLevel < 5) { | ||
586 | muxer.setMusicLevel(2); | ||
587 | } else if (zoomLevel < 7) { | ||
588 | muxer.setMusicLevel(3); | ||
589 | } else { | ||
590 | muxer.setMusicLevel(4); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | void Game::performDash() { | ||
595 | if (map.at(player_x, player_y).tile == Tile::Floor) { | ||
596 | std::vector<coord> freeSpaces; | ||
597 | |||
598 | auto addIfFree = [&] (int x, int y) { | ||
599 | if (map.inBounds(x,y) && map.at(x,y).tile == Tile::Floor) | ||
600 | { | ||
601 | freeSpaces.emplace_back(x, y); | ||
602 | } | ||
603 | }; | ||
604 | |||
605 | addIfFree(player_x - 1, player_y - 1); | ||
606 | addIfFree(player_x , player_y - 1); | ||
607 | addIfFree(player_x + 1, player_y - 1); | ||
608 | addIfFree(player_x - 1, player_y ); | ||
609 | addIfFree(player_x + 1, player_y ); | ||
610 | addIfFree(player_x - 1, player_y + 1); | ||
611 | addIfFree(player_x , player_y + 1); | ||
612 | addIfFree(player_x + 1, player_y + 1); | ||
613 | |||
614 | if (!freeSpaces.empty()) | ||
615 | { | ||
616 | map.at(player_x, player_y).tile = Tile::Lamp; | ||
617 | numLamps++; | ||
618 | dirtyLighting = true; | ||
619 | kickUpDust(player_x, player_y, 0); | ||
620 | muxer.playSoundAtPosition("drop", player_x, player_y); | ||
621 | |||
622 | if (firstInput) | ||
623 | { | ||
624 | for (int i = 0; i < 5; i++) | ||
625 | { | ||
626 | if (!processKeys(lastInput)) | ||
627 | { | ||
628 | std::uniform_int_distribution<int> freeDist(0, freeSpaces.size() - 1); | ||
629 | |||
630 | int freeIndex = freeDist(rng); | ||
631 | coord& moveTo = freeSpaces[freeIndex]; | ||
632 | |||
633 | movePlayer(std::get<0>(moveTo), std::get<1>(moveTo)); | ||
634 | } | ||
635 | |||
636 | tick( | ||
637 | player_x - (RADIUS - 1), | ||
638 | player_y - (RADIUS - 1), | ||
639 | player_x + RADIUS, | ||
640 | player_y + RADIUS); | ||
641 | } | ||
642 | } else { | ||
643 | std::uniform_int_distribution<int> freeDist(0, freeSpaces.size() - 1); | ||
644 | |||
645 | int freeIndex = freeDist(rng); | ||
646 | coord& moveTo = freeSpaces[freeIndex]; | ||
647 | |||
648 | movePlayer(std::get<0>(moveTo), std::get<1>(moveTo)); | ||
649 | } | ||
650 | |||
651 | //muxer.playSoundAtPosition("dash", player_x, player_y); | ||
652 | } | ||
653 | } | ||
654 | } | ||
655 | |||
656 | void Game::update(size_t frameTime) { | ||
657 | SDL_Event e; | ||
658 | |||
659 | while (SDL_PollEvent(&e)) | ||
660 | { | ||
661 | if (e.type == SDL_QUIT) | ||
662 | { | ||
663 | if (losing != LoseState::None) | ||
664 | { | ||
665 | quit = true; | ||
666 | } else { | ||
667 | losing = LoseState::PoppingLamps; | ||
668 | muxer.stopMusic(); | ||
669 | } | ||
670 | } else if (e.type == SDL_KEYDOWN) | ||
671 | { | ||
672 | switch (e.key.keysym.sym) | ||
673 | { | ||
674 | case SDLK_ESCAPE: | ||
675 | { | ||
676 | if (losing != LoseState::None) | ||
677 | { | ||
678 | quit = true; | ||
679 | } else { | ||
680 | losing = LoseState::PoppingLamps; | ||
681 | muxer.stopMusic(); | ||
682 | } | ||
683 | |||
684 | break; | ||
685 | } | ||
686 | |||
687 | case SDLK_SPACE: | ||
688 | { | ||
689 | if (losing == LoseState::None) | ||
690 | { | ||
691 | if (moving) { | ||
692 | queueDash = true; | ||
693 | } else { | ||
694 | performDash(); | ||
695 | } | ||
696 | } | ||
697 | |||
698 | break; | ||
699 | } | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | |||
704 | const Uint8* state = SDL_GetKeyboardState(NULL); | ||
705 | keystate.left = state[SDL_SCANCODE_LEFT]; | ||
706 | keystate.right = state[SDL_SCANCODE_RIGHT]; | ||
707 | keystate.up = state[SDL_SCANCODE_UP]; | ||
708 | keystate.down = state[SDL_SCANCODE_DOWN]; | ||
709 | |||
710 | bumpCooldown.accumulate(frameTime); | ||
711 | if (alreadyBumped && keystate != lastInput && bumpCooldown.step()) { | ||
712 | alreadyBumped = false; | ||
713 | } | ||
714 | |||
715 | if (queueDash && !moving) { | ||
716 | queueDash = false; | ||
717 | performDash(); | ||
718 | } | ||
719 | |||
720 | if (keystate.left || keystate.right || keystate.up || keystate.down) | ||
721 | { | ||
722 | firstInput = true; | ||
723 | lastInput = keystate; | ||
724 | } else if (losing == LoseState::None) { | ||
725 | playerAnim.setAnimation("still"); | ||
726 | } | ||
727 | |||
728 | dustTimer.accumulate(frameTime); | ||
729 | inputTimer.accumulate(frameTime); | ||
730 | |||
731 | while (dustTimer.step()) | ||
732 | { | ||
733 | numDust = 0; | ||
734 | |||
735 | for (MapData& md : map.data()) | ||
736 | { | ||
737 | if (md.tile == Tile::Dust) | ||
738 | { | ||
739 | md.dustLife--; | ||
740 | |||
741 | if (md.dustLife <= 0) | ||
742 | { | ||
743 | md.tile = Tile::Floor; | ||
744 | dirtyLighting = true; | ||
745 | } else { | ||
746 | numDust++; | ||
747 | } | ||
748 | } | ||
749 | } | ||
750 | |||
751 | processKickup(); | ||
752 | } | ||
753 | |||
754 | switch (losing) | ||
755 | { | ||
756 | case LoseState::None: | ||
757 | { | ||
758 | if (moving) { | ||
759 | moveProgress.tick(frameTime); | ||
760 | if (moveProgress.isComplete()) { | ||
761 | moving = false; | ||
762 | } | ||
763 | } | ||
764 | |||
765 | while (inputTimer.step()) | ||
766 | { | ||
767 | if (!moving) { | ||
768 | processKeys(keystate); | ||
769 | } | ||
770 | } | ||
771 | |||
772 | break; | ||
773 | } | ||
774 | |||
775 | case LoseState::PoppingLamps: | ||
776 | { | ||
777 | if (numLamps == 0) | ||
778 | { | ||
779 | if (numDust == 0) | ||
780 | { | ||
781 | losing = LoseState::PoppingPlayer; | ||
782 | } | ||
783 | } else { | ||
784 | losePopLampTimer.accumulate(frameTime); | ||
785 | |||
786 | while (losePopLampTimer.step()) | ||
787 | { | ||
788 | std::vector<std::tuple<int, int>> lamps; | ||
789 | |||
790 | for (int y = map.getTop(); y < map.getBottom(); y++) | ||
791 | { | ||
792 | for (int x = map.getLeft(); x < map.getRight(); x++) | ||
793 | { | ||
794 | if (map.at(x,y).tile == Tile::Lamp) | ||
795 | { | ||
796 | lamps.emplace_back(x, y); | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | |||
801 | std::uniform_int_distribution<int> lampDist(0, lamps.size() - 1); | ||
802 | std::tuple<int, int> popPos = lamps[lampDist(rng)]; | ||
803 | |||
804 | popLamp(std::get<0>(popPos), std::get<1>(popPos), 1); | ||
805 | } | ||
806 | } | ||
807 | |||
808 | break; | ||
809 | } | ||
810 | |||
811 | case LoseState::PoppingPlayer: | ||
812 | { | ||
813 | losePopPlayerTimer.accumulate(frameTime); | ||
814 | |||
815 | if (losePopPlayerTimer.step()) | ||
816 | { | ||
817 | popLamp(player_x, player_y, 10); | ||
818 | renderPlayer = false; | ||
819 | |||
820 | losing = LoseState::Outro; | ||
821 | } | ||
822 | |||
823 | break; | ||
824 | } | ||
825 | |||
826 | case LoseState::Outro: | ||
827 | { | ||
828 | if (numDust == 0) | ||
829 | { | ||
830 | quit = true; | ||
831 | } | ||
832 | |||
833 | break; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | if (dirtyLighting) | ||
838 | { | ||
839 | recalculateLighting(); | ||
840 | |||
841 | for (int y = map.getTop(); y < map.getBottom(); y++) | ||
842 | { | ||
843 | for (int x = map.getLeft(); x < map.getRight(); x++) | ||
844 | { | ||
845 | if (!map.at(x,y).lit && map.at(x,y).wasLit) | ||
846 | { | ||
847 | if (std::bernoulli_distribution(0.5)(rng)) | ||
848 | { | ||
849 | map.at(x,y).tile = Tile::Wall; | ||
850 | } else { | ||
851 | map.at(x,y).tile = Tile::Floor; | ||
852 | } | ||
853 | map.at(x,y).dirtyRender = true; | ||
854 | } | ||
855 | } | ||
856 | } | ||
857 | |||
858 | tick(true); | ||
859 | tick(true); | ||
860 | tick(true); | ||
861 | |||
862 | // TODO: better zoom algorithm | ||
863 | setZoom(litSpots / 1500 + INIT_ZOOM); | ||
864 | } | ||
865 | |||
866 | if (dirtyRender) { | ||
867 | recalculateRender(); | ||
868 | } | ||
869 | |||
870 | zoomTimer.accumulate(frameTime); | ||
871 | while (zoomTimer.step()) | ||
872 | { | ||
873 | if (zooming) | ||
874 | { | ||
875 | zoomProgress++; | ||
876 | |||
877 | if (zoomProgress == zoomLength) | ||
878 | { | ||
879 | zooming = false; | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | |||
884 | playerAnim.update(frameTime); | ||
885 | } | ||
diff --git a/src/game.h b/src/game.h index 9feb774..89b9eb2 100644 --- a/src/game.h +++ b/src/game.h | |||
@@ -87,18 +87,15 @@ struct MapData { | |||
87 | class Game { | 87 | class Game { |
88 | public: | 88 | public: |
89 | 89 | ||
90 | Game(std::mt19937& rng) : | 90 | Game(std::mt19937& rng, Muxer& muxer); |
91 | rng(rng), | 91 | |
92 | map( | 92 | void update(size_t dt); |
93 | -INIT_ZOOM * ZOOM_X_FACTOR / 2, | ||
94 | -INIT_ZOOM * ZOOM_Y_FACTOR / 2, | ||
95 | INIT_ZOOM * ZOOM_X_FACTOR, | ||
96 | INIT_ZOOM * ZOOM_Y_FACTOR) | ||
97 | { | ||
98 | } | ||
99 | 93 | ||
100 | std::mt19937& rng; | 94 | std::mt19937& rng; |
101 | Muxer muxer; | 95 | Muxer& muxer; |
96 | |||
97 | bool quit = false; | ||
98 | LoseState losing = LoseState::None; | ||
102 | 99 | ||
103 | Map<MapData> map; | 100 | Map<MapData> map; |
104 | std::list<Kickup> kickups; | 101 | std::list<Kickup> kickups; |
@@ -129,6 +126,7 @@ public: | |||
129 | int lastZoomWidth; | 126 | int lastZoomWidth; |
130 | int lastZoomHeight; | 127 | int lastZoomHeight; |
131 | 128 | ||
129 | Input keystate; | ||
132 | bool firstInput = false; | 130 | bool firstInput = false; |
133 | Input lastInput; | 131 | Input lastInput; |
134 | bool alreadyBumped = false; | 132 | bool alreadyBumped = false; |
@@ -137,6 +135,44 @@ public: | |||
137 | bool moving = false; | 135 | bool moving = false; |
138 | bool queueDash = false; | 136 | bool queueDash = false; |
139 | 137 | ||
138 | Timer dustTimer = {40}; | ||
139 | Timer inputTimer = {50}; | ||
140 | Timer losePopLampTimer = {800}; | ||
141 | Timer losePopPlayerTimer = {3000}; | ||
142 | Timer zoomTimer = {62}; | ||
143 | |||
144 | private: | ||
145 | |||
146 | void tick( | ||
147 | int x1, | ||
148 | int y1, | ||
149 | int x2, | ||
150 | int y2, | ||
151 | bool invert = false, | ||
152 | bool onlyDark = false); | ||
153 | |||
154 | void tick(bool onlyDark = false); | ||
155 | |||
156 | bool movePlayer(int x, int y); | ||
157 | |||
158 | void recalculateLighting(); | ||
159 | |||
160 | void recalculateRender(); | ||
161 | |||
162 | bool processKeys(const Input& keystate); | ||
163 | |||
164 | void kickUpDust(int x, int y, size_t chain); | ||
165 | |||
166 | void popLamp(int x, int y, size_t chain); | ||
167 | |||
168 | void processKickup(); | ||
169 | |||
170 | void growMap(size_t zoom); | ||
171 | |||
172 | void setZoom(size_t zoom); | ||
173 | |||
174 | void performDash(); | ||
175 | |||
140 | }; | 176 | }; |
141 | 177 | ||
142 | #endif /* end of include guard: GAME_H_7D2B65AE */ | 178 | #endif /* end of include guard: GAME_H_7D2B65AE */ |
diff --git a/src/main.cpp b/src/main.cpp index c0d5b14..ec253ee 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
@@ -5,638 +5,6 @@ | |||
5 | #include "game.h" | 5 | #include "game.h" |
6 | #include "renderer.h" | 6 | #include "renderer.h" |
7 | 7 | ||
8 | inline bool isTileSetOrNotLit(const Map<MapData>& map, int x, int y) | ||
9 | { | ||
10 | return (map.inBounds(x, y) && (map.at(x,y).tile == Tile::Wall || !map.at(x,y).lit)); | ||
11 | } | ||
12 | |||
13 | inline bool isTileSet(const Map<MapData>& map, int x, int y, Tile val = Tile::Wall) | ||
14 | { | ||
15 | return (map.inBounds(x, y) && map.at(x,y).tile == val); | ||
16 | } | ||
17 | |||
18 | inline void incrementIfSet(const Game& game, int& count, int x, int y, Tile val = Tile::Wall) | ||
19 | { | ||
20 | if (isTileSet(game.map, x, y, val)) | ||
21 | { | ||
22 | count++; | ||
23 | } | ||
24 | } | ||
25 | |||
26 | inline int getZoomLevel(const Game& game) { | ||
27 | return game.curZoom - INIT_ZOOM; | ||
28 | } | ||
29 | |||
30 | void tick( | ||
31 | Game& game, | ||
32 | int x1, | ||
33 | int y1, | ||
34 | int x2, | ||
35 | int y2, | ||
36 | bool invert = false, | ||
37 | bool onlyDark = false) | ||
38 | { | ||
39 | Map<MapData> temp(game.map); | ||
40 | |||
41 | for (int y = game.map.getTop(); y < game.map.getBottom(); y++) | ||
42 | { | ||
43 | for (int x = game.map.getLeft(); x < game.map.getRight(); x++) | ||
44 | { | ||
45 | if (invert == (x >= x1 && x < x2 && y >= y1 && y < y2)) | ||
46 | { | ||
47 | continue; | ||
48 | } | ||
49 | |||
50 | if (onlyDark && game.map.at(x,y).lit) | ||
51 | { | ||
52 | continue; | ||
53 | } | ||
54 | |||
55 | if (game.map.at(x,y).tile == Tile::Lamp) | ||
56 | { | ||
57 | continue; | ||
58 | } | ||
59 | |||
60 | int count = 0; | ||
61 | |||
62 | incrementIfSet(game, count, x-1, y-1); | ||
63 | incrementIfSet(game, count, x-1, y ); | ||
64 | incrementIfSet(game, count, x-1, y+1); | ||
65 | incrementIfSet(game, count, x , y-1); | ||
66 | incrementIfSet(game, count, x , y ); | ||
67 | incrementIfSet(game, count, x , y+1); | ||
68 | incrementIfSet(game, count, x+1, y-1); | ||
69 | incrementIfSet(game, count, x+1, y ); | ||
70 | incrementIfSet(game, count, x+1, y+1); | ||
71 | |||
72 | if (count >= 5) | ||
73 | { | ||
74 | temp.at(x,y).tile = Tile::Wall; | ||
75 | } else { | ||
76 | temp.at(x,y).tile = Tile::Floor; | ||
77 | } | ||
78 | |||
79 | if (temp.at(x,y).tile != game.map.at(x,y).tile) { | ||
80 | temp.at(x,y).dirtyRender = true; | ||
81 | game.dirtyRender = true; | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | game.map = std::move(temp); | ||
87 | } | ||
88 | |||
89 | void tick(Game& game, bool onlyDark = false) | ||
90 | { | ||
91 | tick( | ||
92 | game, | ||
93 | game.map.getLeft(), | ||
94 | game.map.getTop(), | ||
95 | game.map.getRight(), | ||
96 | game.map.getBottom(), | ||
97 | false, | ||
98 | onlyDark); | ||
99 | } | ||
100 | |||
101 | bool movePlayer(Game& game, int x, int y) | ||
102 | { | ||
103 | if (x >= game.curBoundX && | ||
104 | y >= game.curBoundY && | ||
105 | x < game.curBoundX + game.curZoom * ZOOM_X_FACTOR && | ||
106 | y < game.curBoundY + game.curZoom * ZOOM_Y_FACTOR && | ||
107 | game.map.at(x,y).tile == Tile::Floor) | ||
108 | { | ||
109 | if (game.map.at(game.player_x, game.player_y).tile == Tile::Floor) | ||
110 | { | ||
111 | game.map.at(game.player_x, game.player_y).tile = Tile::Dust; | ||
112 | game.map.at(game.player_x, game.player_y).dustLife = 1; | ||
113 | game.numDust++; | ||
114 | } | ||
115 | |||
116 | game.player_oldx = game.player_x; | ||
117 | game.player_oldy = game.player_y; | ||
118 | game.player_x = x; | ||
119 | game.player_y = y; | ||
120 | game.muxer.setPlayerLoc(x, y); | ||
121 | game.moving = true; | ||
122 | game.moveProgress.start(66); | ||
123 | |||
124 | game.dirtyLighting = true; | ||
125 | |||
126 | return true; | ||
127 | } else { | ||
128 | if (!game.alreadyBumped) { | ||
129 | game.muxer.playSoundAtPosition("bump", x, y); | ||
130 | game.alreadyBumped = true; | ||
131 | game.bumpCooldown.reset(); | ||
132 | } | ||
133 | |||
134 | return false; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | void recalculateLighting(Game& game) | ||
139 | { | ||
140 | game.litSpots = 0; | ||
141 | game.dirtyRender = true; | ||
142 | |||
143 | for (MapData& md : game.map.data()) | ||
144 | { | ||
145 | md.wasLit = md.lit; | ||
146 | md.lit = false; | ||
147 | md.litTiles.clear(); | ||
148 | |||
149 | if (md.tile == Tile::Wall) { | ||
150 | md.dirtyRender = true; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | fov_settings_type fov; | ||
155 | fov_settings_init(&fov); | ||
156 | |||
157 | fov_settings_set_opacity_test_function( | ||
158 | &fov, | ||
159 | [] (void* data, int x, int y) { | ||
160 | Game& game = *static_cast<Game*>(data); | ||
161 | |||
162 | return game.map.inBounds(x,y) && game.map.at(x,y).tile == Tile::Wall; | ||
163 | }); | ||
164 | |||
165 | fov_settings_set_apply_lighting_function( | ||
166 | &fov, | ||
167 | [] (void* data, int x, int y, int dx, int dy, void* source) { | ||
168 | Game& game = *static_cast<Game*>(data); | ||
169 | |||
170 | if (game.map.inBounds(x, y)) | ||
171 | { | ||
172 | MapData& sourceData = *static_cast<MapData*>(source); | ||
173 | double lightRadius = static_cast<double>(sourceData.lightRadius); | ||
174 | |||
175 | if (!game.map.at(x,y).lit) | ||
176 | { | ||
177 | game.litSpots++; | ||
178 | } | ||
179 | |||
180 | game.map.at(x,y).lit = true; | ||
181 | |||
182 | sourceData.litTiles.emplace(x,y); | ||
183 | } | ||
184 | }); | ||
185 | |||
186 | for (int y = game.map.getTop(); y < game.map.getBottom(); y++) | ||
187 | { | ||
188 | for (int x = game.map.getLeft(); x < game.map.getRight(); x++) | ||
189 | { | ||
190 | Source ls = Source::None; | ||
191 | int lightRadius; | ||
192 | |||
193 | if (game.renderPlayer && game.player_x == x && game.player_y == y) | ||
194 | { | ||
195 | ls = Source::Player; | ||
196 | lightRadius = RADIUS; | ||
197 | } else if (game.map.at(x,y).tile == Tile::Dust) | ||
198 | { | ||
199 | ls = Source::Dust; | ||
200 | lightRadius = 2; | ||
201 | } else if (game.map.at(x,y).tile == Tile::Lamp) | ||
202 | { | ||
203 | ls = Source::Lamp; | ||
204 | lightRadius = RADIUS; | ||
205 | } | ||
206 | |||
207 | game.map.at(x,y).lightType = ls; | ||
208 | |||
209 | if (ls != Source::None) | ||
210 | { | ||
211 | game.map.at(x,y).lightRadius = lightRadius; | ||
212 | game.map.at(x,y).litTiles.emplace(x,y); | ||
213 | |||
214 | fov_circle( | ||
215 | &fov, | ||
216 | static_cast<void*>(&game), | ||
217 | static_cast<void*>(&game.map.at(x,y)), | ||
218 | x, | ||
219 | y, | ||
220 | lightRadius); | ||
221 | |||
222 | game.map.at(x,y).lit = true; | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | game.dirtyLighting = false; | ||
228 | } | ||
229 | |||
230 | void recalculateRender(Game& game) { | ||
231 | for (int y = game.map.getTop(); y < game.map.getBottom(); y++) | ||
232 | { | ||
233 | for (int x = game.map.getLeft(); x < game.map.getRight(); x++) | ||
234 | { | ||
235 | if (game.map.at(x,y).dirtyRender) { | ||
236 | game.map.at(x,y).dirtyRender = false; | ||
237 | |||
238 | if (game.map.at(x,y).tile == Tile::Floor) { | ||
239 | if (std::bernoulli_distribution(0.05)(game.rng)) { | ||
240 | static const std::vector<int> furnishings { | ||
241 | TilesetIndex(20, 16), | ||
242 | TilesetIndex(21, 2), | ||
243 | TilesetIndex(22, 2), | ||
244 | TilesetIndex(21, 3), | ||
245 | TilesetIndex(22, 3)}; | ||
246 | game.map.at(x,y).renderId = furnishings.at(std::uniform_int_distribution<int>(0, furnishings.size()-1)(game.rng)); | ||
247 | } else { | ||
248 | game.map.at(x,y).renderId = -1; | ||
249 | } | ||
250 | } else if (game.map.at(x,y).tile == Tile::Wall) { | ||
251 | static bool initWalls = false; | ||
252 | static std::vector<int> wallRenders(256, TilesetIndex(0, 0)); | ||
253 | if (!initWalls) { | ||
254 | initWalls = true; | ||
255 | |||
256 | // Start in top left and go clockwise. | ||
257 | wallRenders[0b00011100] = TilesetIndex(16, 14); | ||
258 | wallRenders[0b00111100] = TilesetIndex(16, 14); | ||
259 | wallRenders[0b00011110] = TilesetIndex(16, 14); | ||
260 | wallRenders[0b00111110] = TilesetIndex(16, 14); | ||
261 | |||
262 | wallRenders[0b00011111] = TilesetIndex(17, 14); | ||
263 | wallRenders[0b10011111] = TilesetIndex(17, 14); | ||
264 | wallRenders[0b00111111] = TilesetIndex(17, 14); | ||
265 | wallRenders[0b10111111] = TilesetIndex(17, 14); | ||
266 | |||
267 | wallRenders[0b00000111] = TilesetIndex(18, 14); | ||
268 | wallRenders[0b00001111] = TilesetIndex(18, 14); | ||
269 | wallRenders[0b10000111] = TilesetIndex(18, 14); | ||
270 | wallRenders[0b10001111] = TilesetIndex(18, 14); | ||
271 | |||
272 | wallRenders[0b01111100] = TilesetIndex(16, 15); | ||
273 | wallRenders[0b11111100] = TilesetIndex(16, 15); | ||
274 | wallRenders[0b01111110] = TilesetIndex(16, 15); | ||
275 | wallRenders[0b11111110] = TilesetIndex(16, 15); | ||
276 | |||
277 | wallRenders[0b11000111] = TilesetIndex(18, 15); | ||
278 | wallRenders[0b11001111] = TilesetIndex(18, 15); | ||
279 | wallRenders[0b11100111] = TilesetIndex(18, 15); | ||
280 | wallRenders[0b11101111] = TilesetIndex(18, 15); | ||
281 | |||
282 | wallRenders[0b01110000] = TilesetIndex(16, 16); | ||
283 | wallRenders[0b01111000] = TilesetIndex(16, 16); | ||
284 | wallRenders[0b11110000] = TilesetIndex(16, 16); | ||
285 | wallRenders[0b11111000] = TilesetIndex(16, 16); | ||
286 | |||
287 | wallRenders[0b11110001] = TilesetIndex(17, 16); | ||
288 | wallRenders[0b11110011] = TilesetIndex(17, 16); | ||
289 | wallRenders[0b11111001] = TilesetIndex(17, 16); | ||
290 | wallRenders[0b11111011] = TilesetIndex(17, 16); | ||
291 | |||
292 | wallRenders[0b11000001] = TilesetIndex(18, 16); | ||
293 | wallRenders[0b11000011] = TilesetIndex(18, 16); | ||
294 | wallRenders[0b11100001] = TilesetIndex(18, 16); | ||
295 | wallRenders[0b11100011] = TilesetIndex(18, 16); | ||
296 | |||
297 | |||
298 | wallRenders[0b11110111] = TilesetIndex(21, 14); | ||
299 | wallRenders[0b11111101] = TilesetIndex(22, 14); | ||
300 | wallRenders[0b11011111] = TilesetIndex(21, 15); | ||
301 | wallRenders[0b01111111] = TilesetIndex(22, 15); | ||
302 | } | ||
303 | |||
304 | int renderDesc = 0; | ||
305 | if (isTileSetOrNotLit(game.map, x-1, y-1)) renderDesc |= (1 << 7); | ||
306 | if (isTileSetOrNotLit(game.map, x , y-1)) renderDesc |= (1 << 6); | ||
307 | if (isTileSetOrNotLit(game.map, x+1, y-1)) renderDesc |= (1 << 5); | ||
308 | if (isTileSetOrNotLit(game.map, x+1, y )) renderDesc |= (1 << 4); | ||
309 | if (isTileSetOrNotLit(game.map, x+1, y+1)) renderDesc |= (1 << 3); | ||
310 | if (isTileSetOrNotLit(game.map, x , y+1)) renderDesc |= (1 << 2); | ||
311 | if (isTileSetOrNotLit(game.map, x-1, y+1)) renderDesc |= (1 << 1); | ||
312 | if (isTileSetOrNotLit(game.map, x-1, y )) renderDesc |= (1 << 0); | ||
313 | |||
314 | game.map.at(x,y).renderId = wallRenders.at(renderDesc); | ||
315 | |||
316 | if (wallRenders.at(renderDesc) == 0 && renderDesc != 255) { | ||
317 | std::cout << renderDesc << std::endl; | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | |||
324 | game.dirtyRender = false; | ||
325 | } | ||
326 | |||
327 | bool processKeys(Game& game, const Input& keystate) | ||
328 | { | ||
329 | int px = game.player_x; | ||
330 | int py = game.player_y; | ||
331 | Direction dir = Direction::up; | ||
332 | |||
333 | if (keystate.up) | ||
334 | { | ||
335 | py--; | ||
336 | } | ||
337 | |||
338 | if (keystate.down) | ||
339 | { | ||
340 | py++; | ||
341 | dir = Direction::down; | ||
342 | } | ||
343 | |||
344 | if (keystate.left) | ||
345 | { | ||
346 | px--; | ||
347 | dir = Direction::left; | ||
348 | } | ||
349 | |||
350 | if (keystate.right) | ||
351 | { | ||
352 | px++; | ||
353 | dir = Direction::right; | ||
354 | } | ||
355 | |||
356 | if (!(game.player_x == px && game.player_y == py)) | ||
357 | { | ||
358 | game.playerAnim.setAnimation("walk"); | ||
359 | game.playerAnim.setDirection(dir); | ||
360 | |||
361 | bool succeeds = movePlayer(game, px, py); | ||
362 | if (!succeeds && px != game.player_x) { | ||
363 | succeeds = movePlayer(game, px, game.player_y); | ||
364 | } | ||
365 | if (!succeeds && py != game.player_y) { | ||
366 | succeeds = movePlayer(game, game.player_x, py); | ||
367 | } | ||
368 | return succeeds; | ||
369 | } else { | ||
370 | return false; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | void kickUpDust(Game& game, int x, int y, size_t chain) | ||
375 | { | ||
376 | Kickup dk; | ||
377 | dk.x = x; | ||
378 | dk.y = y; | ||
379 | dk.chain = chain; | ||
380 | dk.cur = 0; | ||
381 | dk.radius = RADIUS + (chain + 1) * (chain + 1); | ||
382 | dk.front.emplace(x, y); | ||
383 | dk.done.emplace(x, y); | ||
384 | |||
385 | game.kickups.push_back(dk); | ||
386 | } | ||
387 | |||
388 | void popLamp(Game& game, int x, int y, size_t chain) | ||
389 | { | ||
390 | game.muxer.playSoundAtPosition("pop", x, y); | ||
391 | |||
392 | if (game.map.at(x,y).tile == Tile::Lamp) | ||
393 | { | ||
394 | game.numLamps--; | ||
395 | } | ||
396 | |||
397 | game.map.at(x,y).tile = Tile::Dust; | ||
398 | game.map.at(x,y).dustLife = 2; | ||
399 | game.numDust++; | ||
400 | game.dirtyLighting = true; | ||
401 | |||
402 | kickUpDust(game, x, y, chain); | ||
403 | } | ||
404 | |||
405 | void processKickup(Game& game) | ||
406 | { | ||
407 | for (Kickup& kickup : game.kickups) | ||
408 | { | ||
409 | kickup.cur++; | ||
410 | |||
411 | std::set<coord> newFront; | ||
412 | for (const coord& xy : kickup.front) | ||
413 | { | ||
414 | auto processDir = [&] (int x, int y) { | ||
415 | coord c {x,y}; | ||
416 | |||
417 | if (game.map.inBounds(x,y) && | ||
418 | (game.map.at(x,y).tile == Tile::Floor || | ||
419 | game.map.at(x,y).tile == Tile::Lamp) && | ||
420 | !kickup.done.count(c)) | ||
421 | { | ||
422 | newFront.insert(c); | ||
423 | kickup.done.insert(c); | ||
424 | |||
425 | if (game.map.at(x,y).tile == Tile::Floor) | ||
426 | { | ||
427 | game.map.at(x,y).tile = Tile::Dust; | ||
428 | game.map.at(x,y).dustLife = 2; | ||
429 | game.numDust++; | ||
430 | game.dirtyLighting = true; | ||
431 | } else if (game.map.at(x,y).tile == Tile::Lamp) | ||
432 | { | ||
433 | popLamp(game, x, y, kickup.chain + 1); | ||
434 | } | ||
435 | } | ||
436 | }; | ||
437 | |||
438 | processDir(std::get<0>(xy) - 1, std::get<1>(xy) ); | ||
439 | processDir(std::get<0>(xy) + 1, std::get<1>(xy) ); | ||
440 | processDir(std::get<0>(xy) , std::get<1>(xy) - 1); | ||
441 | processDir(std::get<0>(xy) , std::get<1>(xy) + 1); | ||
442 | |||
443 | if (std::bernoulli_distribution(0.5)(game.rng)) | ||
444 | { | ||
445 | processDir(std::get<0>(xy) - 1, std::get<1>(xy) - 1); | ||
446 | } | ||
447 | |||
448 | if (std::bernoulli_distribution(0.5)(game.rng)) | ||
449 | { | ||
450 | processDir(std::get<0>(xy) - 1, std::get<1>(xy) + 1); | ||
451 | } | ||
452 | |||
453 | if (std::bernoulli_distribution(0.5)(game.rng)) | ||
454 | { | ||
455 | processDir(std::get<0>(xy) + 1, std::get<1>(xy) - 1); | ||
456 | } | ||
457 | |||
458 | if (std::bernoulli_distribution(0.5)(game.rng)) | ||
459 | { | ||
460 | processDir(std::get<0>(xy) + 1, std::get<1>(xy) + 1); | ||
461 | } | ||
462 | } | ||
463 | |||
464 | kickup.front.swap(newFront); | ||
465 | } | ||
466 | |||
467 | erase_if( | ||
468 | game.kickups, | ||
469 | [] (const Kickup& kickup) { | ||
470 | return kickup.cur == kickup.radius; | ||
471 | }); | ||
472 | } | ||
473 | |||
474 | void growMap(Game& game, size_t zoom) | ||
475 | { | ||
476 | int ol = game.map.getLeft(); | ||
477 | int ot = game.map.getTop(); | ||
478 | int ow = game.map.getWidth(); | ||
479 | int oh = game.map.getHeight(); | ||
480 | |||
481 | game.map.resize( | ||
482 | -zoom * ZOOM_X_FACTOR / 2, | ||
483 | -zoom * ZOOM_Y_FACTOR / 2, | ||
484 | zoom * ZOOM_X_FACTOR, | ||
485 | zoom * ZOOM_Y_FACTOR); | ||
486 | |||
487 | game.maxZoom = zoom; | ||
488 | |||
489 | for (int y = game.map.getTop(); y < game.map.getBottom(); y++) | ||
490 | { | ||
491 | for (int x = game.map.getLeft(); x < game.map.getRight(); x++) | ||
492 | { | ||
493 | if (!(x >= ol && x < (ol + ow) && y >= ot && y < (ot + oh))) | ||
494 | { | ||
495 | if (std::bernoulli_distribution(0.5)(game.rng)) | ||
496 | { | ||
497 | game.map.at(x,y).tile = Tile::Wall; | ||
498 | } | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | |||
503 | for (int i = 0; i < 3; i++) | ||
504 | { | ||
505 | tick(game, ol, ot, ol + ow, ot + oh, true); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | void setZoom(Game& game, size_t zoom) | ||
510 | { | ||
511 | if (zoom == game.curZoom) | ||
512 | { | ||
513 | return; | ||
514 | } | ||
515 | |||
516 | if (zoom > game.maxZoom) | ||
517 | { | ||
518 | growMap(game, zoom); | ||
519 | } | ||
520 | |||
521 | std::tie( | ||
522 | game.lastZoomLeft, | ||
523 | game.lastZoomTop, | ||
524 | game.lastZoomWidth, | ||
525 | game.lastZoomHeight) = | ||
526 | Renderer::calculateZoomRect(game); | ||
527 | |||
528 | game.zoomProgress = 0; | ||
529 | game.zoomLength = | ||
530 | std::abs(static_cast<long>(zoom - game.curZoom)) * TILE_WIDTH; | ||
531 | game.curZoom = zoom; | ||
532 | game.zooming = true; | ||
533 | |||
534 | game.curBoundX = game.player_x - zoom * ZOOM_X_FACTOR / 2; | ||
535 | if (game.curBoundX < game.map.getLeft()) | ||
536 | { | ||
537 | game.curBoundX = game.map.getLeft(); | ||
538 | } else if (game.curBoundX + zoom * ZOOM_X_FACTOR >= game.map.getRight()) | ||
539 | { | ||
540 | game.curBoundX = game.map.getRight() - zoom * ZOOM_X_FACTOR; | ||
541 | } | ||
542 | |||
543 | game.curBoundY = game.player_y - zoom * ZOOM_Y_FACTOR / 2; | ||
544 | if (game.curBoundY < game.map.getTop()) | ||
545 | { | ||
546 | game.curBoundY = game.map.getTop(); | ||
547 | } else if (game.curBoundY + zoom * ZOOM_Y_FACTOR >= game.map.getBottom()) | ||
548 | { | ||
549 | game.curBoundY = game.map.getBottom() - zoom * ZOOM_Y_FACTOR; | ||
550 | } | ||
551 | |||
552 | int zoomLevel = getZoomLevel(game); | ||
553 | if (zoomLevel == 0) { | ||
554 | game.muxer.setMusicLevel(0); | ||
555 | } else if (zoomLevel < 3) { | ||
556 | game.muxer.setMusicLevel(1); | ||
557 | } else if (zoomLevel < 5) { | ||
558 | game.muxer.setMusicLevel(2); | ||
559 | } else if (zoomLevel < 7) { | ||
560 | game.muxer.setMusicLevel(3); | ||
561 | } else { | ||
562 | game.muxer.setMusicLevel(4); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | void performDash(Game& game, std::mt19937& rng) { | ||
567 | if (game.map.at(game.player_x, game.player_y).tile == | ||
568 | Tile::Floor) | ||
569 | { | ||
570 | std::vector<coord> freeSpaces; | ||
571 | |||
572 | auto addIfFree = [&] (int x, int y) { | ||
573 | if (game.map.inBounds(x,y) && | ||
574 | game.map.at(x,y).tile == Tile::Floor) | ||
575 | { | ||
576 | freeSpaces.emplace_back(x, y); | ||
577 | } | ||
578 | }; | ||
579 | |||
580 | addIfFree(game.player_x - 1, game.player_y - 1); | ||
581 | addIfFree(game.player_x , game.player_y - 1); | ||
582 | addIfFree(game.player_x + 1, game.player_y - 1); | ||
583 | addIfFree(game.player_x - 1, game.player_y ); | ||
584 | addIfFree(game.player_x + 1, game.player_y ); | ||
585 | addIfFree(game.player_x - 1, game.player_y + 1); | ||
586 | addIfFree(game.player_x , game.player_y + 1); | ||
587 | addIfFree(game.player_x + 1, game.player_y + 1); | ||
588 | |||
589 | if (!freeSpaces.empty()) | ||
590 | { | ||
591 | game.map.at(game.player_x, game.player_y).tile = Tile::Lamp; | ||
592 | game.numLamps++; | ||
593 | game.dirtyLighting = true; | ||
594 | kickUpDust(game, game.player_x, game.player_y, 0); | ||
595 | game.muxer.playSoundAtPosition("drop", game.player_x, game.player_y); | ||
596 | |||
597 | if (game.firstInput) | ||
598 | { | ||
599 | for (int i = 0; i < 5; i++) | ||
600 | { | ||
601 | if (!processKeys(game, game.lastInput)) | ||
602 | { | ||
603 | std::uniform_int_distribution<int> freeDist( | ||
604 | 0, freeSpaces.size() - 1); | ||
605 | |||
606 | int freeIndex = freeDist(rng); | ||
607 | coord& moveTo = freeSpaces[freeIndex]; | ||
608 | |||
609 | movePlayer( | ||
610 | game, | ||
611 | std::get<0>(moveTo), | ||
612 | std::get<1>(moveTo)); | ||
613 | } | ||
614 | |||
615 | tick( | ||
616 | game, | ||
617 | game.player_x - (RADIUS - 1), | ||
618 | game.player_y - (RADIUS - 1), | ||
619 | game.player_x + RADIUS, | ||
620 | game.player_y + RADIUS); | ||
621 | } | ||
622 | } else { | ||
623 | std::uniform_int_distribution<int> freeDist( | ||
624 | 0, freeSpaces.size() - 1); | ||
625 | |||
626 | int freeIndex = freeDist(rng); | ||
627 | coord& moveTo = freeSpaces[freeIndex]; | ||
628 | |||
629 | movePlayer( | ||
630 | game, | ||
631 | std::get<0>(moveTo), | ||
632 | std::get<1>(moveTo)); | ||
633 | } | ||
634 | |||
635 | //game.muxer.playSoundAtPosition("dash", game.player_x, game.player_y); | ||
636 | } | ||
637 | } | ||
638 | } | ||
639 | |||
640 | int main(int, char**) | 8 | int main(int, char**) |
641 | { | 9 | { |
642 | std::random_device randomEngine; | 10 | std::random_device randomEngine; |
@@ -645,296 +13,20 @@ int main(int, char**) | |||
645 | try | 13 | try |
646 | { | 14 | { |
647 | Renderer renderer; | 15 | Renderer renderer; |
16 | Muxer muxer; | ||
648 | 17 | ||
649 | Game game(rng); | 18 | Game game(rng, muxer); |
650 | |||
651 | for (MapData& md : game.map.data()) | ||
652 | { | ||
653 | if (std::bernoulli_distribution(0.5)(rng)) | ||
654 | { | ||
655 | md.tile = Tile::Wall; | ||
656 | } | ||
657 | } | ||
658 | |||
659 | tick(game); | ||
660 | tick(game); | ||
661 | |||
662 | for (int y = -1; y <= 1; y++) | ||
663 | { | ||
664 | for (int x = -1; x <= 1; x++) | ||
665 | { | ||
666 | game.map.at(x,y).tile = Tile::Floor; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | tick(game); | ||
671 | |||
672 | bool quit = false; | ||
673 | LoseState losing = LoseState::None; | ||
674 | Input keystate; | ||
675 | SDL_Event e; | ||
676 | |||
677 | size_t dustDt = 40; | ||
678 | size_t dustAcc = 0; | ||
679 | |||
680 | size_t inputDt = 50; | ||
681 | size_t inputAcc = 0; | ||
682 | |||
683 | size_t losePopLampDt = 800; | ||
684 | size_t losePopLampAcc = losePopLampDt; | ||
685 | |||
686 | size_t losePopPlayerDt = 3000; | ||
687 | size_t losePopPlayerAcc = 0; | ||
688 | |||
689 | size_t zoomDt = 62; | ||
690 | size_t zoomAcc = 0; | ||
691 | 19 | ||
692 | size_t lastTime = SDL_GetTicks(); | 20 | size_t lastTime = SDL_GetTicks(); |
693 | 21 | while (!game.quit) | |
694 | while (!quit) | ||
695 | { | 22 | { |
696 | size_t currentTime = SDL_GetTicks(); | 23 | size_t currentTime = SDL_GetTicks(); |
697 | size_t frameTime = currentTime - lastTime; | 24 | size_t frameTime = currentTime - lastTime; |
698 | lastTime = currentTime; | 25 | lastTime = currentTime; |
699 | 26 | ||
700 | while (SDL_PollEvent(&e)) | 27 | game.update(frameTime); |
701 | { | 28 | renderer.renderGame(game, true); |
702 | if (e.type == SDL_QUIT) | 29 | muxer.update(); |
703 | { | ||
704 | if (losing != LoseState::None) | ||
705 | { | ||
706 | quit = true; | ||
707 | } else { | ||
708 | losing = LoseState::PoppingLamps; | ||
709 | game.muxer.stopMusic(); | ||
710 | } | ||
711 | } else if (e.type == SDL_KEYDOWN) | ||
712 | { | ||
713 | switch (e.key.keysym.sym) | ||
714 | { | ||
715 | case SDLK_ESCAPE: | ||
716 | { | ||
717 | if (losing != LoseState::None) | ||
718 | { | ||
719 | quit = true; | ||
720 | } else { | ||
721 | losing = LoseState::PoppingLamps; | ||
722 | game.muxer.stopMusic(); | ||
723 | } | ||
724 | |||
725 | break; | ||
726 | } | ||
727 | |||
728 | case SDLK_SPACE: | ||
729 | { | ||
730 | if (losing == LoseState::None) | ||
731 | { | ||
732 | if (game.moving) { | ||
733 | game.queueDash = true; | ||
734 | } else { | ||
735 | performDash(game, rng); | ||
736 | } | ||
737 | } | ||
738 | |||
739 | break; | ||
740 | } | ||
741 | } | ||
742 | } | ||
743 | } | ||
744 | |||
745 | const Uint8* state = SDL_GetKeyboardState(NULL); | ||
746 | keystate.left = state[SDL_SCANCODE_LEFT]; | ||
747 | keystate.right = state[SDL_SCANCODE_RIGHT]; | ||
748 | keystate.up = state[SDL_SCANCODE_UP]; | ||
749 | keystate.down = state[SDL_SCANCODE_DOWN]; | ||
750 | |||
751 | game.bumpCooldown.accumulate(frameTime); | ||
752 | if (game.alreadyBumped && keystate != game.lastInput && game.bumpCooldown.step()) { | ||
753 | game.alreadyBumped = false; | ||
754 | } | ||
755 | |||
756 | if (game.queueDash && !game.moving) { | ||
757 | game.queueDash = false; | ||
758 | performDash(game, rng); | ||
759 | } | ||
760 | |||
761 | if (keystate.left || keystate.right || keystate.up || keystate.down) | ||
762 | { | ||
763 | game.firstInput = true; | ||
764 | game.lastInput = keystate; | ||
765 | } else if (losing == LoseState::None) { | ||
766 | game.playerAnim.setAnimation("still"); | ||
767 | } | ||
768 | |||
769 | dustAcc += frameTime; | ||
770 | inputAcc += frameTime; | ||
771 | |||
772 | while (dustAcc >= dustDt) | ||
773 | { | ||
774 | game.numDust = 0; | ||
775 | |||
776 | for (MapData& md : game.map.data()) | ||
777 | { | ||
778 | if (md.tile == Tile::Dust) | ||
779 | { | ||
780 | md.dustLife--; | ||
781 | |||
782 | if (md.dustLife <= 0) | ||
783 | { | ||
784 | md.tile = Tile::Floor; | ||
785 | game.dirtyLighting = true; | ||
786 | } else { | ||
787 | game.numDust++; | ||
788 | } | ||
789 | } | ||
790 | } | ||
791 | |||
792 | processKickup(game); | ||
793 | |||
794 | dustAcc -= dustDt; | ||
795 | } | ||
796 | |||
797 | switch (losing) | ||
798 | { | ||
799 | case LoseState::None: | ||
800 | { | ||
801 | if (game.moving) { | ||
802 | game.moveProgress.tick(frameTime); | ||
803 | if (game.moveProgress.isComplete()) { | ||
804 | game.moving = false; | ||
805 | } | ||
806 | } | ||
807 | |||
808 | while (inputAcc >= inputDt) | ||
809 | { | ||
810 | if (!game.moving) { | ||
811 | processKeys(game, keystate); | ||
812 | } | ||
813 | |||
814 | inputAcc -= inputDt; | ||
815 | } | ||
816 | |||
817 | break; | ||
818 | } | ||
819 | |||
820 | case LoseState::PoppingLamps: | ||
821 | { | ||
822 | if (game.numLamps == 0) | ||
823 | { | ||
824 | if (game.numDust == 0) | ||
825 | { | ||
826 | losing = LoseState::PoppingPlayer; | ||
827 | } | ||
828 | } else { | ||
829 | losePopLampAcc += frameTime; | ||
830 | |||
831 | while (losePopLampAcc >= losePopLampDt) | ||
832 | { | ||
833 | std::vector<std::tuple<int, int>> lamps; | ||
834 | |||
835 | for (int y = game.map.getTop(); y < game.map.getBottom(); y++) | ||
836 | { | ||
837 | for (int x = game.map.getLeft(); x < game.map.getRight(); x++) | ||
838 | { | ||
839 | if (game.map.at(x,y).tile == Tile::Lamp) | ||
840 | { | ||
841 | lamps.emplace_back(x, y); | ||
842 | } | ||
843 | } | ||
844 | } | ||
845 | |||
846 | std::uniform_int_distribution<int> lampDist(0, lamps.size() - 1); | ||
847 | std::tuple<int, int> popPos = lamps[lampDist(rng)]; | ||
848 | |||
849 | popLamp(game, std::get<0>(popPos), std::get<1>(popPos), 1); | ||
850 | |||
851 | losePopLampAcc -= losePopLampDt; | ||
852 | } | ||
853 | } | ||
854 | |||
855 | break; | ||
856 | } | ||
857 | |||
858 | case LoseState::PoppingPlayer: | ||
859 | { | ||
860 | losePopPlayerAcc += frameTime; | ||
861 | |||
862 | if (losePopPlayerAcc >= losePopPlayerDt) | ||
863 | { | ||
864 | popLamp(game, game.player_x, game.player_y, 10); | ||
865 | game.renderPlayer = false; | ||
866 | |||
867 | losing = LoseState::Outro; | ||
868 | } | ||
869 | |||
870 | break; | ||
871 | } | ||
872 | |||
873 | case LoseState::Outro: | ||
874 | { | ||
875 | if (game.numDust == 0) | ||
876 | { | ||
877 | quit = true; | ||
878 | } | ||
879 | |||
880 | break; | ||
881 | } | ||
882 | } | ||
883 | |||
884 | if (game.dirtyLighting) | ||
885 | { | ||
886 | recalculateLighting(game); | ||
887 | |||
888 | for (int y = game.map.getTop(); y < game.map.getBottom(); y++) | ||
889 | { | ||
890 | for (int x = game.map.getLeft(); x < game.map.getRight(); x++) | ||
891 | { | ||
892 | if (!game.map.at(x,y).lit && game.map.at(x,y).wasLit) | ||
893 | { | ||
894 | if (std::bernoulli_distribution(0.5)(rng)) | ||
895 | { | ||
896 | game.map.at(x,y).tile = Tile::Wall; | ||
897 | } else { | ||
898 | game.map.at(x,y).tile = Tile::Floor; | ||
899 | } | ||
900 | game.map.at(x,y).dirtyRender = true; | ||
901 | } | ||
902 | } | ||
903 | } | ||
904 | |||
905 | tick(game, true); | ||
906 | tick(game, true); | ||
907 | tick(game, true); | ||
908 | |||
909 | // TODO: better zoom algorithm | ||
910 | setZoom(game, game.litSpots / 1500 + INIT_ZOOM); | ||
911 | } | ||
912 | |||
913 | if (game.dirtyRender) { | ||
914 | recalculateRender(game); | ||
915 | } | ||
916 | |||
917 | zoomAcc += frameTime; | ||
918 | |||
919 | while (zoomAcc >= zoomDt) | ||
920 | { | ||
921 | if (game.zooming) | ||
922 | { | ||
923 | game.zoomProgress++; | ||
924 | |||
925 | if (game.zoomProgress == game.zoomLength) | ||
926 | { | ||
927 | game.zooming = false; | ||
928 | } | ||
929 | } | ||
930 | |||
931 | zoomAcc -= zoomDt; | ||
932 | } | ||
933 | |||
934 | game.playerAnim.update(frameTime); | ||
935 | |||
936 | game.muxer.update(); | ||
937 | renderer.render(game, true); | ||
938 | } | 30 | } |
939 | } catch (const sdl_error& ex) | 31 | } catch (const sdl_error& ex) |
940 | { | 32 | { |
diff --git a/src/renderer.cpp b/src/renderer.cpp index 1858520..90ce03f 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp | |||
@@ -150,7 +150,7 @@ Renderer::Renderer() | |||
150 | SDL_SetTextureBlendMode(lamp_.get(), SDL_BLENDMODE_BLEND); | 150 | SDL_SetTextureBlendMode(lamp_.get(), SDL_BLENDMODE_BLEND); |
151 | } | 151 | } |
152 | 152 | ||
153 | void Renderer::render( | 153 | void Renderer::renderGame( |
154 | const Game& game, | 154 | const Game& game, |
155 | bool drawDark) | 155 | bool drawDark) |
156 | { | 156 | { |
diff --git a/src/renderer.h b/src/renderer.h index 57d9702..ca4e607 100644 --- a/src/renderer.h +++ b/src/renderer.h | |||
@@ -113,7 +113,7 @@ public: | |||
113 | 113 | ||
114 | Renderer(); | 114 | Renderer(); |
115 | 115 | ||
116 | void render( | 116 | void renderGame( |
117 | const Game& game, | 117 | const Game& game, |
118 | bool drawDark = true); | 118 | bool drawDark = true); |
119 | 119 | ||
diff --git a/src/timer.h b/src/timer.h index ec34f3e..65d5a50 100644 --- a/src/timer.h +++ b/src/timer.h | |||
@@ -23,6 +23,8 @@ public: | |||
23 | acc_ = 0; | 23 | acc_ = 0; |
24 | } | 24 | } |
25 | 25 | ||
26 | int getDt() const { return dt_; } | ||
27 | |||
26 | private: | 28 | private: |
27 | 29 | ||
28 | int dt_; | 30 | int dt_; |