]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/goals.c
(#824) Implement undo_history_push and undo_history_pop
[nothing.git] / src / game / level / goals.c
index 034450c6502ae4750fce0f1dbe91e5c5a91e73fa..cef1df42a46e3c1f5dc22f097413740eee959263 100644 (file)
@@ -1,15 +1,20 @@
-#include <SDL2/SDL.h>
-#include <assert.h>
+#include <stdio.h>
 #include <math.h>
 
+#include <SDL.h>
+
+#include "broadcast.h"
+#include "ebisp/interpreter.h"
+#include "game/level/level_editor/point_layer.h"
 #include "goals.h"
 #include "math/pi.h"
 #include "math/triangle.h"
-#include "str.h"
 #include "system/line_stream.h"
+#include "system/log.h"
 #include "system/lt.h"
 #include "system/nth_alloc.h"
-#include "system/log.h"
+#include "system/stacktrace.h"
+#include "system/str.h"
 
 #define GOAL_RADIUS 10.0f
 #define GOAL_MAX_ID_SIZE 36
@@ -25,9 +30,8 @@ typedef enum Cue_state {
 struct Goals {
     Lt *lt;
     char **ids;
-    Point *points;
+    Point *positions;
     Color *colors;
-    /* TODO(#494): it is not clear how to maintain Cue_state from the scripting language */
     Cue_state *cue_states;
     bool *visible;
     size_t count;
@@ -37,14 +41,11 @@ struct Goals {
 
 Goals *create_goals_from_line_stream(LineStream *line_stream)
 {
-    assert(line_stream);
+    trace_assert(line_stream);
 
-    Lt *const lt = create_lt();
-    if (lt == NULL) {
-        return NULL;
-    }
+    Lt *lt = create_lt();
 
-    Goals *const goals = PUSH_LT(lt, nth_alloc(sizeof(Goals)), free);
+    Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
     if (goals == NULL) {
         RETURN_LT(lt, NULL);
     }
@@ -52,7 +53,7 @@ Goals *create_goals_from_line_stream(LineStream *line_stream)
     goals->count = 0;
     if (sscanf(
             line_stream_next(line_stream),
-            "%lu",
+            "%zu",
             &goals->count) == EOF) {
         log_fail("Could not read amount of goals\n");
         RETURN_LT(lt, NULL);
@@ -60,34 +61,34 @@ Goals *create_goals_from_line_stream(LineStream *line_stream)
 
     goals->ids = PUSH_LT(
         lt,
-        nth_alloc(sizeof(char*) * goals->count),
+        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_alloc(sizeof(char) * GOAL_MAX_ID_SIZE), free);
+        goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
         if (goals->ids[i] == NULL) {
             RETURN_LT(lt, NULL);
         }
     }
 
-    goals->points = PUSH_LT(lt, nth_alloc(sizeof(Point) * goals->count), free);
-    if (goals->points == NULL) {
+    goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
+    if (goals->positions == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    goals->colors = PUSH_LT(lt, nth_alloc(sizeof(Color) * goals->count), free);
+    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_alloc(sizeof(int) * goals->count), free);
+    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_alloc(sizeof(bool) * goals->count), free);
+    goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
     if (goals->visible == NULL) {
         RETURN_LT(lt, NULL);
     }
@@ -98,13 +99,79 @@ Goals *create_goals_from_line_stream(LineStream *line_stream)
                 line_stream_next(line_stream),
                 "%" STRINGIFY(GOAL_MAX_ID_SIZE) "s%f%f%6s",
                 goals->ids[i],
-                &goals->points[i].x,
-                &goals->points[i].y,
+                &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) * GOAL_MAX_ID_SIZE), free);
+        if (goals->ids[i] == NULL) {
+            RETURN_LT(lt, NULL);
+        }
+    }
+
+    goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * 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 Point *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;
     }
@@ -117,7 +184,7 @@ Goals *create_goals_from_line_stream(LineStream *line_stream)
 
 void destroy_goals(Goals *goals)
 {
-    assert(goals);
+    trace_assert(goals);
     RETURN_LT0(goals->lt);
 }
 
