]> git.lizzy.rs Git - nothing.git/blob - src/game/level/regions.c
120145897cb829c4c74a3e0bbdf34806c1cea234
[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
16 enum RegionState {
17     RS_PLAYER_INSIDE = 0,
18     RS_PLAYER_OUTSIDE
19 };
20
21 struct Regions
22 {
23     Lt lt;
24     size_t count;
25     Rect *rects;
26     Color *colors;
27     Script **scripts;
28     enum RegionState *states;
29 };
30
31 Regions *create_regions_from_line_stream(LineStream *line_stream, Broadcast *broadcast)
32 {
33     trace_assert(line_stream);
34
35     Lt lt = create_lt();
36     if (lt == NULL) {
37         return NULL;
38     }
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->rects = PUSH_LT(
58         lt,
59         nth_calloc(1, sizeof(Rect) * regions->count),
60         free);
61     if (regions->rects == NULL) {
62         RETURN_LT(lt, NULL);
63     }
64
65     regions->colors = PUSH_LT(
66         lt,
67         nth_calloc(1, sizeof(Color) * regions->count),
68         free);
69     if (regions->colors == NULL) {
70         RETURN_LT(lt, NULL);
71     }
72
73     regions->scripts = PUSH_LT(
74         lt,
75         nth_calloc(1, sizeof(Script*) * regions->count),
76         free);
77     if (regions->scripts == 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                 "%f%f%f%f%6s",
97                 &regions->rects[i].x,
98                 &regions->rects[i].y,
99                 &regions->rects[i].w,
100                 &regions->rects[i].h,
101                 color) < 0) {
102             log_fail("Could not read size and color of %dth region\n");
103             RETURN_LT(lt, NULL);
104         }
105
106         regions->colors[i] = hexstr(color);
107
108         regions->scripts[i] = PUSH_LT(
109             lt,
110             create_script_from_line_stream(line_stream, broadcast),
111             destroy_script);
112         if (regions->scripts[i] == NULL) {
113             RETURN_LT(lt, NULL);
114         }
115
116         /* TODO(#472): Script doesn't provide its id on missing callback error */
117         if (!script_has_scope_value(regions->scripts[i], "on-enter")) {
118             log_fail("Script does not provide on-enter callback\n");
119             RETURN_LT(lt, NULL);
120         }
121
122         if (!script_has_scope_value(regions->scripts[i], "on-leave")) {
123             log_fail("Script does not provide on-leave callback\n");
124             RETURN_LT(lt, NULL);
125         }
126
127         regions->states[i] = RS_PLAYER_OUTSIDE;
128     }
129
130
131     return regions;
132 }
133
134 void destroy_regions(Regions *regions)
135 {
136     trace_assert(regions);
137     RETURN_LT0(regions->lt);
138 }
139
140 void regions_player_enter(Regions *regions, Player *player)
141 {
142     trace_assert(regions);
143     trace_assert(player);
144
145     for (size_t i = 0; i < regions->count; ++i) {
146         if (regions->states[i] == RS_PLAYER_OUTSIDE &&
147             player_overlaps_rect(player, regions->rects[i])) {
148             regions->states[i] = RS_PLAYER_INSIDE;
149             script_eval(regions->scripts[i], "(on-enter)");
150         }
151     }
152 }
153
154 void regions_player_leave(Regions *regions, Player *player)
155 {
156     trace_assert(regions);
157     trace_assert(player);
158
159     for (size_t i = 0; i < regions->count; ++i) {
160         if (regions->states[i] == RS_PLAYER_INSIDE &&
161             !player_overlaps_rect(player, regions->rects[i])) {
162             regions->states[i] = RS_PLAYER_OUTSIDE;
163             script_eval(regions->scripts[i], "(on-leave)");
164         }
165     }
166 }
167
168 int regions_render(Regions *regions, Camera *camera)
169 {
170     trace_assert(regions);
171     trace_assert(camera);
172
173     for (size_t i = 0; i < regions->count; ++i) {
174         if (camera_render_debug_rect(
175                 camera,
176                 regions->rects[i],
177                 regions->colors[i]) < 0) {
178             return -1;
179         }
180     }
181
182     return 0;
183 }