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