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