]> git.lizzy.rs Git - nothing.git/blob - src/game/level.c
fc7f630dd7dbccc000fbf8bb529875b92ea06fbd
[nothing.git] / src / game / level.c
1 #include <SDL.h>
2 #include "system/stacktrace.h"
3
4 #include "color.h"
5 #include "game/camera.h"
6 #include "game/level.h"
7 #include "game/level/background.h"
8 #include "game/level/boxes.h"
9 #include "game/level/goals.h"
10 #include "game/level/labels.h"
11 #include "game/level/lava.h"
12 #include "game/level/platforms.h"
13 #include "game/level/player.h"
14 #include "game/level/regions.h"
15 #include "game/level/rigid_bodies.h"
16 #include "game/level_metadata.h"
17 #include "game/level/level_editor/rect_layer.h"
18 #include "game/level/level_editor/point_layer.h"
19 #include "game/level/level_editor/player_layer.h"
20 #include "game/level/level_editor/label_layer.h"
21 #include "game/level/level_editor/background_layer.h"
22 #include "system/line_stream.h"
23 #include "system/log.h"
24 #include "system/lt.h"
25 #include "system/nth_alloc.h"
26 #include "system/str.h"
27 #include "game/level/level_editor.h"
28 #include "ui/console.h"
29
30 #define LEVEL_GRAVITY 1500.0f
31 #define JOYSTICK_THRESHOLD 1000
32
33 typedef enum {
34     LEVEL_STATE_IDLE = 0,
35     LEVEL_STATE_PAUSE
36 } LevelState;
37
38 struct Level
39 {
40     Lt *lt;
41
42     LevelState state;
43     LevelMetadata *metadata;
44     Background *background;
45     RigidBodies *rigid_bodies;
46     Player *player;
47     Platforms *platforms;
48     Goals *goals;
49     Lava *lava;
50     Platforms *back_platforms;
51     Boxes *boxes;
52     Labels *labels;
53     Regions *regions;
54     Console *console;
55     int console_enabled;
56 };
57
58 Level *create_level_from_level_editor(const LevelEditor *level_editor)
59 {
60     trace_assert(level_editor);
61
62     Lt *lt = create_lt();
63
64     Level *level = PUSH_LT(
65         lt,
66         nth_calloc(1, sizeof(Level)),
67         free);
68     if (level == NULL) {
69         RETURN_LT(lt, NULL);
70     }
71     level->lt = lt;
72
73     level->background = PUSH_LT(
74         lt,
75         create_background(
76             color_picker_rgba(
77                 &level_editor->background_layer.color_picker)),
78         destroy_background);
79     if (level->background == NULL) {
80         RETURN_LT(lt, NULL);
81     }
82
83     level->rigid_bodies = PUSH_LT(lt, create_rigid_bodies(1024), destroy_rigid_bodies);
84     if (level->rigid_bodies == NULL) {
85         RETURN_LT(lt, NULL);
86     }
87
88     level->player = PUSH_LT(
89         lt,
90         create_player_from_player_layer(
91             &level_editor->player_layer,
92             level->rigid_bodies),
93         destroy_player);
94     if (level->player == NULL) {
95         RETURN_LT(lt, NULL);
96     }
97
98     level->platforms = PUSH_LT(
99         lt,
100         create_platforms_from_rect_layer(level_editor->platforms_layer),
101         destroy_platforms);
102     if (level->platforms == NULL) {
103         RETURN_LT(lt, NULL);
104     }
105
106     level->goals = PUSH_LT(
107         lt,
108         create_goals_from_point_layer(level_editor->goals_layer),
109         destroy_goals);
110     if (level->goals == NULL) {
111         RETURN_LT(lt, NULL);
112     }
113
114     level->lava = PUSH_LT(
115         lt,
116         create_lava_from_rect_layer(level_editor->lava_layer),
117         destroy_lava);
118     if (level->lava == NULL) {
119         RETURN_LT(lt, NULL);
120     }
121
122     level->back_platforms = PUSH_LT(
123         lt,
124         create_platforms_from_rect_layer(level_editor->back_platforms_layer),
125         destroy_platforms);
126     if (level->back_platforms == NULL) {
127         RETURN_LT(lt, NULL);
128     }
129
130     level->boxes = PUSH_LT(
131         lt,
132         create_boxes_from_rect_layer(level_editor->boxes_layer, level->rigid_bodies),
133         destroy_boxes);
134     if (level->boxes == NULL) {
135         RETURN_LT(lt, NULL);
136     }
137
138     level->labels = PUSH_LT(
139         lt,
140         create_labels_from_label_layer(level_editor->label_layer),
141         destroy_labels);
142     if (level->labels == NULL) {
143         RETURN_LT(lt, NULL);
144     }
145
146     level->regions = PUSH_LT(
147         lt,
148         create_regions_from_rect_layer(
149             level_editor->regions_layer,
150             level->labels,
151             level->goals),
152         destroy_regions);
153     if (level->regions == NULL) {
154         RETURN_LT(lt, NULL);
155     }
156
157     level->console = PUSH_LT(
158         lt,
159         create_console(),
160         destroy_console);
161     if (level->console == NULL) {
162         RETURN_LT(lt, NULL);
163     }
164
165     return level;
166 }
167
168 void destroy_level(Level *level)
169 {
170     trace_assert(level);
171     RETURN_LT0(level->lt);
172 }
173
174 int level_render(const Level *level, const Camera *camera)
175 {
176     trace_assert(level);
177
178     if (background_render(level->background, camera) < 0) {
179         return -1;
180     }
181
182     if (platforms_render(level->back_platforms, camera) < 0) {
183         return -1;
184     }
185
186     if (player_render(level->player, camera) < 0) {
187         return -1;
188     }
189
190     if (boxes_render(level->boxes, camera) < 0) {
191         return -1;
192     }
193
194     if (lava_render(level->lava, camera) < 0) {
195         return -1;
196     }
197
198     if (platforms_render(level->platforms, camera) < 0) {
199         return -1;
200     }
201
202     if (goals_render(level->goals, camera) < 0) {
203         return -1;
204     }
205
206     if (labels_render(level->labels, camera) < 0) {
207         return -1;
208     }
209
210     if (regions_render(level->regions, camera) < 0) {
211         return -1;
212     }
213
214     if (level->console_enabled) {
215         if (console_render(level->console, camera) < 0) {
216             return -1;
217         }
218     }
219
220     return 0;
221 }
222
223 int level_update(Level *level, float delta_time)
224 {
225     trace_assert(level);
226     trace_assert(delta_time > 0);
227
228     if (level->console_enabled) {
229         if (console_update(level->console, delta_time) < 0) {
230             return -1;
231         }
232     }
233
234     if (level->state == LEVEL_STATE_PAUSE) {
235         return 0;
236     }
237
238     boxes_float_in_lava(level->boxes, level->lava);
239     rigid_bodies_apply_omniforce(level->rigid_bodies, vec(0.0f, LEVEL_GRAVITY));
240
241     boxes_update(level->boxes, delta_time);
242     player_update(level->player, delta_time);
243
244     rigid_bodies_collide(level->rigid_bodies, level->platforms);
245
246     player_die_from_lava(level->player, level->lava);
247     regions_player_enter(level->regions, level->player);
248     regions_player_leave(level->regions, level->player);
249
250     goals_update(level->goals, delta_time);
251     lava_update(level->lava, delta_time);
252     labels_update(level->labels, delta_time);
253
254     return 0;
255 }
256
257 static
258 int level_event_idle(Level *level, const SDL_Event *event,
259                      Camera *camera, Sound_samples *sound_samples)
260 {
261     trace_assert(level);
262
263     switch (event->type) {
264     case SDL_KEYDOWN:
265         switch (event->key.keysym.sym) {
266         case SDLK_w:
267         case SDLK_UP:
268         case SDLK_SPACE: {
269             player_jump(level->player);
270         } break;
271
272         case SDLK_p: {
273             level->state = LEVEL_STATE_PAUSE;
274             camera->blackwhite_mode = true;
275             sound_samples_toggle_pause(sound_samples);
276         } break;
277
278         case SDLK_l: {
279             camera_toggle_debug_mode(camera);
280         } break;
281         }
282         break;
283
284     case SDL_JOYBUTTONDOWN:
285         if (event->jbutton.button == 1) {
286             player_jump(level->player);
287         }
288         break;
289     }
290
291     return 0;
292 }
293
294 static
295 int level_event_pause(Level *level, const SDL_Event *event,
296                       Camera *camera, Sound_samples *sound_samples)
297 {
298     trace_assert(level);
299
300     switch (event->type) {
301     case SDL_KEYDOWN: {
302         switch (event->key.keysym.sym) {
303         case SDLK_p: {
304             level->state = LEVEL_STATE_IDLE;
305             camera->blackwhite_mode = false;
306             sound_samples_toggle_pause(sound_samples);
307         } break;
308         }
309     } break;
310     }
311
312     return 0;
313 }
314
315 static
316 int level_event_console(Level *level, const SDL_Event *event)
317 {
318     trace_assert(level);
319     trace_assert(event);
320
321     if (level->console_enabled) {
322         switch (event->type) {
323         case SDL_KEYDOWN:
324             switch (event->key.keysym.sym) {
325             case SDLK_ESCAPE:
326                 SDL_StopTextInput();
327                 level->console_enabled = 0;
328                 return 0;
329
330             default: {}
331             }
332
333         default: {}
334         }
335     } else {
336         switch (event->type) {
337         case SDL_KEYUP: {
338             switch (event->key.keysym.sym) {
339             case SDLK_BACKQUOTE:
340             case SDLK_c: {
341                 SDL_StartTextInput();
342                 level->console_enabled = 1;
343                 console_slide_down(level->console);
344             } break;
345             }
346         } break;
347         }
348     }
349
350     return console_handle_event(level->console, event);
351 }
352
353 int level_event(Level *level, const SDL_Event *event,
354                 Camera *camera, Sound_samples *sound_samples)
355 {
356     trace_assert(level);
357     trace_assert(event);
358
359     level_event_console(level, event);
360
361     if (level->console_enabled) {
362         return 0;
363     }
364
365     switch (level->state) {
366     case LEVEL_STATE_IDLE: {
367         return level_event_idle(level, event, camera, sound_samples);
368     } break;
369
370     case LEVEL_STATE_PAUSE: {
371         return level_event_pause(level, event, camera, sound_samples);
372     } break;
373     }
374
375     return 0;
376 }
377
378 int level_input(Level *level,
379                 const Uint8 *const keyboard_state,
380                 SDL_Joystick *the_stick_of_joy)
381 {
382     trace_assert(level);
383     trace_assert(keyboard_state);
384
385     if (level->console_enabled) {
386         return 0;
387     }
388
389     if (level->state == LEVEL_STATE_PAUSE) {
390         return 0;
391     }
392
393     if (keyboard_state[SDL_SCANCODE_A] || keyboard_state[SDL_SCANCODE_LEFT]) {
394         player_move_left(level->player);
395     } else if (keyboard_state[SDL_SCANCODE_D] || keyboard_state[SDL_SCANCODE_RIGHT]) {
396         player_move_right(level->player);
397     } else if (the_stick_of_joy && SDL_JoystickGetAxis(the_stick_of_joy, 0) < -JOYSTICK_THRESHOLD) {
398         player_move_left(level->player);
399     } else if (the_stick_of_joy && SDL_JoystickGetAxis(the_stick_of_joy, 0) > JOYSTICK_THRESHOLD) {
400         player_move_right(level->player);
401     } else {
402         player_stop(level->player);
403     }
404
405     return 0;
406 }
407
408 int level_sound(Level *level, Sound_samples *sound_samples)
409 {
410     if (level->state == LEVEL_STATE_PAUSE) {
411         return 0;
412     }
413
414     if (goals_sound(level->goals, sound_samples) < 0) {
415         return -1;
416     }
417
418     if (player_sound(level->player, sound_samples) < 0) {
419         return -1;
420     }
421
422     return 0;
423 }
424
425 int level_enter_camera_event(Level *level, Camera *camera)
426 {
427     if (level->state == LEVEL_STATE_PAUSE) {
428         return 0;
429     }
430
431     player_focus_camera(level->player, camera);
432     camera_scale(camera, 1.0f);
433
434     goals_cue(level->goals, camera);
435     goals_checkpoint(level->goals, level->player);
436     labels_enter_camera_event(level->labels, camera);
437     return 0;
438 }