]> git.lizzy.rs Git - nothing.git/blob - src/game.c
61805879a4e8cd87f00f9b80d72ed21e10fb8abd
[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
12 typedef enum game_state_t {
13     GAME_STATE_RUNNING = 0,
14     GAME_STATE_PAUSE,
15     GAME_STATE_QUIT,
16
17     GAME_STATE_N
18 } game_state_t;
19
20 typedef struct game_t {
21     lt_t *lt;
22
23     game_state_t state;
24     level_t *level;
25     char *level_file_path;
26     sound_samples_t *sound_samples;
27     camera_t *camera;
28     sprite_font_t *font;
29 } game_t;
30
31 game_t *create_game(const char *level_file_path,
32                     const char *sound_sample_files[],
33                     size_t sound_sample_files_count,
34                     SDL_Renderer *renderer)
35 {
36     assert(level_file_path);
37
38     lt_t *const lt = create_lt();
39     if (lt == NULL) {
40         return NULL;
41     }
42
43     game_t *game = PUSH_LT(lt, malloc(sizeof(game_t)), free);
44     if (game == NULL) {
45         throw_error(ERROR_TYPE_LIBC);
46         RETURN_LT(lt, NULL);
47     }
48
49     game->level = PUSH_LT(
50         lt,
51         create_level_from_file(level_file_path),
52         destroy_level);
53     if (game->level == NULL) {
54         RETURN_LT(lt, NULL);
55     }
56
57     game->level_file_path = PUSH_LT(lt, malloc(sizeof(char) * (strlen(level_file_path) + 1)), free);
58     if (game->level_file_path == NULL) {
59         throw_error(ERROR_TYPE_LIBC);
60         RETURN_LT(lt, NULL);
61     }
62     strcpy(game->level_file_path, level_file_path);
63
64     game->font = PUSH_LT(
65         lt,
66         create_sprite_font_from_file("fonts/charmap-oldschool.bmp", renderer),
67         destroy_sprite_font);
68     if (game->font == NULL) {
69         RETURN_LT(lt, NULL);
70     }
71
72     game->camera = PUSH_LT(lt, create_camera(renderer, game->font), destroy_camera);
73     if (game->camera == NULL) {
74         RETURN_LT(lt, NULL);
75     }
76
77     game->sound_samples = PUSH_LT(
78         lt,
79         create_sound_samples(
80             sound_sample_files,
81             sound_sample_files_count),
82         destroy_sound_samples);
83     if (game->sound_samples == NULL) {
84         RETURN_LT(lt, NULL);
85     }
86
87     game->state = GAME_STATE_RUNNING;
88     game->lt = lt;
89
90     return game;
91 }
92
93 void destroy_game(game_t *game)
94 {
95     assert(game);
96     RETURN_LT0(game->lt);
97 }
98
99 int game_render(const game_t *game)
100 {
101     assert(game);
102
103     if (game->state == GAME_STATE_QUIT) {
104         return 0;
105     }
106
107     if (level_render(game->level, game->camera) < 0) {
108         return -1;
109     }
110
111     if (camera_render_text(game->camera, "hello world", vec(8.0f, 4.0f), color(1.0f, 0.0f, 0.0f, 1.0f), vec(-30.0f, 0.0f)) < 0) {
112         return -1;
113     }
114
115     return 0;
116 }
117
118 int game_sound(game_t *game)
119 {
120     return level_sound(game->level, game->sound_samples);
121 }
122
123 int game_update(game_t *game, float delta_time)
124 {
125     assert(game);
126     assert(delta_time > 0.0f);
127
128     if (game->state == GAME_STATE_QUIT) {
129         return 0;
130     }
131
132     if (game->state == GAME_STATE_RUNNING) {
133         if (level_update(game->level, delta_time) < 0) {
134             return -1;
135         }
136
137         if (level_enter_camera_event(game->level, game->camera) < 0) {
138             return -1;
139         }
140     }
141
142     return 0;
143 }
144
145
146 static int game_event_pause(game_t *game, const SDL_Event *event)
147 {
148     assert(game);
149     assert(event);
150
151     switch (event->type) {
152     case SDL_QUIT:
153         game->state = GAME_STATE_QUIT;
154         break;
155
156     case SDL_KEYDOWN:
157         switch (event->key.keysym.sym) {
158         case SDLK_p:
159             game->state = GAME_STATE_RUNNING;
160             camera_toggle_blackwhite_mode(game->camera);
161             sound_samples_toggle_pause(game->sound_samples);
162             break;
163         case SDLK_l:
164             camera_toggle_debug_mode(game->camera);
165             level_toggle_debug_mode(game->level);
166             break;
167         }
168         break;
169     }
170
171     return level_event(game->level, event);
172 }
173
174 static int game_event_running(game_t *game, const SDL_Event *event)
175 {
176     assert(game);
177     assert(event);
178
179     switch (event->type) {
180     case SDL_QUIT:
181         game->state = GAME_STATE_QUIT;
182         break;
183
184     case SDL_KEYDOWN:
185         switch (event->key.keysym.sym) {
186         case SDLK_r:
187             printf("Reloading the level from '%s'...\n", game->level_file_path);
188
189             game->level = RESET_LT(
190                 game->lt,
191                 game->level,
192                 create_level_from_file(
193                     game->level_file_path));
194
195             if (game->level == NULL) {
196                 print_current_error_msg("Could not reload the level");
197                 game->state = GAME_STATE_QUIT;
198                 return -1;
199             }
200
201             camera_disable_debug_mode(game->camera);
202
203             break;
204
205         case SDLK_q:
206             printf("Reloading the level's platforms from '%s'...\n", game->level_file_path);
207             if (level_reload_preserve_player(game->level, game->level_file_path) < 0) {
208                 print_current_error_msg("Could not reload the level");
209                 game->state = GAME_STATE_QUIT;
210                 return -1;
211             }
212             break;
213
214         case SDLK_p:
215             game->state = GAME_STATE_PAUSE;
216             camera_toggle_blackwhite_mode(game->camera);
217             sound_samples_toggle_pause(game->sound_samples);
218             break;
219
220         case SDLK_l:
221             camera_toggle_debug_mode(game->camera);
222             level_toggle_debug_mode(game->level);
223             break;
224         }
225         break;
226
227     }
228
229     return level_event(game->level, event);
230 }
231
232 int game_event(game_t *game, const SDL_Event *event)
233 {
234     assert(game);
235     assert(event);
236
237     switch (game->state) {
238     case GAME_STATE_RUNNING:
239         return game_event_running(game, event);
240
241     case GAME_STATE_PAUSE:
242         return game_event_pause(game, event);
243
244     default: {}
245     }
246
247     return 0;
248 }
249
250
251 int game_input(game_t *game,
252                const Uint8 *const keyboard_state,
253                SDL_Joystick *the_stick_of_joy)
254 {
255     assert(game);
256     assert(keyboard_state);
257
258     if (game->state == GAME_STATE_QUIT || game->state == GAME_STATE_PAUSE) {
259         return 0;
260     }
261
262     return level_input(game->level, keyboard_state, the_stick_of_joy);
263 }
264
265 int game_over_check(const game_t *game)
266 {
267     return game->state == GAME_STATE_QUIT;
268 }