2 #include "system/stacktrace.h"
7 #include "math/triangle.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"
16 #define GOAL_RADIUS 10.0f
17 #define GOAL_MAX_ID_SIZE 36
19 static int goals_is_goal_hidden(const Goals *goals, size_t i);
21 typedef enum Cue_state {
23 CUE_STATE_HIT_NOTHING,
24 CUE_STATE_SEEN_NOTHING
32 Cue_state *cue_states;
39 Goals *create_goals_from_line_stream(LineStream *line_stream)
41 trace_assert(line_stream);
43 Lt *const lt = create_lt();
48 Goals *const goals = PUSH_LT(lt, nth_alloc(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_alloc(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_alloc(sizeof(char) * GOAL_MAX_ID_SIZE), free);
71 if (goals->ids[i] == NULL) {
76 goals->points = PUSH_LT(lt, nth_alloc(sizeof(Point) * goals->count), free);
77 if (goals->points == NULL) {
81 goals->colors = PUSH_LT(lt, nth_alloc(sizeof(Color) * goals->count), free);
82 if (goals->colors == NULL) {
86 goals->cue_states = PUSH_LT(lt, nth_alloc(sizeof(int) * goals->count), free);
87 if (goals->cue_states == NULL) {
91 goals->visible = PUSH_LT(lt, nth_alloc(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",
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 void destroy_goals(Goals *goals)
122 RETURN_LT0(goals->lt);
125 static int goals_render_core(const Goals *goals,
130 trace_assert(camera);
132 const Point position = vec_sum(
133 goals->points[goal_index],
134 vec(0.0f, sinf(goals->angle) * 10.0f));
136 if (camera_fill_triangle(
138 triangle_mat3x3_product(
139 equilateral_triangle(),
141 trans_mat(position.x, position.y),
142 rot_mat(PI * -0.5f + goals->angle),
143 scale_mat(GOAL_RADIUS))),
144 goals->colors[goal_index]) < 0) {
148 if (camera_render_debug_text(
150 goals->ids[goal_index],
158 int goals_render(const Goals *goals,
162 trace_assert(camera);
164 for (size_t i = 0; i < goals->count; ++i) {
165 if (!goals_is_goal_hidden(goals, i)) {
166 if (goals_render_core(goals, i, camera) < 0) {
175 void goals_update(Goals *goals,
179 trace_assert(delta_time > 0.0f);
180 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
183 void goals_hide_from_player(Goals *goals,
186 goals->player_hitbox = player_hitbox;
190 int goals_sound(Goals *goals,
191 Sound_samples *sound_samples)
193 for (size_t i = 0; i < goals->count; ++i) {
194 switch (goals->cue_states[i]) {
195 case CUE_STATE_HIT_NOTHING:
196 sound_samples_play_sound(sound_samples, 0, 0);
197 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
207 void goals_cue(Goals *goals,
208 const Camera *camera)
210 for (size_t i = 0; i < goals->count; ++i) {
211 switch (goals->cue_states[i]) {
212 case CUE_STATE_VIRGIN:
213 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
214 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
219 case CUE_STATE_SEEN_NOTHING:
220 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
221 goals->cue_states[i] = CUE_STATE_VIRGIN;
230 void goals_checkpoint(const Goals *goals,
234 trace_assert(player);
236 for (size_t i = 0; i < goals->count; ++i) {
237 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
238 player_checkpoint(player, goals->points[i]);
243 static struct EvalResult
244 goals_action(Goals *goals, size_t index, Gc *gc, struct Scope *scope, struct Expr path)
250 const char *target = NULL;
251 struct EvalResult res = match_list(gc, "q*", path, &target, NULL);
256 if (strcmp(target, "show") == 0) {
257 goals->visible[index] = true;
258 return eval_success(NIL(gc));
259 } else if (strcmp(target, "hide") == 0) {
260 goals->visible[index] = false;
261 return eval_success(NIL(gc));
264 return unknown_target(gc, goals->ids[index], target);
268 goals_send(Goals *goals, Gc *gc, struct Scope *scope, struct Expr path)
274 const char *target = NULL;
275 struct Expr rest = void_expr();
276 struct EvalResult res = match_list(gc, "s*", path, &target, &rest);
281 for (size_t i = 0; i < goals->count; ++i) {
282 if (strcmp(target, goals->ids[i]) == 0) {
283 return goals_action(goals, i, gc, scope, rest);
287 return unknown_target(gc, "goals", target);
290 /* Private Functions */
292 static int goals_is_goal_hidden(const Goals *goals, size_t i)
294 return !goals->visible[i];