summary refs log tree commit diff stats
path: root/src/main.cpp
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2022-03-13 13:21:17 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2022-03-13 13:21:17 -0400
commit016d1cdf036039792f50e1ed0431386c7b9e93d7 (patch)
treee5f773f34b05c4fd8c73247eae9d20514fa450df /src/main.cpp
parentb2dfe21775a55e815b2572d844c749c5108671fe (diff)
downloadether-016d1cdf036039792f50e1ed0431386c7b9e93d7.tar.gz
ether-016d1cdf036039792f50e1ed0431386c7b9e93d7.tar.bz2
ether-016d1cdf036039792f50e1ed0431386c7b9e93d7.zip
refactored game code into the game class (for titles / multiple games)
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp920
1 files changed, 6 insertions, 914 deletions
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
8inline 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
13inline 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
18inline 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
26inline int getZoomLevel(const Game& game) {
27 return game.curZoom - INIT_ZOOM;
28}
29
30void 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
89void 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
101bool 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
138void 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
230void 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
327bool 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
374void 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
388void 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
405void 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
474void 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
509void 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
566void 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
640int main(int, char**) 8int 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 {