Nimbin[12]?Games / Entropie / commits / 6dd8b39

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 1.66.0: careful people sort the woodpile and tidy the branches

Christian Immanuel · 2026-10-15 03:18 · 6dd8b398039a80f7e2bb3b8328c8302408e6ef76

- Careful stackers sort the firewood by length (long at one end, short
  at the other) and line up the front of the pile
- Careful workers put the branches and twigs lying about onto a heap at
  the end of the woodpile once the firewood is stacked

Includes 1.65.0 (if not committed separately):
- Smooth off the ladder (a step back, one foot after the other) and
  taking it down (the hand reaches for the rail at chest height)

Includes 1.64.0 (if not committed separately):
- Smooth ladder and climbs: getting on, over the edge at the top, feet
  from where they are; the easy 1 m climb no longer drops you off again

Includes 1.63.0 (if not committed separately):
- The hose melts in the fire (leaks, burns through); duct tape and the
  shears mend it

Includes 1.62.0 (if not committed separately):
- Smooth pull-ups: no hop at the end, feet and knees ease over the edge,
  elbows and hands taking hold blend in (audit walk: joint jumps 161 -> 58)

Includes 1.61.0 (if not committed separately):
- A step ladder in the tool room: stands on its own, at a wall with its
  back to it; climb onto the wall from its top

Includes 1.60.0 (if not committed separately):
- A folding ladder (two 2.5 m halves on a hinge, 5 m open) beside the
  telescopic one; one click at a wall unfolds it and leans it there

Includes 1.59.0 (if not committed separately):
- Stepping up onto blocks above knee high; set moves and jumps only for
  things standing on the ground in front of you

Includes 1.58.0 (if not committed separately):
- Walking over knee-high things is one smooth set move that always
  finishes; at a run: jump up onto blocks, catch climbable edges
 entropie/Makefile             |  2 +-
 entropie/README.md            |  5 ++-
 entropie/STATE.md             |  5 +--
 entropie/commit_message.txt   | 19 +++++-----
 entropie/src/people/ai_work.c | 86 +++++++++++++++++++++++++++++++++++++++++++
 entropie/src/world/object.c   | 23 ++++++++++--
 6 files changed, 122 insertions(+), 18 deletions(-)

diff --git a/entropie/Makefile b/entropie/Makefile
index 0090557..dc13424 100644
--- a/entropie/Makefile
+++ b/entropie/Makefile
@@ -1,5 +1,5 @@
 APP       := entropie
-VERSION   := 1.65.0
+VERSION   := 1.66.0
 
 PREFIX    ?= /usr
 BINDIR    ?= $(PREFIX)/bin
diff --git a/entropie/README.md b/entropie/README.md
index 6f046f0..bc7c611 100644
--- a/entropie/README.md
+++ b/entropie/README.md
@@ -376,7 +376,10 @@ say no more often and don't come to you for a bit.
   first, where pieces were taken off; it shows how many really lie on it). Not
   everyone knows how: "Can you show me?" They watch you until they get it.
   Skilled, careful and sober people stack neat, stable piles; clumsy, hurried
-  or drunk ones just throw it on, and a high loose pile comes down now and then
+  or drunk ones just throw it on, and a high loose pile comes down now and then.
+  The most careful sort the pieces by length (long at one end, short at the
+  other) with the front even, and put the branches lying about onto a heap
+  at the end of the woodpile
   If you keep the axe, the bold ones ask for it, the others wait until you
   put it down
 - The practised cut even pieces, the others by eye. Careful people take
diff --git a/entropie/STATE.md b/entropie/STATE.md
index 6ef0b2d..f25095c 100644
--- a/entropie/STATE.md
+++ b/entropie/STATE.md
@@ -109,7 +109,7 @@ Felling: a started notch is hit again by anyone whose axe reaches its height; a
 
 Work shows: axe strokes throw wood chips (they lie 7-10 s), the chainsaw sprays sawdust (gone in about a second), a pale band of cut wood grows round the bark where a tree, log or stump is being cut (`src/world/chips.c`, Object_markCut).
 
