]> git.lizzy.rs Git - nothing.git/blobdiff - src/game/level/player.c
create_lt() -> {0}
[nothing.git] / src / game / level / player.c
index 0ffb1b1569532749af8844614345a1d11bcf0dce..7d991f84cd3e19aae95588c616950993971bbc1d 100644 (file)
 #include <SDL2/SDL.h>
-#include <assert.h>
+#include "system/stacktrace.h"
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "game/level/player/dying_rect.h"
-#include "game/level/player/rigid_rect.h"
+#include "game/level/explosion.h"
+#include "game/level/script.h"
+#include "game/level/rigid_bodies.h"
 #include "goals.h"
 #include "math/point.h"
 #include "platforms.h"
 #include "player.h"
-#include "system/error.h"
+#include "system/line_stream.h"
+#include "system/log.h"
 #include "system/lt.h"
+#include "system/nth_alloc.h"
 
 #define PLAYER_WIDTH 25.0f
 #define PLAYER_HEIGHT 25.0f
 #define PLAYER_SPEED 500.0f
 #define PLAYER_JUMP 32000.0f
 #define PLAYER_DEATH_DURATION 0.75f
-#define PLAYER_MAX_JUMP_COUNT 2
+#define PLAYER_MAX_JUMP_THRESHOLD 2
 
-typedef enum player_state_t {
+typedef enum Player_state {
     PLAYER_STATE_ALIVE = 0,
     PLAYER_STATE_DYING
-} player_state_t;
+} Player_state;
 
