Nimbin[12]?Games / Entropie / commits / 033b654

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.31.0: rolling over the edge

Christian Immanuel · 2026-10-26 15:28 · 033b654285e88d46549f7dbb851b8651465d965a

- Quite drunk, climbing something chest high ends belly first, then down
  flat on the top and rolled over onto it, and up again
 entropie/Makefile                   |  2 +-
 entropie/README.md                  |  2 +-
 entropie/STATE.md                   | 10 +++++++---
 entropie/commit_message.txt         |  7 +++----
 entropie/src/people/body.c          | 33 +++++++++++++++++++++++++++++++++
 entropie/src/people/body.h          |  4 ++++
 entropie/src/people/body_internal.h |  1 +
 entropie/src/people/body_pose.c     |  5 +++--
 entropie/src/people/climb.c         | 19 +++++++++++++++++++
 entropie/src/world/object.h         |  1 +
 10 files changed, 73 insertions(+), 11 deletions(-)

diff --git a/entropie/Makefile b/entropie/Makefile
index 2e4aeaa..6c47679 100644
--- a/entropie/Makefile
+++ b/entropie/Makefile
@@ -1,5 +1,5 @@
 APP       := entropie
-VERSION   := 2.30.0
+VERSION   := 2.31.0
 
 PREFIX    ?= /usr
 BINDIR    ?= $(PREFIX)/bin
diff --git a/entropie/README.md b/entropie/README.md
index 0a802bc..2d2ee68 100644
--- a/entropie/README.md
+++ b/entropie/README.md
@@ -124,5 +124,5 @@ Dependencies point downward: `main → game → world/people → render → core
 
 ## Version
 
-`make version` prints e.g. `entropie 2.30.0 (build 1fccf58)`. The build id is
+`make version` prints e.g. `entropie 2.31.0 (build 5b62340)`. The build id is
 an md5 of all sources and assets.
diff --git a/entropie/STATE.md b/entropie/STATE.md
index 84d13ed..6614b54 100644
--- a/entropie/STATE.md
+++ b/entropie/STATE.md
@@ -578,7 +578,8 @@ and satellite pictures (about 340 x 340 m).
 - 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
+  the edge, a knee up, then stand up. Quite drunk: no knee up - down flat on
+  the top along the edge, rolled over once onto the back, and 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
@@ -1180,6 +1181,9 @@ Round 2.30:
 - Talking gestures (`Body_talkGesture`: GESTURE_WAVE, SHRUG, POINT; picked in `Ai_say` by words in the line - Hello / Night / Bye, No / can't / Sorry, over there / Look - 80 % of the time; they go on walking up to 2.5 m/s). Checked: Toni waving and shrugging.
 - Sounds: a bush pushed into (NOISE_RUSTLE, `forestry.c`), a gate opening or shutting (NOISE_CREAK) and the boot (NOISE_SLAM) when that changes (`world.c` showProps, `heard_open`), getting out of the car (NOISE_SLAM, `heard_ride`).
 
+Round 2.31:
+- The roll way up (`climb.c` roll_way: a belly climb by somebody over ROLL_DRUNK 0.55 drunk): once the belly is over the edge (ROLL_ONTO 0.42 of the climb) the climb ends on the top (the hips 0.12 m in from the edge) and the body takes over (`Body_rollOnto`: down flat along the edge, face down, `roll_over` turns the body about its length once - ROLL_OVER_TIME 1.1 s, moving inwards like a log, arms in along the body - then on the back where the roll ended (`shift`), and up). Checked on a 1.3 m wall: push up, belly over, flat on it, rolled over, up.
+
 ## Open tasks
 
 Most important first.
@@ -1190,7 +1194,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: 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)
+- Climbing rework, still to do: more ways up by surface and person (in: one hand first, the knee up, the other foot next to it; sitting on it and swinging the legs up; belly first; rolled over onto it)
 - 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
@@ -1215,4 +1219,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.30.0 (build 1fccf58)`
+State of `entropie 2.31.0 (build 5b62340)`
diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt
index caeb652..3eff3d2 100644
--- a/entropie/commit_message.txt
+++ b/entropie/commit_message.txt
@@ -1,5 +1,4 @@
-entropie 2.30.0: waving, creaking gates
+entropie 2.31.0: rolling over the edge
 
-- Talking, people wave hello and goodnight, shrug saying no, point over
-  there
-- Sounds: gates creaking, car doors and the boot, pushing through a bush
+- Quite drunk, climbing something chest high ends belly first, then down
+  flat on the top and rolled over onto it, and up again
diff --git a/entropie/src/people/body.c b/entropie/src/people/body.c
index d778147..cb048ad 100644
--- a/entropie/src/people/body.c
+++ b/entropie/src/people/body.c
@@ -257,6 +257,25 @@ void Body_dropAndRoll(Body *b, Vec3 dir) {
     b->roll_side  = 0.0f;
 }
 
