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

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.25.0: saved up a ladder

Christian Immanuel · 2026-10-21 07:17 · c09ba7c3a1d960ed7f1e1dcbf6546bae9b63cada

- Saving while up a ladder: you load back on it, as high; the others come
  back at its foot
 commit_message.txt          |  6 +++---
 entropie/ARCHITECTURE.md    |  2 +-
 entropie/Makefile           |  2 +-
 entropie/README.md          |  1 +
 entropie/STATE.md           |  7 +++++--
 entropie/commit_message.txt |  6 +++---
 entropie/src/game/save.c    | 17 +++++++++++++++--
 entropie/src/world/ladder.c | 11 +++++++++++
 entropie/src/world/ladder.h |  2 ++
 9 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/commit_message.txt b/commit_message.txt
index 6463217..f50def6 100644
--- a/commit_message.txt
+++ b/commit_message.txt
@@ -1,4 +1,4 @@
-entropie 2.24.0: gone with the wind
+entropie 2.25.0: saved up a ladder
 
-- A strong gust can tear paper or a pullover out of a hand (two hands hold
-  it safe); the others run after theirs and pick it up, or give up
+- Saving while up a ladder: you load back on it, as high; the others come
+  back at its foot
diff --git a/entropie/ARCHITECTURE.md b/entropie/ARCHITECTURE.md
index 03091c7..125ed5c 100644
--- a/entropie/ARCHITECTURE.md
+++ b/entropie/ARCHITECTURE.md
@@ -88,7 +88,7 @@ of view (objects, 8×8 terrain tiles).
   - A key renamed or its meaning changed: raise `SAVE_FORMAT` (save.h) and add a step to `migrate()` that rewrites the old lines.
   - A save from a newer format is refused, never guessed at.
   - A thing the scene no longer makes is dropped; one it newly makes keeps its fresh state.
-- Not kept (comes back fresh): what anybody was in the middle of (AI plans, paths, poses), sparks and smoke. Kept specially: the hose's rope (`rope` line: every point, melted, taped), who sits where (`sit` line: sat down again, staying a while).
+- Not kept (comes back fresh): what anybody was in the middle of (AI plans, paths, poses), sparks and smoke. Kept specially: the hose's rope (`rope` line: every point, melted, taped), who sits where (`sit` line: sat down again, staying a while), who's up a ladder (`ladder` line: you back on it as high, `Ladder_mountAt`; the others at its foot).
 
 ## Versions
 
diff --git a/entropie/Makefile b/entropie/Makefile
index ea56756..51aebbd 100644
--- a/entropie/Makefile
+++ b/entropie/Makefile
@@ -1,5 +1,5 @@
 APP       := entropie
-VERSION   := 2.24.0
+VERSION   := 2.25.0
 
 PREFIX    ?= /usr
 BINDIR    ?= $(PREFIX)/bin
diff --git a/entropie/README.md b/entropie/README.md
index 29a30a4..0c5c9f5 100644
--- a/entropie/README.md
+++ b/entropie/README.md
@@ -694,6 +694,7 @@ say no more often and don't come to you for a bit.
 - Autosave every 5 minutes and on quit
 - Saves live in your data folder (on Linux: `~/.local/share/entropie/entropie/saves`)
 - Old saves keep working with newer versions
+- Saved up a ladder, you load back on it
 
 ## Controls
 
diff --git a/entropie/STATE.md b/entropie/STATE.md
index 7a3ef30..849f6fd 100644
--- a/entropie/STATE.md
+++ b/entropie/STATE.md
@@ -296,6 +296,9 @@ Round 2.23:
 Round 2.24:
 - Blown out of the hand (`world.c` windSnatches): paper (as `paperLike`, the trash that blows about) held in one hand from SNATCH_PAPER 8 m/s wind, a pullover from SNATCH_CLOTH 11.5, only in a gust over SNATCH_GUST 0.3; chance SNATCH_RATE 0.35 / s per 4 m/s over it x gust x (0.5 + drunk + 0.5 careless). Dropped, thrown up and off with the wind, a line said. Two hands on it: never. NPCs go after it (`ai.c` fetchBlown, `ai.blown` / `blown_t`): picked up again, given up after BLOWN_GIVE_UP 25 s or BLOWN_FAR 30 m (in a storm paper outruns them). Not saved (fresh after a load).
 
+Round 2.25:
+- Saved up a ladder (`save.c` `ladder` line: the ladder, how far up): you come back on it as high (`Ladder_mountAt`: hands and feet straight onto the rungs, no easing); the others at its foot (their climb is AI work and starts fresh: not dropped from up there). Checked: save, load, same spot, climbing on.
+
 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).
@@ -446,7 +449,7 @@ Most important first.
 - Weather, still to do: a sound for thunder, wind and rain (no sound in the game yet); hats (nobody wears one yet) blown off
 
 **Saves, still to do**
-- Things being done (a job half way, a ladder being climbed, carrying something together) come back fresh, not as they were
+- Things being done come back fresh: a person's part of a job half way (its progress on the thing is kept, and their order), carrying something together
 
 **Tools for us**
 - Optional local AI (llama.cpp, small model) for talking and tasks; the menu stays as fallback
