]> git.lizzy.rs Git - nothing.git/blob - src/game.c
11c60e6e1fe570c05df7092cb825aa2b9c0fb408
[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_white.bmp",
67                                      color(1.0f, 0.0f, 0.0f, 1.0f),
68                                      renderer),
69         destroy_sprite_font);
70     if (game->font == NULL) {
71         RETURN_LT(lt, NULL);
72     }
73
74     game->camera = PUSH_LT(lt, create_camera(renderer, game->font), destroy_camera);
75     if (game->camera == NULL) {
76         RETURN_LT(lt, NULL);
77     }
78
79     game->sound_samples = PUSH_LT(
80         lt,
81         create_sound_samples(
82             sound_sample_files,
83             sound_sample_files_count),
84         destroy_sound_samples);
85     if (game->sound_samples == NULL) {
86         RETURN_LT(lt, NULL);
87     }
88
89     game->state = GAME_STATE_RUNNING;
90     game->lt = lt;
91
92     return game;
93 }
94
95 void destroy_game(game_t *game)
96 {
97     assert(game);
98     RETURN_LT0(game->lt);
99 }
100
101 int game_render(const game_t *game)
102 {
103     assert(game);
104
105     if (game->state == GAME_STATE_QUIT) {
106         return 0;
107     }
108
109     if (level_render(game->level, game->camera) < 0) {
110         return -1;
111     }
112
113     if (camera_render_text(game->camera, "hello world", 4, vec(-30.0f, 0.0f)) < 0) {
114         return -1;
115     }
116
117     return 0;
118 }
119
120 int game_sound(game_t *game)
121 {
122     return level_sound(game->level, game->sound_samples);
123 }
124
125 int game_update(game_t *game, float delta_time)
126 {
127     assert(game);
128     assert(delta_time > 0.0f);
129
130     if (game->state == GAME_STATE_QUIT) {
131         return 0;
132     }
133
134     if (game->state == GAME_STATE_RUNNING) {
135         if (level_update(game->level, delta_time) < 0) {
136             return -1;
137         }
138
139         if (level_enter_camera_event(game->level, game->camera) < 0) {
140             return -1;
141         }
142     }
143
144     return 0;
145 }
146
147
148 static int game_event_pause(game_t *game, const SDL_Event *event)
149 {
150     assert(game);
151     assert(event);
152
153     switch (event->type) {
154     case SDL_QUIT:
155         game->state = GAME_STATE_QUIT;
156         break;
157
158     case SDL_KEYDOWN:
159         switch (event->key.keysym.sym) {
160         case SDLK_p:
161             game->state = GAME_STATE_RUNNING;
162             camera_toggle_blackwhite_mode(game->camera);
163             sound_samples_toggle_pause(game->sound_samples);
164             break;
165         case SDLK_l:
166             camera_toggle_debug_mode(game->camera);
167             level_toggle_debug_mode(game->level);
168             break;
169         }
170         break;
171     }
172
173     return level_event(game->level, event);
174 }
175
176 static int game_event_running(game_t *game, const SDL_Event *event)
177 {
178     assert(game);
179     assert(event);
180
181     switch (event->type) {
182     case SDL_QUIT:
183         game->state = GAME_STATE_QUIT;
184         break;
185
186     case SDL_KEYDOWN:
187         switch (event->key.keysym.sym) {
188         case SDLK_r:
189             printf("Reloading the level from '%s'...\n", game->level_file_path);
190
191             game->level = RESET_LT(
192                 game->lt,
193                 game->level,
194                 create_level_from_file(
195                     game->level_file_path));
196
197             if (game->level == NULL) {
198                 print_current_error_msg("Could not reload the level");
199                 game->state = GAME_STATE_QUIT;
200                 return -1;
201             }
202
203             camera_disable_debug_mode(game->camera);
204
205             break;
206
207         case SDLK_q:
208             printf("Reloading the level's platforms from '%s'...\n", game->level_file_path);
209             if (level_reload_preserve_player(game->level, game->level_file_path) < 0) {
210                 print_current_error_msg("Could not reload the level");
211                 game->state = GAME_STATE_QUIT;
212                 return -1;
213             }
214             break;
215
216         case SDLK_p:
217             game->state = GAME_STATE_PAUSE;
218             camera_toggle_blackwhite_mode(game->camera);
219             sound_samples_toggle_pause(game->sound_samples);
220             break;
221
222         case SDLK_l:
223             camera_toggle_debug_mode(game->camera);
224             level_toggle_debug_mode(game->level);
225             break;
226         }
227         break;
228
229     }
230
231     return level_event(game->level, event);
232 }
233
234 int game_event(game_t *game, const SDL_Event *event)
235 {
236     assert(game);
237     assert(event);
238
239     switch (game->state) {
240     case GAME_STATE_RUNNING:
241         return game_event_running(game, event);
242
243     case GAME_STATE_PAUSE:
244         return game_event_pause(game, event);
245
246     default: {}
247     }
248
249     return 0;
250 }
251
252
253 int game_input(game_t *game,
254                const Uint8 *const keyboard_state,
255                SDL_Joystick *the_stick_of_joy)
256 {
257     assert(game);
258     assert(keyboard_state);
259
260     if (game->state == GAME_STATE_QUIT || game->state == GAME_STATE_PAUSE) {
261         return 0;
262     }
263
264     return level_input(game->level, keyboard_state, the_stick_of_joy);
265 }
266
267 int game_over_check(const game_t *game)
268 {
269     return game->state == GAME_STATE_QUIT;
270 }