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_point_layer(const PointLayer *point_layer)
40 trace_assert(point_layer);
44 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
49 goals->count = point_layer_count(point_layer);
53 nth_calloc(1, sizeof(char*) * goals->count),
55 if (goals->ids == NULL) {
58 for (size_t i = 0; i < goals->count; ++i) {
59 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
60 if (goals->ids[i] == NULL) {
65 goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
66 if (goals->positions == NULL) {
70 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
71 if (goals->colors == NULL) {
75 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
76 if (goals->cue_states == NULL) {
80 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
81 if (goals->visible == NULL) {
85 const Vec2f *positions = point_layer_positions(point_layer);
86 const Color *colors = point_layer_colors(point_layer);
87 const char *ids = point_layer_ids(point_layer);
89 // TODO(#835): we could use memcpy in create_goals_from_point_layer
90 for (size_t i = 0; i < goals->count; ++i) {
91 goals->positions[i] = positions[i];
92 goals->colors[i] = colors[i];
93 memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);
94 goals->cue_states[i] = CUE_STATE_VIRGIN;
95 goals->visible[i] = true;
104 void destroy_goals(Goals *goals)
107 RETURN_LT0(goals->lt);
110 static int goals_render_core(const Goals *goals,
112 const Camera *camera)
115 trace_assert(camera);
117 const Vec2f position = vec_sum(
118 goals->positions[goal_index],
119 vec(0.0f, sinf(goals->angle) * 10.0f));
121 if (camera_fill_triangle(
123 triangle_mat3x3_product(
124 equilateral_triangle(),
126 trans_mat(position.x, position.y),
127 rot_mat(PI * -0.5f + goals->angle),
128 scale_mat(GOAL_RADIUS))),
129 goals->colors[goal_index]) < 0) {
133 if (camera_render_debug_text(
135 goals->ids[goal_index],
143 int goals_render(const Goals *goals,
144 const Camera *camera)
147 trace_assert(camera);
149 for (size_t i = 0; i < goals->count; ++i) {
150 if (!goals_is_goal_hidden(goals, i)) {
151 if (goals_render_core(goals, i, camera) < 0) {
160 void goals_update(Goals *goals,
164 trace_assert(delta_time > 0.0f);
165 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
168 int goals_sound(Goals *goals,
169 Sound_samples *sound_samples)
171 for (size_t i = 0; i < goals->count; ++i) {
172 switch (goals->cue_states[i]) {
173 case CUE_STATE_HIT_NOTHING:
174 sound_samples_play_sound(sound_samples, 0);
175 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
185 void goals_cue(Goals *goals,
186 const Camera *camera)
188 for (size_t i = 0; i < goals->count; ++i) {
189 switch (goals->cue_states[i]) {
190 case CUE_STATE_VIRGIN:
191 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
192 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
197 case CUE_STATE_SEEN_NOTHING:
198 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
199 goals->cue_states[i] = CUE_STATE_VIRGIN;
208 void goals_checkpoint(const Goals *goals,
212 trace_assert(player);
214 for (size_t i = 0; i < goals->count; ++i) {
215 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
216 player_checkpoint(player, goals->positions[i]);
221 /* Private Functions */
223 static int goals_is_goal_hidden(const Goals *goals, size_t i)
225 return !goals->visible[i];
228 void goals_hide(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
231 trace_assert(goal_id);
233 for (size_t i = 0; i < goals->count; ++i) {
234 if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
235 goals->visible[i] = false;
240 void goals_show(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
243 trace_assert(goal_id);
244 for (size_t i = 0; i < goals->count; ++i) {
245 if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
246 goals->visible[i] = true;