]> git.lizzy.rs Git - nothing.git/blob - src/game/level/boxes.c
Merge pull request #1046 from tsoding/704
[nothing.git] / src / game / level / boxes.c
1 #include "system/stacktrace.h"
2
3 #include "broadcast.h"
4 #include "dynarray.h"
5 #include "ebisp/builtins.h"
6 #include "ebisp/interpreter.h"
7 #include "game/level/boxes.h"
8 #include "game/level/level_editor/rect_layer.h"
9 #include "game/level/player.h"
10 #include "game/level/rigid_bodies.h"
11 #include "math/rand.h"
12 #include "system/line_stream.h"
13 #include "system/log.h"
14 #include "system/lt.h"
15 #include "system/nth_alloc.h"
16 #include "system/str.h"
17
18 struct Boxes
19 {
20     Lt *lt;
21     RigidBodies *rigid_bodies;
22     Dynarray *boxes_ids;
23     Dynarray *body_ids;
24     Dynarray *body_colors;
25 };
26
27 Boxes *create_boxes_from_rect_layer(const RectLayer *layer, RigidBodies *rigid_bodies)
28 {
29     trace_assert(layer);
30     trace_assert(rigid_bodies);
31
32     Lt *lt = create_lt();
33
34     Boxes *boxes = PUSH_LT(lt, nth_calloc(1, sizeof(Boxes)), free);
35     if (boxes == NULL) {
36         RETURN_LT(lt, NULL);
37     }
38     boxes->lt = lt;
39
40     boxes->rigid_bodies = rigid_bodies;
41
42     boxes->boxes_ids = PUSH_LT(
43         lt,
44         create_dynarray(RECT_LAYER_ID_MAX_SIZE),
45         destroy_dynarray);
46     if (boxes->boxes_ids == NULL) {
47         RETURN_LT(lt, NULL);
48     }
49
50     boxes->body_ids = PUSH_LT(lt, create_dynarray(sizeof(RigidBodyId)), destroy_dynarray);
51     if (boxes->body_ids == NULL) {
52         RETURN_LT(lt, NULL);
53     }
54
55     boxes->body_colors = PUSH_LT(lt, create_dynarray(sizeof(Color)), destroy_dynarray);
56     if (boxes->body_colors == NULL) {
57         RETURN_LT(lt, NULL);
58     }
59
60     const size_t count = rect_layer_count(layer);
61     Rect const *rects = rect_layer_rects(layer);
62     Color const *colors = rect_layer_colors(layer);
63     const char *ids = rect_layer_ids(layer);
64
65     for (size_t i = 0; i < count; ++i) {
66         RigidBodyId body_id = rigid_bodies_add(rigid_bodies, rects[i]);
67         dynarray_push(boxes->body_ids, &body_id);
68         dynarray_push(boxes->body_colors, &colors[i]);
69         dynarray_push(boxes->boxes_ids, ids + i * RECT_LAYER_ID_MAX_SIZE);
70     }
71
72     return boxes;
73 }
74
75 void destroy_boxes(Boxes *boxes)
76 {
77     trace_assert(boxes);
78
79     const size_t count = dynarray_count(boxes->body_ids);
80     RigidBodyId *body_ids = dynarray_data(boxes->body_ids);
81
82     for (size_t i = 0; i < count; ++i) {
83         rigid_bodies_remove(boxes->rigid_bodies, body_ids[i]);
84     }
85
86     RETURN_LT0(boxes->lt);
87 }
88
89 int boxes_render(Boxes *boxes, Camera *camera)
90 {
91     trace_assert(boxes);
92     trace_assert(camera);
93
94     const size_t count = dynarray_count(boxes->body_ids);
95     RigidBodyId *body_ids = dynarray_data(boxes->body_ids);
96     Color *body_colors = dynarray_data(boxes->body_colors);
97
98     for (size_t i = 0; i < count; ++i) {
99         if (rigid_bodies_render(
100                 boxes->rigid_bodies,
101                 body_ids[i],
102                 body_colors[i],
103                 camera) < 0) {
104             return -1;
105         }
106     }
107
108     return 0;
109 }
110
111 int boxes_update(Boxes *boxes,
112                  float delta_time)
113 {
114     trace_assert(boxes);
115
116     const size_t count = dynarray_count(boxes->body_ids);
117     RigidBodyId *body_ids = dynarray_data(boxes->body_ids);
118
119     for (size_t i = 0; i < count; ++i) {
120         if (rigid_bodies_update(boxes->rigid_bodies, body_ids[i], delta_time) < 0) {
121             return -1;
122         }
123     }
124
125     return 0;
126 }
127
128 void boxes_float_in_lava(Boxes *boxes, Lava *lava)
129 {
130     trace_assert(boxes);
131     trace_assert(lava);
132
133     const size_t count = dynarray_count(boxes->body_ids);
134     RigidBodyId *body_ids = dynarray_data(boxes->body_ids);
135
136     for (size_t i = 0; i < count; ++i) {
137         lava_float_rigid_body(lava, boxes->rigid_bodies, body_ids[i]);
138     }
139 }
140
141 int boxes_add_box(Boxes *boxes, Rect rect, Color color)
142 {
143     trace_assert(boxes);
144
145     RigidBodyId body_id = rigid_bodies_add(boxes->rigid_bodies, rect);
146     dynarray_push(boxes->body_ids, &body_id);
147     dynarray_push(boxes->body_colors, &color);
148
149     return 0;
150 }
151
152 struct EvalResult
153 boxes_send(Boxes *boxes, Gc *gc, struct Scope *scope, struct Expr path)
154 {
155     trace_assert(boxes);
156     trace_assert(gc);
157     trace_assert(scope);
158
159     struct Expr target = void_expr();
160     struct Expr rest = void_expr();
161     struct EvalResult res = match_list(gc, "e*", path, &target, &rest);
162     if (res.is_error) {
163         return res;
164     }
165
166     if (symbol_p(target)) {
167         const char *action = target.atom->str;
168
169         if (strcmp(action, "new") == 0) {
170             struct Expr optional_args = void_expr();
171             long int x, y, w, h;
172             res = match_list(gc, "dddd*", rest, &x, &y, &w, &h, &optional_args);
173             if (res.is_error) {
174                 return res;
175             }
176
177             Color color = rgba(rand_float(1.0f), rand_float(1.0f), rand_float(1.0f), 1.0f);
178             if (!nil_p(optional_args)) {
179                 const char *color_hex = NULL;
180                 res = match_list(gc, "s*", optional_args, &color_hex, NULL);
181                 color = hexstr(color_hex);
182             }
183
184             boxes_add_box(boxes, rect((float) x, (float) y, (float) w, (float) h), color);
185
186             return eval_success(NIL(gc));
187         } else if (strcmp(action, "coord") == 0) {
188             const char *box_id = NULL;
189             res = match_list(gc, "s", rest, &box_id);
190             if (res.is_error) {
191                 return res;
192             }
193
194             size_t n = dynarray_count(boxes->boxes_ids);
195             RigidBodyId *body_ids = dynarray_data(boxes->body_ids);
196             for (size_t i = 0; i < n; ++i) {
197                 if (strcmp(dynarray_pointer_at(boxes->boxes_ids, i), box_id) == 0) {
198                     Rect hitbox = rigid_bodies_hitbox(boxes->rigid_bodies, body_ids[i]);
199                     return eval_success(
200                         CONS(gc,
201                              NUMBER(gc, (long int)hitbox.x),
202                              NUMBER(gc, (long int)hitbox.y)));
203                 }
204             }
205
206             return eval_failure(SYMBOL(gc, "box-not-found"));
207         }
208
209         return unknown_target(gc, "box", action);
210     }
211
212     return wrong_argument_type(gc, "string-or-symbol-p", target);
213 }
214
215
216 int boxes_delete_at(Boxes *boxes, Vec position)
217 {
218     trace_assert(boxes);
219
220     const size_t count = dynarray_count(boxes->body_ids);
221     RigidBodyId *body_ids = dynarray_data(boxes->body_ids);
222
223     for (size_t i = 0; i < count; ++i) {
224         const Rect hitbox = rigid_bodies_hitbox(
225             boxes->rigid_bodies,
226             body_ids[i]);
227         if (rect_contains_point(hitbox, position)) {
228             rigid_bodies_remove(boxes->rigid_bodies, body_ids[i]);
229             dynarray_delete_at(boxes->body_ids, i);
230             dynarray_delete_at(boxes->body_colors, i);
231             return 0;
232         }
233     }
234
235     return 0;
236 }