-struct player_t {
-    lt_t *lt;
-    player_state_t state;
+struct Player {
+    Lt lt;
+    Player_state state;
 
-    rigid_rect_t *alive_body;
-    dying_rect_t *dying_body;
+    RigidBodies *rigid_bodies;
 
-    int jump_count;
-    color_t color;
+    RigidBodyId alive_body_id;
+    Explosion *dying_body;
+    Script *script;
 
-    vec_t checkpoint;
+    int jump_threshold;
+    Color color;
+
+    Vec checkpoint;
 
     int play_die_cue;
 };
 
-player_t *create_player(float x, float y, color_t color)
+Player *create_player_from_line_stream(LineStream *line_stream, RigidBodies *rigid_bodies, Broadcast *broadcast)
 {
-    lt_t *lt = create_lt();
+    trace_assert(line_stream);
+
+    Lt lt = {0};
 
     if (lt == NULL) {
         return NULL;
     }
 
-    player_t *player = PUSH_LT(lt, malloc(sizeof(player_t)), free);
+    Player *player = PUSH_LT(lt, nth_calloc(1, sizeof(Player)), free);
     if (player == NULL) {
-        throw_error(ERROR_TYPE_LIBC);
         RETURN_LT(lt, NULL);
     }
+    player->lt = lt;
 
-    player->state = PLAYER_STATE_ALIVE;
+    player->rigid_bodies = rigid_bodies;
+
+    float x = 0.0f, y = 0.0f;
+    char colorstr[7];
 
-    player->alive_body = PUSH_LT(
+    if (sscanf(
+            line_stream_next(line_stream),
+            "%f%f%6s",
+            &x, &y, colorstr) == EOF) {
+        log_fail("Could not read player\n");
+        RETURN_LT(lt, NULL);
+    }
+
+    player->script = PUSH_LT(
         lt,
-        create_rigid_rect(
-            rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
-            color),
-        destroy_rigid_rect);
-    if (player->alive_body == NULL) {
+        create_script_from_line_stream(line_stream, broadcast),
+        destroy_script);
+    if (player->script == NULL) {
         RETURN_LT(lt, NULL);
     }
 
+    const Color color = hexstr(colorstr);
+
+    player->alive_body_id = rigid_bodies_add(
+        rigid_bodies,
+        rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT));
+
     player->dying_body = PUSH_LT(
         lt,
-        create_dying_rect(
-            rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
+        create_explosion(
             color,
             PLAYER_DEATH_DURATION),
-        destroy_dying_rect);
+        destroy_explosion);
     if (player->dying_body == NULL) {
         RETURN_LT(lt, NULL);
     }
 
-    player->lt = lt;
-    player->jump_count = 0;
+    player->jump_threshold = 0;
     player->color = color;
     player->checkpoint = vec(x, y);
     player->play_die_cue = 0;
+    player->state = PLAYER_STATE_ALIVE;
 
     return player;
 }
 
-player_t *create_player_from_stream(FILE *stream)
-{
-    float x = 0.0f, y = 0.0f;
-
-    char color[7];
-    if (fscanf(stream, "%f%f%6s", &x, &y, color) == EOF) {
-        throw_error(ERROR_TYPE_LIBC);
-        return NULL;
-    }
-
-    return create_player(x, y, color_from_hexstr(color));
-}
-
-void destroy_player(player_t * player)
+void destroy_player(Player * player)
 {
     RETURN_LT0(player->lt);
 }
 
-solid_ref_t player_as_solid(player_t *player)
+int player_render(const Player * player,
+                  Camera *camera)
 {
-    solid_ref_t ref = {
-        .tag = SOLID_PLAYER,
-        .ptr = (void*) player
-    };
-
-    return ref;
-}
+    trace_assert(player);
+    trace_assert(camera);
 
-int player_render(const player_t * player,
-                  const camera_t *camera)
-{
-    assert(player);
-    assert(camera);
+    char debug_text[256];
 
     switch (player->state) {
-    case PLAYER_STATE_ALIVE:
-        return rigid_rect_render(player->alive_body, camera);
+    case PLAYER_STATE_ALIVE: {
+        snprintf(debug_text, 256, "Jump: %d", player->jump_threshold);
+        Rect hitbox = rigid_bodies_hitbox(player->rigid_bodies, player->alive_body_id);
+
+        if (camera_render_debug_text(camera, debug_text, vec(hitbox.x, hitbox.y - 20.0f)) < 0) {
+            return -1;
+        }
+
+        return rigid_bodies_render(
+            player->rigid_bodies,
+            player->alive_body_id,
+            player->color,
+            camera);
+    }
 
     case PLAYER_STATE_DYING:
-        return dying_rect_render(player->dying_body, camera);
+        return explosion_render(player->dying_body, camera);
 
     default: {}
     }
@@ -132,16 +145,17 @@ int player_render(const player_t * player,
     return 0;
 }
 
-void player_update(player_t *player,
+void player_update(Player *player,
                    float delta_time)
 {
-    assert(player);
+    trace_assert(player);
 
     switch (player->state) {
     case PLAYER_STATE_ALIVE: {
-        rigid_rect_update(player->alive_body, delta_time);
+        rigid_bodies_update(player->rigid_bodies, player->alive_body_id, delta_time);
+
+        const Rect hitbox = rigid_bodies_hitbox(player->rigid_bodies, player->alive_body_id);
 
-        const rect_t hitbox = rigid_rect_hitbox(player->alive_body);
 
         if (hitbox.y > 1000.0f) {
             player_die(player);
@@ -149,17 +163,20 @@ void player_update(player_t *player,
     } break;
 
     case PLAYER_STATE_DYING: {
-        dying_rect_update(player->dying_body, delta_time);
-
-        if (dying_rect_is_dead(player->dying_body)) {
-            player->alive_body = RESET_LT(
-                player->lt,
-                player->alive_body,
-                create_rigid_rect(
-                    rect_from_vecs(
-                        player->checkpoint,
-                        vec(PLAYER_WIDTH, PLAYER_HEIGHT)),
-                    player->color));
+        explosion_update(player->dying_body, delta_time);
+
+        if (explosion_is_done(player->dying_body)) {
+            rigid_bodies_disable(player->rigid_bodies, player->alive_body_id, false);
+            rigid_bodies_transform_velocity(
+                player->rigid_bodies,
+                player->alive_body_id,
+                make_mat3x3(0.0f, 0.0f, 0.0f,
+                            0.0f, 0.0f, 0.0f,
+                            0.0f, 0.0f, 1.0f));
+            rigid_bodies_teleport_to(
+                player->rigid_bodies,
+                player->alive_body_id,
+                player->checkpoint);
             player->state = PLAYER_STATE_ALIVE;
         }
     } break;
@@ -168,75 +185,79 @@ void player_update(player_t *player,
     }
 }
 
-void player_collide_with_solid(player_t *player, solid_ref_t solid)
+void player_move_left(Player *player)
 {
-    if (player->state == PLAYER_STATE_ALIVE) {
-        rigid_rect_collide_with_solid(player->alive_body, solid);
-
-        if (rigid_rect_touches_ground(player->alive_body)) {
-            player->jump_count = 0;
-        }
-    }
+    trace_assert(player);
+    rigid_bodies_move(player->rigid_bodies, player->alive_body_id, vec(-PLAYER_SPEED, 0.0f));
 }
 
-void player_move_left(player_t *player)
+void player_move_right(Player *player)
 {
-    assert(player);
-    rigid_rect_move(player->alive_body, vec(-PLAYER_SPEED, 0.0f));
+    trace_assert(player);
+
+    rigid_bodies_move(player->rigid_bodies, player->alive_body_id, vec(PLAYER_SPEED, 0.0f));
 }
 
-void player_move_right(player_t *player)
+void player_stop(Player *player)
 {
-    assert(player);
+    trace_assert(player);
 
-    rigid_rect_move(player->alive_body, vec(PLAYER_SPEED, 0.0f));
+    rigid_bodies_move(player->rigid_bodies, player->alive_body_id, vec(0.0f, 0.0f));
 }
 
-void player_stop(player_t *player)
+void player_jump(Player *player)
 {
-    assert(player);
+    trace_assert(player);
 
-    rigid_rect_move(player->alive_body, vec(0.0f, 0.0f));
-}
+    if (rigid_bodies_touches_ground(player->rigid_bodies, player->alive_body_id)) {
+        player->jump_threshold = 0;
+    }
 
-void player_jump(player_t *player)
-{
-    assert(player);
-    if (player->jump_count < PLAYER_MAX_JUMP_COUNT) {
-        rigid_rect_transform_velocity(player->alive_body,
-                                      make_mat3x3(1.0f, 0.0f, 0.0f,
-                                                  0.0f, 0.0f, 0.0f,
-                                                  0.0f, 0.0f, 1.0f));
-        rigid_rect_apply_force(player->alive_body,
-                               vec(0.0f, -PLAYER_JUMP));
-        player->jump_count++;
+    if (player->jump_threshold < PLAYER_MAX_JUMP_THRESHOLD) {
+        rigid_bodies_transform_velocity(
+            player->rigid_bodies,
+            player->alive_body_id,
+            make_mat3x3(1.0f, 0.0f, 0.0f,
+                        0.0f, 0.0f, 0.0f,
+                        0.0f, 0.0f, 1.0f));
+        rigid_bodies_apply_force(
+            player->rigid_bodies,
+            player->alive_body_id,
+            vec(0.0f, -PLAYER_JUMP));
+        player->jump_threshold++;
+
+        if (script_has_scope_value(player->script, "on-jump")) {
+            script_eval(player->script, "(on-jump)");
+        }
     }
 }
 
-void player_die(player_t *player)
+void player_die(Player *player)
 {
-    assert(player);
+    trace_assert(player);
 
     if (player->state == PLAYER_STATE_ALIVE) {
+        const Rect hitbox =
+            rigid_bodies_hitbox(
+                player->rigid_bodies,
+                player->alive_body_id);
+
         player->play_die_cue = 1;
-        player->dying_body = RESET_LT(
-            player->lt,
-            player->dying_body,
-            create_dying_rect(
-                rigid_rect_hitbox(player->alive_body),
-                player->color,
-                PLAYER_DEATH_DURATION));
+        explosion_start(player->dying_body, vec(hitbox.x, hitbox.y));
         player->state = PLAYER_STATE_DYING;
+        rigid_bodies_disable(player->rigid_bodies, player->alive_body_id, true);
     }
 }
 
-void player_focus_camera(player_t *player,
-                         camera_t *camera)
+void player_focus_camera(Player *player,
+                         Camera *camera)
 {
-    assert(player);
-    assert(camera);
+    trace_assert(player);
+    trace_assert(camera);
 
-    const rect_t player_hitbox = rigid_rect_hitbox(player->alive_body);
+    const Rect player_hitbox = rigid_bodies_hitbox(
+        player->rigid_bodies,
+        player->alive_body_id);
 
     camera_center_at(
         camera,
@@ -245,29 +266,37 @@ void player_focus_camera(player_t *player,
             vec(0.0f, -player_hitbox.h * 0.5f)));
 }
 
-void player_hide_goals(const player_t *player,
-                       goals_t *goals)
+void player_hide_goals(const Player *player,
+                       Goals *goals)
 {
-    assert(player);
-    assert(goals);
-    goals_hide(goals, rigid_rect_hitbox(player->alive_body));
+    trace_assert(player);
+    trace_assert(goals);
+    goals_hide_from_player(
+        goals,
+        rigid_bodies_hitbox(
+            player->rigid_bodies,
+            player->alive_body_id));
 }
 
-void player_die_from_lava(player_t *player,
-                          const lava_t *lava)
+void player_die_from_lava(Player *player,
+                          const Lava *lava)
 {
-    if (lava_overlaps_rect(lava, rigid_rect_hitbox(player->alive_body))) {
+    if (lava_overlaps_rect(
+            lava,
+            rigid_bodies_hitbox(
+                player->rigid_bodies,
+                player->alive_body_id))) {
         player_die(player);
     }
 }
 
-void player_checkpoint(player_t *player, vec_t checkpoint)
+void player_checkpoint(Player *player, Vec checkpoint)
 {
     player->checkpoint = checkpoint;
 }
 
-int player_sound(player_t *player,
-                 sound_samples_t *sound_samples)
+int player_sound(Player *player,
+                 Sound_samples *sound_samples)
 {
     if (player->play_die_cue) {
         player->play_die_cue = 0;
@@ -280,18 +309,21 @@ int player_sound(player_t *player,
     return 0;
 }
 
-void player_touches_rect_sides(player_t *player,
-                               rect_t object,
-                               int sides[RECT_SIDE_N])
+bool player_overlaps_rect(const Player *player,
+                          Rect rect)
 {
-    if (player->state == PLAYER_STATE_ALIVE) {
-        rigid_rect_touches_rect_sides(player->alive_body, object, sides);
-    }
+    trace_assert(player);
+
+    return player->state == PLAYER_STATE_ALIVE
+        && rects_overlap(
+            rect, rigid_bodies_hitbox(
+                player->rigid_bodies,
+                player->alive_body_id));
 }
 
-void player_apply_force(player_t *player, vec_t force)
+Rect player_hitbox(const Player *player)
 {
-    if (player->state == PLAYER_STATE_ALIVE) {
-        rigid_rect_apply_force(player->alive_body, force);
-    }
+    return rigid_bodies_hitbox(
+        player->rigid_bodies,
+        player->alive_body_id);
 }