]> git.lizzy.rs Git - nothing.git/blob - src/game/level/goals.c
Merge pull request #1 from tsoding/master
[nothing.git] / src / game / level / goals.c
1 #include <SDL2/SDL.h>
2 #include "system/stacktrace.h"
3 #include <math.h>
4
5 #include "goals.h"
6 #include "math/pi.h"
7 #include "math/triangle.h"
8 #include "system/str.h"
9 #include "system/line_stream.h"
10 #include "system/lt.h"
11 #include "system/nth_alloc.h"
12 #include "system/log.h"
13 #include "ebisp/interpreter.h"
14 #include "broadcast.h"
15
16 #define GOAL_RADIUS 10.0f
17 #define GOAL_MAX_ID_SIZE 36
18
19 static int goals_is_goal_hidden(const Goals *goals, size_t i);
20
21 typedef enum Cue_state {
22     CUE_STATE_VIRGIN = 0,
23     CUE_STATE_HIT_NOTHING,
24     CUE_STATE_SEEN_NOTHING
25 } Cue_state;
26
27 struct Goals {
28     Lt *lt;
29     char **ids;
30     Point *points;
31     Color *colors;
32     Cue_state *cue_states;
33     bool *visible;
34     size_t count;
35     Rect player_hitbox;
36     float angle;
37 };
38
39 Goals *create_goals_from_line_stream(LineStream *line_stream)
40 {
41     trace_assert(line_stream);
42
43     Lt *const lt = create_lt();
44     if (lt == NULL) {
45         return NULL;
46     }
47
48     Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
49     if (goals == NULL) {
50         RETURN_LT(lt, NULL);
51     }
52
53     goals->count = 0;
54     if (sscanf(
55             line_stream_next(line_stream),
56             "%lu",
57             &goals->count) == EOF) {
58         log_fail("Could not read amount of goals\n");
59         RETURN_LT(lt, NULL);
60     }
61
62     goals->ids = PUSH_LT(
63         lt,
64         nth_calloc(1, sizeof(char*) * goals->count),
65         free);
66     if (goals->ids == NULL) {
67         RETURN_LT(lt, NULL);
68     }
69     for (size_t i = 0; i < goals->count; ++i) {
70         goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
71         if (goals->ids[i] == NULL) {
72             RETURN_LT(lt, NULL);
73         }
74     }
75
76     goals->points = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
77     if (goals->points == NULL) {
78         RETURN_LT(lt, NULL);
79     }
80
81     goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
82     if (goals->colors == NULL) {
83         RETURN_LT(lt, NULL);
84     }
85
86     goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
87     if (goals->cue_states == NULL) {
88         RETURN_LT(lt, NULL);
89     }
90
91     goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
92     if (goals->visible == NULL) {
93         RETURN_LT(lt, NULL);
94     }
95
96     char color[7];
97     for (size_t i = 0; i < goals->count; ++i) {
98         if (sscanf(
99                 line_stream_next(line_stream),
100                 "%" STRINGIFY(GOAL_MAX_ID_SIZE) "s%f%f%6s",
101                 goals->ids[i],
102                 &goals->points[i].x,
103                 &goals->points[i].y,
104                 color) < 0) {
105             log_fail("Could not read %dth goal\n", i);
106             RETURN_LT(lt, NULL);
107         }
108         goals->colors[i] = hexstr(color);
109         goals->cue_states[i] = CUE_STATE_VIRGIN;
110         goals->visible[i] = true;
111     }
112
113     goals->lt = lt;
114     goals->angle = 0.0f;
115
116     return goals;
117 }
118
119 void destroy_goals(Goals *goals)
120 {
121     trace_assert(goals);
122     RETURN_LT0(goals->lt);
123 }
124
125 static int goals_render_core(const Goals *goals,
126                              size_t goal_index,
127                              Camera *camera)
128 {
129     trace_assert(goals);
130     trace_assert(camera);
131
132     const Point position = vec_sum(
133         goals->points[goal_index],
134         vec(0.0f, sinf(goals->angle) * 10.0f));
135
136     if (camera_fill_triangle(
137             camera,
138             triangle_mat3x3_product(
139                 equilateral_triangle(),
140                 mat3x3_product2(
141                     trans_mat(position.x, position.y),
142                     rot_mat(PI * -0.5f + goals->angle),
143                     scale_mat(GOAL_RADIUS))),
144             goals->colors[goal_index]) < 0) {
145         return -1;
146     }
147
148     if (camera_render_debug_text(
149             camera,
150             goals->ids[goal_index],
151             position) < 0) {
152         return -1;
153     }
154
155     return 0;
156 }
157
158 int goals_render(const Goals *goals,
159                  Camera *camera)
160 {
161     trace_assert(goals);
162     trace_assert(camera);
163
164     for (size_t i = 0; i < goals->count; ++i) {
165         if (!goals_is_goal_hidden(goals, i)) {
166             if (goals_render_core(goals, i, camera) < 0) {
167                 return -1;
168             }
169         }
170     }
171
172     return 0;
173 }
174
175 void goals_update(Goals *goals,
176                   float delta_time)
177 {
178     trace_assert(goals);
179     trace_assert(delta_time > 0.0f);
180     goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
181 }
182
183 void goals_hide_from_player(Goals *goals,
184                             Rect player_hitbox)
185 {
186     goals->player_hitbox = player_hitbox;
187
188 }
189
190 int goals_sound(Goals *goals,
191                 Sound_samples *sound_samples)
192 {
193     for (size_t i = 0; i < goals->count; ++i) {
194         switch (goals->cue_states[i]) {
195         case CUE_STATE_HIT_NOTHING:
196             sound_samples_play_sound(sound_samples, 0, 0);
197             goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
198             break;
199
200         default: {}
201         }
202     }
203
204     return 0;
205 }
206
207 void goals_cue(Goals *goals,
208                const Camera *camera)
209 {
210     for (size_t i = 0; i < goals->count; ++i) {
211         switch (goals->cue_states[i]) {
212         case CUE_STATE_VIRGIN:
213             if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
214                 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
215             }
216
217             break;
218
219         case CUE_STATE_SEEN_NOTHING:
220             if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
221                 goals->cue_states[i] = CUE_STATE_VIRGIN;
222             }
223             break;
224
225         default: {}
226         }
227     }
228 }
229
230 void goals_checkpoint(const Goals *goals,
231                       Player *player)
232 {
233     trace_assert(goals);
234     trace_assert(player);
235
236     for (size_t i = 0; i < goals->count; ++i) {
237         if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
238             player_checkpoint(player, goals->points[i]);
239         }
240     }
241 }
242
243 static struct EvalResult
244 goals_action(Goals *goals, size_t index, Gc *gc, struct Scope *scope, struct Expr path)
245 {
246     trace_assert(goals);
247     trace_assert(gc);
248     trace_assert(scope);
249
250     const char *target = NULL;
251     struct EvalResult res = match_list(gc, "q*", path, &target, NULL);
252     if (res.is_error) {
253         return res;
254     }
255
256     if (strcmp(target, "show") == 0) {
257         goals->visible[index] = true;
258         return eval_success(NIL(gc));
259     } else if (strcmp(target, "hide") == 0) {
260         goals->visible[index] = false;
261         return eval_success(NIL(gc));
262     }
263
264     return unknown_target(gc, goals->ids[index], target);
265 }
266
267 struct EvalResult
268 goals_send(Goals *goals, Gc *gc, struct Scope *scope, struct Expr path)
269 {
270     trace_assert(goals);
271     trace_assert(gc);
272     trace_assert(scope);
273
274     const char *target = NULL;
275     struct Expr rest = void_expr();
276     struct EvalResult res = match_list(gc, "s*", path, &target, &rest);
277     if (res.is_error) {
278         return res;
279     }
280
281     for (size_t i = 0; i < goals->count; ++i) {
282         if (strcmp(target, goals->ids[i]) == 0) {
283             return goals_action(goals, i, gc, scope, rest);
284         }
285     }
286
287     return unknown_target(gc, "goals", target);
288 }
289
290 /* Private Functions */
291
292 static int goals_is_goal_hidden(const Goals *goals, size_t i)
293 {
294     return !goals->visible[i];
295 }