]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/labels.c
(#639) Make rigid bodies interact with platforms
[nothing.git] / src / game / level / labels.c
index 3e2b91cc6e6c60206c29b268abf652205842b59c..9de6d3ca625406b8c893cf62e587758dc6b21c77 100644 (file)
-#include <assert.h>
+#include "system/stacktrace.h"
+#include <stdbool.h>
 
 #include "game/camera.h"
 #include "game/level/labels.h"
-#include "system/error.h"
+#include "str.h"
+#include "system/line_stream.h"
 #include "system/lt.h"
+#include "system/nth_alloc.h"
+#include "system/log.h"
+#include "ebisp/interpreter.h"
+#include "broadcast.h"
 
-#define LABEL_TEXT_MAX_LENGTH 64
+#define LABEL_MAX_ID_SIZE 36
 
-struct labels_t
+enum LabelState
 {
-    lt_t *lt;
-    size_t count;
-    vec_t *positions;
-    color_t *colors;
-    char **texts;
-    float *states;
+    LABEL_STATE_VIRGIN = 0,
+    LABEL_STATE_APPEARED,
+    LABEL_STATE_HIDDEN
 };
 
-static char *trim_endline(char *s)
+struct Labels
 {
-    const size_t n = strlen(s);
-
-    if (n == 0) {
-        return s;
-    }
-
-    if (s[n - 1] == '\n') {
-        s[n - 1] = '\0';
-    }
-
-    return s;
-}
+    Lt *lt;
+    size_t count;
+    char **ids;
+    Vec *positions;
+    Color *colors;
+    char **texts;
+    float *alphas;
+    float *delta_alphas;
+    enum LabelState *states;
+};
 
