]> git.lizzy.rs Git - nothing.git/blob - src/game.c
(#59) Implement procedurally generated background
[nothing.git] / src / game.c
1 #include <SDL2/SDL.h>
2 #include <SDL2/SDL_mixer.h>
3 #include <assert.h>
4 #include <stdio.h>
5
6 #include "game.h"
7 #include "game/level.h"
8 #include "game/sound_medium.h"
9 #include "system/error.h"
10 #include "system/lt.h"
11
12 typedef enum game_state_t {
13     GAME_STATE_RUNNING = 0,
14     GAME_STATE_PAUSE,
15     GAME_STATE_QUIT,
16
17     GAME_STATE_N
18 } game_state_t;
19
20 typedef struct game_t {
21     lt_t *lt;
22
23     game_state_t state;
24     level_t *level;
25     char *level_file_path;
26     sound_medium_t *sound_medium;
27 } game_t;
28
29 game_t *create_game(const char *level_file_path, sound_medium_t *sound_medium)
30 {
31     assert(level_file_path);
32
33     lt_t *const lt = create_lt();
34     if (lt == NULL) {
35         return NULL;
36     }
37
38     game_t *game = PUSH_LT(lt, malloc(sizeof(game_t)), free);
39     if (game == NULL) {
40         throw_error(ERROR_TYPE_LIBC);
41         RETURN_LT(lt, NULL);
42     }
43
44     game->level = PUSH_LT(
45         lt,
46         create_level_from_file(level_file_path),
47         destroy_level);
48     if (game->level == NULL) {
49         RETURN_LT(lt, NULL);
50     }
51
52     game->level_file_path = PUSH_LT(lt, malloc(sizeof(char) * (strlen(level_file_path) + 1)), free);
53     if (game->level_file_path == NULL) {
54         throw_error(ERROR_TYPE_LIBC);
55         RETURN_LT(lt, NULL);
56     }
57
58     strcpy(game->level_file_path, level_file_path);
59
60     game->state = GAME_STATE_RUNNING;
61     game->sound_medium = sound_medium;
62     game->lt = lt;
63
64     return game;
65 }
66
67 void destroy_game(game_t *game)
68 {
69     assert(game);
70     RETURN_LT0(game->lt);
71 }
72
73 int game_render(const game_t *game, SDL_Renderer *renderer)
74 {
75     assert(game);
76     assert(renderer);
77
78     if (game->state == GAME_STATE_QUIT) {
79         return 0;
80     }
81
82     if (level_render(game->level, renderer) < 0) {
83         return -1;
84     }
85
86     SDL_RenderPresent(renderer);
87
88     return 0;
89 }
90
91 int game_sound(game_t *game)
92 {
93     return level_sound(game->level, game->sound_medium);
94 }
95
96 int game_update(game_t *game, float delta_time)
97 {
98     assert(game);
99     assert(delta_time > 0.0f);
100
101     if (game->state == GAME_STATE_QUIT) {
102         return 0;
103     }
104
105     if (game->state == GAME_STATE_RUNNING) {
106         return level_update(game->level, delta_time);
107     }
108
109     return 0;
110 }
111
112
113 static int game_event_pause(game_t *game, const SDL_Event *event)
114 {
115     assert(game);
116     assert(event);
117
118     switch (event->type) {
119     case SDL_QUIT:
120         game->state = GAME_STATE_QUIT;
121         break;
122
123     case SDL_KEYDOWN:
124         switch (event->key.keysym.sym) {
125         case SDLK_p:
126             game->state = GAME_STATE_RUNNING;
127             level_toggle_pause_mode(game->level);
128             sound_medium_toggle_pause(game->sound_medium);
129             break;
130         case SDLK_l:
131             level_toggle_debug_mode(game->level);
132             break;
133         }
134         break;
135     }
136
137     return level_event(game->level, event);
138 }
139
140 static int game_event_running(game_t *game, const SDL_Event *event)
141 {
142     assert(game);
143     assert(event);
144
145     switch (event->type) {
146     case SDL_QUIT:
147         game->state = GAME_STATE_QUIT;
148         break;
149
150     case SDL_KEYDOWN:
151         switch (event->key.keysym.sym) {
152         case SDLK_r:
153             printf("Reloading the level from '%s'...\n", game->level_file_path);
154
155             game->level = RESET_LT(
156                 game->lt,
157                 game->level,
158                 create_level_from_file(
159                     game->level_file_path));
160
161             if (game->level == NULL) {
162                 print_current_error_msg("Could not reload the level");
163                 game->state = GAME_STATE_QUIT;
164                 return -1;
165             }
166             break;
167
168         case SDLK_q:
169             printf("Reloading the level's platforms from '%s'...\n", game->level_file_path);
170             if (level_reload_preserve_player(game->level, game->level_file_path) < 0) {
171                 print_current_error_msg("Could not reload the level");
172                 game->state = GAME_STATE_QUIT;
173                 return -1;
174             }
175             break;
176
177         case SDLK_p:
178             game->state = GAME_STATE_PAUSE;
179             level_toggle_pause_mode(game->level);
180             sound_medium_toggle_pause(game->sound_medium);
181             break;
182
183         case SDLK_l:
184             level_toggle_debug_mode(game->level);
185             break;
186         }
187         break;
188
189     }
190
191     return level_event(game->level, event);
192 }
193
194 int game_event(game_t *game, const SDL_Event *event)
195 {
196     assert(game);
197     assert(event);
198
199     switch (game->state) {
200     case GAME_STATE_RUNNING:
201         return game_event_running(game, event);
202
203     case GAME_STATE_PAUSE:
204         return game_event_pause(game, event);
205
206     default: {}
207     }
208
209     return 0;
210 }
211
212
213 int game_input(game_t *game,
214                const Uint8 *const keyboard_state,
215                SDL_Joystick *the_stick_of_joy)
216 {
217     assert(game);
218     assert(keyboard_state);
219
220     if (game->state == GAME_STATE_QUIT || game->state == GAME_STATE_PAUSE) {
221         return 0;
222     }
223
224     return level_input(game->level, keyboard_state, the_stick_of_joy);
225 }
226
227 int game_over_check(const game_t *game)
228 {
229     return game->state == GAME_STATE_QUIT;
230 }