2 #include "system/stacktrace.h"
7 #include "math/triangle.h"
8 #include "system/str.h"
9 #include "system/line_stream.h"
10 #include "system/lt.h"
11 #include "system/nth_alloc.h"
12 #include "system/log.h"
13 #include "ebisp/interpreter.h"
14 #include "broadcast.h"
15 #include "game/level/level_editor/point_layer.h"
17 #define GOAL_RADIUS 10.0f
18 #define GOAL_MAX_ID_SIZE 36
20 static int goals_is_goal_hidden(const Goals *goals, size_t i);
22 typedef enum Cue_state {
24 CUE_STATE_HIT_NOTHING,
25 CUE_STATE_SEEN_NOTHING
33 Cue_state *cue_states;
40 Goals *create_goals_from_line_stream(LineStream *line_stream)
42 trace_assert(line_stream);
46 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
53 line_stream_next(line_stream),
55 &goals->count) == EOF) {
56 log_fail("Could not read amount of goals\n");
62 nth_calloc(1, sizeof(char*) * goals->count),
64 if (goals->ids == NULL) {
67 for (size_t i = 0; i < goals->count; ++i) {
68 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
69 if (goals->ids[i] == NULL) {
74 goals->points = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
75 if (goals->points == NULL) {
79 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
80 if (goals->colors == NULL) {
84 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
85 if (goals->cue_states == NULL) {
89 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
90 if (goals->visible == NULL) {
95 for (size_t i = 0; i < goals->count; ++i) {
97 line_stream_next(line_stream),
98 "%" STRINGIFY(GOAL_MAX_ID_SIZE) "s%f%f%6s",
103 log_fail("Could not read %dth goal\n", i);
106 goals->colors[i] = hexstr(color);
107 goals->cue_states[i] = CUE_STATE_VIRGIN;
108 goals->visible[i] = true;
117 Goals *create_goals_from_point_layer(const PointLayer *point_layer)
119 trace_assert(point_layer);
121 Lt *lt = create_lt();
123 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
128 goals->count = point_layer_count(point_layer);
130 goals->ids = PUSH_LT(
132 nth_calloc(1, sizeof(char*) * goals->count),
134 if (goals->ids == NULL) {
137 for (size_t i = 0; i < goals->count; ++i) {
138 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
139 if (goals->ids[i] == NULL) {
144 goals->points = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
145 if (goals->points == NULL) {
149 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
150 if (goals->colors == NULL) {
154 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
155 if (goals->cue_states == NULL) {
159 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
160 if (goals->visible == NULL) {
164 const Point *points = point_layer_points(point_layer);
165 const Color *colors = point_layer_colors(point_layer);
166 const char *ids = point_layer_ids(point_layer);
168 // TODO(#835): we could use memcpy in create_goals_from_point_layer
169 for (size_t i = 0; i < goals->count; ++i) {
170 goals->points[i] = points[i];
171 goals->colors[i] = colors[i];
172 memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);
173 goals->cue_states[i] = CUE_STATE_VIRGIN;
174 goals->visible[i] = true;
183 void destroy_goals(Goals *goals)
186 RETURN_LT0(goals->lt);
189 static int goals_render_core(const Goals *goals,
194 trace_assert(camera);
196 const Point position = vec_sum(
197 goals->points[goal_index],
198 vec(0.0f, sinf(goals->angle) * 10.0f));
200 if (camera_fill_triangle(
202 triangle_mat3x3_product(
203 equilateral_triangle(),
205 trans_mat(position.x, position.y),
206 rot_mat(PI * -0.5f + goals->angle),
207 scale_mat(GOAL_RADIUS))),
208 goals->colors[goal_index]) < 0) {
212 if (camera_render_debug_text(
214 goals->ids[goal_index],
222 int goals_render(const Goals *goals,
226 trace_assert(camera);
228 for (size_t i = 0; i < goals->count; ++i) {
229 if (!goals_is_goal_hidden(goals, i)) {
230 if (goals_render_core(goals, i, camera) < 0) {
239 void goals_update(Goals *goals,
243 trace_assert(delta_time > 0.0f);
244 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
247 void goals_hide_from_player(Goals *goals,
250 goals->player_hitbox = player_hitbox;
254 int goals_sound(Goals *goals,
255 Sound_samples *sound_samples)
257 for (size_t i = 0; i < goals->count; ++i) {
258 switch (goals->cue_states[i]) {
259 case CUE_STATE_HIT_NOTHING:
260 sound_samples_play_sound(sound_samples, 0, 0);
261 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
271 void goals_cue(Goals *goals,
272 const Camera *camera)
274 for (size_t i = 0; i < goals->count; ++i) {
275 switch (goals->cue_states[i]) {
276 case CUE_STATE_VIRGIN:
277 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
278 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
283 case CUE_STATE_SEEN_NOTHING:
284 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
285 goals->cue_states[i] = CUE_STATE_VIRGIN;
294 void goals_checkpoint(const Goals *goals,
298 trace_assert(player);
300 for (size_t i = 0; i < goals->count; ++i) {
301 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
302 player_checkpoint(player, goals->points[i]);
307 static struct EvalResult
308 goals_action(Goals *goals, size_t index, Gc *gc, struct Scope *scope, struct Expr path)
314 const char *target = NULL;
315 struct EvalResult res = match_list(gc, "q*", path, &target, NULL);
320 if (strcmp(target, "show") == 0) {
321 goals->visible[index] = true;
322 return eval_success(NIL(gc));
323 } else if (strcmp(target, "hide") == 0) {
324 goals->visible[index] = false;
325 return eval_success(NIL(gc));
328 return unknown_target(gc, goals->ids[index], target);
332 goals_send(Goals *goals, Gc *gc, struct Scope *scope, struct Expr path)
338 const char *target = NULL;
339 struct Expr rest = void_expr();
340 struct EvalResult res = match_list(gc, "s*", path, &target, &rest);
345 for (size_t i = 0; i < goals->count; ++i) {
346 if (strcmp(target, goals->ids[i]) == 0) {
347 return goals_action(goals, i, gc, scope, rest);
351 return unknown_target(gc, "goals", target);
354 /* Private Functions */
356 static int goals_is_goal_hidden(const Goals *goals, size_t i)
358 return !goals->visible[i];