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