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 1.80.0: ashtray, the Urinella shown, things back in the hand
- An old tin by the fire as ashtray: you and the tidy put butts in there - The Urinella is drawn while it's used; the dress is lifted higher - After peeing you take up again what you put down - The others can slip off a wobbly ladder too Includes 1.79.0 (if not committed separately): - Helpers (G) follow you up a leaning ladder onto a roof or wall and down again; without a ladder they pull themselves up after you (if they reach) and jump down when you're down - Pulling up is a module for anybody now (people/climb.c), not only you Includes 1.78.0 (if not committed separately): - Cold nights: away from the fire a jacket goes on (each their own colour) - Working hard in the midday sun your shirt comes off too - Women who never tried a Urinella may try one: some like it, some don't - Dying for a smoke makes restless; a wobbling ladder rocks - Moving heavy wood: tested with a called helper; the player is asked when nobody else is around Includes 1.77.0 (if not committed separately): - Ladders: carried nearly upright when out; stood up on their own they fall over; leaned, how steady they stand depends on angle, ground, feet and what holds them; a wobbly one wobbles, then slips and falls with you - Somebody holds it (hands on the rails, a foot on the bottom rung): helpers (G) when you climb, helpful people when it looks wobbly - The work place: the tidy clear away what lies where they'd stand; no room to swing, they take the piece somewhere with room (carried, or dragged with somebody called to help) - The sporty pull up and climb ladders much quicker Includes 1.76.0 (if not committed separately): - Smoking: packs and tobacco in the pockets (used up); smokers get a craving and light up in a quiet moment - rolling one first, the lighter to it, drags (the tip glows), smoke breathed out, the butt flicked away - Shared: "Got a light?", bumming a cigarette (or a no); talk to ask for one or offer one; K lights yours / puts it out; Tab shows your pockets - Shadows: soft, smooth edges instead of stair steps Includes 1.75.0 (if not committed separately): - Urinellas: one-time use, up to 4 in the pocket; a box by the toilet refills it (the others fetch more when they run out, you click it) - Peeing: what's in the hands is put down first (the others take it up again); standing, the fly is open or the skirt or dress lifted - Lighter: needed to light the fire, runs empty; borrowed when there's none, given back (or not), owners ask for it; talk: borrow, give back, ask for yours back - Working hard in the midday sun the shirt comes off (women keep a top) - Dropping from high up: knees pulled up, legs reach for the ground, deep into the knees, a roll or a crash - Ladders: one-handed climbing (you may slip), a lying ladder is stepped over, kicked it hardly moves and your toe hurts - Dev menu: teleport to the parkour / yard; the player spawns 1 m up Includes 1.74.0 (if not committed separately): - Fix: legs showed through a skirt or dress standing normally; the thighs under it are cloth now and it's wider over the hips - Mila's Urinellas come in a pack of 3 (then she squats); now and then a mishap (on the shoes); used ones go into the bag, are dropped or flung away (drunk) as trash Includes 1.73.0 (if not committed separately): - Clothes: trousers, shorts, skirt, dress; squatting to pee trousers come down, a skirt or dress is gathered up Includes 1.72.0 (if not committed separately): - Fix: walking off the other way from something half stepped over left one foot planted behind, sliding along Includes 1.71.0 (if not committed separately): - Two-handed fidgets: rubbing the hands, hands behind the head, both hands on the hips Includes 1.70.0 (if not committed separately): - More one-hand gestures (neck, nose, ear, hair, thumb in the belt, hand on the chest, shading the eyes); mood and personal habits pick them Includes 1.69.0 (if not committed separately): - Faster with a crowd: 750 people 22 -> 14 ms a frame (kind index, cell grid for company, no foot checks far from you) Includes 1.68.0 (if not committed separately): - The walking map is updated in place when fixed things change (0.3 ms instead of 10 ms) Includes 1.67.0 (if not committed separately): - Pour your drink on the fire (C): a small fire goes out, a big one hisses, vodka flares up Includes 1.66.0 (if not committed separately): - Careful people sort the woodpile by length (front even) and put the branches lying about onto a heap at the end of the woodpile Includes 1.65.0 (if not committed separately): - Smooth off the ladder (a step back, one foot after the other) and taking it down (the hand reaches for the rail at chest height) Includes 1.64.0 (if not committed separately): - Smooth ladder and climbs: getting on, over the edge at the top, feet from where they are; the easy 1 m climb no longer drops you off again Includes 1.63.0 (if not committed separately): - The hose melts in the fire (leaks, burns through); duct tape and the shears mend it Includes 1.62.0 (if not committed separately): - Smooth pull-ups: no hop at the end, feet and knees ease over the edge, elbows and hands taking hold blend in (audit walk: joint jumps 161 -> 58) Includes 1.61.0 (if not committed separately): - A step ladder in the tool room: stands on its own, at a wall with its back to it; climb onto the wall from its top Includes 1.60.0 (if not committed separately): - A folding ladder (two 2.5 m halves on a hinge, 5 m open) beside the telescopic one; one click at a wall unfolds it and leans it there Includes 1.59.0 (if not committed separately): - Stepping up onto blocks above knee high; set moves and jumps only for things standing on the ground in front of you Includes 1.58.0 (if not committed separately): - Walking over knee-high things is one smooth set move that always finishes; at a run: jump up onto blocks, catch climbable edges
entropie/Makefile | 2 +- entropie/README.md | 8 +++++--- entropie/STATE.md | 10 ++++++---- entropie/assets/shaders/figure.frag | 15 ++++++++++----- entropie/commit_message.txt | 8 +++++++- entropie/src/game/game_actions.c | 11 +++++++++-- entropie/src/people/ai_help.c | 18 ++++++++++++++++++ entropie/src/people/body.h | 1 + entropie/src/people/body_pose.c | 9 +++++++++ entropie/src/render/figure.h | 2 ++ entropie/src/render/renderer.c | 6 ++++++ entropie/src/render/renderer.h | 2 +- entropie/src/render/shapes.h | 2 +- entropie/src/render/shapes_props.c | 10 ++++++++++ entropie/src/world/object.c | 1 + entropie/src/world/site.c | 4 ++++ entropie/src/world/world.c | 10 +++++++++- 17 files changed, 100 insertions(+), 19 deletions(-) diff --git a/entropie/Makefile b/entropie/Makefile index 5484ab5..cfd249d 100644 --- a/entropie/Makefile +++ b/entropie/Makefile @@ -1,5 +1,5 @@ APP := entropie -VERSION := 1.79.0 +VERSION := 1.80.0 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin diff --git a/entropie/README.md b/entropie/README.md index 224e40e..8910365 100644 --- a/entropie/README.md +++ b/entropie/README.md @@ -359,6 +359,7 @@ A hand that can't reach its grip lets go and takes hold again. - Somebody holding it (hands on the rails, a foot on the bottom rung) keeps it steady: helpers (G) hold it when you climb, helpful people come over on their own when it looks wobbly +- The others can slip off a wobbly ladder too - Helpers follow you up a leaning ladder onto a roof or wall and down again; without a ladder they pull themselves up after you (if they reach) and jump down when you're down @@ -442,7 +443,8 @@ say no more often and don't come to you for a bit. then the lighter to it - theirs, or "Got a light?" from somebody near - A drag now and then (the tip glows), smoke breathed out, the hand up in front between drags. Hands needed: it goes into the mouth -- Done: flicked away or dropped as a butt (into the fire when close) +- Done: flicked away or dropped as a butt (into the fire when close; the + tidy and you use the old tin by the fire as ashtray) - 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 @@ -466,8 +468,8 @@ say no more often and don't come to you for a bit. or dress is gathered up; standing, the fly is open or the skirt lifted - Women who never tried a Urinella may try one from the box: some like it, some say "not for me" and squat again -- Before peeing, what's in the hands is put down beside you (the others - take it up again after) +- Before peeing, what's in the hands is put down beside you, and taken up + again after (you too). The Urinella shows while it's used A used Urinella goes into the bag (tidy), is dropped (careless) or flung away (drunk); now and then it ends up on the shoes - Clothes: trousers, shorts (Jonas), a skirt (Ida) or a dress (Mila) diff --git a/entropie/STATE.md b/entropie/STATE.md index a6d7020..2e54e50 100644 --- a/entropie/STATE.md +++ b/entropie/STATE.md @@ -68,6 +68,8 @@ Shadows: 3x3 PCF with each tap blended bilinearly between its 4 texels (`common. Climbing for anybody (`people/climb.c`, moved out of the game): `Climb_ledgeAhead`, `Climb_start` (says why not: hands, strength, drunk), `Climb_update` (the pull up, its feet and hands), `Climb_overLadderTop`; the move lives in the person (`climb_move`). Helpers (`ai_help.c` ai_followByLadder): the leader 1.2 m higher (standing, not climbing): a leaning ladder within 25 m from their level to the leader's (top within 1.3 m) - to its foot, up (`ai_climbing`: on a ladder or pulling over its top this runs first, whatever the mode), over the edge; none, and the leader within reach (CLIMB_REACH): walk at it and pull up where the edge ahead is at the leader's level ("Hup!"). The leader 1.2 m lower: to the top of a ladder from up there and down it; none: they just walk off (the landing does the rest). A ladder leading nowhere (no top to get off at): down again after 8 s. `Ai_useWorld` gives the AI the world for this. +Ashtray (FURN_ASHTRAY, an old tin by the fire, `stored` = butts): a finished cigarette within 4 m of it goes in if it's yours or the smoker is tidy (likes trash over 0.2 or pride over 0.4, under 0.6 drunk). The Urinella is drawn while it's used (skeleton `uri`, a funnel from the body to the spout; the stream starts at its end); standing with one, a skirt or dress is lifted higher in front. You take up again what you put down to pee (`ai.set_aside`, within 1.8 m). The others slip off wobbly ladders like you (`ai_climbing`: wobble, then the ladder falls sideways). + Night clothes (`world.c` dressForNight): `chill` 0..1 grows 1/60 s at night (21:00-7:00) away from a burning fire (drunk: slower), falls by a fire (1/60 s) or in the day (2/60 s); over 0.6 the jacket (`look.top` TOP_JACKET, colour per person: `Figure_wardrobe`) goes on, under 0.15 off. Drawn a bit bulkier, long sleeves, a zip and a darker collar. The sun logic only takes off / puts on the shirt, never the jacket. You too (`game.c` sunShirt: working = a stroke in the last 3 s). Urinella, trying: a woman who never had one (`urinella_tried` 0), bladder 0.35-0.65, chance 0.1 + 0.2 energy per think: fetches some from the box (30 m). The first one used decides: like = 0.6 - 0.3 shyness - 0.2 (pride over 0.5) + 0.2 energy; not liked: back to squatting ("not for me"). Craving: dying for a smoke (0.8-1) adds up to 0.5 x smoker to the nerves shown. A wobble rocks the ladder (`shake`, 1.2 s). A heavy piece to drag and nobody to call: the player is asked ("grab it with F"). @@ -186,9 +188,9 @@ 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; slipping for NPCs -- Smoking, still to do: buying more (a kiosk), an ashtray -- Peeing, still to do: a Urinella in the hand (not drawn); the player-woman picks up her things again herself +- 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); emptying the ashtray +- Peeing, still to do: the hands holding the Urinella (now at the belt) - "No shirt no service" policy (decision open) - Clothing, still to do: more outfits for extra people (they all wear trousers); fetching the jacket from somewhere @@ -199,4 +201,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.79.0 (build c478b41)` +State of `entropie 1.80.0 (build ef616ba)` diff --git a/entropie/assets/shaders/figure.frag b/entropie/assets/shaders/figure.frag index dd702d8..8c543cd 100644 --- a/entropie/assets/shaders/figure.frag +++ b/entropie/assets/shaders/figure.frag @@ -41,7 +41,9 @@ uniform float streamWidth; uniform int garment; // 0 trousers, 1 shorts, 2 skirt, 3 dress uniform float undress; // to pee: squatting trousers down / skirt up (0..1); standing fly open / skirt lifted in front (-1..0) uniform vec3 cigA, cigTip; // a cigarette (figure space): the end at the hand / lips, the burning end -uniform float cigGlow; // -1 none, 0 not lit .. 1 a drag +uniform float cigGlow; +uniform vec3 uriA, uriB; // a Urinella held to the body (figure space) +uniform bool uri; // -1 none, 0 not lit .. 1 a drag uniform int top; // 0 a shirt, 1 bare-chested, 2 just a top (shirt off in the sun), 3 a jacket (cold night) uniform mat4 viewProj; @@ -57,14 +59,14 @@ uniform float shadowStrength; uniform float boilTime; uniform sampler2D shadowMap; -const int M_SKIN = 0, M_HAIR = 1, M_SHIRT = 2, M_PANTS = 3, M_SHOES = 4, M_PEE = 5, M_SICK = 6, M_WATER = 7, M_CIG = 8, M_JACKET = 9; +const int M_SKIN = 0, M_HAIR = 1, M_SHIRT = 2, M_PANTS = 3, M_SHOES = 4, M_PEE = 5, M_SICK = 6, M_WATER = 7, M_CIG = 8, M_JACKET = 9, M_URINELLA = 10; const float FIGURE_LIGHT_WRAP = 0.6; // soft, flat faces instead of a hard light split const float SELF_SHADOW_SKIP = 0.10; // meters // ---------- Body parts ---------- -const int MAX_PARTS = 30; +const int MAX_PARTS = 31; vec3 partA[MAX_PARTS], partB[MAX_PARTS]; float partR1[MAX_PARTS], partR2[MAX_PARTS]; float partBlend[MAX_PARTS]; // smooth-union radius with the rest of the body @@ -119,8 +121,8 @@ void buildBody() { vec3 knees = 0.5 * (joints[J_KNEE_L] + joints[J_KNEE_R]); vec3 waistline = pelvis + spineDir * 0.07; float lift = max(-undress, 0.0); // (standing: gathered up in front, held at the hips) - vec3 hem = mix(knees + vec3(0.0, -0.06, 0.0), waistline, 0.6 * max(undress, 0.0) + 0.45 * lift) - + chestForward * 0.05 * lift; + vec3 hem = mix(knees + vec3(0.0, -0.06, 0.0), waistline, 0.6 * max(undress, 0.0) + 0.72 * lift) + + chestForward * 0.09 * lift; float wide = (0.5 * length(joints[J_KNEE_L] - joints[J_KNEE_R]) + 0.08) * (1.0 - 0.3 * lift); addPart(waistline, hem, 0.165, max(wide, 0.165), 0.03, 0.8, lower); // (over the hips and thighs, wider as the knees part) } @@ -154,6 +156,8 @@ void buildBody() { // A cigarette if (cigGlow >= 0.0) addPart(cigA, cigTip, 0.0045, 0.0042, 0.001, 1.0, M_CIG); + // A Urinella: a little funnel from the body to the spout + if (uri) addPart(uriA, uriB, 0.032, 0.009, 0.002, 1.0, M_URINELLA); // A stream down to the ground, thinning out (pee) or in clumps (sick) if (streamKind > 0) { @@ -313,6 +317,7 @@ vec3 materialColor(int mat) { if (mat == M_WATER) return vec3(0.78, 0.90, 0.96); if (mat == M_CIG) return vec3(0.96, 0.95, 0.92); if (mat == M_JACKET) return jacketColor; + if (mat == M_URINELLA) return vec3(0.55, 0.78, 0.92); return skinColor; } diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt index 29a0fce..efae13e 100644 --- a/entropie/commit_message.txt +++ b/entropie/commit_message.txt @@ -1,5 +1,11 @@ -entropie 1.79.0: helpers follow you up ladders and walls +entropie 1.80.0: ashtray, the Urinella shown, things back in the hand +- An old tin by the fire as ashtray: you and the tidy put butts in there +- The Urinella is drawn while it's used; the dress is lifted higher +- After peeing you take up again what you put down +- The others can slip off a wobbly ladder too + +Includes 1.79.0 (if not committed separately): - Helpers (G) follow you up a leaning ladder onto a roof or wall and down again; without a ladder they pull themselves up after you (if they reach) and jump down when you're down diff --git a/entropie/src/game/game_actions.c b/entropie/src/game/game_actions.c index 787e080..e90e0cd 100644 --- a/entropie/src/game/game_actions.c +++ b/entropie/src/game/game_actions.c @@ -809,6 +809,14 @@ void game_handleActions(Game *game, const Input *input) { game->click_action = CLICK_NONE; return; } + for (int k = 0; k < 2; k++) { /* done peeing: what you put down goes back into your hands */ + Object *item = p->ai.set_aside[k]; + if (!item) continue; + p->ai.set_aside[k] = NULL; + if (item->is_held || vec3_length(vec3_sub(item->position, p->position)) > 1.8f) continue; + int hand = p->hands.state[k] == HAND_FREE ? k : Hands_freeHand(p); + if (hand >= 0) Hands_pickUpObject(p, hand, item); + } /* E / Q while holding on to something: everybody holding it lifts it (or puts it down) */ if ((input->use_left || input->use_right) && Hands_isGrabbing(p)) { @@ -852,9 +860,8 @@ void game_handleActions(Game *game, const Input *input) { else if (toilet && toilet->dog.mode) say(game, "Occupied!"); else if (toilet) { Object_useToilet(p, toilet); say(game, "*in the toilet*"); } else { - Object *aside[2]; bool full = p->hands.item[HAND_LEFT] || p->hands.item[HAND_RIGHT]; - Hands_setAside(p, aside); /* (hands free: the dress up, the fly down) */ + Hands_setAside(p, p->ai.set_aside); /* (hands free: the dress up, the fly down; taken up again after) */ Body_pee(&p->body, Object_peeTime(p)); if (full) say(game, "You put your things down first"); } diff --git a/entropie/src/people/ai_help.c b/entropie/src/people/ai_help.c index 318c996..97ecc9c 100644 --- a/entropie/src/people/ai_help.c +++ b/entropie/src/people/ai_help.c @@ -648,6 +648,24 @@ bool ai_climbing(Object *self, float dt) { if (!l) return false; if (!l->leaning && l->placing <= 0.0f) { Ladder_getOff(self); return false; } /* (it fell: see Ladder_topple) */ if (ai->ladder_dir == 0.0f) ai->ladder_dir = -1.0f; + float steady = Ladder_steadiness(l); /* (an unsteady ladder may slip under them too: see the player's ladderSlips) */ + if (steady < 0.98f && self->ladder_off <= 0.0f && g_world) { + float risk = 0.9f * powf(1.0f - steady, 1.5f) * (0.3f + clampf(self->ladder_at / 3.0f, 0.0f, 1.0f)) * (1.0f + fminf(self->drunk, 1.0f)); + if (random01(ai) < risk * dt) { + if (l->ladder_wobble <= 0.0f) { l->ladder_wobble = 30.0f; l->shake = 1.2f; Ai_say(self, "Whoa! It's wobbling!"); } + else { + Vec3 across = vec3_cross(l->lean_normal, vec3(0.0f, 1.0f, 0.0f)); + Vec3 fall = vec3_scale(across, random01(ai) < 0.5f ? 1.0f : -1.0f); + float high = self->ladder_at; + Ladder_topple(g_world, l, fall); + self->velocity = vec3_add(vec3_scale(fall, 1.2f), vec3(0.0f, 0.5f, 0.0f)); + if (high > 0.6f) Body_fall(&self->body, fall); + Ai_say(self, "Aaah!"); + return false; + } + } + l->ladder_wobble = fmaxf(0.0f, l->ladder_wobble - dt); + } int r = Ladder_climb(self, ai->ladder_dir, dt); if (r == CLIMB_AT_EDGE && (!g_world || !Climb_overLadderTop(g_world, self, l))) ai->ladder_dir = -1.0f; /* (nothing up there: down again) */ if (ai->ladder_dir > 0.0f && l->lean_top <= 0.0f && r != CLIMB_AT_EDGE && self->ladder_at > 0.5f) { /* (no getting off at the top: down again) */ diff --git a/entropie/src/people/body.h b/entropie/src/people/body.h index 45cb148..d822a23 100644 --- a/entropie/src/people/body.h +++ b/entropie/src/people/body.h @@ -79,6 +79,7 @@ typedef struct { float crouch_goal; /* 0 = standing .. 1 = deep squat */ float sit_goal; /* 1 = sitting down (sit_style) */ bool squat_pee; /* squats down to pee (women, without a Urinella) */ + bool urinella_use; /* pees standing with a Urinella (it's drawn) */ float seat_height; /* SIT_SEAT: how high the seat is (unscaled... near enough) */ float stand_ahead; /* the feet stand this much further forward (unscaled): sitting down on a seat */ bool on_ladder; /* feet on the rungs (placed by world/ladder.c), not in the air */ diff --git a/entropie/src/people/body_pose.c b/entropie/src/people/body_pose.c index 2c0e43c..5f397f8 100644 --- a/entropie/src/people/body_pose.c +++ b/entropie/src/people/body_pose.c @@ -1013,6 +1013,7 @@ static void placeCigarette(const Body *b, float s, Skeleton *out) { static void solveStream(const Body *b, Vec3 facing, Skeleton *out, StreamArc *arc) { const float GRAVITY = 9.81f; out->stream_kind = STREAM_NONE; + out->uri = false; /* squatting to pee: trousers down, skirt or dress gathered up; standing (a man, a woman with a Urinella): the fly open, the skirt or dress lifted in front (negative). Eased with the pee. */ @@ -1044,6 +1045,12 @@ static void solveStream(const Body *b, Vec3 facing, Skeleton *out, StreamArc *ar down = -v * sinf(pitch); out->stream_kind = STREAM_PEE; out->stream_width = 0.009f + 0.003f * pee; + if (b->urinella_use) { /* held to the body, the spout out in front: the stream from its end */ + out->uri = true; + out->uri_a = vec3_add(j[JOINT_PELVIS], vec3(0.0f, -0.15f, 0.075f)); + out->uri_b = vec3_add(start, vec3_add(vec3_scale(dir, 0.05f), vec3(0.0f, 0.01f, 0.0f))); + start = vec3_add(out->uri_b, vec3_scale(dir, 0.01f)); + } } else if (heave > 0.2f) { start = vec3_add(j[JOINT_HEAD], vec3_sub(vec3_scale(out->head_forward, 0.09f), vec3_scale(out->head_up, 0.06f))); dir = vec3(out->head_forward.x, 0.0f, out->head_forward.z); @@ -1560,6 +1567,8 @@ void Body_solve(Body *b, Vec3 position, Vec3 facing, float height, float dt, Ske out->joints[i] = vec3_scale(out->joints[i], s); out->waist_bend = vec3_scale(out->waist_bend, s); for (int k = 0; k < 4; k++) out->stream[k] = vec3_scale(out->stream[k], s); + out->uri_a = vec3_scale(out->uri_a, s); + out->uri_b = vec3_scale(out->uri_b, s); out->stream_width *= s; landStream(b, position, facing, s, &arc, out); keepBodyOut(b, position, facing, s, dt, false, out); diff --git a/entropie/src/render/figure.h b/entropie/src/render/figure.h index 2a87254..dfc439f 100644 --- a/entropie/src/render/figure.h +++ b/entropie/src/render/figure.h @@ -70,6 +70,8 @@ typedef struct { Vec3 stream[4]; int stream_kind; /* STREAM_NONE / STREAM_PEE / STREAM_VOMIT */ float stream_width; /* meters */ + Vec3 uri_a, uri_b; /* a Urinella held to the body (figure space): the wide end, the spout ... */ + bool uri; /* ... shown */ Vec3 cig_a, cig_tip; /* a cigarette (figure space): the end at the hand / lips, the burning end ... */ float cig_glow; /* ... how it glows (-1: no cigarette, 0: not lit .. 1: a drag) */ float undress; /* to pee: squatting trousers down / skirt up (0..1); standing fly open / skirt lifted in front (-1..0) */ diff --git a/entropie/src/render/renderer.c b/entropie/src/render/renderer.c index 9b6282f..0c79144 100644 --- a/entropie/src/render/renderer.c +++ b/entropie/src/render/renderer.c @@ -100,6 +100,9 @@ static bool loadShaders(Renderer *r) { f->undress = glGetUniformLocation(f->program, "undress"); f->top = glGetUniformLocation(f->program, "top"); f->cig_a = glGetUniformLocation(f->program, "cigA"); + f->uri_a = glGetUniformLocation(f->program, "uriA"); + f->uri_b = glGetUniformLocation(f->program, "uriB"); + f->uri = glGetUniformLocation(f->program, "uri"); f->cig_tip = glGetUniformLocation(f->program, "cigTip"); f->cig_glow = glGetUniformLocation(f->program, "cigGlow"); f->view_pos = glGetUniformLocation(f->program, "viewPos"); @@ -521,6 +524,9 @@ void Renderer_drawFigure(Renderer *r, const FigurePose *pose) { glUniform1f(f->undress, sk->undress); glUniform1i(f->top, pose->look.top); setVec3(f->cig_a, sk->cig_a); + setVec3(f->uri_a, sk->uri_a); + setVec3(f->uri_b, sk->uri_b); + glUniform1i(f->uri, sk->uri ? 1 : 0); setVec3(f->cig_tip, sk->cig_tip); glUniform1f(f->cig_glow, sk->cig_glow); diff --git a/entropie/src/render/renderer.h b/entropie/src/render/renderer.h index 2f5d92e..9500ab0 100644 --- a/entropie/src/render/renderer.h +++ b/entropie/src/render/renderer.h @@ -68,7 +68,7 @@ typedef struct { GLint head_forward, head_up, chest_forward, waist_bend, face, expression; GLint stream, stream_kind, stream_width; GLint garment, undress, top; - GLint cig_a, cig_tip, cig_glow, jacket; + GLint cig_a, cig_tip, cig_glow, jacket, uri_a, uri_b, uri; GLint view_pos, light_dir, light_color, shadow_color, sky_top, sky_horizon; GLint shadow_strength, shadow_map, fire_light; } FigureShader; diff --git a/entropie/src/render/shapes.h b/entropie/src/render/shapes.h index 6333729..1a736d8 100644 --- a/entropie/src/render/shapes.h +++ b/entropie/src/render/shapes.h @@ -105,7 +105,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_COUNT + FURN_CHAIR, FURN_BENCH, FURN_CAR, FURN_TIRES, FURN_TOILET, FURN_TAP, FURN_ASHTRAY, FURN_COUNT } FurnitureKind; #define SEAT_HEIGHT 0.45f /* chairs and log benches */ diff --git a/entropie/src/render/shapes_props.c b/entropie/src/render/shapes_props.c index 697f8a5..98b9e92 100644 --- a/entropie/src/render/shapes_props.c +++ b/entropie/src/render/shapes_props.c @@ -785,6 +785,16 @@ 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_ASHTRAY: { /* an old tin can by the fire, a few butts sticking out */ + const Vec3 tin = { 0.62f, 0.62f, 0.60f }, filter = { 0.86f, 0.6f, 0.34f }; + shapes_addTube(&b, 0.0f, size.x * 0.5f, size.x * 0.48f, size.y, 10, tin, true); + addBlock(&b, vec3(0.0f, size.y * 0.98f, 0.0f), vec3(size.x * 0.8f, 0.006f, size.x * 0.8f), (Vec3){ 0.25f, 0.24f, 0.22f }); /* ash */ + for (int k = 0; k < 3; k++) { + float a = (float)k * 2.1f; + addBlock(&b, vec3(0.02f * cosf(a), size.y + 0.008f, 0.02f * sinf(a)), vec3(0.018f, 0.012f, 0.011f), filter); + } + break; + } case FURN_COUNT: break; } diff --git a/entropie/src/world/object.c b/entropie/src/world/object.c index f5c5109..e0dd5de 100644 --- a/entropie/src/world/object.c +++ b/entropie/src/world/object.c @@ -1009,6 +1009,7 @@ void Object_describe(const Object *obj, char *out, size_t size) { [FURN_CAR] = "An old car, up for repairs", [FURN_TIRES] = "Old tyres", [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; } 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 14f31b0..a502df6 100644 --- a/entropie/src/world/site.c +++ b/entropie/src/world/site.c @@ -844,6 +844,10 @@ static bool furnishYard(World *world) { vec3(1.8f, SEAT_HEIGHT, 0.36f), yawFor(tangent)); if (!bench || !World_add(world, bench)) return false; } + { /* an old tin as ashtray, between two benches */ + Object *tin = Object_createFurniture(FURN_ASHTRAY, court(FIRE_A - 2.3f, FIRE_B - 1.5f), vec3(0.1f, 0.12f, 0.1f), 0.0f); + if (!tin || !World_add(world, tin)) return false; + } for (int k = 0; k < 4; k++) { /* firewood quarters and dry branches */ Vec3 at_pos = court(FIRE_A + 2.3f, FIRE_B + 0.5f + 0.35f * (float)k); if (!addLoose(world, OBJ_FIREWOOD, PALETTE_WARM, at_pos, vec3(0.3f, 0.45f, 4.0f), 0.0f, diff --git a/entropie/src/world/world.c b/entropie/src/world/world.c index a6fcc09..d815bff 100644 --- a/entropie/src/world/world.c +++ b/entropie/src/world/world.c @@ -610,7 +610,14 @@ static void smoke(World *world, Object *o, Vec3 facing, float dt) { if (Body_takeButt(&o->body)) { Vec3 at = Figure_toWorld(o->position, facing, sk->cig_glow >= 0.0f ? sk->cig_tip : sk->joints[JOINT_HAND_R]); Object *fire = Camp_fireNear(world->objects, world->count, o->position, 3.0f, true); - if (!fire) { + Object *tray = NULL; /* (an ashtray near: the tidy and you put it in there) */ + bool tidy = o->type == OBJ_PLAYER || (o->type == OBJ_HUMAN && (o->ai.character.likes[ORDER_TRASH] > 0.2f || o->temperament.pride > 0.4f) && o->drunk < 0.6f); + for (int i = 0; i < world->count && tidy; i++) { + Object *t = world->objects[i]; + if (t->type == OBJ_FURNITURE && t->variant == FURN_ASHTRAY && vec3_length(vec3_sub(t->position, o->position)) < 4.0f) tray = t; + } + if (tray) tray->stored++; + else if (!fire) { Object *butt = Object_create(OBJ_TRASH, PALETTE_WARM, at, vec3(-1.0f, 0.0f, 0.0f), 0.005f); if (butt) { snprintf(butt->name, sizeof(butt->name), "Cigarette butt"); @@ -688,6 +695,7 @@ static void animateCharacter(World *world, Object *o, float dt) { o->body.sulk = o->ai.annoyed; o->body.sit_goal = o->sitting && !o->is_held && !settling ? 1.0f : 0.0f; /* cross-legged, or on a seat */ o->body.squat_pee = o->female && !(o->urinella && o->urinellas > 0) && !o->toilet; + o->body.urinella_use = o->female && !o->body.squat_pee && !o->toilet; o->body.sit_style = o->sit_style; BodyFrame frame = { .position = o->position,