summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp967
-rw-r--r--src/map.h127
-rw-r--r--src/untitled.txt0
-rw-r--r--src/util.h20
4 files changed, 858 insertions, 256 deletions
diff --git a/src/main.cpp b/src/main.cpp index c02fdd5..dacc646 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -3,10 +3,14 @@
3#include <stdexcept> 3#include <stdexcept>
4#include <memory> 4#include <memory>
5#include <vector> 5#include <vector>
6#include <list>
6#include <random> 7#include <random>
7#include <fov.h> 8#include <fov.h>
8#include <deque>
9#include <iostream> 9#include <iostream>
10#include <tuple>
11#include <set>
12#include "util.h"
13#include "map.h"
10 14
11class sdl_error : public std::logic_error { 15class sdl_error : public std::logic_error {
12public: 16public:
@@ -82,12 +86,20 @@ enum class Source {
82 Player 86 Player
83}; 87};
84 88
89enum class LoseState {
90 None,
91 PoppingLamps,
92 PoppingPlayer,
93 Outro
94};
95
85const int GAME_WIDTH = 640*2; 96const int GAME_WIDTH = 640*2;
86const int GAME_HEIGHT = 480*2; 97const int GAME_HEIGHT = 480*2;
87const int TILE_WIDTH = 8*2; 98const int TILE_WIDTH = 8*2;
88const int TILE_HEIGHT = 8*2; 99const int TILE_HEIGHT = TILE_WIDTH;
89const int VIEW_WIDTH = GAME_WIDTH / TILE_WIDTH; 100const int INIT_ZOOM = 10;
90const int VIEW_HEIGHT = GAME_HEIGHT / TILE_HEIGHT; 101const int ZOOM_X_FACTOR = 8;
102const int ZOOM_Y_FACTOR = 6;
91const int RADIUS = 8; 103const int RADIUS = 8;
92 104
93struct Input { 105struct Input {
@@ -97,34 +109,70 @@ struct Input {
97 bool down = false; 109 bool down = false;
98}; 110};
99 111
100class Map { 112using coord = std::tuple<int, int>;
113
114struct Kickup {
115 int x;
116 int y;
117 size_t cur;
118 size_t radius;
119 size_t chain;
120 std::set<coord> done;
121 std::set<coord> front;
122};
123
124struct MapData {
125 Tile tile = Tile::Floor;
126 bool lit = false;
127 bool wasLit = false;
128 double visibility = 0.0;
129 size_t dustLife = 0;
130 Source lightType = Source::None;
131 int lightRadius = 0;
132 std::set<coord> litTiles;
133};
134
135class Game {
101public: 136public:
102 137
103 Map() : 138 Game(std::mt19937& rng) :
104 tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor), 139 rng(rng),
105 lighting(VIEW_WIDTH*VIEW_HEIGHT, false), 140 map(
106 lightStrength(VIEW_WIDTH*VIEW_HEIGHT, 0.0), 141 -INIT_ZOOM * ZOOM_X_FACTOR / 2,
107 lightSource(VIEW_WIDTH*VIEW_HEIGHT, Source::None) 142 -INIT_ZOOM * ZOOM_Y_FACTOR / 2,
143 INIT_ZOOM * ZOOM_X_FACTOR,
144 INIT_ZOOM * ZOOM_Y_FACTOR)
108 { 145 {
109 } 146 }
110 147
111 std::vector<Tile> tiles; 148 std::mt19937& rng;
112 std::vector<bool> lighting; 149
113 std::vector<bool> oldLighting; 150 Map<MapData> map;
114 std::vector<double> lightStrength; 151 std::list<Kickup> kickups;
115 std::vector<Source> lightSource; 152 int litSpots = 0;
116 int lightedSpots = 0; 153 bool dirtyLighting = true;
117}; 154 size_t numLamps = 0;
155 size_t numDust = 0;
156
157 int player_x = 0;
158 int player_y = 0;
159 bool renderPlayer = true;
160
161 int curZoom = INIT_ZOOM;
162 int maxZoom = INIT_ZOOM;
118 163
119int player_x = VIEW_WIDTH / 2; 164 bool zooming = false;
120int player_y = VIEW_HEIGHT / 2; 165 //size_t oldZoom;
166 int zoomProgress = 0;
167
168};
121 169
122void render( 170void render(
123 SDL_Renderer* ren, 171 SDL_Renderer* ren,
124 const Map& map, 172 const Game& game,
125 bool drawDark = true) 173 bool drawDark = true)
126{ 174{
127 texture_ptr playerFade; 175 texture_ptr origFade;
128 { 176 {
129 surface_ptr pfs(IMG_Load("../res/lighting.png")); 177 surface_ptr pfs(IMG_Load("../res/lighting.png"));
130 if (!pfs) 178 if (!pfs)
@@ -132,9 +180,29 @@ void render(
132 throw img_error(); 180 throw img_error();
133 } 181 }
134 182
135 playerFade = texture_ptr(SDL_CreateTextureFromSurface(ren, pfs.get())); 183 origFade = texture_ptr(SDL_CreateTextureFromSurface(ren, pfs.get()));
184 }
185
186 SDL_SetTextureBlendMode(origFade.get(), SDL_BLENDMODE_BLEND);
187
188 texture_ptr playerFade(
189 SDL_CreateTexture(
190 ren,
191 SDL_PIXELFORMAT_RGBA4444,
192 SDL_TEXTUREACCESS_TARGET,
193 144,
194 144));
195
196 if (!playerFade)
197 {
198 throw sdl_error();
136 } 199 }
137 200
201 SDL_SetRenderTarget(ren, playerFade.get());
202 SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
203 SDL_RenderClear(ren);
204 SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr);
205
138 texture_ptr lampFade( 206 texture_ptr lampFade(
139 SDL_CreateTexture( 207 SDL_CreateTexture(
140 ren, 208 ren,
@@ -143,59 +211,83 @@ void render(
143 144, 211 144,
144 144)); 212 144));
145 213
214 if (!lampFade)
146 { 215 {
147 SDL_SetRenderTarget(ren, lampFade.get()); 216 throw sdl_error();
217 }
148 218
149 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE); 219 SDL_SetRenderTarget(ren, lampFade.get());
150 SDL_SetRenderDrawColor(ren, 255, 255, 255, 0);
151 SDL_RenderFillRect(ren, nullptr);
152 220
153 SDL_RenderCopy(ren, playerFade.get(), nullptr, nullptr); 221 SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
222 SDL_RenderClear(ren);
223 SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr);
224
225 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_MOD);
226 SDL_SetRenderDrawColor(ren, 255, 204, 58, 255);
227 SDL_RenderFillRect(ren, nullptr);
154 228
155 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_MOD); 229 texture_ptr dustFade(
156 SDL_SetRenderDrawColor(ren, 255, 180, 0, 255); 230 SDL_CreateTexture(
157 SDL_RenderFillRect(ren, nullptr); 231 ren,
232 SDL_PIXELFORMAT_RGBA4444,
233 SDL_TEXTUREACCESS_TARGET,
234 144,
235 144));
158 236
159 SDL_SetRenderTarget(ren, nullptr); 237 if (!dustFade)
238 {
239 throw sdl_error();
160 } 240 }
161 241
162 int darkR = 40; 242 SDL_SetRenderTarget(ren, dustFade.get());
163 int darkG = 40; 243
164 int darkB = 40; 244 SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
245 SDL_RenderClear(ren);
246 SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr);
247
248 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_MOD);
249 SDL_SetRenderDrawColor(ren, 255, 150, 255, 255);
250 SDL_RenderFillRect(ren, nullptr);
165 251
166 if (!drawDark) 252 texture_ptr canvas(
253 SDL_CreateTexture(
254 ren,
255 SDL_PIXELFORMAT_RGBA8888,
256 SDL_TEXTUREACCESS_TARGET,
257 TILE_WIDTH * game.map.getWidth(),
258 TILE_HEIGHT * game.map.getHeight()));
259
260 if (!canvas)
167 { 261 {
168 darkR = rand() % 255; 262 throw sdl_error();
169 darkG = rand() % 255;
170 darkB = rand() % 255;
171 } 263 }
172 264
173 SDL_SetRenderDrawColor(ren, darkR, darkG, darkB, 255); 265 SDL_SetRenderTarget(ren, canvas.get());
266 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE);
267 SDL_SetRenderDrawColor(ren, rand() % 255, rand() % 255, rand() % 255, 255);
174 SDL_RenderClear(ren); 268 SDL_RenderClear(ren);
175 269
176 for (int y = 0; y < VIEW_HEIGHT; y++) 270 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
177 { 271 {
178 for (int x = 0; x < VIEW_WIDTH; x++) 272 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
179 { 273 {
180 bool draw = true; 274 bool draw = true;
181 275
182 if (player_x == x && player_y == y) 276 if ((game.player_x == x && game.player_y == y) && game.renderPlayer)
183 { 277 {
184 SDL_SetRenderDrawColor(ren, 255, 255, 0, 255); 278 SDL_SetRenderDrawColor(ren, 255, 255, 0, 255);
185 } else if (!map.lighting.at(x+VIEW_WIDTH*y)) 279 /*} else if (!game.map.at(x,y).lit)
186 { 280 {
187 /*if (drawDark) 281 if (drawDark)
188 { 282 {
189 SDL_SetRenderDrawColor(ren, 40, 40, 40, 255); 283 SDL_SetRenderDrawColor(ren, 40, 40, 40, 255);
190 } else { 284 } else {
191 draw = false; 285 draw = false;
192 }*/ 286 }*/
193 draw = false;
194 } else { 287 } else {
195 int alpha = map.lightStrength.at(x+y*VIEW_WIDTH) * 255; 288 int alpha = 255;
196 alpha = 255;
197 289
198 switch (map.tiles.at(x+y*VIEW_WIDTH)) 290 switch (game.map.at(x,y).tile)
199 { 291 {
200 case Tile::Floor: 292 case Tile::Floor:
201 { 293 {
@@ -225,216 +317,322 @@ void render(
225 317
226 if (draw) 318 if (draw)
227 { 319 {
228 SDL_Rect rect{x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; 320 SDL_Rect rect {
229 321 game.map.getTrueX(x) * TILE_WIDTH,
230 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND); 322 game.map.getTrueY(y) * TILE_HEIGHT,
231 SDL_RenderFillRect(ren, &rect); 323 TILE_WIDTH,
324 TILE_HEIGHT};
232 325
326 //SDL_RenderFillRect(ren, &rect);
233 327
328 //int alpha = (1.0 - game.map.at(x,y).visibility) * 255;
329 //SDL_SetRenderDrawColor(ren, 40, 40, 40, 255);
330 SDL_RenderFillRect(ren, &rect);
234 } 331 }
235 } 332 }
236 } 333 }
237 334
238 for (int y = 0; y < VIEW_HEIGHT; y++) 335 texture_ptr mask(
336 SDL_CreateTexture(
337 ren,
338 SDL_PIXELFORMAT_RGBA8888,
339 SDL_TEXTUREACCESS_TARGET,
340 TILE_WIDTH * game.map.getWidth(),
341 TILE_HEIGHT * game.map.getHeight()));
342
343 if (!mask)
344 {
345 throw sdl_error();
346 }
347
348 SDL_SetRenderTarget(ren, mask.get());
349 SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
350 SDL_RenderClear(ren);
351
352 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
239 { 353 {
240 for (int x = 0; x < VIEW_WIDTH; x++) 354 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
241 { 355 {
242 if (map.lightSource.at(x+VIEW_WIDTH*y) != Source::None) 356 if (game.map.at(x,y).lightType != Source::None)
243 { 357 {
244 SDL_Rect fadeRect{x*TILE_WIDTH + (TILE_WIDTH/2) - (144/2), y*TILE_HEIGHT + (TILE_HEIGHT/2) - (144/2), 144, 144}; 358 texture_ptr sourceMask(
245 if (map.lightSource.at(x+VIEW_WIDTH*y) == Source::Lamp) 359 SDL_CreateTexture(
360 ren,
361 SDL_PIXELFORMAT_RGBA8888,
362 SDL_TEXTUREACCESS_TARGET,
363 TILE_WIDTH * game.map.getWidth(),
364 TILE_HEIGHT * game.map.getHeight()));
365
366 if (!sourceMask)
246 { 367 {
247 //SDL_SetTextureBlendMode(lampFade.get(), SDL_BLENDMODE_MOD); 368 throw sdl_error();
248 SDL_RenderCopy(ren, lampFade.get(), nullptr, &fadeRect); 369 }
249 //SDL_SetRenderDrawColor(ren, 255, 180, 0, 50); 370
250 //SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND); 371 SDL_SetRenderTarget(ren, sourceMask.get());
251 //SDL_RenderFillRect(ren, &rect); 372 SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
252 } else if (map.lightSource.at(x+VIEW_WIDTH*y) == Source::Player) 373 SDL_RenderClear(ren);
374
375 SDL_SetRenderDrawColor(ren, 255, 255, 255, 255);
376
377 for (const coord& xy : game.map.at(x,y).litTiles)
253 { 378 {
254 //SDL_SetTextureBlendMode(playerFade.get(), SDL_BLENDMODE_MOD); 379 SDL_Rect rect {
380 game.map.getTrueX(std::get<0>(xy)) * TILE_WIDTH,
381 game.map.getTrueY(std::get<1>(xy)) * TILE_HEIGHT,
382 TILE_WIDTH,
383 TILE_HEIGHT};
384
385 SDL_RenderFillRect(ren, &rect);
386 }
387
388 SDL_Rect fadeRect {
389 (game.map.getTrueX(x) - game.map.at(x,y).lightRadius) * TILE_WIDTH,
390 (game.map.getTrueY(y) - game.map.at(x,y).lightRadius) * TILE_HEIGHT,
391 (game.map.at(x,y).lightRadius * 2 + 1) * TILE_WIDTH,
392 (game.map.at(x,y).lightRadius * 2 + 1) * TILE_HEIGHT};
393
394 if (game.map.at(x,y).lightType == Source::Lamp)
395 {
396 SDL_SetTextureBlendMode(lampFade.get(), SDL_BLENDMODE_MOD);
397 SDL_RenderCopy(ren, lampFade.get(), nullptr, &fadeRect);
398 } else if (game.map.at(x,y).lightType == Source::Player) {
399 SDL_SetTextureBlendMode(playerFade.get(), SDL_BLENDMODE_MOD);
255 SDL_RenderCopy(ren, playerFade.get(), nullptr, &fadeRect); 400 SDL_RenderCopy(ren, playerFade.get(), nullptr, &fadeRect);
401 } else if (game.map.at(x,y).lightType == Source::Dust) {
402 SDL_SetTextureBlendMode(dustFade.get(), SDL_BLENDMODE_MOD);
403 SDL_RenderCopy(ren, dustFade.get(), nullptr, &fadeRect);
256 } 404 }
257 405
258 /*SDL_SetRenderDrawColor(ren, 40, 40, 40, alpha); 406 SDL_SetRenderTarget(ren, mask.get());
259 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND); 407 SDL_SetTextureBlendMode(sourceMask.get(), SDL_BLENDMODE_ADD);
260 SDL_RenderFillRect(ren, &rect);*/ 408 SDL_RenderCopy(ren, sourceMask.get(), nullptr, nullptr);
261 } 409 }
262 } 410 }
263 } 411 }
264 412
265 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE); 413 SDL_SetRenderTarget(ren, canvas.get());
266 SDL_SetRenderDrawColor(ren, darkR, darkG, darkB, 255); 414 SDL_SetTextureBlendMode(mask.get(), SDL_BLENDMODE_MOD);
415 SDL_RenderCopy(ren, mask.get(), nullptr, nullptr);
267 416
268 for (int y = 0; y < VIEW_HEIGHT; y++) 417 SDL_SetRenderTarget(ren, nullptr);
269 {
270 for (int x = 0; x < VIEW_WIDTH; x++)
271 {
272 if (!map.lighting.at(x+VIEW_WIDTH*y))
273 {
274 SDL_Rect rect{x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
275 418
276 SDL_RenderFillRect(ren, &rect); 419 if (!game.zooming)
277 } 420 {
278 } 421 SDL_RenderCopy(ren, canvas.get(), nullptr, nullptr);
422 } else {
423 // TODO: zooming back in to the player
424 SDL_Rect zoomRect {
425 ((game.maxZoom - game.curZoom) * TILE_WIDTH + game.zoomProgress)
426 * ZOOM_X_FACTOR / 2,
427 ((game.maxZoom - game.curZoom) * TILE_HEIGHT + game.zoomProgress)
428 * ZOOM_Y_FACTOR / 2,
429 (game.curZoom * TILE_WIDTH - game.zoomProgress) * ZOOM_X_FACTOR,
430 (game.curZoom * TILE_HEIGHT - game.zoomProgress) * ZOOM_Y_FACTOR
431 };
432
433 SDL_RenderCopy(ren, canvas.get(), &zoomRect, nullptr);
279 } 434 }
280 435
281 SDL_RenderPresent(ren); 436 SDL_RenderPresent(ren);
282} 437}
283 438
284void incrementIfSet(Map& map, int& count, int x, int y, int w, int h, Tile val = Tile::Wall) 439void incrementIfSet(Game& game, int& count, int x, int y, Tile val = Tile::Wall)
285{ 440{
286 if ((x >= 0) && (x < w) && (y >= 0) && (y < h) && (map.tiles[x+w*y] == val)) 441 if (game.map.inBounds(x, y) && game.map.at(x,y).tile == val)
287 { 442 {
288 count++; 443 count++;
289 } 444 }
290} 445}
291 446
292void tick(Map& map, int x1 = 0, int y1 = 0, int x2 = VIEW_WIDTH, int y2 = VIEW_HEIGHT, bool onlyDark = false) 447void tick(
448 Game& game,
449 int x1,
450 int y1,
451 int x2,
452 int y2,
453 bool invert = false,
454 bool onlyDark = false)
293{ 455{
294 std::vector<Tile> temp(map.tiles); 456 Map<MapData> temp(game.map);
295 457
296 for (int y = std::max(y1, 0); y < std::min(y2, VIEW_HEIGHT); y++) 458 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
297 { 459 {
298 for (int x = std::max(x1, 0); x < std::min(x2, VIEW_WIDTH); x++) 460 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
299 { 461 {
300 if (onlyDark && map.lighting[x+y*VIEW_WIDTH]) 462 if (invert == (x >= x1 && x < x2 && y >= y1 && y < y2))
463 {
464 continue;
465 }
466
467 if (onlyDark && game.map.at(x,y).lit)
301 { 468 {
302 continue; 469 continue;
303 } 470 }
304 471
305 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp) 472 if (game.map.at(x,y).tile == Tile::Lamp)
306 { 473 {
307 continue; 474 continue;
308 } 475 }
309 476
310 int count = 0; 477 int count = 0;
311 478
312 incrementIfSet(map, count, x-1, y-1, VIEW_WIDTH, VIEW_HEIGHT); 479 incrementIfSet(game, count, x-1, y-1);
313 incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT); 480 incrementIfSet(game, count, x-1, y );
314 incrementIfSet(map, count, x-1, y+1, VIEW_WIDTH, VIEW_HEIGHT); 481 incrementIfSet(game, count, x-1, y+1);
315 incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT); 482 incrementIfSet(game, count, x , y-1);
316 incrementIfSet(map, count, x , y , VIEW_WIDTH, VIEW_HEIGHT); 483 incrementIfSet(game, count, x , y );
317 incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT); 484 incrementIfSet(game, count, x , y+1);
318 incrementIfSet(map, count, x+1, y-1, VIEW_WIDTH, VIEW_HEIGHT); 485 incrementIfSet(game, count, x+1, y-1);
319 incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT); 486 incrementIfSet(game, count, x+1, y );
320 incrementIfSet(map, count, x+1, y+1, VIEW_WIDTH, VIEW_HEIGHT); 487 incrementIfSet(game, count, x+1, y+1);
321 488
322 if (count >= 5) 489 if (count >= 5)
323 { 490 {
324 temp[x+VIEW_WIDTH*y] = Tile::Wall; 491 temp.at(x,y).tile = Tile::Wall;
325 } else { 492 } else {
326 temp[x+VIEW_WIDTH*y] = Tile::Floor; 493 temp.at(x,y).tile = Tile::Floor;
327 } 494 }
328 } 495 }
329 } 496 }
330 497
331 map.tiles = temp; 498 game.map = std::move(temp);
332} 499}
333 500
334void movePlayer(int x, int y, Map& map) 501void tick(Game& game, bool onlyDark = false)
335{ 502{
336 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT) && 503 tick(
337 map.tiles[x+VIEW_WIDTH*y] == Tile::Floor) 504 game,
505 game.map.getLeft(),
506 game.map.getTop(),
507 game.map.getRight(),
508 game.map.getBottom(),
509 false,
510 onlyDark);
511}
512
513void movePlayer(Game& game, int x, int y)
514{
515 if (game.map.inBounds(x, y) && game.map.at(x,y).tile == Tile::Floor)
338 { 516 {
339 if (map.tiles[player_x+player_y*VIEW_WIDTH] == Tile::Floor) 517 if (game.map.at(game.player_x, game.player_y).tile == Tile::Floor)
340 { 518 {
341 map.tiles[player_x+player_y*VIEW_WIDTH] = Tile::Dust; 519 game.map.at(game.player_x, game.player_y).tile = Tile::Dust;
520 game.map.at(game.player_x, game.player_y).dustLife = 1;
521 game.numDust++;
342 } 522 }
343 523
344 player_x = x; 524 game.player_x = x;
345 player_y = y; 525 game.player_y = y;
526
527 game.dirtyLighting = true;
346 } 528 }
347} 529}
348 530
349void setIfValid(Map& map, int x, int y, Tile val) 531void recalculateLighting(Game& game, fov_settings_type* fov)
350{ 532{
351 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT)) 533 game.litSpots = 0;
534
535 for (MapData& md : game.map.data())
352 { 536 {
353 map.tiles[x+VIEW_WIDTH*y] = val; 537 md.wasLit = md.lit;
538 md.lit = false;
539 md.visibility = 0.0;
540 md.litTiles.clear();
354 } 541 }
355}
356
357void recalculateLighting(Map& map, fov_settings_type* fov)
358{
359 map.oldLighting = map.lighting;
360 map.lighting = std::vector<bool>(VIEW_WIDTH*VIEW_HEIGHT, false);
361 map.lightStrength = std::vector<double>(VIEW_WIDTH*VIEW_HEIGHT, 0.0);
362 map.lightedSpots = 0;
363 map.lightSource = std::vector<Source>(VIEW_WIDTH*VIEW_HEIGHT, Source::None);
364 542
365 fov_settings_set_opacity_test_function( 543 fov_settings_set_opacity_test_function(
366 fov, 544 fov,
367 [] (void* map, int x, int y) { 545 [] (void* data, int x, int y) {
368 return 546 Game& game = *static_cast<Game*>(data);
369 x >= 0 && 547
370 x < VIEW_WIDTH && 548 return game.map.inBounds(x,y) && game.map.at(x,y).tile == Tile::Wall;
371 y >= 0 &&
372 y < VIEW_HEIGHT &&
373 static_cast<Map*>(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Wall;
374 }); 549 });
375 550
376 fov_settings_set_apply_lighting_function( 551 fov_settings_set_apply_lighting_function(
377 fov, 552 fov,
378 [] (void* map, int x, int y, int dx, int dy, void* source) { 553 [] (void* data, int x, int y, int dx, int dy, void* source) {
379 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT)) 554 Game& game = *static_cast<Game*>(data);
555
556 if (game.map.inBounds(x, y))
380 { 557 {
381 Map& m = *static_cast<Map*>(map); 558 MapData& sourceData = *static_cast<MapData*>(source);
382 if (!m.lighting[x+VIEW_WIDTH*y]) 559 double lightRadius = static_cast<double>(sourceData.lightRadius);
560
561 if (!game.map.at(x,y).lit)
383 { 562 {
384 m.lightedSpots++; 563 game.litSpots++;
385 } 564 }
386 565
387 m.lighting[x+VIEW_WIDTH*y] = true; 566 game.map.at(x,y).lit = true;
388 567
389 m.lightStrength[x+VIEW_WIDTH*y] = std::max( 568 /*game.map.at(x,y).visibility = std::max(
390 m.lightStrength[x+VIEW_WIDTH*y], 569 game.map.at(x,y).visibility,
391 std::pow( 570 std::pow(
392 std::max( 571 std::max(
393 0.0, 572 0.0,
394 1.0 - std::sqrt(dx * dx + dy * dy) / static_cast<double>(RADIUS)), 573 1.0 - std::sqrt(dx * dx + dy * dy) / lightRadius),
395 1.0/3.0)); 574 1.0/3.0));*/
575
576 sourceData.litTiles.emplace(x,y);
396 577
397 Source ls = *static_cast<Source*>(source); 578 //Source ls = *static_cast<Source*>(source);
398 if (static_cast<size_t>(ls) > static_cast<size_t>(m.lightSource[x+VIEW_WIDTH*y])) 579 //if (static_cast<size_t>(ls) > static_cast<size_t>(m.lightSource[x+VIEW_WIDTH*y]))
399 { 580 {
400 //m.lightSource[x+VIEW_WIDTH*y] = ls; 581 //m.lightSource[x+VIEW_WIDTH*y] = ls;
401 } 582 }
402 } 583 }
403 }); 584 });
404 585
405 for (int y = 0; y < VIEW_HEIGHT; y++) 586 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
406 { 587 {
407 for (int x = 0; x < VIEW_WIDTH; x++) 588 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
408 { 589 {
409 Source ls = Source::None; 590 Source ls = Source::None;
591 int lightRadius;
410 592
411 if (player_x == x && player_y == y) 593 if (game.renderPlayer && game.player_x == x && game.player_y == y)
412 { 594 {
413 ls = Source::Player; 595 ls = Source::Player;
414 } else if (map.tiles[x+VIEW_WIDTH*y] == Tile::Dust) 596 lightRadius = RADIUS;
597 } else if (game.map.at(x,y).tile == Tile::Dust)
415 { 598 {
416 ls = Source::Dust; 599 ls = Source::Dust;
417 } else if (map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp) 600 lightRadius = 2;
601 } else if (game.map.at(x,y).tile == Tile::Lamp)
418 { 602 {
419 ls = Source::Lamp; 603 ls = Source::Lamp;
604 lightRadius = RADIUS;
420 } 605 }
421 606
607 game.map.at(x,y).lightType = ls;
608 //game.map.at(x,y).litTiles.clear();
609
422 if (ls != Source::None) 610 if (ls != Source::None)
423 { 611 {
424 fov_circle(fov, static_cast<void*>(&map), static_cast<void*>(&ls), x, y, RADIUS); 612 game.map.at(x,y).lightRadius = lightRadius;
425 613 game.map.at(x,y).litTiles.emplace(x,y);
426 map.lighting[x+VIEW_WIDTH*y] = true; 614
427 map.lightStrength[x+VIEW_WIDTH*y] = 1.0; 615 fov_circle(
428 map.lightSource[x+VIEW_WIDTH*y] = ls; 616 fov,
617 static_cast<void*>(&game),
618 static_cast<void*>(&game.map.at(x,y)),
619 x,
620 y,
621 lightRadius);
622
623 game.map.at(x,y).lit = true;
624 game.map.at(x,y).visibility = 1.0;
429 } 625 }
430 } 626 }
431 } 627 }
628
629 game.dirtyLighting = false;
432} 630}
433 631
434void processKeys(Map& map, const Input& keystate) 632void processKeys(Game& game, const Input& keystate)
435{ 633{
436 int px = player_x; 634 int px = game.player_x;
437 int py = player_y; 635 int py = game.player_y;
438 636
439 if (keystate.up) 637 if (keystate.up)
440 { 638 {
@@ -456,12 +654,164 @@ void processKeys(Map& map, const Input& keystate)
456 px++; 654 px++;
457 } 655 }
458 656
459 if (!(player_x == px && player_y == py)) 657 if (!(game.player_x == px && game.player_y == py))
460 { 658 {
461 movePlayer(px, py, map); 659 movePlayer(game, px, py);
462 } 660 }
463} 661}
464 662
663void kickUpDust(Game& game, int x, int y, size_t chain)
664{
665 Kickup dk;
666 dk.x = x;
667 dk.y = y;
668 dk.chain = chain;
669 dk.cur = 0;
670 dk.radius = RADIUS + (chain + 1) * (chain + 1);
671 dk.front.emplace(x, y);
672 dk.done.emplace(x, y);
673
674 game.kickups.push_back(dk);
675}
676
677void popLamp(Game& game, int x, int y, size_t chain)
678{
679 if (game.map.at(x,y).tile == Tile::Lamp)
680 {
681 game.numLamps--;
682 }
683
684 game.map.at(x,y).tile = Tile::Dust;
685 game.map.at(x,y).dustLife = 2;
686 game.numDust++;
687 game.dirtyLighting = true;
688
689 kickUpDust(game, x, y, chain);
690}
691
692void processKickup(Game& game)
693{
694 for (Kickup& kickup : game.kickups)
695 {
696 kickup.cur++;
697
698 std::set<coord> newFront;
699 for (const coord& xy : kickup.front)
700 {
701 auto processDir = [&] (int x, int y) {
702 coord c {x,y};
703
704 if (game.map.inBounds(x,y) &&
705 (game.map.at(x,y).tile == Tile::Floor ||
706 game.map.at(x,y).tile == Tile::Lamp) &&
707 !kickup.done.count(c))
708 {
709 newFront.insert(c);
710 kickup.done.insert(c);
711
712 if (game.map.at(x,y).tile == Tile::Floor)
713 {
714 game.map.at(x,y).tile = Tile::Dust;
715 game.map.at(x,y).dustLife = 2;
716 game.numDust++;
717 game.dirtyLighting = true;
718 } else if (game.map.at(x,y).tile == Tile::Lamp)
719 {
720 popLamp(game, x, y, kickup.chain + 1);
721 }
722 }
723 };
724
725 processDir(std::get<0>(xy) - 1, std::get<1>(xy) );
726 processDir(std::get<0>(xy) + 1, std::get<1>(xy) );
727 processDir(std::get<0>(xy) , std::get<1>(xy) - 1);
728 processDir(std::get<0>(xy) , std::get<1>(xy) + 1);
729
730 if (std::bernoulli_distribution(0.5)(game.rng))
731 {
732 processDir(std::get<0>(xy) - 1, std::get<1>(xy) - 1);
733 }
734
735 if (std::bernoulli_distribution(0.5)(game.rng))
736 {
737 processDir(std::get<0>(xy) - 1, std::get<1>(xy) + 1);
738 }
739
740 if (std::bernoulli_distribution(0.5)(game.rng))
741 {
742 processDir(std::get<0>(xy) + 1, std::get<1>(xy) - 1);
743 }
744
745 if (std::bernoulli_distribution(0.5)(game.rng))
746 {
747 processDir(std::get<0>(xy) + 1, std::get<1>(xy) + 1);
748 }
749 }
750
751 kickup.front.swap(newFront);
752 }
753
754 erase_if(
755 game.kickups,
756 [] (const Kickup& kickup) {
757 return kickup.cur == kickup.radius;
758 });
759}
760
761void growMap(Game& game, size_t zoom)
762{
763 int ol = game.map.getLeft();
764 int ot = game.map.getTop();
765 int ow = game.map.getWidth();
766 int oh = game.map.getHeight();
767
768 game.map.resize(
769 -zoom * ZOOM_X_FACTOR / 2,
770 -zoom * ZOOM_Y_FACTOR / 2,
771 zoom * ZOOM_X_FACTOR,
772 zoom * ZOOM_Y_FACTOR);
773
774 game.maxZoom = zoom;
775
776 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
777 {
778 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
779 {
780 if (!(x >= ol && x < (ol + ow) && y >= ot && y < (ot + oh)))
781 {
782 if (std::bernoulli_distribution(0.5)(game.rng))
783 {
784 game.map.at(x,y).tile = Tile::Wall;
785 }
786 }
787 }
788 }
789
790 for (int i = 0; i < 3; i++)
791 {
792 tick(game, ol, ot, ol + ow, ot + oh, true);
793 }
794}
795
796void setZoom(Game& game, size_t zoom)
797{
798 if (zoom == game.curZoom)
799 {
800 return;
801 }
802
803 if (zoom > game.maxZoom)
804 {
805 growMap(game, zoom);
806 }
807
808 // TODO: don't think this works well with rapid zoom changes
809 game.zoomProgress += (zoom - game.curZoom) * TILE_WIDTH;
810 //game.oldZoom = game.curZoom;
811 game.curZoom = zoom;
812 game.zooming = true;
813}
814
465int main(int, char**) 815int main(int, char**)
466{ 816{
467 std::random_device randomEngine; 817 std::random_device randomEngine;
@@ -498,121 +848,112 @@ int main(int, char**)
498 throw sdl_error(); 848 throw sdl_error();
499 } 849 }
500 850
501 Map map; 851 SDL_SetRenderDrawBlendMode(ren.get(), SDL_BLENDMODE_BLEND);
852
853 Game game(rng);
502 854
503 std::unique_ptr<fov_settings_type> fov(new fov_settings_type()); 855 std::unique_ptr<fov_settings_type> fov(new fov_settings_type());
504 fov_settings_init(fov.get()); 856 fov_settings_init(fov.get());
505 857
506 for (int y = 0; y < VIEW_HEIGHT; y++) 858 for (MapData& md : game.map.data())
507 { 859 {
508 for (int x = 0; x < VIEW_WIDTH; x++) 860 if (std::bernoulli_distribution(0.5)(rng))
509 { 861 {
510 if (std::bernoulli_distribution(0.5)(rng)) 862 md.tile = Tile::Wall;
511 { 863 }
512 map.tiles[x+y*VIEW_WIDTH] = Tile::Wall; 864 }
513 } 865
866 tick(game);
867 tick(game);
868
869 for (int y = -1; y <= 1; y++)
870 {
871 for (int x = -1; x <= 1; x++)
872 {
873 game.map.at(x,y).tile = Tile::Floor;
514 } 874 }
515 } 875 }
516 876
517 tick(map); 877 tick(game);
518 tick(map);
519 tick(map);
520 878
521 bool quit = false; 879 bool quit = false;
880 LoseState losing = LoseState::None;
522 Input keystate; 881 Input keystate;
523 SDL_Event e; 882 SDL_Event e;
883
884 size_t dustDt = 40;
885 size_t dustAcc = 0;
886
887 size_t inputDt = 50;
888 size_t inputAcc = 0;
889
890 size_t losePopLampDt = 800;
891 size_t losePopLampAcc = losePopLampDt;
892
893 size_t losePopPlayerDt = 3000;
894 size_t losePopPlayerAcc = 0;
895
896 size_t zoomDt = 62;
897 size_t zoomAcc = 0;
898
899 size_t lastTime = SDL_GetTicks();
900
524 while (!quit) 901 while (!quit)
525 { 902 {
526 //bool input = false; 903 size_t currentTime = SDL_GetTicks();
527 //int presses = 0; 904 size_t frameTime = currentTime - lastTime;
528 bool pressedSpace = false; 905 lastTime = currentTime;
906
529 while (SDL_PollEvent(&e)) 907 while (SDL_PollEvent(&e))
530 { 908 {
531 if (e.type == SDL_QUIT) 909 if (e.type == SDL_QUIT)
532 { 910 {
533 quit = true; 911 if (losing != LoseState::None)
912 {
913 quit = true;
914 } else {
915 losing = LoseState::PoppingLamps;
916 }
534 } else if (e.type == SDL_KEYDOWN) 917 } else if (e.type == SDL_KEYDOWN)
535 { 918 {
536 //presses++;
537
538 switch (e.key.keysym.sym) 919 switch (e.key.keysym.sym)
539 { 920 {
540 case SDLK_ESCAPE: 921 case SDLK_ESCAPE:
541 { 922 {
542 quit = true; 923 if (losing != LoseState::None)
924 {
925 quit = true;
926 } else {
927 losing = LoseState::PoppingLamps;
928 }
929
543 break; 930 break;
544 } 931 }
545 932
546 case SDLK_SPACE: 933 case SDLK_SPACE:
547 { 934 {
548 pressedSpace = true; 935 if (losing == LoseState::None)
549 //input = true;
550
551 std::deque<std::tuple<int, int>> lamps;
552 lamps.emplace_back(player_x, player_y);
553
554 setIfValid(map, player_x , player_y , Tile::Lamp);
555
556 for (int i = 0; i < 5; i++)
557 {
558 processKeys(map, keystate);
559
560 tick(
561 map,
562 player_x - (RADIUS - 1),
563 player_y - (RADIUS - 1),
564 player_x + RADIUS,
565 player_y + RADIUS);
566
567 render(ren.get(), map, false);
568 SDL_Delay(30);
569 }
570
571 int lamped = 0;
572 while (!lamps.empty())
573 { 936 {
574 lamped++; 937 if (game.map.at(game.player_x, game.player_y).tile ==
575 938 Tile::Floor)
576 int px, py; 939 {
577 std::tie(px, py) = lamps.front(); 940 game.map.at(game.player_x, game.player_y).tile = Tile::Lamp;
578 lamps.pop_front(); 941 game.numLamps++;
579 942 game.dirtyLighting = true;
580 std::unique_ptr<fov_settings_type> dusty(new fov_settings_type); 943 kickUpDust(game, game.player_x, game.player_y, 0);
581 fov_settings_set_opacity_test_function( 944
582 dusty.get(), 945 for (int i = 0; i < 5; i++)
583 [] (void* map, int x, int y) { 946 {
584 return 947 processKeys(game, keystate);
585 x >= 0 && 948
586 x < VIEW_WIDTH && 949 tick(
587 y >= 0 && 950 game,
588 y < VIEW_HEIGHT && 951 game.player_x - (RADIUS - 1),
589 static_cast<Map*>(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Wall; 952 game.player_y - (RADIUS - 1),
590 }); 953 game.player_x + RADIUS,
591 954 game.player_y + RADIUS);
592 fov_settings_set_apply_lighting_function( 955 }
593 dusty.get(), 956 }
594 [] (void* map, int x, int y, int, int, void* source) {
595 Map& m = *static_cast<Map*>(map);
596 auto& lamps = *static_cast<std::deque<std::pair<int, int>>*>(source);
597
598 if ((x >= 0) && (x < VIEW_WIDTH) &&
599 (y >= 0) && (y < VIEW_HEIGHT))
600 {
601 if (m.tiles[x+VIEW_WIDTH*y] == Tile::Floor)
602 {
603 m.tiles[x+VIEW_WIDTH*y] = Tile::Dust;
604 } else if (m.tiles[x+VIEW_WIDTH*y] == Tile::Lamp)
605 {
606 m.tiles[x+VIEW_WIDTH*y] = Tile::Dust;
607 lamps.emplace_back(x, y);
608 }
609 }
610 });
611
612 fov_circle(dusty.get(), static_cast<void*>(&map), static_cast<void*>(&lamps), px, py, RADIUS+lamped*lamped);
613
614 render(ren.get(), map, false);
615 SDL_Delay(50);
616 } 957 }
617 958
618 break; 959 break;
@@ -627,50 +968,164 @@ int main(int, char**)
627 keystate.up = state[SDL_SCANCODE_UP]; 968 keystate.up = state[SDL_SCANCODE_UP];
628 keystate.down = state[SDL_SCANCODE_DOWN]; 969 keystate.down = state[SDL_SCANCODE_DOWN];
629 970
630 bool input = keystate.left || keystate.right || keystate.up || keystate.down || pressedSpace; 971 dustAcc += frameTime;
972 inputAcc += frameTime;
631 973
632 if (input) 974 while (dustAcc >= dustDt)
633 { 975 {
634 for (int y = 0; y < VIEW_HEIGHT; y++) 976 game.numDust = 0;
977
978 for (MapData& md : game.map.data())
635 { 979 {
636 for (int x = 0; x < VIEW_WIDTH; x++) 980 if (md.tile == Tile::Dust)
637 { 981 {
638 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Dust) 982 md.dustLife--;
983
984 if (md.dustLife <= 0)
639 { 985 {
640 map.tiles[x+y*VIEW_WIDTH] = Tile::Floor; 986 md.tile = Tile::Floor;
987 game.dirtyLighting = true;
988 } else {
989 game.numDust++;
641 } 990 }
642 } 991 }
643 } 992 }
993
994 processKickup(game);
995
996 dustAcc -= dustDt;
644 } 997 }
645 998
646 processKeys(map, keystate); 999 switch (losing)
647 recalculateLighting(map, fov.get()); 1000 {
1001 case LoseState::None:
1002 {
1003 while (inputAcc >= inputDt)
1004 {
1005 processKeys(game, keystate);
1006
1007 inputAcc -= inputDt;
1008 }
1009
1010 break;
1011 }
1012
1013 case LoseState::PoppingLamps:
1014 {
1015 if (game.numLamps == 0)
1016 {
1017 if (game.numDust == 0)
1018 {
1019 losing = LoseState::PoppingPlayer;
1020 }
1021 } else {
1022 losePopLampAcc += frameTime;
1023
1024 while (losePopLampAcc >= losePopLampDt)
1025 {
1026 std::vector<std::tuple<int, int>> lamps;
1027
1028 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
1029 {
1030 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
1031 {
1032 if (game.map.at(x,y).tile == Tile::Lamp)
1033 {
1034 lamps.emplace_back(x, y);
1035 }
1036 }
1037 }
1038
1039 std::uniform_int_distribution<int> lampDist(0, lamps.size() - 1);
1040 std::tuple<int, int> popPos = lamps[lampDist(rng)];
1041
1042 popLamp(game, std::get<0>(popPos), std::get<1>(popPos), 1);
1043
1044 losePopLampAcc -= losePopLampDt;
1045 }
1046 }
1047
1048 break;
1049 }
648 1050
649 if (input) 1051 case LoseState::PoppingPlayer:
1052 {
1053 losePopPlayerAcc += frameTime;
1054
1055 if (losePopPlayerAcc >= losePopPlayerDt)
1056 {
1057 popLamp(game, game.player_x, game.player_y, 10);
1058 game.renderPlayer = false;
1059
1060 losing = LoseState::Outro;
1061 }
1062
1063 break;
1064 }
1065
1066 case LoseState::Outro:
1067 {
1068 if (game.numDust == 0)
1069 {
1070 quit = true;
1071 }
1072
1073 break;
1074 }
1075 }
1076
1077 if (game.dirtyLighting)
650 { 1078 {
651 for (int y = 0; y < VIEW_HEIGHT; y++) 1079 recalculateLighting(game, fov.get());
1080
1081 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
652 { 1082 {
653 for (int x = 0; x < VIEW_WIDTH; x++) 1083 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
654 { 1084 {
655 if (!map.lighting[x+y*VIEW_WIDTH] && map.oldLighting[x+y*VIEW_WIDTH]) 1085 if (!game.map.at(x,y).lit && game.map.at(x,y).wasLit)
656 { 1086 {
657 if (std::bernoulli_distribution(0.5)(rng)) 1087 if (std::bernoulli_distribution(0.5)(rng))
658 { 1088 {
659 map.tiles[x+y*VIEW_WIDTH] = Tile::Wall; 1089 game.map.at(x,y).tile = Tile::Wall;
660 } else { 1090 } else {
661 map.tiles[x+y*VIEW_WIDTH] = Tile::Floor; 1091 game.map.at(x,y).tile = Tile::Floor;
662 } 1092 }
663 } 1093 }
664 } 1094 }
665 } 1095 }
666 1096
667 tick(map, 0, 0, VIEW_WIDTH, VIEW_HEIGHT, true); 1097 tick(game, true);
668 tick(map, 0, 0, VIEW_WIDTH, VIEW_HEIGHT, true); 1098 tick(game, true);
669 tick(map, 0, 0, VIEW_WIDTH, VIEW_HEIGHT, true); 1099 tick(game, true);
1100
1101 // TODO: better zoom algorithm
1102 setZoom(game, game.litSpots / 1500 * 2 + INIT_ZOOM);
670 } 1103 }
671 1104
672 render(ren.get(), map, true); 1105 zoomAcc += frameTime;
673 SDL_Delay(50); 1106
1107 while (zoomAcc >= zoomDt)
1108 {
1109 if (game.zooming)
1110 {
1111 if (game.zoomProgress > 0)
1112 {
1113 game.zoomProgress--;
1114 } else if (game.zoomProgress < 0)
1115 {
1116 game.zoomProgress++;
1117 }
1118
1119 if (game.zoomProgress == 0)
1120 {
1121 game.zooming = false;
1122 }
1123 }
1124
1125 zoomAcc -= zoomDt;
1126 }
1127
1128 render(ren.get(), game, true);
674 } 1129 }
675 } catch (const sdl_error& ex) 1130 } catch (const sdl_error& ex)
676 { 1131 {
@@ -681,4 +1136,4 @@ int main(int, char**)
681 SDL_Quit(); 1136 SDL_Quit();
682 1137
683 return 0; 1138 return 0;
684} \ No newline at end of file 1139}
diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..329553c --- /dev/null +++ b/src/map.h
@@ -0,0 +1,127 @@
1#ifndef MAP_H_3AB00D12
2#define MAP_H_3AB00D12
3
4#include <vector>
5#include <algorithm>
6
7template <typename T>
8class Map {
9public:
10
11 Map(
12 int left,
13 int top,
14 int width,
15 int height) :
16 left_(left),
17 top_(top),
18 width_(width),
19 height_(height),
20 data_(width_*height_)
21 {
22 }
23
24 inline int getLeft() const
25 {
26 return left_;
27 }
28
29 inline int getRight() const
30 {
31 return left_ + width_;
32 }
33
34 inline int getTop() const
35 {
36 return top_;
37 }
38
39 inline int getBottom() const
40 {
41 return top_ + height_;
42 }
43
44 inline int getWidth() const
45 {
46 return width_;
47 }
48
49 inline int getHeight() const
50 {
51 return height_;
52 }
53
54 inline int getTrueX(int x) const
55 {
56 return (x - left_);
57 }
58
59 inline int getTrueY(int y) const
60 {
61 return (y - top_);
62 }
63
64 inline bool inBounds(int x, int y) const
65 {
66 return (x >= left_) &&
67 (x < left_ + width_) &&
68 (y >= top_) &&
69 (y < top_ + height_);
70 }
71
72 inline const T& at(int x, int y) const
73 {
74 return data_.at((x - left_) + width_ * (y - top_));
75 }
76
77 inline T& at(int x, int y)
78 {
79 return const_cast<T&>(static_cast<const Map&>(*this).at(x, y));
80 }
81
82 inline const std::vector<T>& data() const
83 {
84 return data_;
85 }
86
87 inline std::vector<T>& data()
88 {
89 return data_;
90 }
91
92 void resize(int newLeft, int newTop, int newWidth, int newHeight)
93 {
94 std::vector<T> newData(newWidth * newHeight);
95
96 int winTop = std::max(top_, newTop);
97 int winBottom = std::min(top_ + height_, newTop + newHeight);
98 int winLeft = std::max(left_, newLeft);
99 int winRight = std::min(left_ + width_, newLeft + newWidth);
100
101 for (int y = winTop; y < winBottom; y++)
102 {
103 std::move(
104 std::next(std::begin(data_), (winLeft - left_) + width_ * (y - top_)),
105 std::next(std::begin(data_), (winRight - left_) + width_ * (y - top_)),
106 std::next(std::begin(newData),
107 (winLeft - newLeft) + newWidth * (y - newTop)));
108 }
109
110 left_ = newLeft;
111 top_ = newTop;
112 width_ = newWidth;
113 height_ = newHeight;
114 data_.swap(newData);
115 }
116
117private:
118
119 int left_;
120 int top_;
121 int width_;
122 int height_;
123
124 std::vector<T> data_;
125};
126
127#endif /* end of include guard: MAP_H_3AB00D12 */
diff --git a/src/untitled.txt b/src/untitled.txt deleted file mode 100644 index e69de29..0000000 --- a/src/untitled.txt +++ /dev/null
diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..150a6a5 --- /dev/null +++ b/src/util.h
@@ -0,0 +1,20 @@
1#ifndef UTIL_H_E9110D4C
2#define UTIL_H_E9110D4C
3
4template <typename Container, typename Predicate>
5void erase_if(Container& items, const Predicate& predicate)
6{
7 for (auto it = std::begin(items); it != std::end(items);)
8 {
9 if (predicate(*it))
10 {
11 it = items.erase(it);
12 }
13 else
14 {
15 ++it;
16 }
17 }
18};
19
20#endif /* end of include guard: UTIL_H_E9110D4C */