]> git.lizzy.rs Git - nothing.git/blob - src/game/level/goals.c
Delete LineStream from the existance
[nothing.git] / src / game / level / goals.c
1 #include <stdio.h>
2 #include <math.h>
3
4 #include <SDL.h>
5
6 #include "game/level/level_editor/point_layer.h"
7 #include "goals.h"
8 #include "math/pi.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"
15
16 #define GOAL_RADIUS 10.0f
17
18 static int goals_is_goal_hidden(const Goals *goals, size_t i);
19
20 typedef enum Cue_state {
21     CUE_STATE_VIRGIN = 0,
22     CUE_STATE_HIT_NOTHING,
23     CUE_STATE_SEEN_NOTHING
24 } Cue_state;
25
26 struct Goals {
27     Lt *lt;
28     char **ids;
29     Vec2f *positions;
30     Color *colors;
31     Cue_state *cue_states;
32     bool *visible;
33     size_t count;
34     float angle;
35 };
36
37 Goals *create_goals_from_point_layer(const PointLayer *point_layer)
38 {
39     trace_assert(point_layer);
40
41     Lt *lt = create_lt();
42
43     Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
44     if (goals == NULL) {
45         RETURN_LT(lt, NULL);
46     }
47
48     goals->count = point_layer_count(point_layer);
49
50     goals->ids = PUSH_LT(
51         lt,
52         nth_calloc(1, sizeof(char*) * goals->count),
53         free);
54     if (goals->ids == NULL) {
55         RETURN_LT(lt, NULL);
56     }
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) {
60             RETURN_LT(lt, NULL);
61         }
62     }
63
64     goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
65     if (goals->positions == NULL) {
66         RETURN_LT(lt, NULL);
67     }
68
69     goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
70     if (goals->colors == NULL) {
71         RETURN_LT(lt, NULL);
72     }
73
74     goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
75     if (goals->cue_states == NULL) {
76         RETURN_LT(lt, NULL);
77     }
78
79     goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
80     if (goals->visible == NULL) {
81         RETURN_LT(lt, NULL);
82     }
83
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);
87
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;
95     }
96
97     goals->lt = lt;
98     goals->angle = 0.0f;
99
100     return goals;
101 }
102
103 void destroy_goals(Goals *goals)
104 {
105     trace_assert(goals);
106     RETURN_LT0(goals->lt);
107 }
108
109 static int goals_render_core(const Goals *goals,
110                              size_t goal_index,
111                              const Camera *camera)
112 {
113     trace_assert(goals);
114     trace_assert(camera);
115
116     const Vec2f position = vec_sum(
117         goals->positions[goal_index],
118         vec(0.0f, sinf(goals->angle) * 10.0f));
119
120     if (camera_fill_triangle(
121             camera,
122             triangle_mat3x3_product(
123                 equilateral_triangle(),
124                 mat3x3_product2(
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) {
129         return -1;
130     }
131
132     if (camera_render_debug_text(
133             camera,
134             goals->ids[goal_index],
135             position) < 0) {
136         return -1;
137     }
138
139     return 0;
140 }
141
142 int goals_render(const Goals *goals,
143                  const Camera *camera)
144 {
145     trace_assert(goals);
146     trace_assert(camera);
147
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) {
151                 return -1;
152             }
153         }
154     }
155
156     return 0;
157 }
158
159 void goals_update(Goals *goals,
160                   float delta_time)
161 {
162     trace_assert(goals);
163     trace_assert(delta_time > 0.0f);
164     goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
165 }
166
167 int goals_sound(Goals *goals,
168                 Sound_samples *sound_samples)
169 {
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;
175             break;
176
177         default: {}
178         }
179     }
180
181     return 0;
182 }
183
184 void goals_cue(Goals *goals,
185                const Camera *camera)
186 {
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;
192             }
193
194             break;
195
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;
199             }
200             break;
201
202         default: {}
203         }
204     }
205 }
206
207 void goals_checkpoint(const Goals *goals,
208                       Player *player)
209 {
210     trace_assert(goals);
211     trace_assert(player);
212
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]);
216         }
217     }
218 }
219
220 /* Private Functions */
221
222 static int goals_is_goal_hidden(const Goals *goals, size_t i)
223 {
224     return !goals->visible[i];
225 }
226
227 void goals_hide(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
228 {
229     trace_assert(goals);
230     trace_assert(goal_id);
231
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;
235         }
236     }
237 }
238
239 void goals_show(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
240 {
241     trace_assert(goals);
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;
246         }
247     }
248 }