]> git.lizzy.rs Git - nothing.git/blob - src/game.c
e322e995f7822993f389cba8ed343329c07a6b49
[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/debug_tree.h"
8 #include "game/level.h"
9 #include "game/sound_samples.h"
10 #include "system/error.h"
11 #include "system/lt.h"
12
13 typedef enum game_state_t {
14     GAME_STATE_RUNNING = 0,
15     GAME_STATE_PAUSE,
16     GAME_STATE_QUIT,
17
18     GAME_STATE_N
19 } game_state_t;
20
21 typedef struct game_t {
22     lt_t *lt;
23
24     game_state_t state;
25     level_t *level;
26     char *level_file_path;
27     sound_samples_t *sound_samples;
28     camera_t *camera;
29     sprite_font_t *font;
30     debug_tree_t *debug_tree;
31     SDL_Renderer *renderer;
32 } game_t;
33
34 game_t *create_game(const char *level_file_path,
35                     const char *sound_sample_files[],
36                     size_t sound_sample_files_count,
37                     SDL_Renderer *renderer)
38 {
39     assert(level_file_path);
40
41     lt_t *const lt = create_lt();
42     if (lt == NULL) {
43         return NULL;
44     }
45
46     game_t *game = PUSH_LT(lt, malloc(sizeof(game_t)), free);
47     if (game == NULL) {
48         throw_error(ERROR_TYPE_LIBC);
49         RETURN_LT(lt, NULL);
50     }
51     game->lt = lt;
52
53     game->renderer = renderer;
54
55     game->level = PUSH_LT(
56         lt,
57         create_level_from_file(level_file_path),
58         destroy_level);
59     if (game->level == NULL) {
60         RETURN_LT(lt, NULL);
61     }
62
63     game->level_file_path = PUSH_LT(lt, malloc(sizeof(char) * (strlen(level_file_path) + 1)), free);
64     if (game->level_file_path == NULL) {
65         throw_error(ERROR_TYPE_LIBC);
66         RETURN_LT(lt, NULL);
67     }
68     strcpy(game->level_file_path, level_file_path);
69
70     game->font = PUSH_LT(
71         lt,
72         create_sprite_font_from_file("fonts/charmap-oldschool.bmp", renderer),
73         destroy_sprite_font);
74     if (game->font == NULL) {
75         RETURN_LT(lt, NULL);
76     }
77
78     game->debug_tree = PUSH_LT(
79         lt,
80         create_debug_tree(game->font),
81         destroy_debug_tree);
82     if (game->debug_tree == NULL) {
83         RETURN_LT(lt, NULL);
84     }
85
86     game->camera = PUSH_LT(lt, create_camera(renderer, game->font), destroy_camera);
87     if (game->camera == NULL) {
88         RETURN_LT(lt, NULL);
89     }
90
91     game->sound_samples = PUSH_LT(
92         lt,
93         create_sound_samples(
94             sound_sample_files,
95             sound_sample_files_count),
96         destroy_sound_samples);
97     if (game->sound_samples == NULL) {
98         RETURN_LT(lt, NULL);
99     }
100
101     game->state = GAME_STATE_RUNNING;
102
103     return game;
104 }
105
106 void destroy_game(game_t *game)
107 {
108     assert(game);
109     RETURN_LT0(game->lt);
110 }
111
112 int game_render(const game_t *game)
113 {
114     assert(game);
115
116     if (game->state == GAME_STATE_QUIT) {
117         return 0;
118     }
119
120     if (level_render(game->level, game->camera) < 0) {
121         return -1;
122     }
123
124     if (debug_tree_render(game->debug_tree, game->renderer) < 0) {
125         return -1;
126     }
127
128     return 0;
129 }
130
131 int game_sound(game_t *game)
132 {
133     return level_sound(game->level, game->sound_samples);
134 }
135
136 int game_update(game_t *game, float delta_time)
137 {
138     assert(game);
139     assert(delta_time > 0.0f);
140
141     if (game->state == GAME_STATE_QUIT) {
142         return 0;
143     }
144
145     if (game->state == GAME_STATE_RUNNING) {
146         if (level_update(game->level, delta_time) < 0) {
147             return -1;
148         }
149
150         if (level_enter_camera_event(game->level, game->camera) < 0) {
151             return -1;
152         }
153     }
154
155     return 0;
156 }
157
158
159 static int game_event_pause(game_t *game, const SDL_Event *event)
160 {
161     assert(game);
162     assert(event);
163
164     switch (event->type) {
165     case SDL_QUIT:
166         game->state = GAME_STATE_QUIT;
167         break;
168
169     case SDL_KEYDOWN:
170         switch (event->key.keysym.sym) {
171         case SDLK_p:
172             game->state = GAME_STATE_RUNNING;
173             camera_toggle_blackwhite_mode(game->camera);
174             sound_samples_toggle_pause(game->sound_samples);
175             break;
176         case SDLK_l:
177             camera_toggle_debug_mode(game->camera);
178             level_toggle_debug_mode(game->level);
179             debug_tree_toggle_enabled(game->debug_tree);
180             break;
181         }
182         break;
183     }
184
185     return level_event(game->level, event);
186 }
187
188 static int game_event_running(game_t *game, const SDL_Event *event)
189 {
190     assert(game);
191     assert(event);
192
193     switch (event->type) {
194     case SDL_QUIT:
195         game->state = GAME_STATE_QUIT;
196         break;
197
198     case SDL_KEYDOWN:
199         switch (event->key.keysym.sym) {
200         case SDLK_r:
201             printf("Reloading the level from '%s'...\n", game->level_file_path);
202
203             game->level = RESET_LT(
204                 game->lt,
205                 game->level,
206                 create_level_from_file(
207                     game->level_file_path));
208
209             if (game->level == NULL) {
210                 print_current_error_msg("Could not reload the level");
211                 game->state = GAME_STATE_QUIT;
212                 return -1;
213             }
214
215             camera_disable_debug_mode(game->camera);
216
217             break;
218
219         case SDLK_q:
220             printf("Reloading the level's platforms from '%s'...\n", game->level_file_path);
221             if (level_reload_preserve_player(game->level, game->level_file_path) < 0) {
222                 print_current_error_msg("Could not reload the level");
223                 game->state = GAME_STATE_QUIT;
224                 return -1;
225             }
226             break;
227
228         case SDLK_p:
229             game->state = GAME_STATE_PAUSE;
230             camera_toggle_blackwhite_mode(game->camera);
231             sound_samples_toggle_pause(game->sound_samples);
232             break;
233
234         case SDLK_l:
235             camera_toggle_debug_mode(game->camera);
236             level_toggle_debug_mode(game->level);
237             debug_tree_toggle_enabled(game->debug_tree);
238             break;
239         }
240         break;
241
242     }
243
244     return level_event(game->level, event);
245 }
246
247 int game_event(game_t *game, const SDL_Event *event)
248 {
249     assert(game);
250     assert(event);
251
252     switch (game->state) {
253     case GAME_STATE_RUNNING:
254         return game_event_running(game, event);
255
256     case GAME_STATE_PAUSE:
257         return game_event_pause(game, event);
258
259     default: {}
260     }
261
262     return 0;
263 }
264
265
266 int game_input(game_t *game,
267                const Uint8 *const keyboard_state,
268                SDL_Joystick *the_stick_of_joy)
269 {
270     assert(game);
271     assert(keyboard_state);
272
273     if (game->state == GAME_STATE_QUIT || game->state == GAME_STATE_PAUSE) {
274         return 0;
275     }
276
277     return level_input(game->level, keyboard_state, the_stick_of_joy);
278 }
279
280 int game_over_check(const game_t *game)
281 {
282     return game->state == GAME_STATE_QUIT;
283 }