Entropie git · main
Entropie festival game; first steps
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.gzentropie 2.15.0: NPCs hang their pullover up
- Warm, with the pullover tied round the waist, tidy people now and then hang it over a railing, a bench or a free chair nearby (and fetch it again when it gets cold)
commit_message.txt | 7 +++-- entropie/Makefile | 2 +- entropie/README.md | 4 ++- entropie/STATE.md | 7 +++-- entropie/src/people/ai.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ entropie/src/people/ai.h | 2 ++ 6 files changed, 86 insertions(+), 7 deletions(-) diff --git a/commit_message.txt b/commit_message.txt index e24e125..58343e9 100644 --- a/commit_message.txt +++ b/commit_message.txt @@ -1,4 +1,5 @@ -entropie 2.14.1: main building ridge fix +entropie 2.15.0: NPCs hang their pullover up -- The left roof's ridge cap stuck out about 4 m past the left gable: the - ridge piece running into the right half's roof was turned the wrong way +- Warm, with the pullover tied round the waist, tidy people now and then + hang it over a railing, a bench or a free chair nearby (and fetch it + again when it gets cold) diff --git a/entropie/Makefile b/entropie/Makefile index 9142441..2f29eaf 100644 --- a/entropie/Makefile +++ b/entropie/Makefile @@ -1,5 +1,5 @@ APP := entropie -VERSION := 2.14.1 +VERSION := 2.15.0 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin diff --git a/entropie/README.md b/entropie/README.md index e375a77..437c0cd 100644 --- a/entropie/README.md +++ b/entropie/README.md @@ -591,7 +591,9 @@ say no more often and don't come to you for a bit. put it down where you look: over a chair's back, a railing or a bench, on a table, or spread on the ground. Sitting on the ground: spread it out and sit on it. Click it to take it back. Others hang theirs over their chair or - sit on it, take it along when they get up, and fetch it when it gets cold + sit on it, take it along when they get up, and fetch it when it gets cold. + The tidy ones, warm with it round the waist, hang it over a railing, a + bench or a free chair near by - Ask them what they're doing, send them back to helping you, or give them a break ## Smoking diff --git a/entropie/STATE.md b/entropie/STATE.md index f3376c5..89051f6 100644 --- a/entropie/STATE.md +++ b/entropie/STATE.md @@ -244,6 +244,9 @@ Round 2.14: Round 2.14.1: - The main building's left roof: its ridge cap stuck out about 4 m past the left gable ("the roof peak of the left building is too far left"). The bit of ridge running on into the right half's roof (`Shapes_structure`, roofs with `valley`) was turned with rotate_z(-90 deg), which sends the tube to -X: now +90 deg, it goes on into the roof across. +Round 2.15: +- Pullover put away on their own (`ai.c` hangPullover, idle / wander): warm (chill under 0.1, no rain), tied round the waist, tidy (ai_stackCare 0.35+): now and then (HANG_CHANCE 0.015/s x tidiness) over to the nearest railing (`railing`: a thin OBJ_WALL piece 0.6-1.4 m high), bench or free chair within 30 m, beside its long edge (a chair: behind its back), looking at its top: `Clothes_spot` -> hung there (`Clothes_putDown`), else that one skipped a while. Not again for HANG_AGAIN 240 s (none near: 60 s). Cold again: fetchPullover gets it as before. + 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). @@ -389,7 +392,7 @@ Most important first. - Ladders, still to do: a holder for a ladder standing free; NPCs taking a ladder somewhere for their own work - Smoking, still to do: paying for a pack (no money in the game yet) - "No shirt no service" policy (decision open) -- Clothing, still to do: more outfits for extra people (only the performance test has any: they all wear trousers); the pullover over a railing NPCs never do on their own +- Clothing, still to do: more outfits for extra people (only the performance test has any: they all wear trousers) - Tents, still to do: NPCs taking theirs down on their own (leaving) - Weather, still to do: a sound for thunder, wind and rain (no sound in the game yet); a hat or anything held blown out of the hands @@ -400,4 +403,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.14.1 (build 11276d9)` +State of `entropie 2.15.0 (build 2bee8b2)` diff --git a/entropie/src/people/ai.c b/entropie/src/people/ai.c index d959418..92682b7 100644 --- a/entropie/src/people/ai.c +++ b/entropie/src/people/ai.c @@ -1832,6 +1832,75 @@ static void workOnTent(Object *self, Object *tent, Object *const *objects, int c } } +/* Warm, the pullover tied round the waist: the tidier now and then hang it + over a railing or a chair back near by instead (and fetch it when cold: + fetchPullover). */ +#define HANG_LOOK 30.0f /* m: a railing, a bench or a chair this near */ +#define HANG_CHANCE 0.015f /* a second (x tidiness), idle or wandering */ +#define HANG_AGAIN 240.0f /* s: tried (or done): not again for this long */ +#define HANG_TIDY 0.35f /* this careful (ai_stackCare) at least */ + +/* A railing: a thin wall piece at about hip to chest height. */ +static bool railing(const Object *o, float feet) { + if (o->type != OBJ_WALL || o->collider_count < 1 || o->broken) return false; + Vec3 h = o->colliders[0].half_extents; + float thin = fminf(h.x, h.z), top = Object_colliderCenter(o, 0).y + h.y - feet; + return thin <= 0.08f && fmaxf(h.x, h.z) > 0.3f && top > 0.6f && top < 1.4f; +} + +static bool hangPullover(Object *self, Object *const *objects, int count, float dt) { + Ai *ai = &self->ai; + ai->hang_wait = fmaxf(0.0f, ai->hang_wait - dt); + Object *on = ai->hang_on; + if (!on) { + if (!self->look.jacket_tied || self->pullover_down || self->chill > 0.1f || ai->hang_wait > 0.0f || !g_world || g_world->rain > 0.05f || + ai->want_jacket || self->sitting || ai_stackCare(self) < HANG_TIDY || random01(ai) > HANG_CHANCE * ai_stackCare(self) * dt) return false; + ai->hang_wait = HANG_AGAIN; + float best = HANG_LOOK; + for (int i = 0; i < count; i++) { + Object *o = objects[i]; + bool seat = o->type == OBJ_FURNITURE && (o->variant == FURN_CHAIR || o->variant == FURN_BENCH) && !o->broken && o->collider_count; + if ((!seat && !railing(o, self->position.y)) || ai_skipped(ai, o)) continue; + if (seat && o->variant == FURN_CHAIR && chairTaken(self, o, objects, count)) continue; + float d = flatDistance(Object_colliderCenter(o, 0), self->position); + if (d < best && fabsf(o->position.y - self->position.y) < 1.5f) { best = d; on = o; } + } + if (!on) { ai->hang_wait = HANG_AGAIN * 0.25f; return false; } + ai->hang_on = on; + } + if (!self->look.jacket_tied || self->pullover_down) { ai->hang_on = NULL; return false; } + /* beside it: a step off its middle (a railing: off its long side, our side; a chair: behind its back) */ + Vec3 c = Object_colliderCenter(on, 0), spot, aim; + if (on->type == OBJ_WALL || on->variant == FURN_BENCH) { /* (a railing, a bench: over its long edge) */ + Vec3 h = on->colliders[0].half_extents; + Vec3 across = h.x < h.z ? on->colliders[0].axes[0] : on->colliders[0].axes[2]; + Vec3 along = h.x < h.z ? on->colliders[0].axes[2] : on->colliders[0].axes[0]; + Vec3 to = vec3_sub(self->position, c); + if (vec3_dot(to, across) < 0.0f) across = vec3_scale(across, -1.0f); + float len = fmaxf(h.x, h.z), run = clampf(vec3_dot(to, along), -len + 0.3f, len - 0.3f); + Vec3 on_it = vec3_add(c, vec3_scale(along, run)); + spot = vec3_add(on_it, vec3_scale(across, 0.5f)); + aim = vec3(on_it.x, c.y + h.y - 0.05f, on_it.z); + } else { + spot = vec3_add(on->position, mat4_mul_dir(mat4_rotate_y(on->rotation.y), vec3(0.0f, 0.0f, -on->size.z * 0.5f - 0.45f))); + aim = vec3_add(on->position, vec3(0.0f, on->size.y, 0.0f)); + } + spot.y = self->position.y; + if (!goToPoint(self, spot, 0.3f, objects, count, dt)) return true; + Vec3 eye = vec3_add(self->position, vec3(0.0f, self->look.height * 0.92f, 0.0f)); + Vec3 look = vec3_normalize(vec3_sub(aim, eye)); + turnTowards(self, vec3(look.x, 0.0f, look.z), dt); + ClothSpot s; + if (Clothes_spot(g_world, self, look, &s) && s.lay == CLOTH_HUNG && Clothes_putDown(g_world, self, &s)) { + if (random01(ai) < 0.4f) Ai_say(self, "Too warm for this - it can hang here."); + } else { + skipTarget(ai, on); + } + ai->hang_on = NULL; + rest(ai, 1.0f, 2.0f); + return true; +} + /* Their tent blowing away: after it (whatever they were doing), and hold it down. */ static bool chaseTent(Object *self, Object *const *objects, int count, float dt) { Ai *ai = &self->ai; @@ -2192,6 +2261,8 @@ void Ai_update(Object *self, Object *const *objects, int count, float dt) { if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER) && pitchTents(self, objects, count, dt)) return; /* A finished cigarette in the fingers: to the tin, a bin, the fire */ if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER || ai->mode == AI_TABLE) && binButt(self, objects, count, dt)) return; + /* Warm: the pullover over a railing or a chair (the tidy) */ + if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER) && hangPullover(self, objects, count, dt)) return; /* Cold, the pullover put down somewhere: off to get it */ if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER || ai->mode == AI_TABLE) && fetchPullover(self, objects, count, dt)) return; /* Out of cigarettes: to the machine */ diff --git a/entropie/src/people/ai.h b/entropie/src/people/ai.h index 1735dd8..a1de845 100644 --- a/entropie/src/people/ai.h +++ b/entropie/src/people/ai.h @@ -180,6 +180,8 @@ typedef struct { bool sheltering; /* in out of the rain (ai.c shelter) */ bool greet; /* just arrived: over to the fire, saying hello, sitting there till the work starts */ bool drying; /* wet through after the rain: sitting by the fire till dry */ + struct Object *hang_on; /* warm, the pullover round the waist: over this (a railing, a chair) it goes ... */ + float hang_wait; /* ... and not thought of again for this long */ bool going_in; /* a resident on the way into the house (ai.c goInside) */ struct Object *tent_job; /* lending a hand with this tent (ai.c pitchTents) ... */ float tent_time; /* ... this long */