6 #include "game/level/level_editor/point_layer.h"
9 #include "math/triangle.h"
10 #include "system/line_stream.h"
11 #include "system/log.h"
12 #include "system/lt.h"
13 #include "system/nth_alloc.h"
14 #include "system/stacktrace.h"
15 #include "system/str.h"
17 #define GOAL_RADIUS 10.0f
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;
38 Goals *create_goals_from_line_stream(LineStream *line_stream)
40 trace_assert(line_stream);
44 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
51 line_stream_next(line_stream),
53 &goals->count) == EOF) {
54 log_fail("Could not read amount of goals\n");
60 nth_calloc(1, sizeof(char*) * goals->count),
62 if (goals->ids == NULL) {
65 for (size_t i = 0; i < goals->count; ++i) {
66 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
67 if (goals->ids[i] == NULL) {
72 goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
73 if (goals->positions == NULL) {
77 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
78 if (goals->colors == NULL) {
82 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
83 if (goals->cue_states == NULL) {
87 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
88 if (goals->visible == NULL) {
93 for (size_t i = 0; i < goals->count; ++i) {
95 line_stream_next(line_stream),
96 "%" STRINGIFY(ENTITY_MAX_ID_SIZE) "s%f%f%6s",
98 &goals->positions[i].x,
99 &goals->positions[i].y,
101 log_fail("Could not read %dth goal\n", i);
104 goals->colors[i] = hexstr(color);
105 goals->cue_states[i] = CUE_STATE_VIRGIN;
106 goals->visible[i] = true;
115 Goals *create_goals_from_point_layer(const PointLayer *point_layer)
117 trace_assert(point_layer);
119 Lt *lt = create_lt();
121 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
126 goals->count = point_layer_count(point_layer);
128 goals->ids = PUSH_LT(
130 nth_calloc(1, sizeof(char*) * goals->count),
132 if (goals->ids == NULL) {
135 for (size_t i = 0; i < goals->count; ++i) {
136 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
137 if (goals->ids[i] == NULL) {
142 goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
143 if (goals->positions == NULL) {
147 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
148 if (goals->colors == NULL) {
152 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
153 if (goals->cue_states == NULL) {
157 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
158 if (goals->visible == NULL) {
162 const Vec2f *positions = point_layer_positions(point_layer);
163 const Color *colors = point_layer_colors(point_layer);
164 const char *ids = point_layer_ids(point_layer);
166 // TODO(#835): we could use memcpy in create_goals_from_point_layer
167 for (size_t i = 0; i < goals->count; ++i) {
168 goals->positions[i] = positions[i];
169 goals->colors[i] = colors[i];
170 memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);
171 goals->cue_states[i] = CUE_STATE_VIRGIN;
172 goals->visible[i] = true;
181 void destroy_goals(Goals *goals)
184 RETURN_LT0(goals->lt);
187 static int goals_render_core(const Goals *goals,
189 const Camera *camera)
192 trace_assert(camera);
194 const Vec2f position = vec_sum(
195 goals->positions[goal_index],
196 vec(0.0f, sinf(goals->angle) * 10.0f));
198 if (camera_fill_triangle(
200 triangle_mat3x3_product(
201 equilateral_triangle(),
203 trans_mat(position.x, position.y),
204 rot_mat(PI * -0.5f + goals->angle),
205 scale_mat(GOAL_RADIUS))),
206 goals->colors[goal_index]) < 0) {
210 if (camera_render_debug_text(
212 goals->ids[goal_index],
220 int goals_render(const Goals *goals,
221 const Camera *camera)
224 trace_assert(camera);
226 for (size_t i = 0; i < goals->count; ++i) {
227 if (!goals_is_goal_hidden(goals, i)) {
228 if (goals_render_core(goals, i, camera) < 0) {
237 void goals_update(Goals *goals,
241 trace_assert(delta_time > 0.0f);
242 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
245 int goals_sound(Goals *goals,
246 Sound_samples *sound_samples)
248 for (size_t i = 0; i < goals->count; ++i) {
249 switch (goals->cue_states[i]) {
250 case CUE_STATE_HIT_NOTHING:
251 sound_samples_play_sound(sound_samples, 0);
252 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
262 void goals_cue(Goals *goals,
263 const Camera *camera)
265 for (size_t i = 0; i < goals->count; ++i) {
266 switch (goals->cue_states[i]) {
267 case CUE_STATE_VIRGIN:
268 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
269 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
274 case CUE_STATE_SEEN_NOTHING:
275 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
276 goals->cue_states[i] = CUE_STATE_VIRGIN;
285 void goals_checkpoint(const Goals *goals,
289 trace_assert(player);
291 for (size_t i = 0; i < goals->count; ++i) {
292 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
293 player_checkpoint(player, goals->positions[i]);
298 /* Private Functions */
300 static int goals_is_goal_hidden(const Goals *goals, size_t i)
302 return !goals->visible[i];
305 void goals_hide(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
308 trace_assert(goal_id);
310 for (size_t i = 0; i < goals->count; ++i) {
311 if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
312 goals->visible[i] = false;
317 void goals_show(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
320 trace_assert(goal_id);
321 for (size_t i = 0; i < goals->count; ++i) {
322 if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
323 goals->visible[i] = true;