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