-#include <assert.h>
+#include <stdio.h>
#include <math.h>
-#include <SDL2/SDL.h>
+#include <SDL.h>
-#include "./lt.h"
-#include "./goals.h"
-#include "./system/error.h"
-#include "./math/pi.h"
-#include "./math/triangle.h"
+#include "game/level/level_editor/point_layer.h"
+#include "goals.h"
+#include "math/pi.h"
+#include "math/triangle.h"
+#include "system/line_stream.h"
+#include "system/log.h"
+#include "system/lt.h"
+#include "system/nth_alloc.h"
+#include "system/stacktrace.h"
+#include "system/str.h"
#define GOAL_RADIUS 10.0f
-static int goals_is_goal_hidden(const goals_t *goals, size_t i);
+static int goals_is_goal_hidden(const Goals *goals, size_t i);
-typedef enum cue_state_t {
+typedef enum Cue_state {
CUE_STATE_VIRGIN = 0,
CUE_STATE_HIT_NOTHING,
CUE_STATE_SEEN_NOTHING
-} cue_state_t;
-
-struct goals_t {
- lt_t *lt;
- point_t *points;
- rect_t *regions;
- color_t *colors;
- cue_state_t *cue_states;
- size_t goals_count;
- rect_t player_hitbox;
+} Cue_state;
+
+struct Goals {
+ Lt *lt;
+ char **ids;
+ Vec2f *positions;
+ Color *colors;
+ Cue_state *cue_states;
+ bool *visible;
+ size_t count;
float angle;
};
-goals_t *create_goals_from_stream(FILE *stream)
+Goals *create_goals_from_line_stream(LineStream *line_stream)
{
- assert(stream);
+ trace_assert(line_stream);
- lt_t *const lt = create_lt();
- if (lt == NULL) {
- return NULL;
- }
+ Lt *lt = create_lt();
- goals_t *const goals = PUSH_LT(lt, malloc(sizeof(goals_t)), free);
+ Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
if (goals == NULL) {
- throw_error(ERROR_TYPE_LIBC);
RETURN_LT(lt, NULL);
}
- goals->goals_count = 0;
- if (fscanf(stream, "%lu", &goals->goals_count) == EOF) {
- throw_error(ERROR_TYPE_LIBC);
+ goals->count = 0;
+ if (sscanf(
+ line_stream_next(line_stream),
+ "%zu",
+ &goals->count) == EOF) {
+ log_fail("Could not read amount of goals\n");
RETURN_LT(lt, NULL);
}
- goals->points = PUSH_LT(lt, malloc(sizeof(point_t) * goals->goals_count), free);
- if (goals->points == NULL) {
- throw_error(ERROR_TYPE_LIBC);
+ goals->ids = PUSH_LT(
+ lt,
+ nth_calloc(1, sizeof(char*) * goals->count),
+ free);
+ if (goals->ids == NULL) {
RETURN_LT(lt, NULL);
}
+ for (size_t i = 0; i < goals->count; ++i) {
+ goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
+ if (goals->ids[i] == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+ }
- goals->regions = PUSH_LT(lt, malloc(sizeof(rect_t) * goals->goals_count), free);
- if (goals->regions == NULL) {
- throw_error(ERROR_TYPE_LIBC);
+ goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
+ if (goals->positions == NULL) {
RETURN_LT(lt, NULL);
}
- goals->colors = PUSH_LT(lt, malloc(sizeof(color_t) * goals->goals_count), free);
+ goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
if (goals->colors == NULL) {
- throw_error(ERROR_TYPE_LIBC);
RETURN_LT(lt, NULL);
}
- goals->cue_states = PUSH_LT(lt, malloc(sizeof(int) * goals->goals_count), free);
+ goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
if (goals->cue_states == NULL) {
- throw_error(ERROR_TYPE_LIBC);
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
+ if (goals->visible == NULL) {
RETURN_LT(lt, NULL);
}
char color[7];
- for (size_t i = 0; i < goals->goals_count; ++i) {
- if (fscanf(stream, "%f%f%f%f%f%f%6s",
- &goals->points[i].x,
- &goals->points[i].y,
- &goals->regions[i].x,
- &goals->regions[i].y,
- &goals->regions[i].w,
- &goals->regions[i].h,
- color) < 0) {
- throw_error(ERROR_TYPE_LIBC);
+ for (size_t i = 0; i < goals->count; ++i) {
+ if (sscanf(
+ line_stream_next(line_stream),
+ "%" STRINGIFY(ENTITY_MAX_ID_SIZE) "s%f%f%6s",
+ goals->ids[i],
+ &goals->positions[i].x,
+ &goals->positions[i].y,
+ color) < 0) {
+ log_fail("Could not read %dth goal\n", i);
RETURN_LT(lt, NULL);
}
- goals->colors[i] = color_from_hexstr(color);
+ goals->colors[i] = hexstr(color);
+ goals->cue_states[i] = CUE_STATE_VIRGIN;
+ goals->visible[i] = true;
+ }
+
+ goals->lt = lt;
+ goals->angle = 0.0f;
+
+ return goals;
+}
+
+Goals *create_goals_from_point_layer(const PointLayer *point_layer)
+{
+ trace_assert(point_layer);
+
+ Lt *lt = create_lt();
+
+ Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
+ if (goals == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->count = point_layer_count(point_layer);
+
+ goals->ids = PUSH_LT(
+ lt,
+ nth_calloc(1, sizeof(char*) * goals->count),
+ free);
+ if (goals->ids == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+ for (size_t i = 0; i < goals->count; ++i) {
+ goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
+ if (goals->ids[i] == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+ }
+
+ goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
+ if (goals->positions == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
+ if (goals->colors == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
+ if (goals->cue_states == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
+ if (goals->visible == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ const Vec2f *positions = point_layer_positions(point_layer);
+ const Color *colors = point_layer_colors(point_layer);
+ const char *ids = point_layer_ids(point_layer);
+
+ // TODO(#835): we could use memcpy in create_goals_from_point_layer
+ for (size_t i = 0; i < goals->count; ++i) {
+ goals->positions[i] = positions[i];
+ goals->colors[i] = colors[i];
+ memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);
goals->cue_states[i] = CUE_STATE_VIRGIN;
+ goals->visible[i] = true;
}
goals->lt = lt;
return goals;
}
-void destroy_goals(goals_t *goals)
+void destroy_goals(Goals *goals)
{
- assert(goals);
+ trace_assert(goals);
RETURN_LT0(goals->lt);
}
-static int goals_render_core(const goals_t *goals,
+static int goals_render_core(const Goals *goals,
size_t goal_index,
- SDL_Renderer *renderer,
- const camera_t *camera)
+ const Camera *camera)
{
- assert(goals);
- assert(renderer);
- assert(camera);
+ trace_assert(goals);
+ trace_assert(camera);
- const point_t position = vec_sum(
- goals->points[goal_index],
+ const Vec2f position = vec_sum(
+ goals->positions[goal_index],
vec(0.0f, sinf(goals->angle) * 10.0f));
- return camera_fill_triangle(
- camera,
- renderer,
- triangle_mat3x3_product(
- equilateral_triangle(),
- mat3x3_product2(
- trans_mat(position.x, position.y),
- rot_mat(PI * -0.5f + goals->angle),
- scale_mat(GOAL_RADIUS))),
- goals->colors[goal_index]);
-}
+ if (camera_fill_triangle(
+ camera,
+ triangle_mat3x3_product(
+ equilateral_triangle(),
+ mat3x3_product2(
+ trans_mat(position.x, position.y),
+ rot_mat(PI * -0.5f + goals->angle),
+ scale_mat(GOAL_RADIUS))),
+ goals->colors[goal_index]) < 0) {
+ return -1;
+ }
-int goals_render(const goals_t *goals,
- SDL_Renderer *renderer,
- const camera_t *camera)
+ if (camera_render_debug_text(
+ camera,
+ goals->ids[goal_index],
+ position) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+int goals_render(const Goals *goals,
+ const Camera *camera)
{
- assert(goals);
- assert(renderer);
- assert(camera);
+ trace_assert(goals);
+ trace_assert(camera);
- for (size_t i = 0; i < goals->goals_count; ++i) {
+ for (size_t i = 0; i < goals->count; ++i) {
if (!goals_is_goal_hidden(goals, i)) {
- if (goals_render_core(goals, i, renderer, camera) < 0) {
+ if (goals_render_core(goals, i, camera) < 0) {
return -1;
}
}
return 0;
}
-void goals_update(goals_t *goals,
+void goals_update(Goals *goals,
float delta_time)
{
- assert(goals);
- assert(delta_time > 0.0f);
+ trace_assert(goals);
+ trace_assert(delta_time > 0.0f);
goals->angle = fmodf(goals->angle + 2.0f * delta_time, 2.0f * PI);
}
-void goals_hide(goals_t *goals,
- rect_t player_hitbox)
-{
- goals->player_hitbox = player_hitbox;
-
-}
-
-int goals_sound(goals_t *goals,
- sound_medium_t *sound_medium)
+int goals_sound(Goals *goals,
+ Sound_samples *sound_samples)
{
- for (size_t i = 0; i < goals->goals_count; ++i) {
+ for (size_t i = 0; i < goals->count; ++i) {
switch (goals->cue_states[i]) {
case CUE_STATE_HIT_NOTHING:
- sound_medium_play_sound(sound_medium, 0, goals->points[i], 0);
+ sound_samples_play_sound(sound_samples, 0);
goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
break;
return 0;
}
-void goals_cue(goals_t *goals,
- SDL_Renderer *renderer,
- const camera_t *camera)
+void goals_cue(Goals *goals,
+ const Camera *camera)
{
- for (size_t i = 0; i < goals->goals_count; ++i) {
+ for (size_t i = 0; i < goals->count; ++i) {
switch (goals->cue_states[i]) {
case CUE_STATE_VIRGIN:
- if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, renderer, goals->points[i])) {
+ if (goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
goals->cue_states[i] = CUE_STATE_HIT_NOTHING;
}
break;
case CUE_STATE_SEEN_NOTHING:
- if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, renderer, goals->points[i])) {
+ if (!goals_is_goal_hidden(goals, i) && camera_is_point_visible(camera, goals->positions[i])) {
goals->cue_states[i] = CUE_STATE_VIRGIN;
}
break;
}
}
-void goals_checkpoint(const goals_t *goals,
- player_t *player)
+void goals_checkpoint(const Goals *goals,
+ Player *player)
{
- assert(goals);
- assert(player);
+ trace_assert(goals);
+ trace_assert(player);
- for (size_t i = 0; i < goals->goals_count; ++i) {
+ for (size_t i = 0; i < goals->count; ++i) {
if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
- player_checkpoint(player, goals->points[i]);
+ player_checkpoint(player, goals->positions[i]);
}
}
}
/* Private Functions */
-static int goals_is_goal_hidden(const goals_t *goals, size_t i)
+static int goals_is_goal_hidden(const Goals *goals, size_t i)
+{
+ return !goals->visible[i];
+}
+
+void goals_hide(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
{
- return rects_overlap(goals->regions[i], goals->player_hitbox);
+ trace_assert(goals);
+ trace_assert(goal_id);
+
+ for (size_t i = 0; i < goals->count; ++i) {
+ if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
+ goals->visible[i] = false;
+ }
+ }
+}
+
+void goals_show(Goals *goals, char goal_id[ENTITY_MAX_ID_SIZE])
+{
+ trace_assert(goals);
+ trace_assert(goal_id);
+ for (size_t i = 0; i < goals->count; ++i) {
+ if (strncmp(goal_id, goals->ids[i], ENTITY_MAX_ID_SIZE) == 0) {
+ goals->visible[i] = true;
+ }
+ }
}