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