7 #include "ebisp/interpreter.h"
8 #include "game/level/level_editor/point_layer.h"
11 #include "math/triangle.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/stacktrace.h"
17 #include "system/str.h"
19 #define GOAL_RADIUS 10.0f
20 #define GOAL_MAX_ID_SIZE 36
22 static int goals_is_goal_hidden(const Goals *goals, size_t i);
24 typedef enum Cue_state {
26 CUE_STATE_HIT_NOTHING,
27 CUE_STATE_SEEN_NOTHING
35 Cue_state *cue_states;
42 Goals *create_goals_from_line_stream(LineStream *line_stream)
44 trace_assert(line_stream);
48 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
55 line_stream_next(line_stream),
57 &goals->count) == EOF) {
58 log_fail("Could not read amount of goals\n");
64 nth_calloc(1, sizeof(char*) * goals->count),
66 if (goals->ids == NULL) {
69 for (size_t i = 0; i < goals->count; ++i) {
70 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
71 if (goals->ids[i] == NULL) {
76 goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
77 if (goals->positions == NULL) {
81 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
82 if (goals->colors == NULL) {
86 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
87 if (goals->cue_states == NULL) {
91 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
92 if (goals->visible == NULL) {
97 for (size_t i = 0; i < goals->count; ++i) {
99 line_stream_next(line_stream),
100 "%" STRINGIFY(GOAL_MAX_ID_SIZE) "s%f%f%6s",
102 &goals->positions[i].x,
103 &goals->positions[i].y,
105 log_fail("Could not read %dth goal\n", i);
108 goals->colors[i] = hexstr(color);
109 goals->cue_states[i] = CUE_STATE_VIRGIN;
110 goals->visible[i] = true;
119 Goals *create_goals_from_point_layer(const PointLayer *point_layer)
121 trace_assert(point_layer);
123 Lt *lt = create_lt();
125 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
130 goals->count = point_layer_count(point_layer);
132 goals->ids = PUSH_LT(
134 nth_calloc(1, sizeof(char*) * goals->count),
136 if (goals->ids == NULL) {
139 for (size_t i = 0; i < goals->count; ++i) {
140 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
141 if (goals->ids[i] == NULL) {
146 goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
147 if (goals->positions == NULL) {
151 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
152 if (goals->colors == NULL) {
156 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
157 if (goals->cue_states == NULL) {
161 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
162 if (goals->visible == NULL) {
166 const Point *positions = point_layer_positions(point_layer);
167 const Color *colors = point_layer_colors(point_layer);
168 const char *ids = point_layer_ids(point_layer);
170 // TODO(#835): we could use memcpy in create_goals_from_point_layer
171 for (size_t i = 0; i < goals->count; ++i) {
172 goals->positions[i] = positions[i];
173 goals->colors[i] = colors[i];
174 memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);
175 goals->cue_states[i] = CUE_STATE_VIRGIN;
176 goals->visible[i] = true;
185 void destroy_goals(Goals *goals)
188 RETURN_LT0(goals->lt);
191 static int goals_render_core(const Goals *goals,
196 trace_assert(camera);
198 const Point position = vec_sum(
199 goals->positions[goal_index],
200 vec(0.0f, sinf(goals->angle) * 10.0f));
202 if (camera_fill_triangle(
204 triangle_mat3x3_product(
205 equilateral_triangle(),
207 trans_mat(position.x, position.y),
208 rot_mat(PI * -0.5f + goals->angle),
209 scale_mat(GOAL_RADIUS))),
210 goals->colors[goal_index]) < 0) {
214 if (camera_render_debug_text(
216 goals->ids[goal_index],
224 int goals_render(const Goals *goals,
228 trace_assert(camera);
230 for (size_t i = 0; i < goals->count; ++i) {
231 if (!goals_is_goal_hidden(goals, i)) {
232 if (goals_render_core(goals, i, camera) < 0) {
241 void goals_update(Goals *goals,
245 trace_assert(delta_time > 0.0f);
246 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
249 void goals_hide_from_player(Goals *goals,
252 goals->player_hitbox = player_hitbox;
256 int goals_sound(Goals *goals,
257 Sound_samples *sound_samples)
259 for (size_t i = 0; i < goals->count; ++i) {
260 switch (goals->cue_states[i]) {
261 case CUE_STATE_HIT_NOTHING:
262 sound_samples_play_sound(sound_samples, 0);
263 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
273 void goals_cue(Goals *goals,
274 const Camera *camera)
276 for (size_t i = 0; i < goals->count; ++i) {
277 switch (goals->cue_states[i]) {
278 case CUE_STATE_VIRGIN:
279 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
280 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
285 case CUE_STATE_SEEN_NOTHING:
286 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
287 goals->cue_states[i] = CUE_STATE_VIRGIN;
296 void goals_checkpoint(const Goals *goals,
300 trace_assert(player);
302 for (size_t i = 0; i < goals->count; ++i) {
303 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
304 player_checkpoint(player, goals->positions[i]);
309 static struct EvalResult
310 goals_action(Goals *goals, size_t index, Gc *gc, struct Scope *scope, struct Expr path)
316 const char *target = NULL;
317 struct EvalResult res = match_list(gc, "q*", path, &target, NULL);
322 if (strcmp(target, "show") == 0) {
323 goals->visible[index] = true;
324 return eval_success(NIL(gc));
325 } else if (strcmp(target, "hide") == 0) {
326 goals->visible[index] = false;
327 return eval_success(NIL(gc));
330 return unknown_target(gc, goals->ids[index], target);
334 goals_send(Goals *goals, Gc *gc, struct Scope *scope, struct Expr path)
340 const char *target = NULL;
341 struct Expr rest = void_expr();
342 struct EvalResult res = match_list(gc, "s*", path, &target, &rest);
347 for (size_t i = 0; i < goals->count; ++i) {
348 if (strcmp(target, goals->ids[i]) == 0) {
349 return goals_action(goals, i, gc, scope, rest);
353 return unknown_target(gc, "goals", target);
356 /* Private Functions */
358 static int goals_is_goal_hidden(const Goals *goals, size_t i)
360 return !goals->visible[i];