6 #include "game/level/level_editor/point_layer.h"
9 #include "math/triangle.h"
10 #include "system/log.h"
11 #include "system/lt.h"
12 #include "system/nth_alloc.h"
13 #include "system/stacktrace.h"
14 #include "system/str.h"
16 #define GOAL_RADIUS 10.0f
18 static int goals_is_goal_hidden(const Goals *goals, size_t i);
20 typedef enum Cue_state {
22 CUE_STATE_HIT_NOTHING,
23 CUE_STATE_SEEN_NOTHING
31 Cue_state *cue_states;
37 Goals *create_goals_from_point_layer(const PointLayer *point_layer)
39 trace_assert(point_layer);
43 Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
48 goals->count = point_layer_count(point_layer);
52 nth_calloc(1, sizeof(char*) * goals->count),
54 if (goals->ids == NULL) {
57 for (size_t i = 0; i < goals->count; ++i) {
58 goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
59 if (goals->ids[i] == NULL) {
64 goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
65 if (goals->positions == NULL) {
69 goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
70 if (goals->colors == NULL) {
74 goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
75 if (goals->cue_states == NULL) {
79 goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
80 if (goals->visible == NULL) {
84 const Vec2f *positions = point_layer_positions(point_layer);
85 const Color *colors = point_layer_colors(point_layer);
86 const char *ids = point_layer_ids(point_layer);
88 // TODO(#835): we could use memcpy in create_goals_from_point_layer
89 for (size_t i = 0; i < goals->count; ++i) {
90 goals->positions[i] = positions[i];
91 goals->colors[i] = colors[i];
92 memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);
93 goals->cue_states[i] = CUE_STATE_VIRGIN;
94 goals->visible[i] = true;
103 void destroy_goals(Goals *goals)
106 RETURN_LT0(goals->lt);
109 static int goals_render_core(const Goals *goals,
111 const Camera *camera)
114 trace_assert(camera);
116 const Vec2f position = vec_sum(
117 goals->positions[goal_index],
118 vec(0.0f, sinf(goals->angle) * 10.0f));
120 if (camera_fill_triangle(
122 triangle_mat3x3_product(
123 equilateral_triangle(),
125 trans_mat(position.x, position.y),
126 rot_mat(PI * -0.5f + goals->angle),
127 scale_mat(GOAL_RADIUS))),
128 goals->colors[goal_index]) < 0) {
132 if (camera_render_debug_text(
134 goals->ids[goal_index],
142 int goals_render(const Goals *goals,
143 const Camera *camera)
146 trace_assert(camera);
148 for (size_t i = 0; i < goals->count; ++i) {
149 if (!goals_is_goal_hidden(goals, i)) {
150 if (goals_render_core(goals, i, camera) < 0) {
159 void goals_update(Goals *goals,
163 trace_assert(delta_time > 0.0f);
164 goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
167 int goals_sound(Goals *goals,
168 Sound_samples *sound_samples)
170 for (size_t i = 0; i < goals->count; ++i) {
171 switch (goals->cue_states[i]) {
172 case CUE_STATE_HIT_NOTHING:
173 sound_samples_play_sound(sound_samples, 0);
174 goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
184 void goals_cue(Goals *goals,
185 const Camera *camera)
187 for (size_t i = 0; i < goals->count; ++i) {
188 switch (goals->cue_states[i]) {
189 case CUE_STATE_VIRGIN:
190 if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
191 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
196 case CUE_STATE_SEEN_NOTHING:
197 if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
198 goals->cue_states[i] = CUE_STATE_VIRGIN;
207 void goals_checkpoint(const Goals *goals,
211 trace_assert(player);
213 for (size_t i = 0; i < goals->count; ++i) {
214 if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
215 player_checkpoint(player, goals->positions[i]);
220 /* Private Functions */
222 static int goals_is_goal_hidden(const Goals *goals, size_t i)
224 return !goals->visible[i];
227 void goals_hide(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
230 trace_assert(goal_id);
232 for (size_t i = 0; i < goals->count; ++i) {
233 if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
234 goals->visible[i] = false;
239 void goals_show(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
242 trace_assert(goal_id);
243 for (size_t i = 0; i < goals->count; ++i) {
244 if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
245 goals->visible[i] = true;