Back

play.c coverage

overall coverage: 43.1%

line# code(run#)
1 #include "play.h"
2 #include "file.h"
3 #include "input.h"
4 #include "coordinates.h"
5 #include "tiles.h"
6
7 #include <SDL.h>
8 #include <SDL_image.h>
9 #include <SDL_ttf.h>
10 #include <stdbool.h>
11
12 #include "debugmalloc.h"
13
14 typedef struct PlayState
15 {
16 Level *firstLevel;
17 Level *level;
18 Level *backupLevel;
19 Coordinates player;
20 int result;
21 bool ctrl;
22 bool edited;
23 bool finished;
24 bool unsaved;
25 char *filename;
26 SDL_Renderer *renderer;
27 SDL_Texture *tiles;
28 TTF_Font *font;
29 } PlayState;
30
31 // Convert ot tileState to tile
32 // Returns brown floor on error
33 static Tile tileStateToTile(TileState state)(30)
34 {
35 switch (state)(30)
36 {
37 case wallS:(24)
38 return wall;(24)
39 case playerS:(0)
40 return player;(0)
41 case playerOnTargetS:(0)
42 return player;(0)
43 case crateS:(1)
44 return crate;(1)
45 case crateOnTargetS:(1)
46 return crateOnTarget;(1)
47 case targetS:(1)
48 return target;(1)
49 case floorTileS:(3)
50 return brownFloor;(3)
51 default:(0)
52 return brownFloor;(0)
53 }
54 }
55
56 // Get tile at coordinates
57 // Returns invalidS for tiles outside of play area
58 static TileState getTileState(Level *level, int x, int y)(20)
59 {
60 if (x < 0 || y < 0 || x >= level->size.x || y >= level->size.y)(20)
61 {
62 return invalidS;(0)
63 }
64 return level->tiles[x + y * level->size.x];(20)
65 }
66
67 // Set state of tile at coordinates
68 // Does nothing for tiles outside of play area
69 static void setTileState(Level *level, int x, int y, TileState state)(3)
70 {
71 if (x < 0 || y < 0 || x >= level->size.x || y >= level->size.y)(3)
72 {
73 return;(0)
74 }
75 level->tiles[x + y * level->size.x] = state;(3)
76 }
77
78 // Render current state of play to renderer
79 // State must include proper renderer, tiles, and font
80 static void render(PlayState *state)(2)
81 {
82 // easier to work with variables this way
83 SDL_Renderer *renderer = state->renderer;(2)
84 SDL_Texture *tiles = state->tiles;(2)
85 TTF_Font *font = state->font;(2)
86 Level *level = state->level;(2)
87
88 SDL_RenderClear(renderer);(2)
89
90 SDL_Color white = {255, 255, 255};(2)
91
92 // start positions for level to center it on screen
93 int startX = 1 + (19 - level->size.x) / 2;(2)
94 int startY = 0 + (11 - level->size.y) / 2;(2)
95
96 renderTiles(renderer, tiles, state->finished ? greenFloor : greyFloor, 0, 0, 19, 11); // background for entire window, based on level finishedness(2)
97 renderTiles(renderer, tiles, brownFloor, startX, startY, startX + level->size.x - 1, startY + level->size.y - 1); // background for level area(2)
98
99 for (int i = 0; i < level->size.x; i++) // render tiles except floors(12)
100 {
101 for (int j = 0; j < level->size.y; j++)(40)
102 {
103 Tile tile = tileStateToTile(level->tiles[i + j * level->size.x]);(30)
104 if (tile != brownFloor)(30)
105 renderTile(renderer, tiles, tile, startX + i, startY + j);(27)
106 }
107 }
108
109 // render player
110 renderTile(renderer, tiles, player, state->player.x + startX, state->player.y + startY);(2)
111
112 // control buttons
113 renderTile(renderer, tiles, home, 0, 0);(2)
114 renderTile(renderer, tiles, retry, 0, 1);(2)
115 renderTile(renderer, tiles, save, 0, 2);(2)
116
117 // player control buttons
118 renderTile(renderer, tiles, up, 0, 6);(2)
119 renderTile(renderer, tiles, left, 0, 7);(2)
120 renderTile(renderer, tiles, right, 0, 8);(2)
121 renderTile(renderer, tiles, down, 0, 9);(2)
122
123 if (state->level->prev != NULL) // prevoius button is previous level exists(2)
124 renderTile(renderer, tiles, left, 0, 11);(0)
125 renderFont(renderer, font, white, level->name, 10, 11, true, true); // level name(2)
126 if (state->level->next != NULL) // next button in next level exists(2)
127 renderTile(renderer, tiles, right, 19, 11);(2)
128
129 SDL_RenderPresent(renderer); // render creation(2)
130 }(2)
131
132 // Check if all targets are covered by crates
133 // Returns true if ^ true
134 static bool checkFinished(PlayState *state)(2)
135 {
136 for (int i = 0; i < state->level->size.x * state->level->size.y; i++)(25)
137 {
138 TileState tile = state->level->tiles[i];(24)
139 if (tile == targetS)(24)
140 {
141 return false;(1)
142 }
143 }
144 return true;(1)
145 }
146
147 // Fill current game state with level data
148 // This is for resetting a level
149 static bool fillState(PlayState *state, Level *level)(1)
150 {
151 if (state->level != NULL) // free level if one is loaded(1)
152 {
153 free(state->level->tiles);(0)
154 free(state->level);(0)
155 }
156
157 state->level = (Level *)malloc(sizeof(Level)); // allocate memory for each component that could change(1)
158 if (state->level == NULL)(1)
159 return false;(0)
160 memcpy(state->level, level, sizeof(Level)); // copy data(1)
161
162 state->level->tiles = (TileState *)malloc(sizeof(TileState) * (level->size.x * level->size.y));(1)
163 if (state->level->tiles == NULL)(1)
164 return false;(0)
165 memcpy(state->level->tiles, level->tiles, sizeof(TileState) * (level->size.x * level->size.y));(1)
166
167 state->backupLevel = level; // store original level pointer(1)
168
169 for (int i = 0; i < level->size.x; i++) // extract player position and change tile under player(6)
170 {
171 for (int j = 0; j < level->size.y; j++)(20)
172 {
173 TileState tile = getTileState(level, i, j);(15)
174 if (tile == playerS || tile == playerOnTargetS)(15)
175 {
176 state->player.x = i;(1)
177 state->player.y = j;(1)
178 setTileState(state->level, i, j, tile == playerS ? floorTileS : targetS);(1)
179 }
180 }
181 }
182
183 state->edited = false;(1)
184 state->finished = checkFinished(state); // chack is level has alerady been finished(1)
185
186 return true;(1)
187 }
188
189 // Copy level data from state to level pointer
190 // Does not modify data in current state, only overwrites level pointer data
191 static void writeState(PlayState *state)(1)
192 {
193 if (state->backupLevel == NULL) // cant save to no level(1)
194 return;(0)
195
196 memcpy(state->backupLevel->tiles, state->level->tiles, sizeof(TileState) * (state->level->size.x * state->level->size.y)); // copy data(1)
197 TileState *currentPlayerPos = state->backupLevel->tiles + state->player.x + state->player.y * state->backupLevel->size.x; // transfer player position too(1)
198 if (*currentPlayerPos == targetS)(1)
199 *currentPlayerPos = playerOnTargetS;(0)
200 else
201 *currentPlayerPos = playerS;(1)
202 state->edited = false;(1)
203 }
204
205 // Save current levels to file
206 // Warns user in case of saving error
207 // Sets sate->result according to user popup state
208 static void saveState(PlayState *state)(0)
209 {
210 writeState(state);(0)
211 state->edited = false;(0)
212 int result = textInput(state->renderer, state->tiles, state->font, "File neve", state->filename, 63);(0)
213 if (result == 0)(0)
214 {
215 state->result = 0;(0)
216 return;(0)
217 }
218 if (result == 2)(0)
219 return;(0)
220
221 bool saveSuccess = saveLevel(state->firstLevel, state->filename);(0)
222 if (saveSuccess)(0)
223 {
224 state->unsaved = false;(0)
225 if (alertBox(state->renderer, state->tiles, state->font, "Sikeres mentés!") == 0)(0)
226 state->result = 0;(0)
227 }
228 else if (alertBox(state->renderer, state->tiles, state->font, "Sikertelen mentés") == 0)(0)
229 state->result = 0;(0)
230 }
231
232 // Free memory used by level state storage
233 // Does not set level pointer to null (even though it should)
234 static void freeState(PlayState *state)(1)
235 {
236 if (state->level != NULL)(1)
237 {
238 free(state->level->tiles);(1)
239 free(state->level);(1)
240 }
241 }(1)
242
243 // Prompt player to save data or discard
244 // Returns false on SDL_Quit event
245 static bool promptEdit(PlayState *state)(0)
246 {
247 int result = dialogBox(state->renderer, state->tiles, state->font, "Szeretnéd eltárolni a módosításaidat?");(0)
248 if (result == 0)(0)
249 {
250 state->result = 0;(0)
251 return false;(0)
252 }
253 if (result == 1)(0)
254 writeState(state);(0)
255 return true;(0)
256 }
257
258 // Loads next level to state
259 // Prompts player if works should be stored
260 static void nextLevel(PlayState *state)(0)
261 {
262 if (state->edited && !state->finished)(0)
263 {
264 if (!promptEdit(state))(0)
265 return;(0)
266 }
267 if (state->level->next != NULL)(0)
268 {
269 Level *nextLevel = state->level->next;(0)
270 fillState(state, nextLevel);(0)
271 }
272 }
273
274 // Loads prevoius level to state
275 // Prompts player if works should be stored
276 static void prevLevel(PlayState *state)(0)
277 {
278 if (state->edited && !state->finished)(0)
279 {
280 if (!promptEdit(state))(0)
281 return;(0)
282 }
283 if (state->level->prev != NULL)(0)
284 {
285 Level *prevLevel = state->level->prev;(0)
286 fillState(state, prevLevel);(0)
287 }
288 }
289
290 // Check validity of levels
291 // Checks number of players and crate count and target count relation
292 // Returns true if all levels are valid
293 static bool checkLevels(Level *level)(1)
294 {
295
296 while (level != NULL)(6)
297 {
298 int playerCount = 0;(5)
299 int crateCount = 0;(5)
300 int targetCount = 0;(5)
301 for (int i = 0; i < level->size.x * level->size.y; i++)(144)
302 {
303 if (level->tiles[i] == playerS || level->tiles[i] == playerOnTargetS)(139)
304 {
305 playerCount++;(5)
306 }
307 if (level->tiles[i] == crateS || level->tiles[i] == crateOnTargetS)(139)
308 {
309 crateCount++;(9)
310 }
311 if (level->tiles[i] == targetS || level->tiles[i] == crateOnTargetS || level->tiles[i] == playerOnTargetS)(139)
312 {
313 targetCount++;(9)
314 }
315 }
316 if (playerCount != 1 || crateCount < targetCount)(5)
317 {
318 return false;(0)
319 }
320 level = level->next;(5)
321 }
322 return true;(1)
323 }
324
325 // Check if current level is in a win state
326 // Win state is when all targets are covered by crates
327 // Prompts player on this event
328 // Returns nothing
329 // Use checkFinished for most cases
330 static void checkWinState(PlayState *state)(1)
331 {
332 if (checkFinished(state))(1)
333 {
334 state->finished = true;(1)
335 writeState(state);(1)
336 if (alertBox(state->renderer, state->tiles, state->font, "Sikeresen tejesítetted a pályát!") == 0)(1)
337 state->result = 0;(0)
338 }
339 }(1)
340
341 // Move player left
342 // Returns true if rerender is needed
343 static bool moveLeft(PlayState *state)(0)
344 {
345 Coordinates *player = &state->player;(0)
346 if (getTileState(state->level, player->x - 1, player->y) == crateS ||(0)
347 getTileState(state->level, player->x - 1, player->y) == crateOnTargetS) // crate in front of player(0)
348 {
349 if (getTileState(state->level, player->x - 2, player->y) == floorTileS ||(0)
350 getTileState(state->level, player->x - 2, player->y) == targetS) // crate can move(0)
351 {
352 if (getTileState(state->level, player->x - 1, player->y) == crateS) // crate not on target(0)
353 setTileState(state->level, player->x - 1, player->y, floorTileS); // replace crate with floor(0)
354 else
355 setTileState(state->level, player->x - 1, player->y, targetS); // replace player with target(0)
356 if (getTileState(state->level, player->x - 2, player->y) == floorTileS) // crate going to be on floor(0)
357 setTileState(state->level, player->x - 2, player->y, crateS); // replace with crate(0)
358 else
359 setTileState(state->level, player->x - 2, player->y, crateOnTargetS); // replace with crate on target(0)
360 player->x--; // move player(0)
361 checkWinState(state);(0)
362 return true;(0)
363 }
364 return false;(0)
365 }
366 if (getTileState(state->level, player->x - 1, player->y) == floorTileS ||(0)
367 getTileState(state->level, player->x - 1, player->y) == targetS) // player can move(0)
368 {
369 player->x--; // move player(0)
370 return true;(0)
371 }
372 return false;(0)
373 }
374
375 // Move player up
376 // Returns true if rerender is needed
377 static bool moveUp(PlayState *state)(0)
378 {
379 Coordinates *player = &state->player;(0)
380 if (getTileState(state->level, player->x, player->y - 1) == crateS ||(0)
381 getTileState(state->level, player->x, player->y - 1) == crateOnTargetS) // crate in front of player(0)
382 {
383 if (getTileState(state->level, player->x, player->y - 2) == floorTileS ||(0)
384 getTileState(state->level, player->x, player->y - 2) == targetS) // crate can move(0)
385 {
386 if (getTileState(state->level, player->x, player->y - 1) == crateS) // crate not on target(0)
387 setTileState(state->level, player->x, player->y - 1, floorTileS); // replace crate with floor(0)
388 else
389 setTileState(state->level, player->x, player->y - 1, targetS); // replace player with target(0)
390 if (getTileState(state->level, player->x, player->y - 2) == floorTileS) // crate going to be on floor(0)
391 setTileState(state->level, player->x, player->y - 2, crateS); // replace with crate(0)
392 else
393 setTileState(state->level, player->x, player->y - 2, crateOnTargetS); // replace with crate on target(0)
394 player->y--; // move player(0)
395 checkWinState(state);(0)
396 return true;(0)
397 }
398 return false;(0)
399 }
400 if (getTileState(state->level, player->x, player->y - 1) == floorTileS ||(0)
401 getTileState(state->level, player->x, player->y - 1) == targetS) // player can move(0)
402 {
403 player->y--; // move player(0)
404 return true;(0)
405 }
406 return false;(0)
407 }
408
409 // Move player right
410 // Returns true if rerender is needed
411 static bool moveRight(PlayState *state)(1)
412 {
413 Coordinates *player = &state->player;(1)
414 if (getTileState(state->level, player->x + 1, player->y) == crateS ||(1)
415 getTileState(state->level, player->x + 1, player->y) == crateOnTargetS) // crate in front of player(0)
416 {
417 if (getTileState(state->level, player->x + 2, player->y) == floorTileS ||(2)
418 getTileState(state->level, player->x + 2, player->y) == targetS) // crate can move(1)
419 {
420 if (getTileState(state->level, player->x + 1, player->y) == crateS) // crate not on target(1)
421 setTileState(state->level, player->x + 1, player->y, floorTileS); // replace crate with floor(1)
422 else
423 setTileState(state->level, player->x + 1, player->y, targetS); // replace player with target(0)
424 if (getTileState(state->level, player->x + 2, player->y) == floorTileS) // crate going to be on floor(1)
425 setTileState(state->level, player->x + 2, player->y, crateS); // replace with crate(0)
426 else
427 setTileState(state->level, player->x + 2, player->y, crateOnTargetS); // replace with crate on target(1)
428 player->x++; // move player(1)
429 checkWinState(state);(1)
430 return true;(1)
431 }
432 return false;(0)
433 }
434 if (getTileState(state->level, player->x + 1, player->y) == floorTileS ||(0)
435 getTileState(state->level, player->x + 1, player->y) == targetS) // player can move(0)
436 {
437 player->x++; // move player(0)
438 return true;(0)
439 }
440 return false;(0)
441 }
442
443 // Move player down
444 // Returns true if rerender is needed
445 static bool moveDown(PlayState *state)(0)
446 {
447 Coordinates *player = &state->player;(0)
448 if (getTileState(state->level, player->x, player->y + 1) == crateS ||(0)
449 getTileState(state->level, player->x, player->y + 1) == crateOnTargetS) // crate in front of player(0)
450 {
451 if (getTileState(state->level, player->x, player->y + 2) == floorTileS ||(0)
452 getTileState(state->level, player->x, player->y + 2) == targetS) // crate can move(0)
453 {
454 if (getTileState(state->level, player->x, player->y + 1) == crateS) // crate not on target(0)
455 setTileState(state->level, player->x, player->y + 1, floorTileS); // replace crate with floor(0)
456 else
457 setTileState(state->level, player->x, player->y + 1, targetS); // replace player with target(0)
458 if (getTileState(state->level, player->x, player->y + 2) == floorTileS) // crate going to be on floor(0)
459 setTileState(state->level, player->x, player->y + 2, crateS); // replace with crate(0)
460 else
461 setTileState(state->level, player->x, player->y + 2, crateOnTargetS); // replace with crate on target(0)
462 player->y++; // move player(0)
463 checkWinState(state);(0)
464 return true;(0)
465 }
466 return false;(0)
467 }
468 if (getTileState(state->level, player->x, player->y + 1) == floorTileS ||(0)
469 getTileState(state->level, player->x, player->y + 1) == targetS) // player can move(0)
470 {
471 player->y++; // move player(0)
472 return true;(0)
473 }
474 return false;(0)
475 }
476
477 // Process player movement
478 // Direction: 0 - left, 1 - up, 2 - right, 3 - down
479 // Returns true if rerender is needed
480 static bool processMovement(int dir, PlayState *state)(1)
481 {
482 state->edited = true;(1)
483 state->unsaved = true;(1)
484
485 switch (dir)(1)
486 {
487 case 0: // left(0)
488 return moveLeft(state);(0)
489 case 1: // up(0)
490 return moveUp(state);(0)
491 case 2: // right(1)
492 return moveRight(state);(1)
493 case 3: // down(0)
494 return moveDown(state);(0)
495 default:(0)
496 return false;(0)
497 }
498 }
499
500 // Handle exit to menu
501 // Prompts player is work is nusaved, does not save work for player
502 // Sets state->reuslt according to user input
503 static void handleExitToMenu(PlayState *state)(1)
504 {
505 if (state->unsaved)(1)
506 {
507 int dialogResult = dialogBox(state->renderer, state->tiles, state->font, "Biztosan szeretnél mentés nélkül kilépni?");(1)
508 if (dialogResult == 0)(1)
509 {
510 state->result = 0;(0)
511 }
512 if (dialogResult == 1)(1)
513 {
514 state->result = 1;(1)
515 }
516 }
517 else
518 {
519 state->result = 1;(0)
520 }
521 }(1)
522
523 // Handle SDL key down event
524 // Returns true if erernder is needed
525 static bool handleKeydown(PlayState *state, SDL_Scancode key)(2)
526 {
527 switch (key)(2)
528 {
529 case 0x50: // left arrow(0)
530 case 0x04: // letter A
531 if (state->ctrl)(0)
532 return false;(0)
533 return processMovement(0, state);(0)
534 case 0x52: // up arrow(0)
535 case 0x1A: // letter W
536 if (state->ctrl)(0)
537 return false;(0)
538 return processMovement(1, state);(0)
539 case 0x4F: // right arrow(1)
540 case 0x07: // letter D
541 if (state->ctrl)(1)
542 return false;(0)
543 return processMovement(2, state);(1)
544 case 0x51: // down arrow(0)
545 case 0x16: // letter S
546 if (state->ctrl)(0)
547 {
548 saveState(state);(0)
549 state->ctrl = false;(0)
550 return true;(0)
551 }
552 return processMovement(3, state);(0)
553 case 0x15: // letter r(0)
554 if (!state->ctrl)(0)
555 return false;(0)
556 fillState(state, state->backupLevel);(0)
557 return true;(0)
558 case 0x29: // esc(1)
559 if (state->ctrl)(1)
560 return false;(0)
561 handleExitToMenu(state);(1)
562 return true;(1)
563 case 0x4b: // page up(0)
564 if (state->ctrl)(0)
565 return false;(0)
566 nextLevel(state);(0)
567 return true;(0)
568 case 0x4e: // page down(0)
569 if (state->ctrl)(0)
570 return false;(0)
571 prevLevel(state);(0)
572 return true;(0)
573 case 0xe0: // left ctrl(0)
574 case 0xe4: // right ctrl
575 state->ctrl = true;(0)
576 return false;(0)
577 default:(0)
578 //printf("0x%02x\n", event.key.keysym.scancode);
579 return false;(0)
580 }
581 }
582
583 // Handle SDL key down up
584 // Returns true if erernder is needed
585 static bool handleKeyup(PlayState *state, SDL_Scancode key)(2)
586 {
587 switch (key)(2)
588 {
589 case 0xe0: // left ctrl(0)
590 case 0xe4: // right ctrl
591 state->ctrl = false;(0)
592 return false;(0)
593 default:(2)
594 return false;(2)
595 }
596 }
597
598 // Handle SDL mouse click
599 // Returns true if erernder is needed
600 static bool handleClick(PlayState *state, int x, int y)(0)
601 {
602 if (clickTile(0, 6, x, y)) // up(0)
603 return processMovement(1, state);(0)
604 if (clickTile(0, 9, x, y)) // down(0)
605 return processMovement(3, state);(0)
606 if (clickTile(0, 7, x, y)) // left(0)
607 return processMovement(0, state);(0)
608 if (clickTile(0, 8, x, y)) // right(0)
609 return processMovement(2, state);(0)
610 if (clickTile(0, 0, x, y))(0)
611 { // back to main menu
612 handleExitToMenu(state);(0)
613 return true;(0)
614 }
615 if (clickTile(0, 1, x, y)) // restart level(0)
616 {
617 fillState(state, state->backupLevel);(0)
618 return true;(0)
619 }
620 if (clickTile(0, 2, x, y)) // save level(0)
621 {
622 saveState(state);(0)
623 return true;(0)
624 }
625 if (clickTile(0, 11, x, y)) // previouse level(0)
626 {
627 prevLevel(state);(0)
628 return true;(0)
629 }
630 if (clickTile(19, 11, x, y)) // next level(0)
631 {
632 nextLevel(state);(0)
633 return true;(0)
634 }
635 return false;(0)
636 }
637
638 // Handles SDL event
639 // Returns true if rerender is needed
640 static bool handleEvent(SDL_Event event, PlayState *state)(4)
641 {
642 switch (event.type)(4)
643 {
644 case SDL_KEYDOWN:(2)
645 return handleKeydown(state, event.key.keysym.scancode);(2)
646 case SDL_KEYUP:(2)
647 return handleKeyup(state, event.key.keysym.scancode);(2)
648 case SDL_MOUSEBUTTONDOWN:(0)
649 return handleClick(state, event.button.x, event.button.y);(0)
650 case SDL_QUIT: // exit program(0)
651 state->result = 0;(0)
652 return false;(0)
653 default:(0)
654 return false;(0)
655 break;
656 }
657 }
658
659 // Load and play levels given in file
660 // Returns 0 on SDL_Quit, 1 on exit to menu
661 int playLevel(SDL_Renderer *renderer, SDL_Texture *tiles, TTF_Font *font, char *filename)(1)
662 {
663 LoadLevelResult result = loadLevel(filename);(1)
664 switch (result.result)(1)
665 {
666 case 1:(0)
667 unloadLevel(result.level);(0)
668 return alertBox(renderer, tiles, font, "Nem lehet megnyitni a fájlt");(1)
669 break;
670 case 2:(0)
671 unloadLevel(result.level);(0)
672 return alertBox(renderer, tiles, font, "Memóriafoglalási hiba");(0)
673 break;
674 case 3:(0)
675 unloadLevel(result.level);(0)
676 return alertBox(renderer, tiles, font, "A fájl hibás karaktereket tartalmaz");(0)
677 break;
678 case 4:(0)
679 switch (dialogBox(renderer, tiles, font, "Néhány szint túl nagy. Biztosan megnyitod?"))(0)
680 {
681 case 0:(0)
682 unloadLevel(result.level);(0)
683 return 0;(0)
684 break;
685 case 1:(0)
686 break;(0)
687 case 2:(0)
688 unloadLevel(result.level);(0)
689 return 1;(0)
690 break;
691 default:(0)
692 break;(0)
693 }
694 default:(1)
695 break;(1)
696 }
697
698 if (result.level == NULL)(1)
699 {
700 return alertBox(renderer, tiles, font, "A fájl nem tartalmaz szinteket");(0)
701 }
702 if (!checkLevels(result.level))(1)
703 {
704 unloadLevel(result.level);(0)
705 return alertBox(renderer, tiles, font, "Néhány szint hibás");(0)
706 }
707
708 PlayState state;
709 state.level = NULL;(1)
710 state.firstLevel = result.level;(1)
711 if (!fillState(&state, result.level))(1)
712 {
713 unloadLevel(result.level);(0)
714 return alertBox(renderer, tiles, font, "Memóriafoglalási hiba");(0)
715 }
716 state.result = -1;(1)
717 state.renderer = renderer;(1)
718 state.tiles = tiles;(1)
719 state.font = font;(1)
720 state.ctrl = false;(1)
721 state.unsaved = false;(1)
722 state.filename = filename;(1)
723
724 render(&state);(1)
725
726 SDL_Event ev;
727 while (SDL_WaitEvent(&ev))(4)
728 {
729 bool rerender = handleEvent(ev, &state);(4)
730 if (state.result != -1) // if result was set(4)
731 {
732 unloadLevel(result.level);(1)
733 freeState(&state);(1)
734 return state.result; // return to main(1)
735 }
736 if (rerender) // if rerender is needed(3)
737 render(&state);(1)
738 }
739 }(0)