7 #include "math/triangle.h"
8 #include "system/error.h"
11 #define GOAL_RADIUS 10.0f
13 static int goals_is_goal_hidden(const goals_t *goals, size_t i);
15 typedef enum cue_state_t {
17 CUE_STATE_HIT_NOTHING,
18 CUE_STATE_SEEN_NOTHING
26 cue_state_t *cue_states;
32 goals_t *create_goals_from_stream(FILE *stream)
36 lt_t *const lt = create_lt();
41 goals_t *const goals = PUSH_LT(lt, malloc(sizeof(goals_t)), free);
43 throw_error(ERROR_TYPE_LIBC);
47 goals->goals_count = 0;
48 if (fscanf(stream, "%lu", &goals->goals_count) == EOF) {
49 throw_error(ERROR_TYPE_LIBC);
53 goals->points = PUSH_LT(lt, malloc(sizeof(point_t) * goals->goals_count), free);
54 if (goals->points == NULL) {
55 throw_error(ERROR_TYPE_LIBC);
59 goals->regions = PUSH_LT(lt, malloc(sizeof(rect_t) * goals->goals_count), free);
60 if (goals->regions == NULL) {
61 throw_error(ERROR_TYPE_LIBC);
65 goals->colors = PUSH_LT(lt, malloc(sizeof(color_t) * goals->goals_count), free);
66 if (goals->colors == NULL) {
67 throw_error(ERROR_TYPE_LIBC);
71 goals->cue_states = PUSH_LT(lt, malloc(sizeof(int) * goals->goals_count), free);
72 if (goals->cue_states == NULL) {
73 throw_error(ERROR_TYPE_LIBC);
78 for (size_t i = 0; i < goals->goals_count; ++i) {
79 if (fscanf(stream, "%f%f%f%f%f%f%6s",
87 throw_error(ERROR_TYPE_LIBC);
90 goals->colors[i] = color_from_hexstr(color);
91 goals->cue_states[i] = CUE_STATE_VIRGIN;
100 void destroy_goals(goals_t *goals)
103 RETURN_LT0(goals->lt);
106 static int goals_render_core(const goals_t *goals,
108 const camera_t *camera)
113 const point_t position = vec_sum(
114 goals->points[goal_index],
115 vec(0.0f, sinf(goals->angle) * 10.0f));
117 return camera_fill_triangle(
119 triangle_mat3x3_product(
120 equilateral_triangle(),
122 trans_mat(position.x, position.y),
123 rot_mat(PI * -0.5f + goals->angle),
124 scale_mat(GOAL_RADIUS))),
125 goals->colors[goal_index]);
128 int goals_render(const goals_t *goals,
129 const camera_t *camera)
135 for (size_t i = 0; i < goals->goals_count; ++i) {
136 if (!goals_is_goal_hidden(goals, i)) {
137 if (goals_render_core(goals, i, camera) < 0) {
146 void goals_update(goals_t *goals,
150 assert(delta_time > 0.0f);
151 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
154 void goals_hide(goals_t *goals,
155 rect_t player_hitbox)
157 goals->player_hitbox = player_hitbox;
161 int goals_sound(goals_t *goals,
162 sound_samples_t *sound_samples)
164 for (size_t i = 0; i < goals->goals_count; ++i) {
165 switch (goals->cue_states[i]) {
166 case CUE_STATE_HIT_NOTHING:
167 sound_samples_play_sound(sound_samples, 0, 0);
168 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
178 void goals_cue(goals_t *goals,
179 const camera_t *camera)
181 for (size_t i = 0; i < goals->goals_count; ++i) {
182 switch (goals->cue_states[i]) {
183 case CUE_STATE_VIRGIN:
184 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
185 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
190 case CUE_STATE_SEEN_NOTHING:
191 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
192 goals->cue_states[i] = CUE_STATE_VIRGIN;
201 void goals_checkpoint(const goals_t *goals,
207 for (size_t i = 0; i < goals->goals_count; ++i) {
208 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
209 player_checkpoint(player, goals->points[i]);
214 /* Private Functions */
216 static int goals_is_goal_hidden(const goals_t *goals, size_t i)
218 return rects_overlap(goals->regions[i], goals->player_hitbox);