+void Body_rollOnto(Body *b, Vec3 along, float side) {
+    if (b->pose != POSE_UP) return;
+    along = flat(along);
+    b->pose       = POSE_FALLING;
+    b->pose_time  = 0.0f;
+    b->fall_dir   = vec3_length(along) > 1e-3f ? vec3_normalize(along) : b->last_facing;
+    b->lie_offset = 0.0f;  /* (the hips where it is: on the edge) */
+    b->face_down  = true;
+    b->asleep     = false;
+    b->from_knees = true;
+    b->fall_style = FALL_PLANK;
+    b->fall_twist = 0.0f;
+    b->fall_time  = 0.45f; /* (down onto it, not a fall) */
+    b->down_time  = ROLL_OVER_TIME + 0.5f;
+    b->rolling    = false;
+    b->roll = b->roll_side = 0.0f;
+    b->roll_over  = side >= 0.0f ? 1.0f : -1.0f;
+}
+
 #define LAND_EASY  5.0f  /* m/s down (about 1.3 m): the legs take it as they are */
 #define LAND_DEEP_ 7.0f  /* (2.5 m) deep into the knees; faster: roll or crash */
 #define LAND_BREAK 9.5f  /* (4.6 m) nobody lands that on their feet ... */
@@ -484,6 +503,20 @@ static bool updateDown(Body *b, const BodyFrame *f, float s) {
         if (b->pose_time >= LIE_DOWN_TIME) { b->pose = POSE_DOWN; b->pose_time = 0.0f; }
         break;
     case POSE_DOWN:
+        if (b->roll_over != 0.0f) { /* over once, face down onto the back, moving sideways onto it like a log */
+            float k = fminf(1.0f, b->pose_time / ROLL_OVER_TIME);
+            b->rolling = true;
+            b->roll = b->roll_over * PI_F * smoothstepf(0.0f, 1.0f, k);
+            b->roll_side = b->roll * ROLL_RADIUS;
+            if (k >= 1.0f) { /* on the back now: lying where the roll ended */
+                b->shift = vec3_add(b->shift, vec3_scale(vec3_normalize(vec3_cross(b->fall_dir, UP)), b->roll_side * s));
+                b->face_down = false;
+                b->rolling = false;
+                b->roll = b->roll_side = b->roll_over = 0.0f;
+                b->down_time = 0.35f;
+            }
+            break;
+        }
         if (b->rolling && b->pose_time < ROLL_TIME) { /* side to side, the whole body turning about its length */
             b->roll = ROLL_REACH * sinf(b->pose_time * ROLL_PACE);
             b->roll_side = b->roll * ROLL_RADIUS;
diff --git a/entropie/src/people/body.h b/entropie/src/people/body.h
index ea9995a..e598b65 100644
--- a/entropie/src/people/body.h
+++ b/entropie/src/people/body.h
@@ -250,6 +250,7 @@ typedef struct {
     bool  rolling;
     float roll;              /* radians about the long axis */
     float roll_side;         /* meters rolled sideways */
+    float roll_over;         /* rolling over onto something (+1 / -1 the way round, 0: not): face down to on the back, once */
 
     /* Peeing */
     Vec3  pee_aim;           /* world direction to aim at (zero: just ahead and down) */
@@ -312,6 +313,9 @@ void  Body_stopSmoking(Body *body);
 bool  Body_takeButt(Body *body);
 /* On fire: quickly down to the ground, stretched out, rolling from side to side. */
 void  Body_dropAndRoll(Body *body, Vec3 dir);
+/* Up over an edge (the roll way): down flat on the top, along `along`, rolled
+   over once onto the back sideways (side +1: the way cross(along, up) points), then up. */
+void  Body_rollOnto(Body *body, Vec3 along, float side);
 /* Tripped over something with this foot (0 left, 1 right): a lurch that way,
    maybe a fall. severity 0..1 (drunk, running, clumsy). */
 void  Body_trip(Body *body, int foot, Vec3 facing, float severity);
diff --git a/entropie/src/people/body_internal.h b/entropie/src/people/body_internal.h
index f401252..64a142a 100644
--- a/entropie/src/people/body_internal.h
+++ b/entropie/src/people/body_internal.h
@@ -102,6 +102,7 @@ enum { FALL_PLANK, FALL_CRUMPLE, FALL_TWIST, FALL_DIVE };
 #define ROLL_TIME         (2.0f * PI_F / ROLL_PACE) /* one way, back, the other way and back */
 #define ROLL_REST         0.4f   /* lying a moment after rolling */
 #define ROLL_RADIUS       0.14f  /* the body rolls sideways like a log this thick */
+#define ROLL_OVER_TIME    1.1f   /* s rolling over once (the roll way up) */
 
 /* Jumping */
 #define TAKE_OFF_SPEED    1.0f   /* rising this fast off the ground is a jump */
diff --git a/entropie/src/people/body_pose.c b/entropie/src/people/body_pose.c
index 834958a..6667d2c 100644
--- a/entropie/src/people/body_pose.c
+++ b/entropie/src/people/body_pose.c
@@ -883,7 +883,7 @@ static void solveLying(const Body *b, Vec3 d, float s, Skeleton *out) {
         j[hip + 1] = knee_up ? AT(sign * 0.13f, 0.56f, 0.2f) : AT(sign * 0.12f, 0.49f, 0.02f);
         j[hip + 2] = knee_up ? AT(sign * 0.14f, 0.14f, 0.0f) : AT(sign * 0.15f, 0.075f, 0.0f);
         j[hip + 3] = down ? AT(sign * 0.16f, -0.04f, 0.06f) : AT(sign * 0.2f, 0.06f, 0.13f);
-        if (b->rolling) { /* stretched out like a log: legs together, toes pointed */
+        if (b->rolling && b->roll_over == 0.0f) { /* stretched out like a log: legs together, toes pointed */
             j[hip + 1] = AT(sign * 0.08f, 0.49f, 0.0f);
             j[hip + 2] = AT(sign * 0.065f, 0.075f, 0.0f);
             j[hip + 3] = AT(sign * 0.065f, -0.06f, -0.03f);
@@ -893,7 +893,8 @@ static void solveLying(const Body *b, Vec3 d, float s, Skeleton *out) {
         j[sh] = AT(sign * SHOULDER_X, PELVIS_Y + SPINE + SHOULDER_UP, 0.0f);
         Vec3 palm = down ? AT(sign * 0.27f, PELVIS_Y + SPINE + 0.32f, 0.0f)  /* caught the fall by the head */
                          : AT(sign * 0.5f, PELVIS_Y + 0.0f, 0.03f);        /* arms out */
-        if (b->rolling) palm = AT(sign * 0.13f, PELVIS_Y + SPINE + 0.68f, 0.02f); /* arms stretched over the head */
+        if (b->rolling && b->roll_over == 0.0f) palm = AT(sign * 0.13f, PELVIS_Y + SPINE + 0.68f, 0.02f); /* arms stretched over the head */
+        else if (b->roll_over != 0.0f) palm = AT(sign * 0.22f, PELVIS_Y + 0.05f, down ? -0.06f : 0.06f); /* (arms in, along the body) */
         reachArm(j, sh, palm, down ? vec3_scale(body_right, sign) : vec3_scale(body_up, -1.0f));
     }
     #undef AT
diff --git a/entropie/src/people/climb.c b/entropie/src/people/climb.c
index c44fea6..66c1586 100644
--- a/entropie/src/people/climb.c
+++ b/entropie/src/people/climb.c
@@ -15,6 +15,8 @@
 #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 ROLL_DRUNK  0.55f /* the roll way: this drunk, belly first and then down flat on it and rolled over */
+#define ROLL_ONTO   0.42f /* ... the belly over the edge by then (of the climb): the body takes over */
 #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 */
 
@@ -117,6 +119,7 @@ int Climb_start(const World *world, Object *p, float top, Vec3 probe) {
     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.roll_way = p->climb_move.belly_way && p->drunk > ROLL_DRUNK; /* (too drunk for a knee up: onto it and rolled over) */
     p->climb_move.belly = 0.0f;
     if (p->climb_move.belly_way) {
         p->climb_move.time = BELLY_TIME / fmaxf(vigor, 0.4f);
@@ -263,6 +266,22 @@ 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;
+    if (c->roll_way && t >= ROLL_ONTO) { /* lying over it: flat onto the top along the edge, then rolled over onto it */
+        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);
+        Vec3 along = c->across;
+        float side = vec3_dot(vec3_cross(along, vec3(0.0f, 1.0f, 0.0f)), f) > 0.0f ? 1.0f : -1.0f; /* (rolling inwards) */
+        Vec3 on = vec3_add(c->edge, vec3_scale(f, 0.12f * s));
+        p->position = vec3(on.x, b.y, on.z);
+        p->climbing = false;
+        p->climb_feet = false;
+        p->is_grounded = true;
+        p->velocity = vec3_zero();
+        c->belly = 0.0f;
+        Object_syncColliders(p);
+        Body_rollOnto(&p->body, along, side);
+        return true;
+    }
     const float hang = c->hang;
     bool high = hang > a.y + 0.02f || c->time > 1.2f || c->belly_way;
     float y, over;
diff --git a/entropie/src/world/object.h b/entropie/src/world/object.h
index 4f7ba45..916793f 100644
--- a/entropie/src/world/object.h
+++ b/entropie/src/world/object.h
@@ -133,6 +133,7 @@ typedef struct {
     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) */
+    bool  roll_way;         /* ... (drunk) not a knee up after it, but down flat on the top and rolled over onto it (Body_rollOnto) */
 } ClimbMove;
 
 typedef struct Object {