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