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