@@ -455,4 +458,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.24.0 (build d783eec)`
+State of `entropie 2.25.0 (build 681ea05)`
diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt
index 6463217..f50def6 100644
--- a/entropie/commit_message.txt
+++ b/entropie/commit_message.txt
@@ -1,4 +1,4 @@
-entropie 2.24.0: gone with the wind
+entropie 2.25.0: saved up a ladder
 
-- A strong gust can tear paper or a pullover out of a hand (two hands hold
-  it safe); the others run after theirs and pick it up, or give up
+- Saving while up a ladder: you load back on it, as high; the others come
+  back at its foot
diff --git a/entropie/src/game/save.c b/entropie/src/game/save.c
index b51ff02..475a993 100644
--- a/entropie/src/game/save.c
+++ b/entropie/src/game/save.c
@@ -203,6 +203,8 @@ bool Save_write(const Game *game, const char *dir, const char *name, char *err,
             fprintf(f, "\n");
             if (o->keys) fprintf(f, "keys %s\n", o->keys);
             if (o->body.asleep) fprintf(f, "asleep 1\n");
+            if (o->on_ladder) /* (you up a ladder: back on it, as high; the others come back at its foot) */
+                fprintf(f, "ladder %d %.9g\n", idOf(&ids, o->on_ladder), (double)o->ladder_at);
             if (o->sitting && !o->riding) /* (where they sit: on what, facing where) */
                 fprintf(f, "sit %d %.9g %.9g %.9g\n", idOf(&ids, o->seat), (double)o->sit_dir.x, (double)o->sit_dir.y, (double)o->sit_dir.z);
             for (int h = 0; h < 2; h++)
@@ -578,7 +580,8 @@ bool Save_read(Game *game, const char *dir, const char *name, char *err, size_t
         if (o->ai.mode != AI_IDLE && o->ai.mode != AI_WANDER && o->ai.mode != AI_WORK) o->ai.mode = AI_IDLE;
         Object_syncColliders(o);
         bool asleep = false, sits = false;
-        Object *seat = NULL;
+        Object *seat = NULL, *ladder = NULL;
+        float ladder_at = 0.0f;
         Vec3 sit_dir = vec3(0.0f, 0.0f, 1.0f);
         for (int i = r->first; i < r->first + r->lines; i++) {
             char buf[256], *s = buf;
@@ -586,6 +589,7 @@ bool Save_read(Game *game, const char *dir, const char *name, char *err, size_t
             char *key = word(&s);
             if (!strcmp(key, "asleep")) asleep = true;
             else if (!strcmp(key, "sit")) { sits = true; seat = byId(&p, numI(&s)); sit_dir = numV(&s); }
+            else if (!strcmp(key, "ladder")) { ladder = byId(&p, numI(&s)); ladder_at = numF(&s); }
             else if (!strcmp(key, "hand")) {
                 int h = numI(&s);
                 Object *item = byId(&p, numI(&s));
@@ -604,7 +608,16 @@ bool Save_read(Game *game, const char *dir, const char *name, char *err, size_t
             Object *tent = o->in_tent;
             o->in_tent = NULL;
             Tent_crawlIn(tent, o);
-        } else if (asleep) Body_lieDown(&o->body);
+        } else if (ladder && ladder->type == OBJ_LADDER && ladder->leaning && !ladder->is_held) {
+            if (o->type == OBJ_PLAYER) Ladder_mountAt(o, ladder, ladder_at);
+            else { /* (their climb is AI work, and that starts fresh: down at its foot, not dropped from up there) */
+                Vec3 foot = vec3_add(ladder->position, vec3_scale(ladder->lean_normal, 0.45f));
+                o->position = vec3(foot.x, World_groundHeight(w, foot.x, foot.z, foot.y + 0.5f), foot.z);
+                Object_syncColliders(o);
+                o->body.replant = true;
+            }
+        }
+        else if (asleep) Body_lieDown(&o->body);
         else if (sits && Object_sit(o, seat, vec3_add(o->position, vec3_scale(sit_dir, 3.0f)))) /* (sat down again where they sat ... */
             o->ai.timer = 20.0f + 0.37f * (float)(k % 41);                                    /* ... and stay a while) */
     }
diff --git a/entropie/src/world/ladder.c b/entropie/src/world/ladder.c
index 7a56f4f..392ed9b 100644
--- a/entropie/src/world/ladder.c
+++ b/entropie/src/world/ladder.c
@@ -636,6 +636,17 @@ void Ladder_mount(Object *who, Object *l, bool at_top) {
     Object_syncColliders(who);
 }
 
+void Ladder_mountAt(Object *who, Object *l, float at) {
+    who->on_ladder = l;
+    who->ladder_at = clampf(at, 0.0f, highest(l));
+    who->ladder_shift = vec3_zero();
+    who->ladder_off = 0.0f;
+    who->ladder_limbs_ok = false; /* (no easing from where they were: straight onto the rungs) */
+    who->climbing = true;
+    who->sitting = false;
+    place(who);
+}
+
 /* Where you stand once off it at the bottom. */
 static Vec3 offSpot(const Object *l) { return vec3_add(l->position, vec3_scale(l->lean_normal, 0.45f)); }
 
diff --git a/entropie/src/world/ladder.h b/entropie/src/world/ladder.h
index 5073734..7d26c99 100644
--- a/entropie/src/world/ladder.h
+++ b/entropie/src/world/ladder.h
@@ -38,6 +38,8 @@ bool        Ladder_take(Object *who, Object *ladder);
 /* Gets on at the bottom or at the top. */
 void        Ladder_mount(Object *who, Object *ladder, bool at_top);
 enum { CLIMB_ON, CLIMB_OFF_BOTTOM, CLIMB_AT_EDGE };
+/* On it right away this far up (a game loaded): hands and feet straight onto the rungs. */
+void        Ladder_mountAt(Object *who, Object *ladder, float at);
 /* Climbing up (input > 0) or down. CLIMB_AT_EDGE: at the top, wanting over the edge. */
 int         Ladder_climb(Object *who, float input, float dt);
 /* Lets go of the ladder (on the ground at its foot, or handed over to a climb). */