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.0.0: a cigarette machine
- An old cigarette machine hangs on the main building, right of the door: click it for a pack of 20 (free for now: no money in the game yet) - Smokers who run out and get nothing from anyone near (you get asked first) walk over to the machine, get a pack and light up
entropie/Makefile | 2 +- entropie/README.md | 4 +++ entropie/STATE.md | 7 +++-- entropie/commit_message.txt | 12 ++++----- entropie/src/game/game_actions.c | 13 ++++++++- entropie/src/people/ai.c | 55 ++++++++++++++++++++++++++++++++++++-- entropie/src/people/ai.h | 3 +++ entropie/src/render/shapes.h | 3 ++- entropie/src/render/shapes_props.c | 17 ++++++++++++ entropie/src/world/object.c | 1 + entropie/src/world/site.c | 5 ++++ 11 files changed, 108 insertions(+), 14 deletions(-) diff --git a/entropie/Makefile b/entropie/Makefile index 52ec634..eb73309 100644 --- a/entropie/Makefile +++ b/entropie/Makefile @@ -1,5 +1,5 @@ APP := entropie -VERSION := 1.99.0 +VERSION := 2.0.0 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin diff --git a/entropie/README.md b/entropie/README.md index 2c19385..a427630 100644 --- a/entropie/README.md +++ b/entropie/README.md @@ -529,6 +529,10 @@ say no more often and don't come to you for a bit. - K: light one (yours, or somebody next to you gives you a light), K again puts it out. Talk: ask somebody for a cigarette, or offer one - Packs and tobacco run out; Tab (skills page) shows your pockets +- An old cigarette machine hangs on the main building, right of the door: + click it for a pack of 20 (there's no money in the game yet). Out of + smokes and nobody gives them one (you get asked first), the others walk + over and get a pack too ## Day and needs diff --git a/entropie/STATE.md b/entropie/STATE.md index 77ae157..27c8533 100644 --- a/entropie/STATE.md +++ b/entropie/STATE.md @@ -146,6 +146,9 @@ Round 1.99: - Breathing (`body_pose.c` solveStanding): `breath_phase` runs at the breathing rate (1.5 + 0.6 nerves + 3 exertion rad/s); it was sin(clock x rate), which raced through whole breaths whenever the rate changed (recovering after running: the shoulders twitched fast). - Catching breath (`body.c` fidgets): `puffed` = smoothstep(0.35, 0.75, exertion); fidgets come up to 4x sooner. New FIDGET_KNEES (bent over, `bentDown` = max(being sick, 0.85 x catchingBreath, eased 0.9 s), hands on the thighs above the knees; weight 4 puffed x (1.15 - fitness) - proud) and FIDGET_ON_HEAD (fingers laced on top of the head, elbows up, chest open; 3.5 puffed x (0.2 + fitness)); hands on the hips +2 puffed, a stretch +1.2 puffed x fitness. +Round 2.0: +- Cigarette machine (FURN_SMOKES, `shapes_props.c`: red box on the wall, packs behind glass, knobs, coin slot, tray): on the main building's front SMOKES_FROM_TAP 2.65 m along the wall from the tap, past the door (`site.c`). Player: click within 0.9 m -> SMOKES_PACKS 20 cigarettes (`game_actions.c` smokesMachine). NPCs (`ai.c`): out of smokes, nobody near or refused ("Buy your own"), or the player asked once already without anything coming (`asked_you`) -> `want_smokes` if idle / wandering / at a table and the machine within SMOKES_WALK 150 m ("Right, I'll get a pack from the machine."); `buySmokes`: there (goTo 0.6 m) a hand to it, +20, lights one soon; gives up after 120 s. Free for now. + 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); the coat rack (FURN_COATRACK, in your kitchen by the doors, garage coords 20.6 / 2.4) shows the jackets hanging on it (`Shapes_coatRack`, up to 6, a bitmask of whose in `shown`). `jacket_hung` (characters, true at the start): cold (chill 0.6+) and the jacket with them: on it goes (as before); hanging: NPCs `ai.want_jacket` -> `ai.c` fetchJacket (idle / wander: goTo the rack, on with it, "Ah, better."; gives up after 90 s or warm again); you are told once ("your jacket hangs on the rack in your garage") and click the rack (`game_actions.c` coatRack: on, or back onto it). Warm again: it comes off and stays with them. @@ -287,7 +290,7 @@ Most important first. **People** - The work place, still to do: other jobs than split / cut (felling room, trash); walking a heavy piece round tight corners - Ladders, still to do: a holder for a ladder standing free; NPCs taking a ladder somewhere for their own work -- Smoking, still to do: buying more (a kiosk) +- 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) @@ -298,4 +301,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 1.99.0 (build 39a2b19)` +State of `entropie 2.0.0 (build 20324f8)` diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt index 6c0ad47..b7df0a9 100644 --- a/entropie/commit_message.txt +++ b/entropie/commit_message.txt @@ -1,8 +1,6 @@ -entropie 1.99.0: catching breath, calm breathing +entropie 2.0.0: a cigarette machine -- Fixed: after running the shoulders twitched very fast (the breathing - sped through whole breaths whenever it slowed down again); breathing is - now calm, quicker only the more out of breath -- Out of breath and standing still, people catch it their own way: the - unfit bent over with the hands on the knees, the sporty hands on top of - the head or a light stretch, anyone hands on the hips +- An old cigarette machine hangs on the main building, right of the door: + click it for a pack of 20 (free for now: no money in the game yet) +- Smokers who run out and get nothing from anyone near (you get asked + first) walk over to the machine, get a pack and light up diff --git a/entropie/src/game/game_actions.c b/entropie/src/game/game_actions.c index 9223792..323477c 100644 --- a/entropie/src/game/game_actions.c +++ b/entropie/src/game/game_actions.c @@ -442,6 +442,17 @@ static bool swingGate(Game *game) { return true; } +/* At the cigarette machine: a pack. */ +static bool smokesMachine(Game *game) { + Object *m = furnitureNear(game, FURN_SMOKES, 0.9f); + if (!m) return false; + Object *p = game->player; + Hands_touch(p, vec3_add(Object_colliderCenter(m, 0), vec3(0.0f, 0.2f, 0.0f))); + p->cigarettes += SMOKES_PACKS; + say(game, "*clunk* - a pack of cigarettes from the machine"); + return true; +} + /* At the coat rack: your jacket off it and on, or off and onto it. */ static bool coatRack(Game *game) { Object *p = game->player; @@ -708,7 +719,7 @@ static int leftClick(Game *game) { Talk_showHere(&game->world, p, shown); return CLICK_NONE; } - if (mendHose(game) || useLadder(game) || tendFire(game) || throwAway(game) || coatRack(game) || swingGate(game)) return CLICK_NONE; + if (mendHose(game) || useLadder(game) || tendFire(game) || throwAway(game) || coatRack(game) || smokesMachine(game) || swingGate(game)) return CLICK_NONE; int watering = useWater(game); if (watering >= 0) return watering; if (bagTrash(game)) return CLICK_BAG; diff --git a/entropie/src/people/ai.c b/entropie/src/people/ai.c index d844454..3b9b894 100644 --- a/entropie/src/people/ai.c +++ b/entropie/src/people/ai.c @@ -1480,6 +1480,46 @@ static bool quietMoment(const Object *self) { return ai->mode == AI_WORK && (ai->resting || ai->order == ORDER_FIRE); } +#define SMOKES_WALK 150.0f /* m: the cigarette machine this near is worth the walk */ +#define SMOKES_GIVE_UP 120.0f + +static Object *smokesMachine(Object *const *objects, int count) { + for (int i = 0; i < count; i++) + if (objects[i]->type == OBJ_FURNITURE && objects[i]->variant == FURN_SMOKES) return objects[i]; + return NULL; +} + +/* None left and nobody gives one: off to the cigarette machine (when free to). */ +static void goForSmokes(Object *self, Object *const *objects, int count) { + Ai *ai = &self->ai; + Object *m = smokesMachine(objects, count); + if (ai->want_smokes || !m || flatDistance(m->position, self->position) > SMOKES_WALK) return; + if (ai->mode != AI_IDLE && ai->mode != AI_WANDER && ai->mode != AI_TABLE) return; /* (busy: later) */ + ai->want_smokes = true; + ai->smokes_time = 0.0f; + Ai_say(self, "Right, I'll get a pack from the machine."); +} + +/* At the machine: a pack, and back to whatever. */ +static bool buySmokes(Object *self, Object *const *objects, int count, float dt) { + Ai *ai = &self->ai; + if (!ai->want_smokes) return false; + Object *m = smokesMachine(objects, count); + if (!m || Pockets_hasSmoke(self) || (ai->smokes_time += dt) > SMOKES_GIVE_UP) { + ai->want_smokes = false; + return false; + } + self->sitting = false; + if (!goTo(self, m, objects, count, 0.6f, dt)) return true; + Hands_touch(self, vec3_add(Object_colliderCenter(m, 0), vec3(0.0f, 0.2f, 0.0f))); + self->cigarettes += SMOKES_PACKS; + ai->want_smokes = false; + self->smoke_ask = 1.0f; /* (and lights one in a moment) */ + if (random01(ai) < 0.5f) Ai_say(self, "*clunk* - there we go."); + rest(ai, 1.0f, 2.0f); + return true; +} + static void smokeBreak(Object *self, Object *const *objects, int count, float dt) { Ai *ai = &self->ai; if (self->smoker <= 0.0f) return; @@ -1494,19 +1534,28 @@ static void smokeBreak(Object *self, Object *const *objects, int count, float dt self->smoke_ask = 40.0f + 40.0f * random01(ai); if (!giver) { if (self->craving > 0.95f) Ai_say(self, "I could really use a smoke..."); + goForSmokes(self, objects, count); + return; + } + if (giver->type == OBJ_PLAYER) { + if (ai->asked_you) { goForSmokes(self, objects, count); ai->asked_you = false; return; } + Ai_say(self, "Hey - got a cigarette for me?"); + ai->asked_you = true; return; } - if (giver->type == OBJ_PLAYER) { Ai_say(self, "Hey - got a cigarette for me?"); return; } Ai_say(self, withName("Can I bum a cigarette, %s?", giver)); int has = giver->cigarettes + giver->tobacco; - if (giver->type == OBJ_HUMAN && (has < 3 || giver->ai.annoyed > 0.5f || random01(ai) > 0.4f + 0.6f * giver->ai.character.willing)) + if (giver->type == OBJ_HUMAN && (has < 3 || giver->ai.annoyed > 0.5f || random01(ai) > 0.4f + 0.6f * giver->ai.character.willing)) { Ai_say(giver, has < 3 ? "Sorry, those are my last ones." : "Buy your own for once."); + goForSmokes(self, objects, count); + } else if (Pockets_giveSmoke(giver, self)) { if (giver->type == OBJ_HUMAN) Ai_say(giver, giver->tobacco > 0 && giver->cigarettes == 0 ? "Here, I rolled you one." : "Sure, here."); self->smoke_ask = 2.0f; /* (and lights it in a moment) */ } return; } + ai->asked_you = false; /* (got some) */ Object *light = self->lighter && self->lighter_uses > 0 ? self : Pockets_lighterNear(self, objects, count, 4.0f); if (!light) { Ai_say(self, "Anyone got a light?"); @@ -1680,6 +1729,8 @@ void Ai_update(Object *self, Object *const *objects, int count, float dt) { if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER) && fetchJacket(self, objects, count, dt)) return; /* Warm again: the jacket back onto the rack */ if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER) && hangJacket(self, objects, count, dt)) return; + /* Out of cigarettes: to the machine */ + if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER || ai->mode == AI_TABLE) && buySmokes(self, objects, count, dt)) return; /* Tidy people pick things up on the way */ if ((ai->mode == AI_IDLE || ai->mode == AI_WANDER || (ai->mode == AI_HELP && !ai->pushing && !ai->copied) || ai->mode == AI_SUPPLY || ai->mode == AI_FETCH) && ai_tidyUp(self, objects, count, dt)) diff --git a/entropie/src/people/ai.h b/entropie/src/people/ai.h index 00a5518..a819e29 100644 --- a/entropie/src/people/ai.h +++ b/entropie/src/people/ai.h @@ -174,6 +174,9 @@ typedef struct { float tray_time; /* on the way to empty the ashtray this long */ bool want_jacket; /* cold, the jacket on the rack: off to get it */ bool hang_jacket; /* warm again, the jacket tied round the waist: back onto the rack with it */ + bool want_smokes; /* out of cigarettes, nobody gives one: off to the machine */ + float smokes_time; /* ... on the way this long */ + bool asked_you; /* asked the player for one (nothing came of it: the machine next time) */ float jacket_time; /* ... on the way this long */ bool tool_waiting; /* waiting for the player to put the axe down */ unsigned char banned; /* tools (1 << ToolKind) they were told to leave alone ... */ diff --git a/entropie/src/render/shapes.h b/entropie/src/render/shapes.h index fc8dfdc..81b7df2 100644 --- a/entropie/src/render/shapes.h +++ b/entropie/src/render/shapes.h @@ -113,7 +113,7 @@ Mesh Shapes_grill(void); typedef enum { FURN_WORKBENCH, FURN_TOOLWALL, FURN_SHELF, FURN_STOVE, FURN_COUNTER, FURN_TABLE, - FURN_CHAIR, FURN_BENCH, FURN_CAR, FURN_TIRES, FURN_TOILET, FURN_TAP, FURN_ASHTRAY, FURN_COATRACK, FURN_GATE, FURN_COUNT + FURN_CHAIR, FURN_BENCH, FURN_CAR, FURN_TIRES, FURN_TOILET, FURN_TAP, FURN_ASHTRAY, FURN_COATRACK, FURN_GATE, FURN_SMOKES, FURN_COUNT } FurnitureKind; #define SEAT_HEIGHT 0.45f /* chairs and log benches */ @@ -146,6 +146,7 @@ Mesh Shapes_tapeRoll(void); /* A watering can, centered, spout towards +Z. */ Mesh Shapes_wateringCan(void); #define TAP_HEIGHT 0.8f /* where the hose comes out of the tap */ +#define SMOKES_PACKS 20 /* a pack from the cigarette machine (FURN_SMOKES: on a wall, back at z = -hz) */ /* A telescopic ladder: rungs on tubes that slide into each other. Local +Y up along it from the feet (y = 0), rungs along X. extend 0 = slid together .. 1 = out. */ #define LADDER_RUNGS 20 diff --git a/entropie/src/render/shapes_props.c b/entropie/src/render/shapes_props.c index 39086bd..de7d0f7 100644 --- a/entropie/src/render/shapes_props.c +++ b/entropie/src/render/shapes_props.c @@ -860,6 +860,23 @@ Mesh Shapes_furniture(FurnitureKind kind, Vec3 size) { transformSince(&b, first, mat4_mul(mat4_translate(vec3(0.0f, 0.4f, -hz + 0.1f)), mat4_rotate_x(PI_F / 2.0f))); break; } + case FURN_SMOKES: { /* an old cigarette machine on the wall (back at z = -hz): a row of packs behind glass, pull knobs, the coin slot, the tray */ + const Vec3 body = { 0.66f, 0.13f, 0.12f }, cream = { 0.90f, 0.86f, 0.74f }, glass = { 0.30f, 0.38f, 0.44f }; + const float bottom = 0.95f, h = 0.78f, d = 0.22f, front = -hz + d; + addBlock(&b, vec3(0.0f, bottom + h * 0.5f, -hz + d * 0.5f), vec3(size.x, h, d), body); + addBlock(&b, vec3(0.0f, bottom + h - 0.06f, front + 0.005f), vec3(size.x - 0.06f, 0.07f, 0.01f), cream); /* the name plate */ + addBlock(&b, vec3(0.0f, bottom + h * 0.6f, front + 0.005f), vec3(size.x - 0.08f, 0.26f, 0.01f), glass); + static const Vec3 PACKS[] = { { 0.85f, 0.85f, 0.82f }, { 0.75f, 0.12f, 0.10f }, { 0.20f, 0.30f, 0.62f }, { 0.88f, 0.75f, 0.20f }, { 0.25f, 0.50f, 0.28f } }; + const int n = 5; + for (int k = 0; k < n; k++) { + float x = -size.x * 0.5f + 0.06f + (size.x - 0.12f) * ((float)k + 0.5f) / (float)n; + addBlock(&b, vec3(x, bottom + h * 0.6f, front + 0.012f), vec3(0.055f, 0.08f, 0.01f), PACKS[k]); /* a pack on show */ + addBlock(&b, vec3(x, bottom + h * 0.33f, front + 0.02f), vec3(0.05f, 0.025f, 0.04f), COLOR_STEEL); /* its knob */ + } + addBlock(&b, vec3(size.x * 0.32f, bottom + h * 0.16f, front + 0.008f), vec3(0.05f, 0.08f, 0.015f), COLOR_STEEL); /* coin slot */ + addBlock(&b, vec3(-size.x * 0.08f, bottom + 0.05f, front + 0.03f), vec3(size.x * 0.5f, 0.05f, 0.06f), COLOR_IRON); /* the tray */ + break; + } case FURN_ASHTRAY: buildAshtray(&b, size, 3); break; diff --git a/entropie/src/world/object.c b/entropie/src/world/object.c index f7019fc..1d2c750 100644 --- a/entropie/src/world/object.c +++ b/entropie/src/world/object.c @@ -1175,6 +1175,7 @@ void Object_describe(const Object *obj, char *out, size_t size) { [FURN_TOILET] = "Toilet - P to use it", [FURN_TAP] = "Tap - the garden hose; fill the watering can here", }; 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_COATRACK) { snprintf(out, size, "Coat rack - everybody's jacket hangs here (click: yours on or off)"); 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/site.c b/entropie/src/world/site.c index 4d44873..6837e5f 100644 --- a/entropie/src/world/site.c +++ b/entropie/src/world/site.c @@ -10,6 +10,7 @@ /* A point on the traced map, in pixels (x right, y down). */ typedef struct { float x, y; } Px; +#define SMOKES_FROM_TAP 2.65f /* m along the wall from the tap, past the door: the cigarette machine */ #define MAP_CENTER_X 400.0f #define MAP_CENTER_Y 385.0f #define COUNT(a) ((int)(sizeof(a) / sizeof((a)[0]))) @@ -990,6 +991,10 @@ bool Site_build(World *world) { const float across_yaw = yaw_along(mapDir(COURT_ANGLE - 90.0f)); Object *tap = Object_createFurniture(FURN_TAP, court(6.15f, -9.75f), vec3(0.3f, 1.0f, 0.3f), across_yaw); if (!tap || !World_add(world, tap)) return false; + /* An old cigarette machine on the wall further along */ + Vec3 tap_front = tap->colliders[0].axes[2], along_wall = vec3(-tap_front.z, 0.0f, tap_front.x); + Object *smokes = Object_createFurniture(FURN_SMOKES, vec3_add(tap->position, vec3_scale(along_wall, -SMOKES_FROM_TAP)), vec3(0.5f, 1.75f, 0.25f), across_yaw); + if (!smokes || !World_add(world, smokes)) return false; Object *hose = Object_create(OBJ_HOSE, PALETTE_WARM, vec3_add(court(7.0f, -9.4f), vec3(0.0f, 0.1f, 0.0f)), vec3_zero(), 0.6f); if (!hose) return false; hose->hose_tap = tap;