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.38.0: a shelter in the yard
- A shelter by the fire: a roof on posts, two log benches and a table - In hard rain the guests sit it out there or in your garages' kitchen, whichever is nearer with a seat free
commit_message.txt | 10 ++++------ entropie/Makefile | 2 +- entropie/README.md | 2 +- entropie/STATE.md | 15 ++++++++++----- entropie/commit_message.txt | 10 ++++------ entropie/src/people/ai.c | 25 ++++++++++++++++++++++--- entropie/src/people/ai.h | 3 ++- entropie/src/world/manor.c | 38 ++++++++++++++++++++++++++++++++++++++ entropie/src/world/manor.h | 2 ++ entropie/src/world/site.c | 10 ++++++++++ entropie/src/world/site.h | 2 ++ 11 files changed, 96 insertions(+), 23 deletions(-) diff --git a/commit_message.txt b/commit_message.txt index a418266..c9d5195 100644 --- a/commit_message.txt +++ b/commit_message.txt @@ -1,7 +1,5 @@ -entropie 2.37.0: umbrellas inside out, hats +entropie 2.38.0: a shelter in the yard -- A strong gust can blow an open umbrella inside out for a moment; the - third time (or in a storm) it's broken for good -- Hats: Toni and Kurti wear caps, Jonas a beanie. The wind can take a cap - off; it bowls along the ground, they chase it and put it back on - (pulled down tighter each time) +- A shelter by the fire: a roof on posts, two log benches and a table +- In hard rain the guests sit it out there or in your garages' kitchen, + whichever is nearer with a seat free diff --git a/entropie/Makefile b/entropie/Makefile index 0c05bb2..15eaaa1 100644 --- a/entropie/Makefile +++ b/entropie/Makefile @@ -1,5 +1,5 @@ APP := entropie -VERSION := 2.37.0 +VERSION := 2.38.0 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin diff --git a/entropie/README.md b/entropie/README.md index 3fc8f72..67c8158 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.37.0 (build 1a6ad0e)`. The build id is +`make version` prints e.g. `entropie 2.38.0 (build ee5055b)`. The build id is an md5 of all sources and assets. diff --git a/entropie/STATE.md b/entropie/STATE.md index bffff4d..7837b1a 100644 --- a/entropie/STATE.md +++ b/entropie/STATE.md @@ -297,9 +297,10 @@ Painted in the rotoscope style of *Waking Life* (2001): there for me?") and they walk along side by side under it (yours too); it leans over the two of them - People get out of it: Kurti and his sons into the house, the others into - their tent (at night, or when it's nearer) or your garages' kitchen. Raining - hard, they sit it out in there (the two chairs, a log bench by the back - wall, else the floor); out again when it stops + their tent (at night, or when it's nearer), your garages' kitchen or the + shelter in the yard (a roof on posts by the fire, two log benches and a + table under it) - the nearest with a seat free. Raining hard, they sit it + out there (else on the floor); out again when it stops - Out in the rain your clothes get wet (darker; Tab: Wet) and you get cold. They dry by a fire quickest, in the day slower, at night slowest. Wet through, the others go and sit by a burning fire @@ -1230,6 +1231,10 @@ Round 2.37 (umbrellas blown inside out, hats): - Hats (`FigureLook.hat` HAT_CAP / HAT_BEANIE, `hat_color`; `figure.frag` hatDistance: a cap's crown and a brim tipped down over the brow, a beanie down to the ears with a knot and ribs; under a hood: none): Toni a red cap, Kurti an old green one, Jonas a blue beanie (`Figure_wardrobe` by index % 7: 3, 4, 6). Saved with the person. - Blown off (`world.c` windHat): in a gust (HAT_GUST 0.4) over HAT_WIND 9 m/s, HAT_RATE 0.3/s for every 3 m/s over it x gust (a beanie a tenth), divided by 1 + 3 x `hats_lost` (pulled down tighter each time): an OBJ_HAT (`Shapes_hat`, its colour, `owner`) flies off with the wind and bowls along like paper (`windBlows`); NPCs go after it (`ai.blown`, as for paper); picked up by its owner it goes back on (`hatBackOn`). Checked: Toni at wind level 0.8 - off, chased 7-14 m, back on in 3-14 s; less often each time. +Round 2.38 (a shelter in the yard): +- `manor.c` Shelter_build: a roof on six posts (5 x 3.6 m, eaves 2.25 m, a gable 1 m up; its roof slabs solid, so `Weather_covered` holds under it), paving slabs, a log bench along each long side (3.4 m) and a table between them; in the yard at court(SHELTER_A 24.5, SHELTER_B 3.5), about 11 m from the fire towards the barn, along the garages. +- Rain places (`Site_rainPlaces`: the garages' kitchen, the shelter): sheltering guests pick the nearest with a free seat (`ai.rain_place`, chosen once per shower); a bench is walked up to from the front where along it they are (round its end they got stuck outside a post and never sat). Checked: hard rain at midday - all three guests on one shelter bench within 20-60 s, dry, up when it stopped. + ## Open tasks Most important first. @@ -1252,7 +1257,7 @@ Most important first. - "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) - Tents, still to do: NPCs taking theirs down on their own (leaving) -- Weather, still to do: umbrellas while working (now only idle people fetch one); more roofed places to sit out the rain together (outdoors: a shelter, a pavilion - `Site_rainRoom` is the one place now) +- Weather, still to do: umbrellas while working (now only idle people fetch one) - Sound, still to do: the house's doors (they have no doors that open yet) **Saves, still to do** @@ -1265,4 +1270,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.37.0 (build 1a6ad0e)` +State of `entropie 2.38.0 (build ee5055b)` diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt index a418266..c9d5195 100644 --- a/entropie/commit_message.txt +++ b/entropie/commit_message.txt @@ -1,7 +1,5 @@ -entropie 2.37.0: umbrellas inside out, hats +entropie 2.38.0: a shelter in the yard -- A strong gust can blow an open umbrella inside out for a moment; the - third time (or in a storm) it's broken for good -- Hats: Toni and Kurti wear caps, Jonas a beanie. The wind can take a cap - off; it bowls along the ground, they chase it and put it back on - (pulled down tighter each time) +- A shelter by the fire: a roof on posts, two log benches and a table +- In hard rain the guests sit it out there or in your garages' kitchen, + whichever is nearer with a seat free diff --git a/entropie/src/people/ai.c b/entropie/src/people/ai.c index e7e46cb..ab6b836 100644 --- a/entropie/src/people/ai.c +++ b/entropie/src/people/ai.c @@ -2156,7 +2156,16 @@ static bool rainRoom(Object *self, Object *const *objects, int count, float dt) if (self->sitting && ai->rain_seated) { rest(ai, 3.0f, 6.0f); return true; } /* (sitting it out) */ ai->rain_seated = false; if (self->sitting) self->sitting = false; - Vec3 room = Site_rainRoom(); + Vec3 places[4]; + int n = Site_rainPlaces(places, 4); + if (ai->rain_place <= 0 || ai->rain_place > n) { /* where to: the nearest with a seat free (else just the nearest) */ + float best = 1e9f; + for (int k = 0; k < n; k++) { + float d = flatDistance(places[k], self->position) + (freeSeatIn(self, objects, count, places[k]) ? 0.0f : 60.0f); + if (d < best) { best = d; ai->rain_place = k + 1; } + } + } + Vec3 room = places[ai->rain_place - 1]; Vec3 spot = vec3_add(room, vec3(0.8f * ai->side, 0.0f, 0.8f * ai->side)); if (flatDistance(room, self->position) > 3.5f || g_world->rain < RAIN_SIT) { if (goToPoint(self, spot, 0.7f, objects, count, dt)) rest(ai, 3.0f, 6.0f); @@ -2164,8 +2173,17 @@ static bool rainRoom(Object *self, Object *const *objects, int count, float dt) } Object *seat = freeSeatIn(self, objects, count, room); if (seat) { - float near = 0.6f + 0.5f * seat->size.x; - if (flatDistance(seat->position, self->position) > near && !goToPoint(self, seat->position, near, objects, count, dt)) return true; + Vec3 at = seat->position; /* (a chair: up to it; a bench: in front of it, where along it we are - not round its end, through a post) */ + float near = 0.9f; + if (seat->variant == FURN_BENCH) { + Vec3 axis = seat->colliders[0].axes[0], front = vec3_sub(room, seat->position); + float half = fmaxf(0.0f, 0.5f * seat->size.x - 0.4f), along = clampf(vec3_dot(vec3_sub(self->position, seat->position), axis), -half, half); + front = flat(vec3_sub(front, vec3_scale(axis, vec3_dot(front, axis)))); + front = vec3_length(front) > 1e-3f ? vec3_normalize(front) : vec3(0.0f, 0.0f, 1.0f); + at = vec3_add(vec3_add(seat->position, vec3_scale(axis, along)), vec3_scale(front, 0.5f)); + near = 0.3f; + } + if (flatDistance(at, self->position) > near && !goToPoint(self, at, near, objects, count, dt)) return true; stand(self); if (Object_sit(self, seat, room)) { ai->rain_seated = true; @@ -2205,6 +2223,7 @@ static bool shelter(Object *self, Object *const *objects, int count, float dt) { if (!g_world || g_world->rain < SHELTER_RAIN || self->indoors > 0.0f || self->in_tent || self->body.asleep || self->riding) { if (!g_world || g_world->rain < SHELTER_RAIN * 0.5f) { ai->sheltering = false; + ai->rain_place = 0; if (ai->rain_seated) { /* (over: up again) */ ai->rain_seated = false; if (self->sitting && random01(ai) < 0.4f) Ai_say(self, random01(ai) < 0.5f ? "It's stopped raining." : "Right, the rain's over."); diff --git a/entropie/src/people/ai.h b/entropie/src/people/ai.h index 553e18f..b2cd12c 100644 --- a/entropie/src/people/ai.h +++ b/entropie/src/people/ai.h @@ -182,7 +182,8 @@ typedef struct { bool asked_you; /* asked the player for one (nothing came of it: the machine next time) */ struct Object *take_from; /* a bottle from this crate, or the next thing out of this car's boot: please (see car.c Car_serve) */ bool sheltering; /* in out of the rain (ai.c shelter) */ - bool rain_seated; /* ... sat down to wait it out (in the garages' kitchen) */ + bool rain_seated; /* ... sat down to wait it out (the garages' kitchen, the shelter) ... */ + int rain_place; /* ... which of those (Site_rainPlaces), + 1 (0: not chosen yet) */ bool greet; /* just arrived: over to the fire, saying hello, sitting there till the work starts ... */ bool greet_stand; /* ... no room on the benches: standing with the others here instead ... */ Vec3 greet_at; diff --git a/entropie/src/world/manor.c b/entropie/src/world/manor.c index 1282775..fee4c7e 100644 --- a/entropie/src/world/manor.c +++ b/entropie/src/world/manor.c @@ -479,6 +479,44 @@ bool Shell_build(World *world, Vec3 origin, float yaw) { return look && World_add(world, look); } +/* ---------- The shelter: a roof on posts in the yard, benches under it ---------- */ +#define SHELTER_LEN 5.0f /* m along the ridge */ +#define SHELTER_WID 3.6f /* m across */ +#define SHELTER_EAVES 2.25f /* m: the eaves (headroom at the sides) */ +#define SHELTER_RISE 1.0f /* m: the ridge over the eaves */ + +bool Shelter_build(World *world, Vec3 origin, float yaw) { + static Plan plan; + Plan *p = &plan; + memset(p, 0, sizeof(*p)); + p->world = world; + p->origin = origin; + p->yaw = yaw; + p->ok = true; + const Vec3 WOOD = { 0.40f, 0.29f, 0.18f }, FLOOR = { 0.52f, 0.49f, 0.44f }; + const float hx = SHELTER_LEN * 0.5f - 0.1f, hz = SHELTER_WID * 0.5f - 0.1f, w = 0.08f; + for (int i = -1; i <= 1; i++) /* six posts: the corners and the middle of each long side */ + for (int s = -1; s <= 1; s += 2) + box(p, vec3((float)i * hx - w, 0.0f, (float)s * hz - w), vec3((float)i * hx + w, SHELTER_EAVES, (float)s * hz + w), WOOD, SOLID); + for (int s = -1; s <= 1; s += 2) /* the beams along the eaves */ + box(p, vec3(-hx - 0.15f, SHELTER_EAVES - 0.16f, (float)s * hz - w), vec3(hx + 0.15f, SHELTER_EAVES, (float)s * hz + w), WOOD, LOOK_ONLY); + box(p, vec3(-hx, 0.0f, -hz), vec3(hx, 0.03f, hz), FLOOR, LOOK_ONLY); /* (paving slabs under it) */ + p->roofs[p->n_roofs++] = (ShapeRoof){ vec3(0.0f, 0.0f, 0.0f), SHELTER_LEN + 0.6f, SHELTER_WID + 0.6f, SHELTER_EAVES, SHELTER_RISE, + BUILDING_PLASTER_DARK, false, 0.0f }; + roofSlabs(p, &p->roofs[0]); + if (!p->ok) return false; + Mesh mesh = Shapes_structure(p->slabs, p->n_slabs, p->openings, p->n_openings, p->roofs, p->n_roofs); + if (!mesh.vao) return false; + Object *look = Object_createStructure(mesh, origin, yaw, vec3(SHELTER_LEN, SHELTER_EAVES + SHELTER_RISE, SHELTER_WID)); + if (!look || !World_add(world, look)) return false; + for (int s = -1; s <= 1; s += 2) { /* a log bench along each long side, a table between them */ + Object *bench = Object_createFurniture(FURN_BENCH, toWorld(p, vec3(0.0f, 0.0f, (float)s * (hz - 0.4f))), vec3(3.4f, SEAT_HEIGHT, 0.36f), yaw); + if (!bench || !World_add(world, bench)) return false; + } + Object *table = Object_createFurniture(FURN_TABLE, toWorld(p, vec3(0.0f, 0.0f, 0.0f)), vec3(2.6f, 0.75f, 0.8f), yaw); + return table && World_add(world, table); +} + bool Manor_build(World *world, Vec3 origin, float yaw) { static Plan plan; /* (big: not on the stack) */ Plan *p = &plan; diff --git a/entropie/src/world/manor.h b/entropie/src/world/manor.h index c609180..96ab35d 100644 --- a/entropie/src/world/manor.h +++ b/entropie/src/world/manor.h @@ -26,5 +26,7 @@ bool Manor_build(World *world, Vec3 origin, float yaw); /* Your unfinished building: a brick shell under a roof, open at the front (-z) to its extension (the frame where the bar gets built); +z against the barn. */ bool Shell_build(World *world, Vec3 origin, float yaw); +/* A shelter in the yard: a roof on six posts, two log benches and a table under it (out of the rain together). */ +bool Shelter_build(World *world, Vec3 origin, float yaw); #endif /* WORLD_MANOR_H */ diff --git a/entropie/src/world/site.c b/entropie/src/world/site.c index f00574a..5b26bc2 100644 --- a/entropie/src/world/site.c +++ b/entropie/src/world/site.c @@ -314,6 +314,8 @@ static const CourtDoorBuilding COURT[] = { #define YARD_B 12.0f #define TAP_A 3.0f /* the tap: on the right end of the main building */ #define TAP_B 17.25f +#define SHELTER_A 24.5f /* the shelter: a roof on posts by the fire, towards the barn */ +#define SHELTER_B 3.5f #define FIRE_A 16.0f /* the fireplace: near the main building and your garages */ #define FIRE_B -4.0f #define BENCH_RADIUS 2.8f /* log benches round it */ @@ -578,6 +580,13 @@ Vec3 Site_rainRoom(void) { /* the middle of the kitchen in your garages: where t return placed(vec3(23.6f, 0.0f, 1.2f), WALLED_CENTER, g_garages.origin, g_garages.yaw, g_garages.zsign); } +int Site_rainPlaces(Vec3 *out, int max) { /* under a roof together: the kitchen, the shelter in the yard */ + int n = 0; + if (n < max) out[n++] = Site_rainRoom(); + if (n < max) out[n++] = court(SHELTER_A, SHELTER_B); + return n; +} + Vec3 Site_houseDoor(void) { return court(MANOR_A + 6.0f, MANOR_B - 7.6f); } /* (out in front of the main building's left door) */ bool Site_inHouse(float x, float z) { @@ -1093,6 +1102,7 @@ bool Site_build(World *world) { if (!placePieces(world, WALLED, COUNT(WALLED), WALLED_CENTER, walled, wyaw, zsign) || !placePieces(world, FRAME, COUNT(FRAME), FRAME_CENTER, court(FRAME_A, FRAME_B), across, 1.0f) || !Shell_build(world, placed(SHELL_AT, FRAME_CENTER, court(FRAME_A, FRAME_B), across, 1.0f), across) || + !Shelter_build(world, court(SHELTER_A, SHELTER_B), yaw_along(mapDir(COURT_ANGLE))) || !furnishGarages(world, walled, wyaw, zsign) || !hangGates(world, walled, wyaw, zsign)) return false; if (!buildGarages(world) || !plantOrchard(world) || !plantMeadows(world) || !furnishYard(world)) return false; diff --git a/entropie/src/world/site.h b/entropie/src/world/site.h index e6f4af5..4fb3265 100644 --- a/entropie/src/world/site.h +++ b/entropie/src/world/site.h @@ -29,6 +29,8 @@ Vec3 Site_drinksSpot(void); /* The middle of the kitchen in your garages: a roof to wait out the rain under, seats round it. */ Vec3 Site_rainRoom(void); +/* Every place like that (the kitchen, the shelter in the yard): their middles, how many. */ +int Site_rainPlaces(Vec3 *out, int max); Vec3 Site_campSpot(int k); Vec3 Site_campAlong(void); Vec3 Site_campDoor(void);