Nimbin[12]?Games / Entropie / commits / a1b56ea

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.21.0: the careful way up

Christian Immanuel · 2026-10-20 21:59 · a1b56ea052dfa7dcf93bd89e146f3cf1d361f836

- Hip-high ledges: less sporty and older people turn round, hop up to sit
  on the edge with the legs hanging, swing the legs up onto it (sitting
  cross-legged a moment) and stand up
 build.sh                    |  2 ++
 commit_message.txt          |  8 +++----
 entropie/Makefile           |  2 +-
 entropie/README.md          |  4 +++-
 entropie/STATE.md           |  7 ++++--
 entropie/src/people/climb.c | 55 +++++++++++++++++++++++++++++++++++++++++++++
 entropie/src/world/object.h |  4 ++++
 entropie/src/world/world.c  |  7 +++---
 8 files changed, 78 insertions(+), 11 deletions(-)

diff --git a/build.sh b/build.sh
index 3bb2829..8c57d4f 100644
--- a/build.sh
+++ b/build.sh
@@ -1 +1,3 @@
+
+[ -f /home/Shared/Claude/entropie/commit_message.txt ] || exit
 cd .. && rm -rf entropie; mv $SHARED_CLAUDE/entropie/commit_message.txt . && tar -xvf $SHARED_CLAUDE/entropie/entropie.tar.gz && echo "$(git add . && git commit -m "$(cat commit_message.txt)")" && cd entropie && make clean && make && cat ../commit_message.txt
diff --git a/commit_message.txt b/commit_message.txt
index 0e1a9a7..755deb6 100644
--- a/commit_message.txt
+++ b/commit_message.txt
@@ -1,5 +1,5 @@
-entropie 2.20.0: C23, climbing hand by hand
+entropie 2.21.0: the careful way up
 
-- Build as C23 (-std=c23, or -std=c2x on compilers that call it that);
-  everything compiles clean, nothing needed changing
-- Climbing a high ledge: one hand reaches the edge first, the other follows
+- Hip-high ledges: less sporty and older people turn round, hop up to sit
+  on the edge with the legs hanging, swing the legs up onto it (sitting
+  cross-legged a moment) and stand up
diff --git a/entropie/Makefile b/entropie/Makefile
index df6f81e..278d9c1 100644
--- a/entropie/Makefile
+++ b/entropie/Makefile
@@ -1,5 +1,5 @@
 APP       := entropie
-VERSION   := 2.20.0
+VERSION   := 2.21.0
 
 PREFIX    ?= /usr
 BINDIR    ?= $(PREFIX)/bin
diff --git a/entropie/README.md b/entropie/README.md
index 5c1fb1d..e922de1 100644
--- a/entropie/README.md
+++ b/entropie/README.md
@@ -336,7 +336,9 @@ and satellite pictures (about 340 x 340 m).
 - Walking up to something you can climb, your hands go onto its edge; pulling
   up, the feet push against its face, then one knee and foot come over the
   edge, then the other (never through it). The hands stay pressed on top and
-  the back bends over the edge
+  the back bends over the edge. One hand gets there first, 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
 - 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 0c36bf7..ccbcc37 100644
--- a/entropie/STATE.md
+++ b/entropie/STATE.md
@@ -284,6 +284,9 @@ Round 2.20:
 - C23: the Makefile asks the compiler for `-std=c23` and falls back to `-std=c2x` (GCC 13 / Clang 17 and older call it that); everything compiles clean as C2x with -Wall -Wextra -Wpedantic -Wshadow. (It was C11 from the start, out of caution; nothing needed changing.) README: a C23 compiler (GCC 9+ / Clang 9+).
 - Climbing up a high ledge: one hand reaches the edge first (your main hand), the other follows from down by the shoulder (`Hands.edge_lead` / `edge_trail`, set by `Climb_update`: trailing till t 0.24, the unfit a bit longer). Checked on a 1.7 m wall: hand, hand, pull up, a knee on the top, over.
 
