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