Nimbin[12]?Games / Entropie / commits / 55b9065

Entropie git · main

Entropie festival game; first steps

sdl c game entropie cmake · first commit 2026-10-10 · last commit 2026-11-02 (17 hours ago) · synced 8 hours ago

C 88.5% Markdown 9.1% GLSL 2.3%
git clone https://git.christianimmanuel.de/games/Entropie.gitwget https://git.christianimmanuel.de/games/Entropie/archive/Entropie.tar.gz

entropie 2.23.0: belly first

Christian Immanuel · 2026-10-20 22:30 · 55b9065c38e6e7e51a89cc69d675054153a4dca1

- Chest high ledges: the less sporty (or drunk) push up onto the belly, lie
  over the edge, bring a knee up and stand up
 commit_message.txt              |  6 +++---
 entropie/Makefile               |  2 +-
 entropie/README.md              |  2 ++
 entropie/STATE.md               |  7 +++++--
 entropie/commit_message.txt     |  6 +++---
 entropie/src/people/body.h      |  3 ++-
 entropie/src/people/body_pose.c |  3 +++
 entropie/src/people/climb.c     | 27 +++++++++++++++++++++++++--
 entropie/src/world/object.h     |  2 ++
 entropie/src/world/world.c      |  1 +
 10 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/commit_message.txt b/commit_message.txt
index a0d247c..e0d62fe 100644
--- a/commit_message.txt
+++ b/commit_message.txt
@@ -1,4 +1,4 @@
-entropie 2.22.0: the leading shoulder
+entropie 2.23.0: belly first
 
-- Climbing a high ledge: the shoulder of the hand that reaches first turns
-  ahead, easing back as the other hand follows
+- Chest high ledges: the less sporty (or drunk) push up onto the belly, lie
+  over the edge, bring a knee up and stand up
diff --git a/entropie/Makefile b/entropie/Makefile
index d5ad372..4ecbe6e 100644
--- a/entropie/Makefile
+++ b/entropie/Makefile
@@ -1,5 +1,5 @@
 APP       := entropie
-VERSION   := 2.22.0
+VERSION   := 2.23.0
 
 PREFIX    ?= /usr
 BINDIR    ?= $(PREFIX)/bin
diff --git a/entropie/README.md b/entropie/README.md
index 0246db2..382a0a9 100644
--- a/entropie/README.md
+++ b/entropie/README.md
@@ -340,6 +340,8 @@ and satellite pictures (about 340 x 340 m).
   turned ahead), the other follows
 - Hip high, the less sporty and the old take the careful way: back to it, a
   hop up to sit on the edge, legs swung up onto it, then stand up
+- Chest high, the less sporty (or drunk) go belly first: push up, lie over
+  the edge, a knee up, then stand up
 - Jumps take off from one foot (rarely both at once); at a run, the rear foot
   pushes off and the front one lands first
 - Drunk, walking into a wall or a person easily ends on the ground
diff --git a/entropie/STATE.md b/entropie/STATE.md
index 1ff37d7..bdaedcc 100644
--- a/entropie/STATE.md
+++ b/entropie/STATE.md
@@ -290,6 +290,9 @@ Round 2.21:
 Round 2.22:
 - Climbing a high ledge, the shoulder of the first hand goes ahead: the shoulders turn up to REACH_TURN 0.35 rad to that side while the other hand still trails (`Hands.edge_turn`, set by `Climb_update`; `Body.reach_turn`, added to the chest turn in `body_pose.c`), easing back as the second hand arrives.
 
