]> git.lizzy.rs Git - nothing.git/blob - src/game/level/lava.c
Merge pull request #1055 from tsoding/1045
[nothing.git] / src / game / level / lava.c
1 #include <SDL.h>
2 #include "system/stacktrace.h"
3 #include <stdio.h>
4
5 #include "color.h"
6 #include "game/level/lava/wavy_rect.h"
7 #include "lava.h"
8 #include "math/rect.h"
9 #include "system/lt.h"
10 #include "system/line_stream.h"
11 #include "system/nth_alloc.h"
12 #include "system/log.h"
13 #include "game/level/level_editor/rect_layer.h"
14
15 #define LAVA_BOINGNESS 2500.0f
16
17 struct Lava {
18     Lt *lt;
19     size_t rects_count;
20     Wavy_rect **rects;
21 };
22
23 Lava *create_lava_from_line_stream(LineStream *line_stream)
24 {
25     trace_assert(line_stream);
26
27     Lt *lt = create_lt();
28
29     Lava *lava = PUSH_LT(lt, nth_calloc(1, sizeof(Lava)), free);
30     if (lava == NULL) {
31         RETURN_LT(lt, NULL);
32     }
33
34     if (sscanf(
35             line_stream_next(line_stream),
36             "%zu",
37             &lava->rects_count) < 0) {
38         log_fail("Could not read amount of lava\n");
39         RETURN_LT(lt, NULL);
40     }
41
42     lava->rects = PUSH_LT(lt, nth_calloc(1, sizeof(Wavy_rect*) * lava->rects_count), free);
43     if (lava->rects == NULL) {
44         RETURN_LT(lt, NULL);
45     }
46
47     for (size_t i = 0; i < lava->rects_count; ++i) {
48         lava->rects[i] = PUSH_LT(lt, create_wavy_rect_from_line_stream(line_stream), destroy_wavy_rect);
49         if (lava->rects[i] == NULL) {
50             RETURN_LT(lt, NULL);
51         }
52     }
53
54     lava->lt = lt;
55
56     return lava;
57 }
58
59 Lava *create_lava_from_rect_layer(const RectLayer *rect_layer)
60 {
61     Lt *lt = create_lt();
62
63     Lava *lava = PUSH_LT(lt, nth_calloc(1, sizeof(Lava)), free);
64     if (lava == NULL) {
65         RETURN_LT(lt, NULL);
66     }
67     lava->lt = lt;
68
69     lava->rects_count = rect_layer_count(rect_layer);
70     lava->rects = PUSH_LT(lt, nth_calloc(lava->rects_count, sizeof(Wavy_rect*)), free);
71     if (lava->rects == NULL) {
72         RETURN_LT(lt, NULL);
73     }
74
75     const Rect *rects = rect_layer_rects(rect_layer);
76     const Color *colors = rect_layer_colors(rect_layer);
77     for (size_t i = 0; i < lava->rects_count; ++i) {
78         lava->rects[i] = PUSH_LT(lt, create_wavy_rect(rects[i], colors[i]), destroy_wavy_rect);
79         if (lava->rects[i] == NULL) {
80             RETURN_LT(lt, NULL);
81         }
82     }
83
84     return lava;
85 }
86
87 void destroy_lava(Lava *lava)
88 {
89     trace_assert(lava);
90     RETURN_LT0(lava->lt);
91 }
92
93 /* TODO(#449): lava does not render its id in debug mode */
94 int lava_render(const Lava *lava,
95                 const Camera *camera)
96 {
97     trace_assert(lava);
98     trace_assert(camera);
99
100     for (size_t i = 0; i < lava->rects_count; ++i) {
101         if (wavy_rect_render(lava->rects[i], camera) < 0) {
102             return -1;
103         }
104     }
105
106     return 0;
107 }
108
109 int lava_update(Lava *lava, float delta_time)
110 {
111     trace_assert(lava);
112
113     for (size_t i = 0; i < lava->rects_count; ++i) {
114         if (wavy_rect_update(lava->rects[i], delta_time) < 0) {
115             return -1;
116         }
117     }
118
119     return 0;
120 }
121
122 bool lava_overlaps_rect(const Lava *lava,
123                         Rect rect)
124 {
125     trace_assert(lava);
126
127     for (size_t i = 0; i < lava->rects_count; ++i) {
128         if (rects_overlap(wavy_rect_hitbox(lava->rects[i]), rect)) {
129             return true;
130         }
131     }
132
133     return 0;
134 }
135
136 void lava_float_rigid_body(Lava *lava, RigidBodies *rigid_bodies, RigidBodyId id)
137 {
138     trace_assert(lava);
139
140     const Rect object_hitbox = rigid_bodies_hitbox(rigid_bodies, id);
141     for (size_t i = 0; i < lava->rects_count; ++i) {
142         const Rect lava_hitbox = wavy_rect_hitbox(lava->rects[i]);
143         if (rects_overlap(object_hitbox, lava_hitbox)) {
144             const Rect overlap_area = rects_overlap_area(object_hitbox, lava_hitbox);
145             const float k = overlap_area.w * overlap_area.h / (object_hitbox.w * object_hitbox.h);
146             rigid_bodies_apply_force(
147                 rigid_bodies,
148                 id,
149                 vec(0.0f, -k * LAVA_BOINGNESS));
150             rigid_bodies_damper(rigid_bodies, id, vec(0.0f, -0.9f));
151         }
152     }
153 }