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);
44 Lt *const lt = create_lt();
49 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
56 line_stream_next(line_stream),
58 &goals->count) == EOF) {
59 log_fail("Could not read amount of goals\n");
65 nth_calloc(1, sizeof(char*) * goals->count),
67 if (goals->ids == NULL) {
70 for (size_t i = 0; i < goals->count; ++i) {
71 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
72 if (goals->ids[i] == NULL) {
77 goals->points = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
78 if (goals->points == NULL) {
82 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
83 if (goals->colors == NULL) {
87 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
88 if (goals->cue_states == NULL) {
92 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
93 if (goals->visible == NULL) {
98 for (size_t i = 0; i < goals->count; ++i) {
100 line_stream_next(line_stream),
101 "%" STRINGIFY(GOAL_MAX_ID_SIZE) "s%f%f%6s",
106 log_fail("Could not read %dth goal\n", i);
109 goals->colors[i] = hexstr(color);
110 goals->cue_states[i] = CUE_STATE_VIRGIN;
111 goals->visible[i] = true;
120 Goals *create_goals_from_point_rect_layer(PointLayer *point_rect_layer)
122 trace_assert(point_rect_layer);
124 Lt *const lt = create_lt();
129 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
134 goals->count = point_layer_count(point_rect_layer);
136 goals->ids = PUSH_LT(
138 nth_calloc(1, sizeof(char*) * goals->count),
140 if (goals->ids == NULL) {
143 for (size_t i = 0; i < goals->count; ++i) {
144 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
145 if (goals->ids[i] == NULL) {
150 goals->points = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
151 if (goals->points == NULL) {
155 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
156 if (goals->colors == NULL) {
160 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
161 if (goals->cue_states == NULL) {
165 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
166 if (goals->visible == NULL) {
170 const Point *points = point_layer_points(point_rect_layer);
171 const Color *colors = point_layer_colors(point_rect_layer);
172 const char *ids = point_layer_ids(point_rect_layer);
174 // TODO(#835): we could use memcpy in create_goals_from_point_rect_layer
175 for (size_t i = 0; i < goals->count; ++i) {
176 goals->points[i] = points[i];
177 goals->colors[i] = colors[i];
178 memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);
179 goals->cue_states[i] = CUE_STATE_VIRGIN;
180 goals->visible[i] = true;
189 void destroy_goals(Goals *goals)
192 RETURN_LT0(goals->lt);
195 static int goals_render_core(const Goals *goals,
200 trace_assert(camera);
202 const Point position = vec_sum(
203 goals->points[goal_index],
204 vec(0.0f, sinf(goals->angle) * 10.0f));
206 if (camera_fill_triangle(
208 triangle_mat3x3_product(
209 equilateral_triangle(),
211 trans_mat(position.x, position.y),
212 rot_mat(PI * -0.5f + goals->angle),
213 scale_mat(GOAL_RADIUS))),
214 goals->colors[goal_index]) < 0) {
218 if (camera_render_debug_text(
220 goals->ids[goal_index],
228 int goals_render(const Goals *goals,
232 trace_assert(camera);
234 for (size_t i = 0; i < goals->count; ++i) {
235 if (!goals_is_goal_hidden(goals, i)) {
236 if (goals_render_core(goals, i, camera) < 0) {
245 void goals_update(Goals *goals,
249 trace_assert(delta_time > 0.0f);
250 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
253 void goals_hide_from_player(Goals *goals,
256 goals->player_hitbox = player_hitbox;
260 int goals_sound(Goals *goals,
261 Sound_samples *sound_samples)
263 for (size_t i = 0; i < goals->count; ++i) {
264 switch (goals->cue_states[i]) {
265 case CUE_STATE_HIT_NOTHING:
266 sound_samples_play_sound(sound_samples, 0, 0);
267 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
277 void goals_cue(Goals *goals,
278 const Camera *camera)
280 for (size_t i = 0; i < goals->count; ++i) {
281 switch (goals->cue_states[i]) {
282 case CUE_STATE_VIRGIN:
283 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
284 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
289 case CUE_STATE_SEEN_NOTHING:
290 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
291 goals->cue_states[i] = CUE_STATE_VIRGIN;
300 void goals_checkpoint(const Goals *goals,
304 trace_assert(player);
306 for (size_t i = 0; i < goals->count; ++i) {
307 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
308 player_checkpoint(player, goals->points[i]);
313 static struct EvalResult
314 goals_action(Goals *goals, size_t index, Gc *gc, struct Scope *scope, struct Expr path)
320 const char *target = NULL;
321 struct EvalResult res = match_list(gc, "q*", path, &target, NULL);
326 if (strcmp(target, "show") == 0) {
327 goals->visible[index] = true;
328 return eval_success(NIL(gc));
329 } else if (strcmp(target, "hide") == 0) {
330 goals->visible[index] = false;
331 return eval_success(NIL(gc));
334 return unknown_target(gc, goals->ids[index], target);
338 goals_send(Goals *goals, Gc *gc, struct Scope *scope, struct Expr path)
344 const char *target = NULL;
345 struct Expr rest = void_expr();
346 struct EvalResult res = match_list(gc, "s*", path, &target, &rest);
351 for (size_t i = 0; i < goals->count; ++i) {
352 if (strcmp(target, goals->ids[i]) == 0) {
353 return goals_action(goals, i, gc, scope, rest);
357 return unknown_target(gc, "goals", target);
360 /* Private Functions */
362 static int goals_is_goal_hidden(const Goals *goals, size_t i)
364 return !goals->visible[i];