]> git.lizzy.rs Git - nothing.git/blob - src/game.c
(#594) assert -> trace_assert
[nothing.git] / src / game.c
1 #include <SDL2/SDL.h>
2 #include <SDL2/SDL_mixer.h>
3 #include "system/stacktrace.h"
4 #include <stdio.h>
5
6 #include "game.h"
7 #include "game/level.h"
8 #include "game/sound_samples.h"
9 #include "system/log.h"
10 #include "system/lt.h"
11 #include "system/nth_alloc.h"
12 #include "ui/console.h"
13 #include "ui/edit_field.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     Console *console;
34     SDL_Renderer *renderer;
35 } Game;
36
37 Game *create_game(const char *level_file_path,
38                     const char *sound_sample_files[],
39                     size_t sound_sample_files_count,
40                     SDL_Renderer *renderer)
41 {
42     trace_assert(level_file_path);
43
44     Lt *const lt = create_lt();
45     if (lt == NULL) {
46         return NULL;
47     }
48
49     Game *game = PUSH_LT(lt, nth_alloc(sizeof(Game)), free);
50     if (game == NULL) {
51         RETURN_LT(lt, NULL);
52     }
53     game->lt = lt;
54
55     game->renderer = renderer;
56
57     game->level = PUSH_LT(
58         lt,
59         create_level_from_file(level_file_path),
60         destroy_level);
61     if (game->level == NULL) {
62         RETURN_LT(lt, NULL);
63     }
64
65     game->level_file_path = PUSH_LT(lt, nth_alloc(sizeof(char) * (strlen(level_file_path) + 1)), free);
66     if (game->level_file_path == NULL) {
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->camera = PUSH_LT(lt, create_camera(renderer, game->font), destroy_camera);
80     if (game->camera == NULL) {
81         RETURN_LT(lt, NULL);
82     }
83
84     game->sound_samples = PUSH_LT(
85         lt,
86         create_sound_samples(
87             sound_sample_files,
88             sound_sample_files_count),
89         destroy_sound_samples);
90     if (game->sound_samples == NULL) {
91         RETURN_LT(lt, NULL);
92     }
93
94     game->console = PUSH_LT(
95         lt,
96         create_console(game->level, game->font),
97         destroy_console);
98     if (game->console == 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     trace_assert(game);
110     RETURN_LT0(game->lt);
111 }
112
113 int game_render(const Game *game)
114 {
115     trace_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 (game->state == GAME_STATE_CONSOLE) {
126         if (console_render(game->console, game->renderer) < 0) {
127             return -1;
128         }
129     }
130
131     return 0;
132 }
133
134 int game_sound(Game *game)
135 {
136     return level_sound(game->level, game->sound_samples);
137 }
138
139 int game_update(Game *game, float delta_time)
140 {
141     trace_assert(game);
142     trace_assert(delta_time > 0.0f);
143
144     if (game->state == GAME_STATE_QUIT) {
145         return 0;
146     }
147
148     if (game->state == GAME_STATE_RUNNING || game->state == GAME_STATE_CONSOLE) {
149         if (level_update(game->level, delta_time) < 0) {
150             return -1;
151         }
152
153         if (level_enter_camera_event(game->level, game->camera) < 0) {
154             return -1;
155         }
156
157         if (console_update(game->console, delta_time) < 0) {
158             return -1;
159         }
160     }
161
162     return 0;
163 }
164
165
166 static int game_event_pause(Game *game, const SDL_Event *event)
167 {
168     trace_assert(game);
169     trace_assert(event);
170
171     switch (event->type) {
172     case SDL_QUIT:
173         game->state = GAME_STATE_QUIT;
174         break;
175
176     case SDL_KEYDOWN:
177         switch (event->key.keysym.sym) {
178         case SDLK_p:
179             game->state = GAME_STATE_RUNNING;
180             camera_toggle_blackwhite_mode(game->camera);
181             sound_samples_toggle_pause(game->sound_samples);
182             break;
183         case SDLK_l:
184             camera_toggle_debug_mode(game->camera);
185             level_toggle_debug_mode(game->level);
186             break;
187         }
188         break;
189     }
190
191     return level_event(game->level, event);
192 }
193
194 static int game_event_running(Game *game, const SDL_Event *event)
195 {
196     trace_assert(game);
197     trace_assert(event);
198
199     switch (event->type) {
200     case SDL_QUIT:
201         game->state = GAME_STATE_QUIT;
202         break;
203
204     case SDL_KEYDOWN:
205         switch (event->key.keysym.sym) {
206         case SDLK_r:
207             log_info("Reloading the level from '%s'...\n", game->level_file_path);
208
209             game->level = RESET_LT(
210                 game->lt,
211                 game->level,
212                 create_level_from_file(
213                     game->level_file_path));
214
215             if (game->level == NULL) {
216                 log_fail("Could not reload level %s\n", game->level_file_path);
217                 game->state = GAME_STATE_QUIT;
218                 return -1;
219             }
220
221             camera_disable_debug_mode(game->camera);
222
223             break;
224
225         case SDLK_q:
226             log_info("Reloading the level's platforms from '%s'...\n", game->level_file_path);
227             if (level_reload_preserve_player(game->level, game->level_file_path) < 0) {
228                 log_fail("Could not reload level %s\n", game->level_file_path);
229                 game->state = GAME_STATE_QUIT;
230                 return -1;
231             }
232             break;
233
234         case SDLK_p:
235             game->state = GAME_STATE_PAUSE;
236             camera_toggle_blackwhite_mode(game->camera);
237             sound_samples_toggle_pause(game->sound_samples);
238             break;
239
240         case SDLK_l:
241             camera_toggle_debug_mode(game->camera);
242             level_toggle_debug_mode(game->level);
243             break;
244         }
245         break;
246     case SDL_KEYUP:
247         switch (event->key.keysym.sym) {
248         case SDLK_BACKQUOTE:
249         case SDLK_c:
250             SDL_StartTextInput();
251             game->state = GAME_STATE_CONSOLE;
252             console_slide_down(game->console);
253             break;
254         }
255         break;
256
257     }
258
259     return level_event(game->level, event);
260 }
261
262 static int game_event_console(Game *game, const SDL_Event *event)
263 {
264     switch (event->type) {
265     case SDL_QUIT:
266         game->state = GAME_STATE_QUIT;
267         return 0;
268
269     case SDL_KEYDOWN:
270         switch (event->key.keysym.sym) {
271         case SDLK_ESCAPE:
272             SDL_StopTextInput();
273             game->state = GAME_STATE_RUNNING;
274             return 0;
275
276         default: {}
277         }
278
279     default: {}
280     }
281
282     return console_handle_event(game->console, event);
283 }
284
285 int game_event(Game *game, const SDL_Event *event)
286 {
287     trace_assert(game);
288     trace_assert(event);
289
290     switch (game->state) {
291     case GAME_STATE_RUNNING:
292         return game_event_running(game, event);
293
294     case GAME_STATE_PAUSE:
295         return game_event_pause(game, event);
296
297     case GAME_STATE_CONSOLE:
298         return game_event_console(game, event);
299
300     default: {}
301     }
302
303     return 0;
304 }
305
306
307 int game_input(Game *game,
308                const Uint8 *const keyboard_state,
309                SDL_Joystick *the_stick_of_joy)
310 {
311     trace_assert(game);
312     trace_assert(keyboard_state);
313
314     if (game->state == GAME_STATE_QUIT  ||
315         game->state == GAME_STATE_PAUSE ||
316         game->state == GAME_STATE_CONSOLE) {
317         return 0;
318     }
319
320     return level_input(game->level, keyboard_state, the_stick_of_joy);
321 }
322
323 int game_over_check(const Game *game)
324 {
325     return game->state == GAME_STATE_QUIT;
326 }