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