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.14.0: wind follow-ups
- Trees and bushes sway with the wind - Paper and plastic litter and pullovers lying about get blown along - Owners run after their tent when the wind blows it about and hold it down
commit_message.txt | 11 ++++------- entropie/Makefile | 2 +- entropie/README.md | 3 ++- entropie/STATE.md | 11 ++++++++--- entropie/src/people/ai.c | 16 ++++++++++++++++ entropie/src/world/object.h | 1 + entropie/src/world/tent.c | 2 ++ entropie/src/world/world.c | 41 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 75 insertions(+), 12 deletions(-) diff --git a/commit_message.txt b/commit_message.txt index fdf2961..3f639fc 100644 --- a/commit_message.txt +++ b/commit_message.txt @@ -1,8 +1,5 @@ -entropie 2.13.0: wind +entropie 2.14.0: wind follow-ups -- Wind with calm and windy spells and gusts (windier with rain and storms) -- Rain slants and drifts with it; fires now smoke, and smoke and flames - go with the wind -- Tents not pegged down (under half the pegs) blow about in strong wind - until they snag or someone works on them; the hint line warns you -- Dev menu: wind (on its own, calm, a breeze, a storm) +- Trees and bushes sway with the wind +- Paper and plastic litter and pullovers lying about get blown along +- Owners run after their tent when the wind blows it about and hold it down diff --git a/entropie/Makefile b/entropie/Makefile index 796f03f..f18e08d 100644 --- a/entropie/Makefile +++ b/entropie/Makefile @@ -1,5 +1,5 @@ APP := entropie -VERSION := 2.13.0 +VERSION := 2.14.0 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin diff --git a/entropie/README.md b/entropie/README.md index f839f4c..e375a77 100644 --- a/entropie/README.md +++ b/entropie/README.md @@ -59,7 +59,8 @@ Painted in the rotoscope style of *Waking Life* (2001): - Wind: calm or windy spells, gusts on top (windier with rain). The rain slants, the fire's smoke and flames go with it - A tent not pegged down (under half its pegs) blows about in strong wind - until it snags on something or somebody works on it + until it snags on something or somebody works on it; its owner comes running +- Trees and bushes sway; paper, plastic and a pullover lying about get blown along ## Tents diff --git a/entropie/STATE.md b/entropie/STATE.md index 3bd2853..06b09cd 100644 --- a/entropie/STATE.md +++ b/entropie/STATE.md @@ -236,6 +236,11 @@ Round 2.13: - Rain drops drift with it and slant (`Shapes_rain` lean: the top upwind). Smoke and sawdust slow to the wind's speed (`Chips_update` wind). Fires smoke now (`Chips_smoke`, a big soft grey puff every 0.22 s / flame size, rising 0.9, spreading 0.22 m/s). Flames sheared downwind (`drawFlames`, 0.07 x wind, at most 0.8). - Tents in the wind (`tent.c` blowAbout): not up and under half the pegs in, nobody working on it for BLOW_HELD 1.5 s: on its poles from 4 m/s, flat from 6.5 m/s, it slides 0.13 m/s per m/s over that (flat half), turning a little, on the ground; a ray along the wind (0.3 m up) hitting something static: snagged, it stays. `world.tent_blowing` -> the hint line: "Volkram's tent is blowing about in the wind - peg it down!" (not again for 60 s). +Round 2.14: +- Trees (standing) and bushes sway with the wind (`world.c` windSway: sheared from their foot, SWAY_TREE 0.06 / SWAY_BUSH 0.10 per m of height in the strongest wind, x a beat of their own; a little even when calm). Drawing only: their shadows and colliders stay. +- Light things blown along (`world.c` windBlows, before the physics step): paper and plastic litter from 5 m/s, a pullover put down from 9 m/s; BLOW_SHOVE 0.9 m/s^2 per m/s over that against the ground's grip; paper spins. +- Owners chase their tent (`ai.c` chaseTent, before the rain: idle, wander, at a table, working, fetching): the wind pushed it lately (`tent_blown` 6 s) and it's within 70 m: "Hey - my tent!", over to it and on with it (working on it holds it: it doesn't blow while worked 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). @@ -382,8 +387,8 @@ Most important first. - 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 -- Tents, still to do: NPCs taking theirs down on their own (leaving); owners running after theirs when it blows away -- Weather, still to do: a sound for thunder, wind and rain (no sound in the game yet); trees and bushes swaying; loose light things (paper, a pullover) blown about +- 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 - Main building: "the left building's roof peak is too far left" - to be clarified **Tools for us** @@ -393,4 +398,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.13.0 (build f0f0b53)` +State of `entropie 2.14.0 (build 11cb1c9)` diff --git a/entropie/src/people/ai.c b/entropie/src/people/ai.c index bda7612..d959418 100644 --- a/entropie/src/people/ai.c +++ b/entropie/src/people/ai.c @@ -1832,6 +1832,19 @@ static void workOnTent(Object *self, Object *tent, Object *const *objects, int c } } +/* 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; + if (self->body.asleep || self->in_tent || self->indoors > 0.0f || self->riding || ai->unload) return false; + Object *tent = Tent_of(objects, count, self); + if (!tent || tent->tent_blown <= 0.0f || flatDistance(tent->position, self->position) > TENT_WALK) return false; + if (tent->tent_idle > 3.0f && ai->speech_time <= 0.0f && random01(ai) < 0.5f * dt) + Ai_say(self, random01(ai) < 0.5f ? "Hey - my tent!" : "No no no - come back here!"); + if (self->sitting) self->sitting = false; + workOnTent(self, tent, objects, count, dt); + return true; +} + static bool pitchTents(Object *self, Object *const *objects, int count, float dt) { Ai *ai = &self->ai; if (ai->unload || self->body.asleep || self->in_tent) return false; @@ -2158,6 +2171,9 @@ void Ai_update(Object *self, Object *const *objects, int count, float dt) { if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER || ai->mode == AI_HELP) && ai_holdLadder(self, objects, count, dt)) return; /* Done with a tool: careful people put it back where it belongs, the others leave it lying */ if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER) && ai_putAway(self, objects, count, dt)) return; + /* Their tent blowing away: after it */ + if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER || ai->mode == AI_TABLE || ai->mode == AI_WORK || ai->mode == AI_FETCH) && + chaseTent(self, objects, count, dt)) return; /* Rain: inside */ if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER || ai->mode == AI_TABLE || ai->mode == AI_WORK || ai->mode == AI_FETCH) && shelter(self, objects, count, dt)) return; diff --git a/entropie/src/world/object.h b/entropie/src/world/object.h index 493b6d0..8cb0ab2 100644 --- a/entropie/src/world/object.h +++ b/entropie/src/world/object.h @@ -171,6 +171,7 @@ typedef struct Object { int tent_stage; /* tents: TentStage ... */ float tent_work; /* ... how far the stage is (0..1) ... */ float tent_idle; /* ... seconds since anybody worked on it */ + float tent_blown; /* tents: seconds since the wind last pushed it about (0: not lately) */ float smoke_t; /* fireplaces: till the next puff of smoke */ int tent_beds; /* ... sleeping bags (bit 0 owner, 2 owner2) and mats (1, 3) put in */ bool tent_down; /* ... being taken down: the stages backwards, then packed into its bag */ diff --git a/entropie/src/world/tent.c b/entropie/src/world/tent.c index 6e13496..77132f8 100644 --- a/entropie/src/world/tent.c +++ b/entropie/src/world/tent.c @@ -293,6 +293,7 @@ static void blowAbout(World *world, Object *tent, float dt) { Object_setRotation(tent, vec3(0.0f, tent->rotation.y + 0.06f * push * sinf(tent->position.x * 1.7f + tent->position.z) * dt, 0.0f)); Object_syncColliders(tent); world->tent_blowing = tent; + tent->tent_blown = 6.0f; /* (its owner comes running) */ } #define RAIN_NAP_END 0.15f /* rain: under this, out of the tent again */ @@ -303,6 +304,7 @@ void Tent_update(World *world, float dt) { Object *o = world->objects[i]; if (o->type == OBJ_TENT) { o->tent_idle += dt; + o->tent_blown = fmaxf(0.0f, o->tent_blown - dt); if (o->tent_down && !o->broken && o->tent_stage == TENT_LAID && o->tent_work >= 1.0f) pack(world, o); else if (!o->broken) blowAbout(world, o, dt); continue; diff --git a/entropie/src/world/world.c b/entropie/src/world/world.c index 658a95b..0d3a7bb 100644 --- a/entropie/src/world/world.c +++ b/entropie/src/world/world.c @@ -1253,6 +1253,25 @@ static void emptyTray(World *world, Object *o) { if (!Hands_pickUpObject(o, hand, butts)) Hands_receive(o, hand, butts); /* (the tin a bit far: tipped into the hand all the same) */ } +/* Light things lying about (paper and plastic litter, a pullover put down) + blown along the ground by a strong wind, tumbling as they go. */ +#define BLOW_PAPER 5.0f /* m/s: paper and plastic go from this wind ... */ +#define BLOW_CLOTH 9.0f /* ... a pullover from this */ +#define BLOW_SHOVE 0.9f /* m/s^2 for each m/s over it (against the ground's grip) */ + +static void windBlows(World *world, Object *o, float dt) { + if (o->is_static || o->is_held || o->broken || !o->is_grounded || o->lifted) return; + bool paper = o->type == OBJ_TRASH && o->size.x > 0.0f && ((o->variant & 3) == PALETTE_WARM || (o->variant & 3) == PALETTE_STANDARD); + bool cloth = o->type == OBJ_CLOTHES; + if (!paper && !cloth) return; + float speed = hypotf(world->wind.x, world->wind.z), from = paper ? BLOW_PAPER : BLOW_CLOTH; + if (speed <= from) return; + float shove = (speed - from) * BLOW_SHOVE * (cloth ? 0.6f : 1.0f) * dt / speed; + o->velocity.x += world->wind.x * shove; + o->velocity.z += world->wind.z * shove; + if (paper) o->angular_velocity.y += (sinf(o->position.x * 3.1f) > 0.0f ? 1.0f : -1.0f) * 2.0f * shove * speed; +} + void World_update(World *world, float dt, float game_dt) { Object_indexKinds(world->objects, world->count); world->dt_props = dt; @@ -1307,6 +1326,7 @@ void World_update(World *world, float dt, float game_dt) { Physics_useGrid(&world->grid); for (int i = 0; i < world->count; i++) { Object *o = world->objects[i]; + windBlows(world, o, dt); Physics_step(o, world->objects, world->count, &world->terrain, dt); landThrown(o); } @@ -1478,6 +1498,25 @@ static void drawMark(Renderer *renderer, const Mesh *block, const Object *o) { } } +/* Trees and bushes bending with the wind (a lean growing with the height, + swaying with the gusts; each its own beat). Their shadows stay put. */ +#define SWAY_TREE 0.06f /* lean per m of height in the strongest wind */ +#define SWAY_BUSH 0.10f + +static Mat4 windSway(const World *world, const Object *o, float t) { + float k = o->type == OBJ_BUSH ? SWAY_BUSH : SWAY_TREE; + float speed = hypotf(world->wind.x, world->wind.z), level = fminf(speed / WIND_MAX, 1.4f); + float phase = o->position.x * 0.37f + o->position.z * 0.61f; + float beat = 0.65f + 0.35f * sinf(t * (o->type == OBJ_BUSH ? 2.6f : 1.4f) + phase); + Vec3 dir = speed > 0.01f ? vec3_scale(world->wind, 1.0f / speed) : vec3(1.0f, 0.0f, 0.0f); + float lean = k * (level * beat + 0.04f * sinf(t * 0.8f + phase)); /* (a little even when it's calm) */ + Mat4 shear = mat4_identity(); + shear.m[4] = dir.x * lean; + shear.m[6] = dir.z * lean; + Vec3 base = o->position; + return mat4_mul(mat4_translate(base), mat4_mul(shear, mat4_translate(vec3_scale(base, -1.0f)))); +} + void World_draw(World *world, Renderer *renderer, bool draw_player) { Terrain_syncTexture(&world->terrain); { @@ -1523,6 +1562,8 @@ void World_draw(World *world, Renderer *renderer, bool draw_player) { Vec3 tint = vec3_lerp(vec3_lerp(vec3(1.0f, 1.0f, 1.0f), vec3(0.9f, 0.78f, 0.62f), obj->type == OBJ_SAUSAGE ? 0.0f : brown), vec3(0.2f, 0.17f, 0.15f), black); Renderer_drawMeshTinted(renderer, &obj->mesh, Object_modelMatrix(obj), tint, 0.0f); + } else if ((obj->type == OBJ_TREE && !obj->toppled) || obj->type == OBJ_BUSH) { + Renderer_drawMesh(renderer, &obj->mesh, mat4_mul(windSway(world, obj, renderer->boil_time), Object_modelMatrix(obj))); } else { Renderer_drawMesh(renderer, &obj->mesh, Object_modelMatrix(obj)); if (obj->type == OBJ_FIREPLACE && obj->grill_mesh.vao) { /* the grate swings a little on its chain */