#include "world/injury.h" #include "people/hands.h" #include #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; }