-labels_t *create_labels_from_stream(FILE *stream)
+Labels *create_labels_from_line_stream(LineStream *line_stream)
 {
-    assert(stream);
+    trace_assert(line_stream);
 
-    lt_t *const lt = create_lt();
+    Lt *const lt = create_lt();
     if (lt == NULL) {
         return NULL;
     }
 
-    labels_t * const labels = PUSH_LT(lt, malloc(sizeof(labels_t)), free);
+    Labels * const labels = PUSH_LT(lt, nth_alloc(sizeof(Labels)), free);
     if (labels == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
         RETURN_LT(lt, NULL);
     }
     labels->lt = lt;
 
-    if (fscanf(stream, "%lu", &labels->count) == EOF) {
-        throw_error(ERROR_TYPE_LIBC);
+    if (sscanf(
+            line_stream_next(line_stream),
+            "%lu",
+            &labels->count) == EOF) {
+        log_fail("Could not read amount of labels\n");
+        RETURN_LT(lt, NULL);
+    }
+
+    labels->ids = PUSH_LT(lt, nth_alloc(sizeof(char*) * labels->count), free);
+    if (labels->ids == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    labels->positions = PUSH_LT(lt, malloc(sizeof(vec_t) * labels->count), free);
+    labels->positions = PUSH_LT(lt, nth_alloc(sizeof(Vec) * labels->count), free);
     if (labels->positions == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
         RETURN_LT(lt, NULL);
     }
 
-    labels->colors = PUSH_LT(lt, malloc(sizeof(color_t) * labels->count), free);
+    labels->colors = PUSH_LT(lt, nth_alloc(sizeof(Color) * labels->count), free);
     if (labels->colors == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
         RETURN_LT(lt, NULL);
     }
 
-    labels->texts = PUSH_LT(lt, malloc(sizeof(char*) * labels->count), free);
+    labels->texts = PUSH_LT(lt, nth_alloc(sizeof(char*) * labels->count), free);
     if (labels->texts == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
         RETURN_LT(lt, NULL);
     }
 
-    labels->states = PUSH_LT(lt, malloc(sizeof(float) * labels->count), free);
+    labels->alphas = PUSH_LT(lt, nth_alloc(sizeof(float) * labels->count), free);
+    if (labels->alphas == NULL) {
+        RETURN_LT(lt, NULL);
+    }
+
+    labels->delta_alphas = PUSH_LT(lt, nth_alloc(sizeof(float) * labels->count), free);
+    if (labels->delta_alphas == NULL) {
+        RETURN_LT(lt, NULL);
+    }
+
+    labels->states = PUSH_LT(lt, nth_alloc(sizeof(enum LabelState) * labels->count), free);
     if (labels->states == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
         RETURN_LT(lt, NULL);
     }
 
     char color[7];
     for (size_t i = 0; i < labels->count; ++i) {
-        labels->states[i] = 1.0f;
+        labels->alphas[i] = 0.0f;
+        labels->delta_alphas[i] = 0.0f;
+        labels->states[i] = LABEL_STATE_VIRGIN;
+        labels->texts[i] = NULL;
 
-        labels->texts[i] = PUSH_LT(lt, malloc(sizeof(char) * (LABEL_TEXT_MAX_LENGTH + 1)), free);
-        if (labels->texts[i] == NULL) {
-            throw_error(ERROR_TYPE_LIBC);
+        labels->ids[i] = PUSH_LT(lt, nth_alloc(sizeof(char) * LABEL_MAX_ID_SIZE), free);
+        if (labels->ids[i] == NULL) {
             RETURN_LT(lt, NULL);
         }
 
-        if (fscanf(stream, "%f%f%6s\n",
-                   &labels->positions[i].x,
-                   &labels->positions[i].y,
-                   color) == EOF) {
-            throw_error(ERROR_TYPE_LIBC);
+        if (sscanf(
+                line_stream_next(line_stream),
+                "%" STRINGIFY(LABEL_MAX_ID_SIZE) "s%f%f%6s\n",
+                labels->ids[i],
+                &labels->positions[i].x,
+                &labels->positions[i].y,
+                color) == EOF) {
+            log_fail("Could not read position and color of %dth label\n", i);
             RETURN_LT(lt, NULL);
         }
 
-        labels->colors[i] = color_from_hexstr(color);
+        labels->colors[i] = hexstr(color);
 
-        if (fgets(labels->texts[i], LABEL_TEXT_MAX_LENGTH, stream) == NULL) {
-            throw_error(ERROR_TYPE_LIBC);
+        const char *label_text = line_stream_next(line_stream);
+        if (label_text == NULL) {
+            log_fail("Could not read text of %dth label\n", i);
+            RETURN_LT(lt, NULL);
+        }
+
+        labels->texts[i] = PUSH_LT(
+            lt,
+            string_duplicate(label_text, NULL),
+            free);
+        if (labels->texts[i] == NULL) {
             RETURN_LT(lt, NULL);
         }
 
@@ -108,29 +136,31 @@ labels_t *create_labels_from_stream(FILE *stream)
     return labels;
 }
 
-void destroy_labels(labels_t *label)
+void destroy_labels(Labels *label)
 {
-    assert(label);
+    trace_assert(label);
     RETURN_LT0(label->lt);
 }
 
-int labels_render(const labels_t *label,
-                 camera_t *camera)
+int labels_render(const Labels *label,
+                 Camera *camera)
 {
-    assert(label);
-    assert(camera);
+    trace_assert(label);
+    trace_assert(camera);
 
-    /* TODO: position and transparency of label is not dependent on its state */
     for (size_t i = 0; i < label->count; ++i) {
+        /* Easing */
+        const float state = label->alphas[i] * (2 - label->alphas[i]);
+
         if (camera_render_text(camera,
                                label->texts[i],
                                vec(2.0f, 2.0f),
-                               color(label->colors[i].r,
-                                     label->colors[i].g,
-                                     label->colors[i].b,
-                                     label->states[i]),
+                               rgba(label->colors[i].r,
+                                    label->colors[i].g,
+                                    label->colors[i].b,
+                                    state),
                                vec_sum(label->positions[i],
-                                       vec(0.0f, -8.0f * label->states[i]))) < 0) {
+                                       vec(0.0f, -8.0f * state))) < 0) {
             return -1;
         }
     }
@@ -138,22 +168,97 @@ int labels_render(const labels_t *label,
     return 0;
 }
 
-void labels_update(labels_t *label,
+void labels_update(Labels *label,
                    float delta_time)
 {
-    assert(label);
+    trace_assert(label);
     (void) delta_time;
 
     for (size_t i = 0; i < label->count; ++i) {
-        label->states[i] = fmodf(label->states[i] + delta_time, 1.0f);
+        label->alphas[i] = label->alphas[i] + label->delta_alphas[i] * delta_time;
+
+        if (label->alphas[i] < 0.0f) {
+            label->alphas[i] = 0.0f;
+            label->delta_alphas[i] = 0.0f;
+        }
+
+        if (label->alphas[i] > 1.0f) {
+            label->alphas[i] = 1.0f;
+            label->delta_alphas[i] = 0.0f;
+        }
+    }
+}
+
+void labels_enter_camera_event(Labels *labels,
+                               const Camera *camera)
+{
+    trace_assert(labels);
+    trace_assert(camera);
+
+    for (size_t i = 0; i < labels->count; ++i) {
+        const int became_visible = camera_is_text_visible(
+            camera,
+            vec(2.0f, 2.0f),
+            labels->positions[i],
+            labels->texts[i]);
+
+        if (labels->states[i] == LABEL_STATE_VIRGIN && became_visible) {
+            labels->states[i] = LABEL_STATE_APPEARED;
+            labels->alphas[i] = 0.0f;
+            labels->delta_alphas[i] = 1.0f;
+        }
+    }
+}
+
+static struct EvalResult
+labels_action(Labels *labels,
+              size_t index,
+              Gc *gc,
+              struct Scope *scope,
+              struct Expr path)
+{
+    trace_assert(labels);
+    trace_assert(gc);
+    trace_assert(scope);
+
+    const char *target = NULL;
+    struct Expr rest = void_expr();
+    struct EvalResult res = match_list(gc, "q*", path, &target, &rest);
+    if (res.is_error) {
+        return res;
     }
+
+    if (strcmp(target, "hide") == 0) {
+        if (labels->states[index] != LABEL_STATE_HIDDEN) {
+            labels->states[index] = LABEL_STATE_HIDDEN;
+            labels->alphas[index] = 1.0f;
+            labels->delta_alphas[index] = -3.0f;
+        }
+        return eval_success(NIL(gc));
+    }
+
+    return unknown_target(gc, labels->ids[index], target);
 }
 
-void labels_enter_camera_event(labels_t *labels,
-                               const camera_t *camera)
+struct EvalResult
+labels_send(Labels *labels, Gc *gc, struct Scope *scope, struct Expr path)
 {
-    assert(labels);
-    assert(camera);
+    trace_assert(labels);
+    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 < labels->count; ++i) {
+        if (strcmp(target, labels->ids[i]) == 0) {
+            return labels_action(labels, i, gc, scope, rest);
+        }
+    }
 
-    /* TODO: labels_enter_camera_event is not implemented */
+    return unknown_target(gc, "label", target);
 }