]> git.lizzy.rs Git - nothing.git/blob - src/game/level/regions.c
(#819) Integrate LevelEditor Regions with Level
[nothing.git] / src / game / level / regions.c
1 #include "system/stacktrace.h"
2
3 #include "ebisp/gc.h"
4 #include "ebisp/interpreter.h"
5 #include "ebisp/parser.h"
6 #include "ebisp/scope.h"
7 #include "player.h"
8 #include "regions.h"
9 #include "script.h"
10 #include "system/str.h"
11 #include "system/line_stream.h"
12 #include "system/log.h"
13 #include "system/lt.h"
14 #include "system/nth_alloc.h"
15 #include "game/level/level_editor/rect_layer.h"
16
17 #define ID_MAX_SIZE 36
18
19 enum RegionState {
20     RS_PLAYER_OUTSIDE = 0,
21     RS_PLAYER_INSIDE
22 };
23
24 struct Regions
25 {
26     Lt *lt;
27     size_t count;
28     char *ids;
29     Rect *rects;
30     Color *colors;
31     enum RegionState *states;
32 };
33
34 Regions *create_regions_from_line_stream(LineStream *line_stream)
35 {
36     trace_assert(line_stream);
37
38     Lt *lt = create_lt();
39
40     Regions *regions = PUSH_LT(
41         lt,
42         nth_calloc(1, sizeof(Regions)),
43         free);
44     if (regions == NULL) {
45         RETURN_LT(lt, NULL);
46     }
47     regions->lt = lt;
48
49     if(sscanf(
50            line_stream_next(line_stream),
51            "%lu",
52            &regions->count) < 0) {
53         log_fail("Could not read amount of script regions\n");
54         RETURN_LT(lt, NULL);
55     }
56
57     regions->ids = PUSH_LT(
58         lt,
59         nth_calloc(regions->count * ID_MAX_SIZE, sizeof(char)),
60         free);
61     if (regions->ids == NULL) {
62         RETURN_LT(lt, NULL);
63     }
64
65     regions->rects = PUSH_LT(
66         lt,
67         nth_calloc(1, sizeof(Rect) * regions->count),
68         free);
69     if (regions->rects == NULL) {
70         RETURN_LT(lt, NULL);
71     }
72
73     regions->colors = PUSH_LT(
74         lt,
75         nth_calloc(1, sizeof(Color) * regions->count),
76         free);
77     if (regions->colors == NULL) {
78         RETURN_LT(lt, NULL);
79     }
80
81     regions->states = PUSH_LT(
82         lt,
83         nth_calloc(1, sizeof(enum RegionState) * regions->count),
84         free);
85     if (regions->states == NULL) {
86         RETURN_LT(lt, NULL);
87     }
88
89     log_info("Amount of regions: %lu\n", regions->count);
90
91     char color[7];
92
93     for (size_t i = 0; i < regions->count; ++i) {
94         if (sscanf(
95                 line_stream_next(line_stream),
96                 "%" STRINGIFY(ID_MAX_SIZE) "s%f%f%f%f%6s",
97                 regions->ids + ID_MAX_SIZE * i,
98                 &regions->rects[i].x,
99                 &regions->rects[i].y,
100                 &regions->rects[i].w,
101                 &regions->rects[i].h,
102                 color) < 0) {
103             log_fail("Could not read size and color of %dth region\n");
104             RETURN_LT(lt, NULL);
105         }
106
107         regions->colors[i] = hexstr(color);
108         regions->states[i] = RS_PLAYER_OUTSIDE;
109     }
110
111
112     return regions;
113 }
114
115 Regions *create_regions_from_rect_layer(const RectLayer *rect_layer)
116 {
117     trace_assert(rect_layer);
118
119     Lt *lt = create_lt();
120
121     Regions *regions = PUSH_LT(
122         lt,
123         nth_calloc(1, sizeof(Regions)),
124         free);
125     if (regions == NULL) {
126         RETURN_LT(lt, NULL);
127     }
128     regions->lt = lt;
129
130     regions->count = rect_layer_count(rect_layer);
131
132     regions->ids = PUSH_LT(
133         lt,
134         nth_calloc(regions->count * ID_MAX_SIZE, sizeof(char)),
135         free);
136     if (regions->ids == NULL) {
137         RETURN_LT(lt, NULL);
138     }
139     memcpy(regions->ids,
140            rect_layer_ids(rect_layer),
141            regions->count * ID_MAX_SIZE * sizeof(char));
142
143
144     regions->rects = PUSH_LT(
145         lt,
146         nth_calloc(1, sizeof(Rect) * regions->count),
147         free);
148     if (regions->rects == NULL) {
149         RETURN_LT(lt, NULL);
150     }
151     memcpy(regions->rects,
152            rect_layer_rects(rect_layer),
153            regions->count * sizeof(Rect));
154
155
156     regions->colors = PUSH_LT(
157         lt,
158         nth_calloc(1, sizeof(Color) * regions->count),
159         free);
160     if (regions->colors == NULL) {
161         RETURN_LT(lt, NULL);
162     }
163     memcpy(regions->colors,
164            rect_layer_colors(rect_layer),
165            regions->count * sizeof(Color));
166
167     regions->states = PUSH_LT(
168         lt,
169         nth_calloc(1, sizeof(enum RegionState) * regions->count),
170         free);
171     if (regions->states == NULL) {
172         RETURN_LT(lt, NULL);
173     }
174
175     return regions;
176 }
177
178 void destroy_regions(Regions *regions)
179 {
180     trace_assert(regions);
181     RETURN_LT0(regions->lt);
182 }
183
184 void regions_player_enter(Regions *regions, Player *player, Script *supa_script)
185 {
186     trace_assert(regions);
187     trace_assert(player);
188
189     for (size_t i = 0; i < regions->count; ++i) {
190         if (regions->states[i] == RS_PLAYER_OUTSIDE &&
191             player_overlaps_rect(player, regions->rects[i])) {
192             regions->states[i] = RS_PLAYER_INSIDE;
193
194             Gc *gc = script_gc(supa_script);
195             if (script_has_scope_value(supa_script, "on-region-enter")) {
196                 script_eval(
197                     supa_script,
198                     list(gc, "qs",
199                          "on-region-enter",
200                          regions->ids + i * ID_MAX_SIZE));
201             }
202         }
203     }
204 }
205
206 void regions_player_leave(Regions *regions, Player *player, Script *supa_script)
207 {
208     trace_assert(regions);
209     trace_assert(player);
210     trace_assert(supa_script);
211
212     for (size_t i = 0; i < regions->count; ++i) {
213         if (regions->states[i] == RS_PLAYER_INSIDE &&
214             !player_overlaps_rect(player, regions->rects[i])) {
215             regions->states[i] = RS_PLAYER_OUTSIDE;
216             Gc *gc = script_gc(supa_script);
217             if (script_has_scope_value(supa_script, "on-region-leave")) {
218                 script_eval(
219                     supa_script,
220                     list(gc, "qs",
221                          "on-region-leave",
222                          regions->ids + i * ID_MAX_SIZE));
223             }
224         }
225     }
226 }
227
228 int regions_render(Regions *regions, Camera *camera)
229 {
230     trace_assert(regions);
231     trace_assert(camera);
232
233     for (size_t i = 0; i < regions->count; ++i) {
234         if (camera_render_debug_rect(
235                 camera,
236                 regions->rects[i],
237                 regions->colors[i]) < 0) {
238             return -1;
239         }
240     }
241
242     return 0;
243 }