-Piling styles: how neatly someone stacks (`ai_stackCare`: firewood skill and liking, clumsiness, tempo, drink, nerves, pride, energy) sets how far each piece lands off its place (pushed in, to the side, askew). Below 0.55 care a pile 3+ layers high may come down as it grows (more often the looser and higher): the top pieces slide off and are loose again ("Oops..."); they get restacked.
+Piling styles: how neatly someone stacks (`ai_stackCare`: firewood skill and liking, clumsiness, tempo, drink, nerves, pride, energy) sets how far each piece lands off its place (pushed in, to the side, askew). Below 0.55 care a pile 3+ layers high may come down as it grows (more often the looser and higher): the top pieces slide off and are loose again ("Oops..."); they get restacked. Care 0.7 and up (`object.c` Object_stackFirewood): sorted by length - pieces 4 cm and more under 0.6 m take the last free place of the lowest layer with room, the others the first - and pushed in so every front end lines up (+Z side of the pile). Care 0.6 and up (`ai_work.c` tidyBranches, after the firewood is stacked): branches and twigs up to 3 kg lying about the work area go onto a heap 0.8 m off the end of the woodpile, two at a time (`stored` = on the heap). Chips are left: they're gone in 10 s anyway.
 
 Woodpile: firewood is stacked into the lowest free place (gaps left by pieces taken off are filled first); it counts what really lies on it; a piece that fell off is loose again (gets restacked).
 
@@ -147,7 +147,6 @@ Most important first.
 - More gestures and feelings to pick personalities from (a list to choose from)
 
 **People**