+Round 2.21:
+- The careful way up (`climb.c` sitWay, `ClimbMove.sit_way`): something SIT_LOW 0.55 .. SIT_HIGH 1.05 m high (scaled), for the less sporty (fitness under SIT_FIT 0.45) or old (pace under 0.8): turned round with the back to it, a hop up so the hips sit on the edge, legs hanging (hands behind on it), the knees swing up and round onto it (turning back to face it: sitting cross-legged on top for a moment), stood up. SIT_TIME 3.2 s fresh. The body sits for it (`world.c`: sit_goal from `climb_move.sit_now`, not the pull-up pose meanwhile).
+
 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).
@@ -419,7 +422,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: the shoulder going ahead with the first hand; other ways up by height, surface and person: sit on it and lift the legs, or belly first and roll (one hand first, the knee up, the other foot next to it: in)
+- Climbing rework, still to do: the shoulder going ahead with the first hand; 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)
 - 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
@@ -443,4 +446,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.20.0 (build 025b698)`
+State of `entropie 2.21.0 (build 3f347be)`
diff --git a/entropie/src/people/climb.c b/entropie/src/people/climb.c
index d6bfe67..2b6de15 100644
--- a/entropie/src/people/climb.c
+++ b/entropie/src/people/climb.c
@@ -6,6 +6,10 @@
 /* What's in front at climbing distance and could be climbed from feet_y:
    its top (the edge), or -1e9 if nothing (too high, no room up there). */
 #define CLIMB_CLEAR 0.05f /* m over where the hands go ... */
+#define SIT_LOW     0.55f /* the careful way up (sitting on it): something this high (scaled) ... */
+#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 CLIMB_OVER  0.5f  /* ... from this high over it at the body: the way there is clear */
 
 static bool onlyWalls(const Object *o, const void *ctx) {
@@ -97,6 +101,12 @@ int Climb_start(const World *world, Object *p, float top, Vec3 probe) {
     p->climb_move.time = (hard ? 1.3f + 0.7f * fmaxf(rise / s - CLIMB_EASY, 0.0f) : 0.6f + rise * 0.6f) / fmaxf(vigor, 0.4f)
                      / (hard ? sport : sqrtf(sport));
     p->climb_move.t = 0.0f;
+    /* hip high, and careful (not so sporty, or old): turned round, sat on it, legs up and over */
+    p->climb_move.sit_way = !hard && rise > SIT_LOW * s && rise < SIT_HIGH * s && (p->fitness < SIT_FIT || (p->pace > 0.05f && p->pace < 0.8f));
+    p->climb_move.sit_now = false;
+    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);
     Climb_noteFeet(p);
     p->climbing = true;
     p->velocity = vec3_zero();
@@ -186,10 +196,55 @@ static void climbFeet(const World *world, Object *p, float t, bool high, float s
 }
 
 
+/* The careful way up (hip high): turn round with the back to it, sit up on
+   the edge (hands behind on it), swing the legs up and round onto it (sitting
+   cross-legged on top for a moment), and stand up. */
+static void sitWay(const World *world, Object *p, float t, float s) {
+    ClimbMove *c = &p->climb_move;
+    const Vec3 a = c->from, b = c->to;
+    Vec3 f = vec3(b.x - a.x, 0.0f, b.z - a.z);
+    f = vec3_length(f) > 1e-3f ? vec3_normalize(f) : Object_facing(p);
+    const float rise = b.y - a.y;
+    /* where the hips sit on the edge: just over it; standing there (facing out) a step in front of it */
+    Vec3 edge_in = vec3_add(vec3(a.x, a.y, a.z), vec3_scale(f, c->face + 0.12f * s));
+    Vec3 stand = vec3_sub(edge_in, vec3_scale(f, 0.36f * s));
+    float turn = smoothstepf(0.04f, 0.24f, t), swing = smoothstepf(0.48f, 0.76f, t), rise_up = smoothstepf(0.8f, 1.0f, t);
+    /* facing: round with the back to it, then round again (the legs coming up) to face onto it */
+    p->rotation.y = c->yaw0 + c->swing * PI_F * (turn - swing);
+    Vec3 pos = vec3_lerp(vec3(a.x, a.y, a.z), stand, turn);           /* a step back to it, turning */
+    pos = vec3_lerp(pos, vec3(b.x, b.y, b.z), smoothstepf(0.5f, 0.8f, t)); /* up and onto it, swinging round */
+    /* a hop up onto the edge (the hips on it, the legs hanging), then the legs up onto it */
+    const float hang = fminf(0.45f * s, rise - 0.05f), hop = smoothstepf(0.24f, 0.4f, t), legs_up = smoothstepf(0.48f, 0.72f, t);
+    pos.y = lerpf(lerpf(a.y, b.y - hang, hop), b.y, legs_up);
+    p->position = pos;
+    p->velocity = vec3_zero();
+    Object_syncColliders(p);
+    c->sit_now = turn > 0.7f && rise_up < 0.5f; /* (sitting down already as the turn ends: the body takes a moment to get down) */
+    p->sit_style = swing > 0.5f ? SIT_GROUND : SIT_SEAT;      /* on the edge, then cross-legged on top */
+    p->body.seat_height = lerpf(lerpf(rise, hang, hop), 0.0f, legs_up) + 0.02f;
+    if (t > 0.2f && t < 0.62f) /* the hands behind on the edge, pushing up */
+        Hands_holdEdge(p, vec3_add(edge_in, vec3(0.0f, rise, 0.0f)), c->across, 0.0f);
+    (void)world;
+}
+
 bool Climb_update(const World *world, Object *p, float dt) {
     const float s = p->look.height / 1.75f;
     ClimbMove *c = &p->climb_move;
     c->t += dt / c->time;
+    if (c->sit_way) {
+        float ts = clampf(c->t, 0.0f, 1.0f);
+        sitWay(world, p, ts, s);
+        if (ts >= 1.0f) {
+            p->climbing = false;
+            c->sit_now = false;
+            p->sit_style = SIT_SEAT;
+            p->body.seat_height = SEAT_HEIGHT;
+            p->is_grounded = true;
+            p->body.replant = true;
+            p->body.velocity = vec3_zero();
+        }
+        return !p->climbing;
+    }
     float t = clampf(c->t, 0.0f, 1.0f);
     const Vec3 a = c->from, b = c->to;
     const float hang = c->hang;
diff --git a/entropie/src/world/object.h b/entropie/src/world/object.h
index 38c66eb..c9f4deb 100644
--- a/entropie/src/world/object.h
+++ b/entropie/src/world/object.h
@@ -123,6 +123,10 @@ typedef struct {
     float hang;             /* feet this high while hanging on before the pull up */
     float face;             /* how far ahead of where it started the face of it is (m) */
     Vec3  ankle0[2], toe0[2]; /* where the feet were when it started (eased from there) */
+    bool  sit_way;          /* the careful way up something hip high: turn round, sit on it, legs up, stand up ... */
+    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) */
 } ClimbMove;
 
 typedef struct Object {
diff --git a/entropie/src/world/world.c b/entropie/src/world/world.c
index f462d95..22e59f9 100644
--- a/entropie/src/world/world.c
+++ b/entropie/src/world/world.c
@@ -885,11 +885,12 @@ static void animateCharacter(World *world, Object *o, float dt) {
     }
     Object_leaveSeat(o, dt);
     o->body.stand_ahead = o->sitting && o->seat ? 0.12f : 0.0f; /* (feet clear of it) */
-    o->body.on_ladder = o->on_ladder != NULL || o->climbing; /* (or pulling up over a ledge) */
-    o->body.pulling_up = o->climbing && o->on_ladder == NULL;
+    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.fitness = o->fitness;
     o->body.sulk = o->ai.annoyed;
-    o->body.sit_goal = o->sitting && !o->is_held && !settling ? 1.0f : 0.0f; /* cross-legged, or on a seat */
+    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 */
     o->body.squat_pee = o->female && !(o->urinella && o->urinellas > 0) && !o->toilet;
     o->body.urinella_use = o->female && !o->body.squat_pee && !o->toilet;
     o->body.sit_style = o->sit_style;