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