@@ -125,11 +192,11 @@ static int goals_render_core(const Goals *goals,
                              size_t goal_index,
                              Camera *camera)
 {
-    assert(goals);
-    assert(camera);
+    trace_assert(goals);
+    trace_assert(camera);
 
     const Point position = vec_sum(
-        goals->points[goal_index],
+        goals->positions[goal_index],
         vec(0.0f, sinf(goals->angle) * 10.0f));
 
     if (camera_fill_triangle(
@@ -154,12 +221,11 @@ static int goals_render_core(const Goals *goals,
     return 0;
 }
 
-/* TODO(#448): goals do not render their ids in debug mode */
 int goals_render(const Goals *goals,
                  Camera *camera)
 {
-    assert(goals);
-    assert(camera);
+    trace_assert(goals);
+    trace_assert(camera);
 
     for (size_t i = 0; i < goals->count; ++i) {
         if (!goals_is_goal_hidden(goals, i)) {
@@ -175,8 +241,8 @@ int goals_render(const Goals *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);
 }
 
@@ -193,7 +259,7 @@ int goals_sound(Goals *goals,
     for (size_t i = 0; i < goals->count; ++i) {
         switch (goals->cue_states[i]) {
         case CUE_STATE_HIT_NOTHING:
-            sound_samples_play_sound(sound_samples, 0, 0);
+            sound_samples_play_sound(sound_samples, 0);
             goals->cue_states[i] = CUE_STATE_SEEN_NOTHING;
             break;
 
@@ -210,14 +276,14 @@ void goals_cue(Goals *goals,
     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, 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, 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;
@@ -230,40 +296,61 @@ void goals_cue(Goals *goals,
 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->count; ++i) {
         if (goals->cue_states[i] == CUE_STATE_HIT_NOTHING) {
-            player_checkpoint(player, goals->points[i]);
+            player_checkpoint(player, goals->positions[i]);
         }
     }
 }
 
-void goals_hide(Goals *goals, const char *id)
+static struct EvalResult
+goals_action(Goals *goals, size_t index, Gc *gc, struct Scope *scope, struct Expr path)
 {
-    assert(goals);
-    assert(id);
+    trace_assert(goals);
+    trace_assert(gc);
+    trace_assert(scope);
+
+    const char *target = NULL;
+    struct EvalResult res = match_list(gc, "q*", path, &target, NULL);
+    if (res.is_error) {
+        return res;
+    }
 
-    for (size_t i = 0; i < goals->count; ++i) {
-        if (strcmp(id, goals->ids[i]) == 0) {
-            goals->visible[i] = false;
-            return;
-        }
+    if (strcmp(target, "show") == 0) {
+        goals->visible[index] = true;
+        return eval_success(NIL(gc));
+    } else if (strcmp(target, "hide") == 0) {
+        goals->visible[index] = false;
+        return eval_success(NIL(gc));
     }
+
+    return unknown_target(gc, goals->ids[index], target);
 }
 
-void goals_show(Goals *goals, const char *id)
+struct EvalResult
+goals_send(Goals *goals, Gc *gc, struct Scope *scope, struct Expr path)
 {
-    assert(goals);
-    assert(id);
+    trace_assert(goals);
+    trace_assert(gc);
+    trace_assert(scope);
+
+    const char *target = NULL;
+    struct Expr rest = void_expr();
+    struct EvalResult res = match_list(gc, "s*", path, &target, &rest);
+    if (res.is_error) {
+        return res;
+    }
 
     for (size_t i = 0; i < goals->count; ++i) {
-        if (strcmp(id, goals->ids[i]) == 0) {
-            goals->visible[i] = true;
-            return;
+        if (strcmp(target, goals->ids[i]) == 0) {
+            return goals_action(goals, i, gc, scope, rest);
         }
     }
+
+    return unknown_target(gc, "goals", target);
 }
 
 /* Private Functions */