+Round 2.23:
+- The belly way up (`climb.c`, `ClimbMove.belly_way` / `belly`): something BELLY_LOW 1.0 .. BELLY_HIGH 1.55 m high (scaled), both hands free, standing, for the less sporty (fitness under BELLY_FIT 0.45) or drunk (over 0.4): hands on the edge, a push up till the hips are just over it (feet BELLY_DROP 0.9 below the top), the upper body lies flat over it (forearms on top; `Body.belly_over`, BELLY_PITCH 1.0 rad added to the bend in `body_pose.c`), wriggling on a little, a knee up, standing up. BELLY_TIME 2.6 s fresh. Checked on a 1.3 m wall.
+
 Unfinished building (Shell_build, at SHELL_AT in the frame's frame): brick shell 6.4 x 4.7, walls 2.9, open front (2 m) to the frame (now only the front half: pillars at z -13.8 / -9.2), window holes, bare floor, tiled roof with slabs. Barn: brick courses on BUILDING_BRICK walls (`addBrickCourses`: mortar a shade lighter, so the ink doesn't trace it), ivy (`Shapes_ivy`, OBJ_STRUCTUREs) on both long sides; the woodpile (OBJ_WOODPILE "Woodpile", WOODPILE_A/B) left of the toilet, everybody's woodpile from the start (`scene.c` Scene_finish). Fireplace tripod: wooden poles, feet TRIPOD_OUT 0.9 m outside the stones, TRIPOD_PAST 0.4 m past the top, a lashing; each pole an OBJ_WALL along it ("Tripod pole"). Gates (FURN_GATE, green boards): in your garages' doorways (GATES: hinge, end), `gate_open` / `gate_t`, `hinge`, `gate_shut` / `gate_out`; Object_swingGate (1.2 s), driven by showProps; a click within 1.2 m opens / shuts both leaves.
 
 Props that show (1.89, `world.c` showProps every frame): the tin's mesh is built again when its butts change (`Shapes_ashtray`: up to 12 show, the ash rises, a heap from 14; `shown` = what's built).
@@ -425,7 +428,7 @@ Most important first.
 
 **Body and moving**
 - Obstacle approach, still to do: thin round logs (under 0.2 m) are still stepped over; a step in between on top of something unstable (if clumsy); NPCs: pull up on their own for their own reasons (now only following a leader), jumping onto things
-- Climbing rework, still to do: another way up by height, surface and person: belly first and roll (in: one hand first, the knee up, the other foot next to it; sitting on it and swinging the legs up)
+- Climbing rework, still to do: another way up by height, surface and person: rolling over the edge (lying on it, rolled onto the top) (in: one hand first, the knee up, the other foot next to it; sitting on it and swinging the legs up; belly first)
 - Balance: hips over the feet, look for stable footing, play with balance
 - Personal movement styles, still to do: gesture variants; stepping over and climbing their own way; sporty ones more elegant (walking styles are in)
 - More gestures and feelings to pick personalities from: the lists in Body / Fidgets and Gestures can grow
@@ -449,4 +452,4 @@ Most important first.
 - Drawing many figures on a real graphics card: not measured (software GL: 300 people cost 3x the rest of the scene)
 
 ---
-State of `entropie 2.22.0 (build 6c2f7b9)`
+State of `entropie 2.23.0 (build 43b0331)`
diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt
index a0d247c..e0d62fe 100644
--- a/entropie/commit_message.txt
+++ b/entropie/commit_message.txt
@@ -1,4 +1,4 @@
-entropie 2.22.0: the leading shoulder
+entropie 2.23.0: belly first
 
