Nimbin[12]?Games / Entropie / entropie/src/world/injury.c

Entropie git · main

Entropie festival game; first steps

sdl c game entropie cmake · first commit 2026-10-10 · last commit 2026-11-02 (18 hours ago) · synced 10 hours ago

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.gz
entropie/src/world/injury.c 3.5 KB · 90 lines raw
#include "world/injury.h"
#include "people/hands.h"

#include <math.h>

#define ARM_STRENGTH 0.55f /* a cast on the arm: this much of their strength ... */
#define ARM_TEMPO    0.75f /* ... and of their tempo at work */
#define LEG_SPEED    0.42f /* a cast on the leg: this much of their speed ... */
#define LEG_JUMP     0.35f /* ... and of their jump */
#define SPRAIN_TIME  (8.0f * 3600.0f) /* game s limping on a twisted ankle ... */
#define SPRAIN_SPEED 0.6f  /* ... this much of their speed ... */
#define SPRAIN_JUMP  0.5f  /* ... and jump */

static float dice(World *world) {
    world->rng = world->rng * 1664525u + 1013904223u;
    return (float)(world->rng >> 8) / 16777216.0f;
}

int Injury_roll(World *world, float chance) {
    if (dice(world) >= chance) return INJ_NONE;
    return dice(world) < 0.55f ? INJ_LEG : INJ_ARM;
}

bool Injury_break(World *world, Object *who, int kind) {
    if (!who || !who->is_character || who->type == OBJ_DOG || kind == INJ_NONE || who->injured || who->hospital_until > 0.0f) return false;
    who->injured = kind;
    who->injury_side = dice(world) < 0.5f ? 0 : 1;
    if (Hands_isGrabbing(who)) Hands_release(who); /* (whatever they held: down) */
    for (int h = 0; h < 2; h++) if (who->hands.state[h] != HAND_FREE) Hands_drop(who, h);
    if (who->body.pose == POSE_UP) Body_fall(&who->body, Object_facing(who));
    who->body.down_time = -1.0f; /* (they stay down: the ambulance) */
    who->body.asleep = false;
    if (who->type != OBJ_PLAYER) Ai_say(who, kind == INJ_LEG ? "AAARGH! My leg - it's broken!" : "AAARGH! My arm! I heard it crack!");
    World_noise(world, NOISE_THUD, who->position, 1.0f);
    return true;
}

int Injury_castKind(const Object *who) {
    return who->look.cast == 0 ? INJ_NONE : who->look.cast <= 2 ? INJ_ARM : INJ_LEG;
}

void Injury_setCast(Object *who, int kind, int side, bool on) {
    int limb = kind == INJ_ARM ? 1 + side : kind == INJ_LEG ? 3 + side : 0;
    if (on == (who->look.cast != 0) || limb == 0) return;
    float k = on ? 1.0f : -1.0f;
    if (kind == INJ_ARM) {
        who->strength *= powf(ARM_STRENGTH, k);
        who->tempo *= powf(ARM_TEMPO, k);
    } else {
        who->top_speed *= powf(LEG_SPEED, k);
        who->jump_speed *= powf(LEG_JUMP, k);
        who->pace *= powf(LEG_SPEED + 0.1f, k);
    }
    who->look.cast = on ? limb : 0;
}

static void sprainOn(Object *who, bool on) {
    float k = on ? 1.0f : -1.0f;
    who->top_speed *= powf(SPRAIN_SPEED, k);
    who->jump_speed *= powf(SPRAIN_JUMP, k);
    who->pace *= powf(SPRAIN_SPEED + 0.15f, k);
}

bool Injury_sprain(World *world, Object *who) {
    (void)world;
    if (!who || !who->is_character || who->type == OBJ_DOG || who->sprain > 0.0f || who->injured) return false;
    who->sprain = SPRAIN_TIME;
    sprainOn(who, true);
    if (who->type != OBJ_PLAYER) Ai_say(who, "Ow! My ankle - twisted it. That'll be a few hours of limping.");
    return true;
}

void Injury_update(Object *who, float game_dt) {
    if (who->sprain <= 0.0f) return;
    if ((who->sprain -= game_dt) > 0.0f) return;
    who->sprain = 0.0f;
    sprainOn(who, false);
    if (who->type != OBJ_PLAYER) Ai_say(who, "Ankle's fine again.");
}

void Injury_heal(Object *who) {
    if (who->sprain > 0.0f) { who->sprain = 0.0f; sprainOn(who, false); }
    if (who->look.cast) Injury_setCast(who, Injury_castKind(who), (who->look.cast - 1) % 2, false);
    who->cast_until = 0;
    if (who->injured) { /* (lying there with it: up again) */
        who->injured = INJ_NONE;
        who->body.down_time = 0.0f;
    }
    who->scrapes = 0;
}