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"
14 #define GOAL_RADIUS 10.0f
15 #define GOAL_MAX_ID_SIZE 36
17 static int goals_is_goal_hidden(const Goals *goals, size_t i);
19 typedef enum Cue_state {
21 CUE_STATE_HIT_NOTHING,
22 CUE_STATE_SEEN_NOTHING
30 /* TODO(#494): it is not clear how to maintain Cue_state from the scripting language */
31 Cue_state *cue_states;
38 Goals *create_goals_from_line_stream(LineStream *line_stream)
42 Lt *const lt = create_lt();
47 Goals *const goals = PUSH_LT(lt, nth_alloc(sizeof(Goals)), free);
54 line_stream_next(line_stream),
56 &goals->count) == EOF) {
57 log_fail("Could not read amount of goals\n");
63 nth_alloc(sizeof(char*) * goals->count),
65 if (goals->ids == NULL) {
68 for (size_t i = 0; i < goals->count; ++i) {
69 goals->ids[i] = PUSH_LT(lt, nth_alloc(sizeof(char) * GOAL_MAX_ID_SIZE), free);
70 if (goals->ids[i] == NULL) {
75 goals->points = PUSH_LT(lt, nth_alloc(sizeof(Point) * goals->count), free);
76 if (goals->points == NULL) {
80 goals->colors = PUSH_LT(lt, nth_alloc(sizeof(Color) * goals->count), free);
81 if (goals->colors == NULL) {
85 goals->cue_states = PUSH_LT(lt, nth_alloc(sizeof(int) * goals->count), free);
86 if (goals->cue_states == NULL) {
90 goals->visible = PUSH_LT(lt, nth_alloc(sizeof(bool) * goals->count), free);
91 if (goals->visible == NULL) {
96 for (size_t i = 0; i < goals->count; ++i) {
98 line_stream_next(line_stream),
99 "%" STRINGIFY(GOAL_MAX_ID_SIZE) "s%f%f%6s",
104 log_fail("Could not read %dth goal\n", i);
107 goals->colors[i] = hexstr(color);
108 goals->cue_states[i] = CUE_STATE_VIRGIN;
109 goals->visible[i] = true;
118 void destroy_goals(Goals *goals)
121 RETURN_LT0(goals->lt);
124 static int goals_render_core(const Goals *goals,
131 const Point position = vec_sum(
132 goals->points[goal_index],
133 vec(0.0f, sinf(goals->angle) * 10.0f));
135 if (camera_fill_triangle(
137 triangle_mat3x3_product(
138 equilateral_triangle(),
140 trans_mat(position.x, position.y),
141 rot_mat(PI * -0.5f + goals->angle),
142 scale_mat(GOAL_RADIUS))),
143 goals->colors[goal_index]) < 0) {
147 if (camera_render_debug_text(
149 goals->ids[goal_index],
157 int goals_render(const Goals *goals,
163 for (size_t i = 0; i < goals->count; ++i) {
164 if (!goals_is_goal_hidden(goals, i)) {
165 if (goals_render_core(goals, i, camera) < 0) {
174 void goals_update(Goals *goals,
178 assert(delta_time > 0.0f);
179 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
182 void goals_hide_from_player(Goals *goals,
185 goals->player_hitbox = player_hitbox;
189 int goals_sound(Goals *goals,
190 Sound_samples *sound_samples)
192 for (size_t i = 0; i < goals->count; ++i) {
193 switch (goals->cue_states[i]) {
194 case CUE_STATE_HIT_NOTHING:
195 sound_samples_play_sound(sound_samples, 0, 0);
196 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
206 void goals_cue(Goals *goals,
207 const Camera *camera)
209 for (size_t i = 0; i < goals->count; ++i) {
210 switch (goals->cue_states[i]) {
211 case CUE_STATE_VIRGIN:
212 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
213 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
218 case CUE_STATE_SEEN_NOTHING:
219 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
220 goals->cue_states[i] = CUE_STATE_VIRGIN;
229 void goals_checkpoint(const Goals *goals,
235 for (size_t i = 0; i < goals->count; ++i) {
236 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
237 player_checkpoint(player, goals->points[i]);
242 void goals_hide(Goals *goals, const char *id)
247 for (size_t i = 0; i < goals->count; ++i) {
248 if (strcmp(id, goals->ids[i]) == 0) {
249 goals->visible[i] = false;
255 void goals_show(Goals *goals, const char *id)
260 for (size_t i = 0; i < goals->count; ++i) {
261 if (strcmp(id, goals->ids[i]) == 0) {
262 goals->visible[i] = true;
268 /* Private Functions */
270 static int goals_is_goal_hidden(const Goals *goals, size_t i)
272 return !goals->visible[i];