]> git.lizzy.rs Git - nothing.git/blob - src/game.c
Merge pull request #371 from tsoding/log
[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 "ui/edit_field.h"
9 #include "game/level.h"
10 #include "ui/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         if (console_update(game->console, delta_time) < 0) {
173             return -1;
174         }
175     }
176
177     return 0;
178 }
179
180
181 static int game_event_pause(Game *game, const SDL_Event *event)
182 {
183     assert(game);
184     assert(event);
185
186     switch (event->type) {
187     case SDL_QUIT:
188         game->state = GAME_STATE_QUIT;
189         break;
190
191     case SDL_KEYDOWN:
192         switch (event->key.keysym.sym) {
193         case SDLK_p:
194             game->state = GAME_STATE_RUNNING;
195             camera_toggle_blackwhite_mode(game->camera);
196             sound_samples_toggle_pause(game->sound_samples);
197             break;
198         case SDLK_l:
199             camera_toggle_debug_mode(game->camera);
200             level_toggle_debug_mode(game->level);
201             debug_tree_toggle_enabled(game->debug_tree);
202             break;
203         }
204         break;
205     }
206
207     return level_event(game->level, event);
208 }
209
210 static int game_event_running(Game *game, const SDL_Event *event)
211 {
212     assert(game);
213     assert(event);
214
215     switch (event->type) {
216     case SDL_QUIT:
217         game->state = GAME_STATE_QUIT;
218         break;
219
220     case SDL_KEYDOWN:
221         switch (event->key.keysym.sym) {
222         case SDLK_r:
223             printf("Reloading the level from '%s'...\n", game->level_file_path);
224
225             game->level = RESET_LT(
226                 game->lt,
227                 game->level,
228                 create_level_from_file(
229                     game->level_file_path));
230
231             if (game->level == NULL) {
232                 print_current_error_msg("Could not reload the level");
233                 game->state = GAME_STATE_QUIT;
234                 return -1;
235             }
236
237             camera_disable_debug_mode(game->camera);
238
239             break;
240
241         case SDLK_q:
242             printf("Reloading the level's platforms from '%s'...\n", game->level_file_path);
243             if (level_reload_preserve_player(game->level, game->level_file_path) < 0) {
244                 print_current_error_msg("Could not reload the level");
245                 game->state = GAME_STATE_QUIT;
246                 return -1;
247             }
248             break;
249
250         case SDLK_p:
251             game->state = GAME_STATE_PAUSE;
252             camera_toggle_blackwhite_mode(game->camera);
253             sound_samples_toggle_pause(game->sound_samples);
254             break;
255
256         case SDLK_l:
257             camera_toggle_debug_mode(game->camera);
258             level_toggle_debug_mode(game->level);
259             debug_tree_toggle_enabled(game->debug_tree);
260             break;
261
262         case SDLK_BACKQUOTE:
263             game->state = GAME_STATE_CONSOLE;
264             console_slide_down(game->console);
265             break;
266         }
267         break;
268
269     }
270
271     return level_event(game->level, event);
272 }
273
274 static int game_event_console(Game *game, const SDL_Event *event)
275 {
276     switch (event->type) {
277     case SDL_QUIT:
278         game->state = GAME_STATE_QUIT;
279         return 0;
280
281     case SDL_KEYDOWN:
282         switch (event->key.keysym.sym) {
283         case SDLK_ESCAPE:
284         case SDLK_BACKQUOTE:
285             game->state = GAME_STATE_RUNNING;
286             return 0;
287
288         default: {}
289         }
290
291     default: {}
292     }
293
294     return console_handle_event(game->console, event);
295 }
296
297 int game_event(Game *game, const SDL_Event *event)
298 {
299     assert(game);
300     assert(event);
301
302     switch (game->state) {
303     case GAME_STATE_RUNNING:
304         return game_event_running(game, event);
305
306     case GAME_STATE_PAUSE:
307         return game_event_pause(game, event);
308
309     case GAME_STATE_CONSOLE:
310         return game_event_console(game, event);
311
312     default: {}
313     }
314
315     return 0;
316 }
317
318
319 int game_input(Game *game,
320                const Uint8 *const keyboard_state,
321                SDL_Joystick *the_stick_of_joy)
322 {
323     assert(game);
324     assert(keyboard_state);
325
326     if (game->state == GAME_STATE_QUIT  ||
327         game->state == GAME_STATE_PAUSE ||
328         game->state == GAME_STATE_CONSOLE) {
329         return 0;
330     }
331
332     return level_input(game->level, keyboard_state, the_stick_of_joy);
333 }
334
335 int game_over_check(const Game *game)
336 {
337     return game->state == GAME_STATE_QUIT;
338 }