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.42.0: pavilions by the house, beer table sitting, Kurti shows you all the way
- Pavilions turned 90 degrees and moved in front of the main building's right half, left of its porch - Beer benches: you step over the bench and sit facing the table (turned away from it: back to the table as before); the others always face it - Benches have evenly spaced places, so a third person always fits - People no longer slide along the ground while seated when they set off (Kurti showing the way, project work, sharing an umbrella) - Kurti calls everybody to the end of the garages by the barn, points up the path and explains the rest; then the marker shows your tent spot - The chat at the fire waits until everybody has sat down
commit_message.txt | 27 +++++------- entropie/Makefile | 2 +- entropie/README.md | 4 +- entropie/STATE.md | 28 ++++++++++--- entropie/commit_message.txt | 27 +++++------- entropie/src/game/game.h | 4 +- entropie/src/game/game_arrival.c | 90 ++++++++++++++++++++++++++++++---------- entropie/src/game/game_shop.c | 2 + entropie/src/people/ai.c | 5 ++- entropie/src/people/ai_project.c | 5 +-- entropie/src/world/manor.c | 1 + entropie/src/world/object.c | 37 +++++++++++++---- entropie/src/world/object.h | 1 + entropie/src/world/site.c | 8 ++-- entropie/src/world/site.h | 2 + 15 files changed, 164 insertions(+), 79 deletions(-) diff --git a/commit_message.txt b/commit_message.txt index fbd34bf..0aab3e9 100644 --- a/commit_message.txt +++ b/commit_message.txt @@ -1,17 +1,12 @@ -entropie 2.41.0: materials and money, the start shows the way, pavilions, GPU rests +entropie 2.42.0: pavilions by the house, beer table sitting, Kurti shows you all the way -- Cash box (1200 EUR, saved, on the F2 projects page) -- Building material: bundles of boards, nails, screws, paint (OBJ_MATERIAL). - Stage steps need it lying by them: deck and roof boards plus nails or - screws, decoration paint; used up when the step is done -- Shopping run: ask whoever has the car keys (Volkram), pick the list; he - drives off and comes back an hour later, the crew unloads (material to a - store in front of the car room, food into the kitchen) -- Food runs out now (food crate 40 portions, cool box 24 sausages) -- Crew fetches material from the store to a stage that waits for it -- Arrival: a golden marker over Kurti, the car, Kurti again; Kurti walks - you to your camping spot, then the marker shows your tent spot -- Yard: the roof on posts replaced by two party pavilions with beer table sets -- Kartoffelacker moved behind the road to the chicken farm, a strip of wood - right of it -- GPU: vsync plus a 60 fps frame cap (it ran flat out before) +- Pavilions turned 90 degrees and moved in front of the main building's + right half, left of its porch +- Beer benches: you step over the bench and sit facing the table (turned + away from it: back to the table as before); the others always face it +- Benches have evenly spaced places, so a third person always fits +- People no longer slide along the ground while seated when they set off + (Kurti showing the way, project work, sharing an umbrella) +- Kurti calls everybody to the end of the garages by the barn, points up + the path and explains the rest; then the marker shows your tent spot +- The chat at the fire waits until everybody has sat down diff --git a/entropie/Makefile b/entropie/Makefile index 2b1095f..56b75f6 100644 --- a/entropie/Makefile +++ b/entropie/Makefile @@ -1,5 +1,5 @@ APP := entropie -VERSION := 2.41.0 +VERSION := 2.42.0 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin diff --git a/entropie/README.md b/entropie/README.md index 9953134..041205d 100644 --- a/entropie/README.md +++ b/entropie/README.md @@ -17,7 +17,7 @@ people living there. forest, roads. Painted in the rotoscope style of *Waking Life* - **Arriving:** by car with Volkram, Jana and Toni. Say hello to Kurti and his sons, unload the car, pitch the tents. A golden marker shows who or - what's next; Kurti walks you to your camping spot + what's next; Kurti shows you all the way up to the camping meadow - **People:** everyone has their own temperament, build, skills, walk and habits. They eat, drink, smoke, pee, sleep, work, chat and say no - **The festival:** the crew turns up over the first day. Four floors get @@ -134,5 +134,5 @@ Dependencies point downward: `main → game → world/people → render → core ## Version -`make version` prints e.g. `entropie 2.41.0 (build 6232605)`. The build id is +`make version` prints e.g. `entropie 2.42.0 (build e597e7a)`. The build id is an md5 of all sources and assets. diff --git a/entropie/STATE.md b/entropie/STATE.md index 0ad72ab..cf3c317 100644 --- a/entropie/STATE.md +++ b/entropie/STATE.md @@ -341,11 +341,14 @@ Painted in the rotoscope style of *Waking Life* (2001): - Then the work: the boot opens, the others unload. Crates go into the kitchen in your garages, the camping things up to the meadow behind them. Help: left click at the boot takes out the next thing (crates: both hands) +- Kurti's chat waits till everybody sits (or stands with the others) at the + fire - the last one in isn't left out - A golden diamond floats over who or what to go to next: Kurti (say hello, the chat), the car ("get your things from the car - then come to me"), Kurti again (with something of yours in your hands, or all of it out: he - walks you up to the meadow, waiting when you fall behind: "this is a good - spot for your tent"), then your tent's spot till it stands + calls everybody along to the end of your garages by the barn, waiting + when you fall behind; the others gather round; he points up the path and + says the rest), then your tent's spot till it stands - In the boot: 2 crates of beer, 2 of water, one of soda (cola and orange), one of Mate, everybody's sleeping bag and mat, the big tent (Volkram and Jana) and two small ones (Toni, you) - A crate is heavy: carrying it tires you (the weaker sooner). Worn out, you @@ -426,9 +429,15 @@ Painted in the rotoscope style of *Waking Life* (2001): 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), your garages' kitchen or the - two party pavilions in the yard (side by side by the fire, a beer table - set under each) - the nearest with a seat free. Raining hard, they sit it + two party pavilions in the yard (in a row in front of the main building's + right half, left of its porch; a beer table set under each) - the nearest + with a seat free. Raining hard, they sit it out there (else on the floor); out again when it stops +- A beer bench (C): walking up to it you step over it and sit at the table, + facing it; turned away from it, you sit down with your back to the table. + The others always sit at the table. Benches have their places evenly + along them (three on the fire's benches and the beer benches): the third + always fits - 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 @@ -1389,6 +1398,15 @@ Round 2.41 (materials and money; the start shows the way; the pavilions; the GPU - The GPU: vsync (adaptive if offered) and a frame cap of FRAME_CAP 60 (`platform.c` Platform_swap: never quicker than 1/60 s a frame) - it ran flat out before. - Checked: a run with 4 bundles, nails and screws, paint, food (245 EUR): walked over in 1 s, off, away, back, all 11 things unloaded in 4 min (store 7, kitchen 2 food boxes); Kilian fetched 2 bundles and nails to the Obstwiese and the deck got going; saved and loaded while away (back as it should); the start: marker on Kurti, the car, Kurti, the tent spot - Kurti walked you up there. +Round 2.42 (the pavilions in front of the house; sitting at a beer table; Kurti shows you all the way up): +- The pavilions: turned 90 degrees (in a row along the front) and moved in front of the main building's right half, left of its porch: court(SHELTER_A 10.2, SHELTER_B 3.8), 1.7 m off its wall. +- Beer benches (`Object.table`: set in `Shelter_build`): `Object_sit` sits at the table, facing it - the others always, you when not turned away from the bench (`Object_facing` . to the bench > -0.2); from the far side, stepped over (`sit_backing` from the start: straight onto the spot, no turning round in front of it). NPCs walk up to it from behind (`rainRoom`). Its description says so. +- Bench places (`freeAlong`): a bench's places are evenly along it (n = 2 half / SEAT_SPACE + 1, three on the fire's and the beer benches), the free one nearest where they come to it; sat anywhere, two left no room for a third. +- Getting up: `ai_errand`, `ai_projectWork` and walking under somebody's umbrella "stood" a seated person without getting them up - they slid along the ground sitting (Kurti, showing the way). Now up first. +- Kurti shows you all where to camp: with your things he calls everybody along (`guide`: `Arrival.guide_line`, `guide_t`) to `Site_campPath` (court(36, -11): the end of your garages by the barn, the foot of the path up), the three friends round him (`ai.errand`, no waiting); there (GATHER_NEAR 5.5 m, or after GATHER_WAIT 45 s) he faces up the path, points (TALK_POINT) and says three lines (GUIDE_LINE 3.8 s apart); then everybody is back to the day. `ai_errand` no longer drops what's carried (the shopping driver puts it down in `game_shopStart`). +- The chat with Kurti waits till the three friends sit (or stand with the others) - the slowest (Volkram, the driver) was still walking up when it started and was left standing. +- Checked: Jana and Volkram stepped over and sat facing the table, one each side; the start: all four at the foot of the path in 25 s, his three lines, then the tent spot marked; at the fire everybody sat before the chat (You, Toni, Kurti / Volkram, Jana, Martin / Jonas); hard rain: Volkram and Jana at the beer tables. + ## Open tasks Most important first. @@ -1432,4 +1450,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.41.0 (build 6232605)` +State of `entropie 2.42.0 (build e597e7a)` diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt index fbd34bf..0aab3e9 100644 --- a/entropie/commit_message.txt +++ b/entropie/commit_message.txt @@ -1,17 +1,12 @@ -entropie 2.41.0: materials and money, the start shows the way, pavilions, GPU rests +entropie 2.42.0: pavilions by the house, beer table sitting, Kurti shows you all the way -- Cash box (1200 EUR, saved, on the F2 projects page) -- Building material: bundles of boards, nails, screws, paint (OBJ_MATERIAL). - Stage steps need it lying by them: deck and roof boards plus nails or - screws, decoration paint; used up when the step is done -- Shopping run: ask whoever has the car keys (Volkram), pick the list; he - drives off and comes back an hour later, the crew unloads (material to a - store in front of the car room, food into the kitchen) -- Food runs out now (food crate 40 portions, cool box 24 sausages) -- Crew fetches material from the store to a stage that waits for it -- Arrival: a golden marker over Kurti, the car, Kurti again; Kurti walks - you to your camping spot, then the marker shows your tent spot -- Yard: the roof on posts replaced by two party pavilions with beer table sets -- Kartoffelacker moved behind the road to the chicken farm, a strip of wood - right of it -- GPU: vsync plus a 60 fps frame cap (it ran flat out before) +- Pavilions turned 90 degrees and moved in front of the main building's + right half, left of its porch +- Beer benches: you step over the bench and sit facing the table (turned + away from it: back to the table as before); the others always face it +- Benches have evenly spaced places, so a third person always fits +- People no longer slide along the ground while seated when they set off + (Kurti showing the way, project work, sharing an umbrella) +- Kurti calls everybody to the end of the garages by the barn, points up + the path and explains the rest; then the marker shows your tent spot +- The chat at the fire waits until everybody has sat down diff --git a/entropie/src/game/game.h b/entropie/src/game/game.h index e7d2054..ece0ad4 100644 --- a/entropie/src/game/game.h +++ b/entropie/src/game/game.h @@ -31,7 +31,9 @@ typedef struct { float chat_wait; /* ... since the hello */ int welcome; /* Kurti and his sons welcoming you at the fire: lines said so far ... */ float welcome_t; /* ... until the next */ - int guide; /* Kurti showing you where to camp: 0 not yet, 1 on the way, 2 shown */ + int guide; /* Kurti showing you all where to camp: 0 not yet, 1 on the way and telling, 2 shown ... */ + int guide_line; /* ... his lines said so far ... */ + float guide_t; /* ... since the last (or waiting for the others) */ } Arrival; /* A shopping run (game_shop.c): over to the car, out along the way in, away, back, parked, the boot open. */ diff --git a/entropie/src/game/game_arrival.c b/entropie/src/game/game_arrival.c index d3541b8..241f52e 100644 --- a/entropie/src/game/game_arrival.c +++ b/entropie/src/game/game_arrival.c @@ -159,8 +159,10 @@ static void welcome(Game *game, float dt) { /* ---------- Kurti shows you where to camp ---------- */ -#define GUIDE_NEAR 4.0f /* m: by Kurti with your things, he takes you there */ -#define GUIDE_THERE 6.0f /* m: you by him (he's there): shown */ +#define GUIDE_NEAR 4.0f /* m: by Kurti with your things, he calls everybody over */ +#define GATHER_NEAR 5.5f /* m from where he stands: there */ +#define GATHER_WAIT 45.0f /* s he waits there for the others (then he starts anyway) */ +#define GUIDE_LINE 3.8f /* s between his lines */ #define MARK_ABOVE 0.75f /* m: the marker over a head */ static bool carrying(const Object *p) { @@ -175,34 +177,74 @@ static bool yourThingsOut(const Game *game) { return true; } -static void guide(Game *game) { +static void sendTo(Object *o, Vec3 to, Object *with) { + if (Ai_isHelping(o)) Ai_stopHelping(o); + o->ai.mode = AI_IDLE; + o->ai.errand = true; + o->ai.errand_there = false; + o->ai.errand_to = to; + o->ai.errand_with = with; +} + +static float flatGap(const Object *a, Vec3 b) { return hypotf(a->position.x - b.x, a->position.z - b.z); } + +/* Everybody to the foot of the path up behind your garages: Kurti shows the way up, says the rest. */ +static void guide(Game *game, float dt) { + static const char *const SHOW[] = { + "All here? Up this path - the meadow behind the garages is yours for the tents.", + "Pitch them where you like up there. The trees and bushes stay, mind.", + "Toilet's in the house, water in the kitchen. Make yourselves at home!", + }; + const int lines = (int)(sizeof SHOW / sizeof SHOW[0]); Arrival *a = &game->arrival; if (a->task != TASK_UNLOAD || a->guide >= 2) return; Object *kurti = person(game, "Kurti"), *p = game->player; if (!kurti) { a->guide = 2; return; } - Vec3 spot = Site_campSpot(0); + Vec3 foot = Site_campPath(), up = vec3_scale(Car_campDoor(), -1.0f), side = vec3(-up.z, 0.0f, up.x); if (a->guide == 0) { if (!carrying(p) && !yourThingsOut(game)) return; - if (hypotf(kurti->position.x - p->position.x, kurti->position.z - p->position.z) > GUIDE_NEAR || p->riding) return; - Ai_say(kurti, "Got your things? Come with me - I'll show you where you can camp."); + if (flatGap(kurti, p->position) > GUIDE_NEAR || p->riding) return; + Ai_say(kurti, "Got your things? Everybody, come along - I'll show you where you camp!"); a->guide = 1; - say(game, "Follow Kurti - he shows you where you can camp"); + a->guide_line = 0; + a->guide_t = 0.0f; + say(game, "Follow Kurti - he shows you all where you can camp"); + } + /* (off they go - again after loading): Kurti to the foot of the path, the others round him */ + if (!kurti->ai.errand) sendTo(kurti, foot, p); + for (int k = 0; k < 3; k++) { + Object *o = person(game, FRIENDS[k]); + if (!o || o->ai.errand || o->riding) continue; + sendTo(o, vec3_add(foot, vec3_add(vec3_scale(up, -2.2f), vec3_scale(side, 1.4f * (float)(k - 1)))), NULL); } - if (!kurti->ai.errand) { /* (off he goes - again after loading) */ - if (Ai_isHelping(kurti)) Ai_stopHelping(kurti); - kurti->ai.mode = AI_IDLE; - kurti->ai.errand = true; - kurti->ai.errand_there = false; - kurti->ai.errand_to = vec3_add(spot, vec3_scale(Car_campDoor(), CAMP_BEDS_OUT + 1.5f)); /* (in front of where the tent's door will be) */ - kurti->ai.errand_with = p; + if (!kurti->ai.errand_there) return; + kurti->ai.errand_with = NULL; /* (there: no more looking back for you - up the path he looks, while he talks) */ + float yaw = atan2f(up.z, up.x) + PI_F / 2.0f, turn = remainderf(yaw - kurti->rotation.y, 2.0f * PI_F); + kurti->rotation.y += clampf(turn, -3.0f * dt, 3.0f * dt); + bool all = flatGap(p, foot) < GATHER_NEAR; + for (int k = 0; k < 3 && all; k++) { + Object *o = person(game, FRIENDS[k]); + if (o && !Body_isDown(&o->body) && flatGap(o, foot) > GATHER_NEAR) all = false; } - if (kurti->ai.errand_there && hypotf(kurti->position.x - p->position.x, kurti->position.z - p->position.z) < GUIDE_THERE) { - Ai_say(kurti, "Here - this is a good spot for your tent. The others go up next to you."); - kurti->ai.errand = false; - kurti->ai.errand_with = NULL; - a->guide = 2; - say(game, "Your tent goes here - put it down and hold left click on it to put it up"); + a->guide_t += dt; + if (a->guide_line == 0 && !all && a->guide_t < GATHER_WAIT) return; /* (waiting for the others) */ + if (a->guide_line > 0 && a->guide_t < GUIDE_LINE) return; + if (a->guide_line < lines) { + Ai_say(kurti, SHOW[a->guide_line]); + if (a->guide_line == 0) Body_talkGesture(&kurti->body, TALK_POINT); + a->guide_line++; + a->guide_t = 0.0f; + return; } + /* said: on with the day */ + kurti->ai.errand = false; + kurti->ai.errand_with = NULL; + for (int k = 0; k < 3; k++) { + Object *o = person(game, FRIENDS[k]); + if (o) o->ai.errand = false; + } + a->guide = 2; + say(game, "Up the path behind the garages: put your tent up on the meadow (hold left click on it)"); } /* Your tent: standing, or where it's to go up. */ @@ -250,7 +292,7 @@ void game_arrival(Game *game, float dt) { Arrival *a = &game->arrival; Object *car = a->car; hostsStay(game); - guide(game); + guide(game, dt); welcome(game, dt); chat(game, dt); settled(game); @@ -333,6 +375,10 @@ static void chat(Game *game, float dt) { a->chat_wait += dt; if (a->chat == 0) { bool sat = p->sitting && kurti && hypotf(kurti->position.x - p->position.x, kurti->position.z - p->position.z) < 5.0f; + for (int k = 0; k < 3 && sat; k++) { /* (and the others: sat down too, or standing with them - the last one isn't left out) */ + const Object *o = person(game, FRIENDS[k]); + if (o && !o->sitting && !o->ai.greet_stand) sat = false; + } if (!sat && a->chat_wait < CHAT_WAIT) return; a->welcome_t = 0.0f; } @@ -364,7 +410,7 @@ const char *game_task(Game *game) { case TASK_CHAT: return "To do: sit down with them (C) and have a chat"; case TASK_UNLOAD: if (a->guide == 0) return "To do: get your things from the car (left click at the boot), then over to Kurti - he shows you where to camp"; - if (a->guide == 1) return "To do: follow Kurti - he shows you where you can camp"; + if (a->guide == 1) return "To do: follow Kurti to the end of the garages - he shows you all where to camp"; return "To do: put your tent up (hold left click on it), help the others empty the car"; default: return NULL; } diff --git a/entropie/src/game/game_shop.c b/entropie/src/game/game_shop.c index d739627..12a813e 100644 --- a/entropie/src/game/game_shop.c +++ b/entropie/src/game/game_shop.c @@ -49,7 +49,9 @@ void game_shopStart(Game *game, Object *driver, const int list[SHOP_ITEMS]) { e->stage = ERRAND_TO_CAR; if (Ai_isHelping(driver)) Ai_stopHelping(driver); driver->ai.mode = AI_IDLE; + for (int h = 0; h < 2; h++) if (driver->hands.item[h] && driver->hands.state[h] == HAND_HOLDING) Hands_drop(driver, h); /* (hands free to drive) */ driver->ai.errand = true; + driver->ai.errand_with = NULL; driver->ai.errand_there = false; driver->ai.errand_to = Car_door(car, 0); game->world.shopping = true; diff --git a/entropie/src/people/ai.c b/entropie/src/people/ai.c index e712660..43569b0 100644 --- a/entropie/src/people/ai.c +++ b/entropie/src/people/ai.c @@ -2117,7 +2117,7 @@ static bool walkUnder(Object *self, Object *const *objects, int count, float dt) } h->umbrella_guest = self; h->umbrella_guest_t = 0.5f; - if (self->sitting) stand(self); + if (self->sitting) self->sitting = false; /* (up first) */ Vec3 facing = Object_facing(h), right = vec3_normalize(vec3_cross(facing, UP)); float side = h->hands.item[1] == u ? 1.0f : -1.0f; /* (the umbrella between them) */ Vec3 spot = vec3_add(h->position, vec3_add(vec3_scale(right, side * SHARE_GAP * h->look.height / 1.75f), vec3_scale(facing, -0.05f))); @@ -2187,7 +2187,8 @@ static bool rainRoom(Object *self, Object *const *objects, int count, float dt) 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); + Vec3 axis = seat->colliders[0].axes[0], front = seat->table ? vec3_sub(seat->position, seat->table->position) /* (a beer bench: from behind it, over it) */ + : 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); diff --git a/entropie/src/people/ai_project.c b/entropie/src/people/ai_project.c index 1066a56..a9987da 100644 --- a/entropie/src/people/ai_project.c +++ b/entropie/src/people/ai_project.c @@ -192,9 +192,8 @@ static bool fetchMaterial(Object *self, Object *stage, Object *const *objects, i bool ai_errand(Object *self, Object *const *objects, int count, float dt) { Ai *ai = &self->ai; if (!ai->errand) return false; - if (self->sitting) stand(self); + if (self->sitting) self->sitting = false; /* (up first) */ self->indoors = 0.0f; - for (int h = 0; h < 2; h++) if (self->hands.item[h] && self->hands.state[h] == HAND_HOLDING && !ai->errand_with) Hands_drop(self, h); const Object *w = ai->errand_with; if (w && !ai->errand_there && flatDistance(w->position, self->position) > GUIDE_WAIT) { /* (they're coming? waiting, looking back) */ stand(self); @@ -248,7 +247,7 @@ bool ai_projectWork(Object *self, Object *const *objects, int count, float dt) { } } if ((ai->shift += gdt) > SHIFT) return stop(self, lead ? "Break! Back in a bit." : NULL); - if (self->sitting) stand(self); + if (self->sitting) self->sitting = false; /* (up first) */ if (fetchMaterial(self, stage, objects, count, dt)) return true; freeHands(self, NULL); float side = ai->side != 0.0f ? ai->side * 0.8f : (lead ? 0.0f : 0.6f); diff --git a/entropie/src/world/manor.c b/entropie/src/world/manor.c index d3c89b4..078ad1e 100644 --- a/entropie/src/world/manor.c +++ b/entropie/src/world/manor.c @@ -513,6 +513,7 @@ bool Shelter_build(World *world, Vec3 origin, float yaw) { for (int s = -1; s <= 1; s += 2) { Object *bench = Object_createFurniture(FURN_BENCH, toWorld(p, vec3(x, 0.0f, (float)s * 0.62f)), vec3(2.2f, SEAT_HEIGHT, 0.25f), yaw); if (!bench || !World_add(world, bench)) return false; + bench->table = table; } } return p->ok; diff --git a/entropie/src/world/object.c b/entropie/src/world/object.c index 989339e..cfc16c5 100644 --- a/entropie/src/world/object.c +++ b/entropie/src/world/object.c @@ -832,17 +832,29 @@ void Object_seePeople(Object *const *objects, int count) { g_people = objects; g /* Where along a bench or log (from its middle, axis along it) somebody can sit nearest to `want`, clear of everybody already on it; NAN: full. */ +static bool clearAt(const Object *who, const Object *seat, Vec3 c, Vec3 axis, float cand) { + for (int i = 0; i < g_people_n; i++) { + const Object *o = g_people[i]; + if (o == who || !o->is_character || o->seat != seat || !o->sitting) continue; + if (fabsf(vec3_dot(vec3_sub(o->sit_at, c), axis) - cand) < SEAT_SPACE - 0.06f) return false; /* (a little give: moved up exactly that far) */ + } + return true; +} + static float freeAlong(const Object *who, const Object *seat, Vec3 c, Vec3 axis, float want, float half) { + if (seat->type == OBJ_FURNITURE) { /* a bench: its places, evenly along it (sat anywhere, a third didn't fit) - the free one nearest */ + int n = (int)(2.0f * half / SEAT_SPACE) + 1; + float gap = n > 1 ? 2.0f * half / (float)(n - 1) : 0.0f, best = NAN; + for (int k = 0; k < n; k++) { + float cand = n > 1 ? -half + gap * (float)k : 0.0f; + if (clearAt(who, seat, c, axis, cand) && (isnan(best) || fabsf(cand - want) < fabsf(best - want))) best = cand; + } + if (!isnan(best)) return best; + } for (int k = 0; k <= 2 * (int)(half / 0.1f) + 2; k++) { float cand = want + 0.1f * (float)((k + 1) / 2) * (k % 2 ? 1.0f : -1.0f); if (cand < -half || cand > half) continue; - bool clear = true; - for (int i = 0; i < g_people_n && clear; i++) { - const Object *o = g_people[i]; - if (o == who || !o->is_character || o->seat != seat || !o->sitting) continue; - clear = fabsf(vec3_dot(vec3_sub(o->sit_at, c), axis) - cand) >= SEAT_SPACE - 0.06f; /* (a little give: moved up exactly that far) */ - } - if (clear) return cand; + if (clearAt(who, seat, c, axis, cand)) return cand; } return NAN; } @@ -993,6 +1005,14 @@ bool Object_sit(Object *who, Object *seat, Vec3 toward) { return true; } if (seat->variant == FURN_CHAIR && seatTaken(who, seat)) return noRoom(who); + bool over = false; /* a beer bench: at its table, stepped over it (the others always; you walking up to it, not turned away) */ + if (seat->variant == FURN_BENCH && seat->table) { + Vec3 to_seat = vec3(seat->position.x - who->position.x, 0.0f, seat->position.z - who->position.z); + Vec3 to_table = vec3(seat->table->position.x - who->position.x, 0.0f, seat->table->position.z - who->position.z); + bool beyond = vec3_length(to_table) > vec3_length(to_seat); /* (we're on the far side of the bench from the table) */ + bool facing = vec3_length(to_seat) < 1e-3f || vec3_dot(Object_facing(who), vec3_normalize(to_seat)) > -0.2f; + if (who->type != OBJ_PLAYER || facing) { toward = seat->table->position; over = beyond; } + } Vec3 n = seat->colliders[0].axes[2]; /* across the seat */ Vec3 to = vec3_sub(toward, seat->position); if (seat->variant == FURN_CHAIR || vec3_dot(n, to) < 0.0f) n = seat->variant == FURN_CHAIR ? n : vec3_scale(n, -1.0f); @@ -1020,7 +1040,7 @@ bool Object_sit(Object *who, Object *seat, Vec3 toward) { who->sit_yaw = atan2f(n.z, n.x) + PI_F / 2.0f; /* facing n */ who->sit_dir = n; who->sit_moving = true; - who->sit_backing = false; + who->sit_backing = over; /* (over the bench: straight to the spot, no turning round in front of it) */ who->velocity = vec3_zero(); who->sit_style = SIT_SEAT; who->body.seat_height = SEAT_HEIGHT; @@ -1481,6 +1501,7 @@ void Object_describe(const Object *obj, char *out, size_t size) { }; if (obj->variant == FURN_ASHTRAY) { snprintf(out, size, "Ashtray (an old tin) - %d butts in it", obj->stored); break; } if (obj->variant == FURN_SMOKES) { snprintf(out, size, "Cigarette machine - click: a pack of %d", SMOKES_PACKS); break; } + if (obj->variant == FURN_BENCH && obj->table) { snprintf(out, size, "Beer bench - C: over it and sit at the table (turned away: your back to it)"); break; } snprintf(out, size, "%s", obj->variant >= 0 && obj->variant < FURN_COUNT && WHAT[obj->variant] ? WHAT[obj->variant] : "Furniture"); break; } diff --git a/entropie/src/world/object.h b/entropie/src/world/object.h index b2c777c..759eac6 100644 --- a/entropie/src/world/object.h +++ b/entropie/src/world/object.h @@ -313,6 +313,7 @@ typedef struct Object { int build_stage; /* a stage (OBJ_STAGE): how far it's built (BuildStage) ... */ float build_work; /* ... person-hours of work into the next bit */ int stock; /* a bought food box (OBJ_SUPPLY): portions left (-1: empty); 0: never runs out (the scene's) */ + struct Object *table; /* a bench of a beer table set: its table (sat at facing it, stepped over) */ float commitment; /* people: 0..1 how much they're into their part of the festival */ int leads, helps; /* people: the Project they lead, one they help with (world/cast.h; PROJECT_NONE 0) */ struct { /* dogs */ diff --git a/entropie/src/world/site.c b/entropie/src/world/site.c index b07e61a..9d30cf0 100644 --- a/entropie/src/world/site.c +++ b/entropie/src/world/site.c @@ -315,8 +315,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 pavilions: two side by side, beer tables under them, by the fire towards the barn */ -#define SHELTER_B 3.5f +#define SHELTER_A 10.2f /* the pavilions: two side by side, beer tables under them, in front of the main building's */ +#define SHELTER_B 3.8f /* right half, left of its porch (in a row along the front) */ #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 */ @@ -1111,7 +1111,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))) || + !Shelter_build(world, court(SHELTER_A, SHELTER_B), yaw_along(mapDir(COURT_ANGLE - 90.0f))) || !furnishGarages(world, walled, wyaw, zsign) || !hangGates(world, walled, wyaw, zsign)) return false; if (!buildGarages(world) || !plantOrchard(world) || !plantMeadows(world) || !furnishYard(world)) return false; @@ -1282,6 +1282,8 @@ static const struct { Project project; float a, b, front; } FLOORS[] = { { PROJECT_HIDDEN, -20.0f, -2.0f, 1.0f }, /* behind the main building, facing its back */ }; +Vec3 Site_campPath(void) { return court(36.0f, -11.0f); } /* (the foot of the path up behind your garages: their end by the barn) */ + Vec3 Site_floorSpot(int project) { for (int k = 0; k < COUNT(FLOORS); k++) if ((int)FLOORS[k].project == project) return court(FLOORS[k].a, FLOORS[k].b); diff --git a/entropie/src/world/site.h b/entropie/src/world/site.h index ac9b991..1c799f5 100644 --- a/entropie/src/world/site.h +++ b/entropie/src/world/site.h @@ -33,6 +33,8 @@ Vec3 Site_materialSpot(void); Vec3 Site_rainRoom(void); /* Where a floor's stage stands (the floors: world/stage.h). */ Vec3 Site_floorSpot(int project); +/* The foot of the path up to the tents' meadow (the end of your garages by the barn). */ +Vec3 Site_campPath(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);