-- Climbing a high ledge: the shoulder of the hand that reaches first turns
-  ahead, easing back as the other hand follows
+- Chest high ledges: the less sporty (or drunk) push up onto the belly, lie
+  over the edge, bring a knee up and stand up
diff --git a/entropie/src/people/body.h b/entropie/src/people/body.h
index fe7598f..fb79485 100644
--- a/entropie/src/people/body.h
+++ b/entropie/src/people/body.h
@@ -181,7 +181,8 @@ typedef struct {
     bool  replant;           /* plant the feet again next update */
     bool  pulling_up;        /* climbing up over an edge (on_ladder too): the legs still keep clear of it */
     float pull_knees;        /* ... its knees up and out, eased (0..1) */
-    float reach_bend, reach_bend_v; /* ... and the back bends over as far as it takes to keep the hands on it */
+    float reach_bend, reach_bend_v; /* ... and the back bends over as far as it takes to keep the hands on it ... */
+    float belly_over;        /* ... or lies flat over the edge on the belly (0..1) */
     float fitness;           /* how sporty (0..1): runs smoother, steps over things surer */
     float bob, bob_v;        /* running: the body's rise and fall with each stride (sprung, -1..1) */
     Vec3  shift;             /* move the character here when getting up (taken by the world) */
diff --git a/entropie/src/people/body_pose.c b/entropie/src/people/body_pose.c
index 1397a4b..da0d17d 100644
--- a/entropie/src/people/body_pose.c
+++ b/entropie/src/people/body_pose.c
@@ -113,6 +113,7 @@ static Vec3 reachPole(Vec3 shoulder, Vec3 palm, float sign) {
 }
 
 /* Damped spring step towards a target. */
+#define BELLY_PITCH 1.0f /* rad the body bends forward lying over an edge on the belly */
 #define SPRING_STEP 0.02f  /* s: a slow frame is split into steps this short (60 fps: one) (a stiff spring blew up at 10 fps: NaN arms, a crash) */
 
 static void spring(float *value, float *velocity, float target, float stiffness, float damping, float dt) {
@@ -567,6 +568,8 @@ static void solveStanding(Body *b, Vec3 position, Vec3 facing, float s, float dt
             pitch -= SWING_ARCH * up * both;
         }
     }
+    /* Belly first over an edge: the upper body lies flat over it */
+    pitch += BELLY_PITCH * b->belly_over;
     /* Pulling up onto something: the back bends over the edge as far as it
        takes to keep both hands on it (the shoulders come over the hands) */
     {
diff --git a/entropie/src/people/climb.c b/entropie/src/people/climb.c
index 268d30f..c44fea6 100644
--- a/entropie/src/people/climb.c
+++ b/entropie/src/people/climb.c
@@ -10,6 +10,11 @@
 #define SIT_HIGH    1.05f /* ... up to this */
 #define SIT_FIT     0.45f /* ... for those less sporty than this (or old: slow on their feet) */
 #define SIT_TIME    3.2f  /* s it takes (fresh) */
+#define BELLY_LOW   1.0f  /* the belly way: ledges this high (scaled) ... */
+#define BELLY_HIGH  1.55f /* ... up to this (higher: hanging on and pulling up) ... */
+#define BELLY_FIT   0.45f /* ... for those less sporty than this (or drunk) */
+#define BELLY_DROP  0.9f  /* lying over it: the feet this far below the edge (scaled: the hips just over it) */
+#define BELLY_TIME  2.6f  /* s it takes (fresh) */
 #define REACH_TURN  0.35f /* rad the shoulders turn, the first hand's side going up ahead */
 #define CLIMB_OVER  0.5f  /* ... from this high over it at the body: the way there is clear */
 
@@ -108,6 +113,16 @@ int Climb_start(const World *world, Object *p, float top, Vec3 probe) {
     p->climb_move.yaw0 = p->rotation.y;
     p->climb_move.swing = p->main_hand == HAND_LEFT ? -1.0f : 1.0f;
     if (p->climb_move.sit_way) p->climb_move.time = SIT_TIME / fmaxf(vigor, 0.4f);
+    /* chest high and not so sporty (or drunk): pushed up onto the belly, lying over it, a knee up, stand up */
+    bool hands_free = p->hands.state[HAND_LEFT] == HAND_FREE && p->hands.state[HAND_RIGHT] == HAND_FREE;
+    p->climb_move.belly_way = !p->climb_move.sit_way && hands_free && p->is_grounded && rise > BELLY_LOW * s && rise < BELLY_HIGH * s
+                           && (p->fitness < BELLY_FIT || p->drunk > 0.4f);
+    p->climb_move.belly = 0.0f;
+    if (p->climb_move.belly_way) {
+        p->climb_move.time = BELLY_TIME / fmaxf(vigor, 0.4f);
+        p->climb_move.hang = p->position.y;
+        if (!hard) p->needs.stamina = fmaxf(0.0f, p->needs.stamina - 0.02f * rise / s);
+    }
     Climb_noteFeet(p);
     p->climbing = true;
     p->velocity = vec3_zero();
@@ -249,10 +264,17 @@ bool Climb_update(const World *world, Object *p, float dt) {
     float t = clampf(c->t, 0.0f, 1.0f);
     const Vec3 a = c->from, b = c->to;
     const float hang = c->hang;
-    bool high = hang > a.y + 0.02f || c->time > 1.2f;
+    bool high = hang > a.y + 0.02f || c->time > 1.2f || c->belly_way;
     float y, over;
     float knees = 0.0f;
-    if (high) { /* up to hang on (a little hop), hang a moment, pull up, then over the edge */
+    if (c->belly_way) { /* a push up on the arms, the belly onto the edge, lying over it, a knee up onto it, standing up */
+        float push = smoothstepf(0.1f, 0.34f, t), rise = smoothstepf(0.56f, 0.88f, t);
+        float belly_y = fminf(b.y - BELLY_DROP * s, a.y + 0.6f * s);
+        y = lerpf(lerpf(a.y, belly_y, push), b.y + 0.02f, rise);
+        over = 0.12f * smoothstepf(0.3f, 0.5f, t) + 0.88f * smoothstepf(0.62f, 1.0f, t); /* (wriggling on a little, then onto it) */
+        c->belly = smoothstepf(0.22f, 0.4f, t) * (1.0f - smoothstepf(0.62f, 0.92f, t));
+        knees = 0.7f * smoothstepf(0.58f, 0.78f, t);
+    } else if (high) { /* up to hang on (a little hop), hang a moment, pull up, then over the edge */
         /* pulled up till the arms press down on it (hips near the edge), then
            the knee comes up and you rise onto it - the hands stay on it all along */
         float grab = smoothstepf(0.0f, 0.18f, t), pull = smoothstepf(0.28f, 0.62f, t), rise = smoothstepf(0.56f, 0.88f, t);
@@ -281,6 +303,7 @@ bool Climb_update(const World *world, Object *p, float dt) {
         Vec3 before = vec3_add(c->edge, vec3_add(vec3_scale(fwd, -0.12f * s), vec3(0.0f, 0.1f * s, 0.0f)));
         /* (coming over the edge the hands go on ahead onto the top: pressed flat on it, under the shoulders) */
         Vec3 on = vec3_add(c->edge, vec3_scale(fwd, 0.35f * s * smoothstepf(0.55f, 0.9f, t)));
+        if (c->belly_way) on = vec3_add(c->edge, vec3_scale(fwd, 0.3f * s * smoothstepf(0.25f, 0.45f, t) + 0.1f * s * smoothstepf(0.6f, 0.9f, t))); /* (forearms flat on it, lying over) */
         Hands_holdEdge(p, vec3_lerp(before, on, onto), vec3_scale(c->across, lerpf(1.9f, 1.0f, onto)), knees);
         /* (one hand reaches up first, the other after it - the sporty quicker; that shoulder goes ahead) */
         p->hands.edge_lead = p->main_hand;
diff --git a/entropie/src/world/object.h b/entropie/src/world/object.h
index c9f4deb..37cd252 100644
--- a/entropie/src/world/object.h
+++ b/entropie/src/world/object.h
@@ -127,6 +127,8 @@ typedef struct {
     bool  sit_now;          /* ... sitting on it right now (the body sits: see world.c) ... */
     float yaw0;             /* ... facing the ledge when it started (rotation.y) */
     float swing;            /* ... which way round the legs come up (+1 / -1) */
+    bool  belly_way;        /* chest high, not so sporty (or drunk): a push up onto the belly, lying over the edge, a knee up, stand up ... */
+    float belly;            /* ... lying over it this much right now (0..1: the body bends over, see world.c) */
 } ClimbMove;
 
 typedef struct Object {
diff --git a/entropie/src/world/world.c b/entropie/src/world/world.c
index 22e59f9..c8635ec 100644
--- a/entropie/src/world/world.c
+++ b/entropie/src/world/world.c
@@ -888,6 +888,7 @@ static void animateCharacter(World *world, Object *o, float dt) {
     const bool sit_climb = o->climbing && o->climb_move.sit_way; /* (the careful way up: sitting on it, not pulling up) */
     o->body.on_ladder = o->on_ladder != NULL || (o->climbing && !sit_climb); /* (or pulling up over a ledge) */
     o->body.pulling_up = o->climbing && o->on_ladder == NULL && !sit_climb;
+    o->body.belly_over = o->climbing && o->climb_move.belly_way ? o->climb_move.belly : 0.0f;
     o->body.fitness = o->fitness;
     o->body.sulk = o->ai.annoyed;
     o->body.sit_goal = (o->sitting && !o->is_held && !settling) || (sit_climb && o->climb_move.sit_now) ? 1.0f : 0.0f; /* cross-legged, or on a seat */