]> git.lizzy.rs Git - nothing.git/blob - src/game/level/goals.c
Merge pull request #180 from tsoding/sound-medium-refactor
[nothing.git] / src / game / level / goals.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3 #include <math.h>
4
5 #include "goals.h"
6 #include "math/pi.h"
7 #include "math/triangle.h"
8 #include "system/error.h"
9 #include "system/lt.h"
10
11 #define GOAL_RADIUS 10.0f
12
13 static int goals_is_goal_hidden(const goals_t *goals, size_t i);
14
15 typedef enum cue_state_t {
16     CUE_STATE_VIRGIN = 0,
17     CUE_STATE_HIT_NOTHING,
18     CUE_STATE_SEEN_NOTHING
19 } cue_state_t;
20
21 struct goals_t {
22     lt_t *lt;
23     point_t *points;
24     rect_t *regions;
25     color_t *colors;
26     cue_state_t *cue_states;
27     size_t goals_count;
28     rect_t player_hitbox;
29     float angle;
30 };
31
32 goals_t *create_goals_from_stream(FILE *stream)
33 {
34     assert(stream);
35
36     lt_t *const lt = create_lt();
37     if (lt == NULL) {
38         return NULL;
39     }
40
41     goals_t *const goals = PUSH_LT(lt, malloc(sizeof(goals_t)), free);
42     if (goals == NULL) {
43         throw_error(ERROR_TYPE_LIBC);
44         RETURN_LT(lt, NULL);
45     }
46
47     goals->goals_count = 0;
48     if (fscanf(stream, "%lu", &goals->goals_count) == EOF) {
49         throw_error(ERROR_TYPE_LIBC);
50         RETURN_LT(lt, NULL);
51     }
52
53     goals->points = PUSH_LT(lt, malloc(sizeof(point_t) * goals->goals_count), free);
54     if (goals->points == NULL) {
55         throw_error(ERROR_TYPE_LIBC);
56         RETURN_LT(lt, NULL);
57     }
58
59     goals->regions = PUSH_LT(lt, malloc(sizeof(rect_t) * goals->goals_count), free);
60     if (goals->regions == NULL) {
61         throw_error(ERROR_TYPE_LIBC);
62         RETURN_LT(lt, NULL);
63     }
64
65     goals->colors = PUSH_LT(lt, malloc(sizeof(color_t) * goals->goals_count), free);
66     if (goals->colors == NULL) {
67         throw_error(ERROR_TYPE_LIBC);
68         RETURN_LT(lt, NULL);
69     }
70
71     goals->cue_states = PUSH_LT(lt, malloc(sizeof(int) * goals->goals_count), free);
72     if (goals->cue_states == NULL) {
73         throw_error(ERROR_TYPE_LIBC);
74         RETURN_LT(lt, NULL);
75     }
76
77     char color[7];
78     for (size_t i = 0; i < goals->goals_count; ++i) {
79         if (fscanf(stream, "%f%f%f%f%f%f%6s",
80                    &goals->points[i].x,
81                    &goals->points[i].y,
82                    &goals->regions[i].x,
83                    &goals->regions[i].y,
84                    &goals->regions[i].w,
85                    &goals->regions[i].h,
86                    color) < 0) {
87             throw_error(ERROR_TYPE_LIBC);
88             RETURN_LT(lt, NULL);
89         }
90         goals->colors[i] = color_from_hexstr(color);
91         goals->cue_states[i] = CUE_STATE_VIRGIN;
92     }
93
94     goals->lt = lt;
95     goals->angle = 0.0f;
96
97     return goals;
98 }
99
100 void destroy_goals(goals_t *goals)
101 {
102     assert(goals);
103     RETURN_LT0(goals->lt);
104 }
105
106 static int goals_render_core(const goals_t *goals,
107                              size_t goal_index,
108                              const camera_t *camera)
109 {
110     assert(goals);
111     assert(camera);
112
113     const point_t position = vec_sum(
114         goals->points[goal_index],
115         vec(0.0f, sinf(goals->angle) * 10.0f));
116
117     return camera_fill_triangle(
118         camera,
119         triangle_mat3x3_product(
120             equilateral_triangle(),
121             mat3x3_product2(
122                 trans_mat(position.x, position.y),
123                 rot_mat(PI * -0.5f + goals->angle),
124                 scale_mat(GOAL_RADIUS))),
125         goals->colors[goal_index]);
126 }
127
128 int goals_render(const goals_t *goals,
129                  const camera_t *camera)
130
131 {
132     assert(goals);
133     assert(camera);
134
135     for (size_t i = 0; i < goals->goals_count; ++i) {
136         if (!goals_is_goal_hidden(goals, i)) {
137             if (goals_render_core(goals, i, camera) < 0) {
138                 return -1;
139             }
140         }
141     }
142
143     return 0;
144 }
145
146 void goals_update(goals_t *goals,
147                   float delta_time)
148 {
149     assert(goals);
150     assert(delta_time > 0.0f);
151     goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
152 }
153
154 void goals_hide(goals_t *goals,
155                 rect_t player_hitbox)
156 {
157     goals->player_hitbox = player_hitbox;
158
159 }
160
161 int goals_sound(goals_t *goals,
162                 sound_samples_t *sound_samples)
163 {
164     for (size_t i = 0; i < goals->goals_count; ++i) {
165         switch (goals->cue_states[i]) {
166         case CUE_STATE_HIT_NOTHING:
167             sound_samples_play_sound(sound_samples, 0, 0);
168             goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
169             break;
170
171         default: {}
172         }
173     }
174
175     return 0;
176 }
177
178 void goals_cue(goals_t *goals,
179                const camera_t *camera)
180 {
181     for (size_t i = 0; i < goals->goals_count; ++i) {
182         switch (goals->cue_states[i]) {
183         case CUE_STATE_VIRGIN:
184             if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
185                 goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
186             }
187
188             break;
189
190         case CUE_STATE_SEEN_NOTHING:
191             if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->points[i])) {
192                 goals->cue_states[i] = CUE_STATE_VIRGIN;
193             }
194             break;
195
196         default: {}
197         }
198     }
199 }
200
201 void goals_checkpoint(const goals_t *goals,
202                       player_t *player)
203 {
204     assert(goals);
205     assert(player);
206
207     for (size_t i = 0; i < goals->goals_count; ++i) {
208         if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
209             player_checkpoint(player, goals->points[i]);
210         }
211     }
212 }
213
214 /* Private Functions */
215
216 static int goals_is_goal_hidden(const goals_t *goals, size_t i)
217 {
218     return rects_overlap(goals->regions[i], goals->player_hitbox);
219 }