-- The skilled take care, still to do: sort wood by length on the pile, sweep up chips and twigs
 - Peeing properly: open the fly; women crouch and pull down / lift the skirt or dress; Urinella (some don't like it; mishaps; tidy, careless or high disposal)
 - Clothing (trousers, skirt, dress, fly) – needed for the above
 
@@ -162,4 +161,4 @@ Most important first.
 - The walking map rebuild takes ~9 ms when fixed things change (a felled tree)
 
 ---
-State of `entropie 1.65.0 (build 7f81926)`
+State of `entropie 1.66.0 (build 2a3c0b1)`
diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt
index 67cd231..49993a3 100644
--- a/entropie/commit_message.txt
+++ b/entropie/commit_message.txt
@@ -1,12 +1,13 @@
-entropie 1.65.0: smooth off the ladder and taking it down
-
-- Stepping off a ladder at the bottom: a short step back, one foot down
-  after the other (the feet jumped 18 cm)
-- Taking a leaning ladder down: the hand reaches for the rail at chest
-  height (it reached for the middle of the ladder, high up the wall) and
-  the ladder stays as steep as it leaned
-- Getting up onto a roof from a ladder: no hop at the end
-- Audit ladder: joint jumps 65 -> 45 (163 in 1.63)
+entropie 1.66.0: careful people sort the woodpile and tidy the branches
+
+- Careful stackers sort the firewood by length (long at one end, short
+  at the other) and line up the front of the pile
+- Careful workers put the branches and twigs lying about onto a heap at
+  the end of the woodpile once the firewood is stacked
+
+Includes 1.65.0 (if not committed separately):
+- Smooth off the ladder (a step back, one foot after the other) and
+  taking it down (the hand reaches for the rail at chest height)
 
 Includes 1.64.0 (if not committed separately):
 - Smooth ladder and climbs: getting on, over the edge at the top, feet
diff --git a/entropie/src/people/ai_work.c b/entropie/src/people/ai_work.c
index b601b44..981049f 100644
--- a/entropie/src/people/ai_work.c
+++ b/entropie/src/people/ai_work.c
@@ -329,6 +329,90 @@ static bool carryFirewood(Object *self, Object *const *objects, int count, float
     return true;
 }
 
+/* ---------- Tidying up: branches and twigs onto a heap by the woodpile ---------- */
+
+#define TIDY_CARE   0.6f  /* this careful (ai_stackCare): branches lying about go onto a heap */
+#define TIDY_HEAVY  3.0f  /* (kg; heavier ones stay where they are) */
+
+/* Where the branches go: a heap just off the end of the woodpile. */
+static Vec3 brushHeap(const Object *pile) {
+    Vec3 along = pile->colliders[0].axes[0];
+    return vec3_add(pile->position, vec3_scale(along, pile->size.x * 0.5f + 0.8f));
+}
+
+static int branchesInHands(const Object *self) {
+    int n = 0;
+    for (int i = 0; i < 2; i++)
+        if (self->hands.state[i] == HAND_HOLDING && self->hands.item[i]->type == OBJ_BRANCH) n++;
+    return n;
+}
+
+/* A branch or twig lying about the work area (not on the heap yet). */
+static Object *looseBranch(const Object *self, Object *const *objects, int count, Vec3 area, Vec3 heap) {
+    Object *best = NULL;
+    float best_dist = 1e9f;
+    for (int i = 0; i < count; i++) {
+        Object *o = objects[i];
+        if (o->type != OBJ_BRANCH || o->stored || o->is_held || o->broken || o->weight > TIDY_HEAVY) continue;
+        if (flatDistance(o->position, area) > WOOD_RADIUS || flatDistance(o->position, heap) < 1.0f) continue;
+        if (claimed(self, objects, count, o)) continue;
+        float d = flatDistance(o->position, self->position);
+        if (d < best_dist) { best_dist = d; best = o; }
+    }
+    return best;
+}
+
+/* Careful people don't leave the branches lying about: two at a time onto the heap. */
+static bool tidyBranches(Object *self, Object *const *objects, int count, float dt) {
+    Ai *ai = &self->ai;
+    Object *pile = ai->woodpile;
+    if (!pile || ai_stackCare(self) < TIDY_CARE) return false;
+    if (self->hands.state[0] == HAND_REACHING || self->hands.state[1] == HAND_REACHING) { stand(self); return true; }
+    const Vec3 heap = brushHeap(pile);
+    int carried = branchesInHands(self);
+    Object *next = carried < 2 ? looseBranch(self, objects, count, ai->work_area, heap) : NULL;
+    if (next && (carried == 0 || flatDistance(next->position, self->position) < 3.0f)) {
+        for (int hand = 0; hand < 2; hand++) /* (hands free for it: the tool stays here) */
+            if (self->hands.state[hand] == HAND_HOLDING && self->hands.item[hand]->type != OBJ_BRANCH) {
+                if (toolOf(self->hands.item[hand]) != TOOL_NONE) ai->tool = self->hands.item[hand];
+                Hands_drop(self, hand);
+                stand(self);
+                return true;
+            }
+        ai->job_target = next;
+        if (Hands_gapFrom(self->position, self->look.height, next) < PICKUP_REACH) {
+            stand(self);
+            turnTowards(self, vec3_sub(next->position, self->position), dt);
+            int hand = Hands_freeHand(self);
+            if (hand >= 0) Hands_pickUpObject(self, hand, next);
+            return true;
+        }
+        Vec3 dir = ai_steer(self, next, objects, count, next->position);
+        if (vec3_length(dir) < 0.5f) { stand(self); return true; }
+        ai_walk(self, dir, WALK_SPEED * 0.8f, dt);
+        return true;
+    }
+    if (carried == 0) return false;
+    ai->job_target = NULL;
+    Vec3 to = vec3_sub(heap, self->position);
+    to.y = 0.0f;
+    if (vec3_length(to) > 0.5f) {
+        Vec3 dir = ai_steer(self, NULL, objects, count, heap);
+        if (vec3_length(dir) < 0.5f) { stand(self); return true; }
+        ai_walk(self, dir, WALK_SPEED * 0.75f, dt);
+        return true;
+    }
+    stand(self);
+    turnTowards(self, to, dt);
+    for (int hand = 0; hand < 2; hand++) {
+        Object *b = self->hands.item[hand];
+        if (self->hands.state[hand] != HAND_HOLDING || !b || b->type != OBJ_BRANCH) continue;
+        Hands_drop(self, hand);
+        b->stored = 1; /* (on the heap) */
+    }
+    return true;
+}
+
 /* Skilled, sure-handed, sober and unhurried: neat, stable piles. The others
    just put it on (and a high loose pile comes down now and then). */
 float ai_stackCare(const Object *self) {
@@ -811,6 +895,7 @@ void ai_updateWork(Object *self, Object *const *objects, int count, float dt) {
     }
 
     if (firewoodInHands(self) > 0 && carryFirewood(self, objects, count, dt)) return;
+    if (branchesInHands(self) > 0 && tidyBranches(self, objects, count, dt)) return;
     WoodTask t;
     if (ai_nextWoodTask(self, objects, count, ai->work_area, ai->order == ORDER_TREES, &t)) {
         if (thinkItOver(self, t.target, dt)) return;
@@ -819,6 +904,7 @@ void ai_updateWork(Object *self, Object *const *objects, int count, float dt) {
         return;
     }
     if (carryFirewood(self, objects, count, dt)) return;
+    if (tidyBranches(self, objects, count, dt)) return;
 
     /* Done here. Firewood left lying because nobody said where it goes: ask. */
     if (!ai->woodpile && !ai->no_pile && closestLoosePiece(self, objects, count) && player) {
diff --git a/entropie/src/world/object.c b/entropie/src/world/object.c
index bc4a44e..9b838fd 100644
--- a/entropie/src/world/object.c
+++ b/entropie/src/world/object.c
@@ -821,14 +821,22 @@ static float pileDice(Vec3 p, int k) {
 }
 
 #define PILE_SLIP_FROM 3 /* a loose pile this many layers high may come down */
+#define PILE_SORT_CARE 0.7f  /* this careful: sorted by length, the front even */
+#define PILE_PIECE     0.6f  /* the usual length of a piece */
+#define PILE_SAME      0.04f /* (this close to it counts as usual) */
 
 int Object_stackFirewood(Object *pile, Object *piece, Object *const *objects, int count, float care) {
-    /* The lowest place that's free (pieces taken off leave gaps lower down) */
+    /* The lowest place that's free (pieces taken off leave gaps lower down). Careful
+       people sort by length: long pieces from one end of the layer, short ones from the other */
     const float r = piece->size.x * 0.5f;
-    int layer = 0;
-    Vec3 center = pileSlot(pile, r, 0, &layer);
+    const bool sorts = care >= PILE_SORT_CARE;
+    const bool short_one = piece->size.y < PILE_PIECE - PILE_SAME;
+    int layer = 0, first_layer = -1;
+    Vec3 center = pileSlot(pile, r, 0, &layer), chosen = center;
+    int chosen_layer = 0;
     for (int k = 0; k < 400; k++) {
         center = pileSlot(pile, r, k, &layer);
+        if (first_layer >= 0 && layer != first_layer) break; /* (sorting: that layer's free places looked at) */
         bool taken = false;
         for (int i = 0; i < count && !taken; i++) {
             const Object *o = objects[i];
@@ -836,9 +844,16 @@ int Object_stackFirewood(Object *pile, Object *piece, Object *const *objects, in
             Vec3 d = vec3_sub(Object_colliderCenter(o, 0), center);
             if (fabsf(d.y) < r * 0.7f && fabsf(vec3_dot(d, pile->colliders[0].axes[0])) < r * 0.7f) taken = true;
         }
-        if (!taken) break;
+        if (taken) continue;
+        if (first_layer < 0) { chosen = center; chosen_layer = layer; first_layer = layer; }
+        else if (short_one) { chosen = center; chosen_layer = layer; } /* (the last free one: the other end) */
+        if (!sorts || !short_one) break;
     }
+    center = chosen;
+    layer = chosen_layer;
     Vec3 across = pile->colliders[0].axes[2], along = pile->colliders[0].axes[0];
+    if (sorts) /* (and pushed in so the front is even, whatever the length) */
+        center = vec3_add(center, vec3_scale(across, (PILE_PIECE - piece->size.y) * 0.5f));
     const Vec3 up = vec3(0.0f, 1.0f, 0.0f);
     /* Careless: not quite in its place - pushed in more or less, a bit to the side, askew */
     const float loose = 1.0f - clampf(care, 0.0f, 1.0f);