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/src/game/game_injury.c raw
/*
* Broken bones (world/injury.h): somebody lies there hurt - an ambulance is
* called. A while later it comes in along the way in by car (lights, siren),
* stops by the yard, the paramedics fetch them, off it goes. They're at the
* hospital (out of sight: in Berlin with the others between weekends) and
* come back a day and a half later - or with the next weekend, whichever is
* first - with a cast (an arm: weaker, slower at work; a leg: slow on their
* feet). The cast comes off two weekends on.
*
* You: the ambulance takes you; six hours later you're back with a cast.
* A guest: the ambulance takes them, and that's their festival over.
*/
#include <math.h>
#include "game/game_internal.h"
#include "world/car.h"
#include "world/cast.h"
#include "world/injury.h"
#include "world/manor.h"
#define AMB_COMES 1200.0f /* game s till it's here (out in the country) */
#define AMB_SPEED 9.0f /* m/s along the way in */
#define AMB_STOP 12.0f /* m short of where your car stops */
#define AMB_LOADING 10.0f /* real s the paramedics take */
#define AWAY_HOURS 36.0f /* story hours at the hospital (a cast on, then back) */
#define YOU_AWAY 6.0f /* ... you: hours */
#define CAST_WEEKENDS 2 /* the cast comes off this many weekends on */
#define YOU_WAIT 4.0f /* real s lying there before you're taken */
static const char *limb(int kind) { return kind == INJ_ARM ? "arm" : "leg"; }
static void putOnGround(Game *game, Object *o) {
Vec3 path[16];
int n = 0;
float yaw;
Site_arrivalPath(path, &n, &yaw);
Vec3 at = n > 4 ? path[4] : Site_yard();
at.y = World_groundHeight(&game->world, at.x, at.z, at.y + 3.0f);
o->sitting = false;
o->seat = NULL;
o->ai.meeting = false;
o->position = at;
o->velocity = o->movement = vec3_zero();
o->body.replant = true;
Object_syncColliders(o);
}
/* Back from the hospital: the cast on. */
static void back(Game *game, Object *o, bool to_ground) {
int kind = o->injured ? o->injured : INJ_LEG;
Injury_setCast(o, kind, o->injury_side, true);
o->injured = INJ_NONE;
o->hospital_until = 0.0f;
o->cast_until = game->weekend + CAST_WEEKENDS;
if (to_ground) putOnGround(game, o);
if (o->type == OBJ_HUMAN) Ai_say(o, kind == INJ_ARM ? "I'm back! Arm in plaster - I'll do what I can one-handed." : "Back again! Slow on this leg, but I'm here.");
snprintf(game->story_line, sizeof game->story_line, "%s %s back from the hospital - with a cast on the %s", o->type == OBJ_PLAYER ? "You" : o->name,
o->type == OBJ_PLAYER ? "are" : "is", limb(kind));
say(game, game->story_line);
game->message_time = 6.0f;
}
/* You: taken to the hospital, back hours later with the cast. */
static void youHurt(Game *game, float dt) {
Object *p = game->player;
if (!p->injured) { game->you_hurt_t = 0.0f; return; }
if (game->you_hurt_t == 0.0f) {
snprintf(game->story_line, sizeof game->story_line, "Your %s - it's broken. Somebody calls the ambulance...", limb(p->injured));
say(game, game->story_line);
game->message_time = YOU_WAIT + 1.0f;
}
if ((game->you_hurt_t += dt) < YOU_WAIT) return;
game->you_hurt_t = 0.0f;
float add = YOU_AWAY;
game->story_hours += add;
game->daycycle.seconds = fmodf(game->daycycle.seconds + add * 3600.0f, 24.0f * 3600.0f);
p->body.down_time = 0.0f;
p->body.pose = POSE_UP;
p->body.replant = true;
Vec3 at = Site_yard();
at.y = World_groundHeight(&game->world, at.x, at.z, at.y + 3.0f);
p->position = at;
p->velocity = p->movement = vec3_zero();
Object_syncColliders(p);
game->on_rope = false;
back(game, p, false);
}
static Object *waiting(const Game *game) {
for (int i = 0; i < game->world.count; i++) {
Object *o = game->world.objects[i];
if (o->type == OBJ_HUMAN && o->injured && o->hospital_until <= 0.0f && !o->gone_home) return o;
}
return NULL;
}
static Object *crewNear(const Game *game, const Object *hurt) {
Object *best = NULL;
float best_d = 60.0f;
for (int i = 0; i < game->world.count; i++) {
Object *o = game->world.objects[i];
if (o == hurt || o->type != OBJ_HUMAN || o->cast_id <= 0 || o->injured || Body_isDown(&o->body) || Game_inBerlin(o)) continue;
float d = hypotf(o->position.x - hurt->position.x, o->position.z - hurt->position.z);
if (d < best_d) { best_d = d; best = o; }
}
return best;
}
static void ambulance(Game *game, float dt) {
Ambulance *a = &game->ambulance;
World *w = &game->world;
switch (a->stage) {
case AMB_NONE: {
Object *hurt = waiting(game);
if (!hurt) return;
a->who = hurt;
a->stage = AMB_CALLED;
a->t = 0.0f;
Object *c = crewNear(game, hurt);
if (c) Ai_say(c, "Don't move - I'm calling 112! The ambulance is on its way.");
snprintf(game->story_line, sizeof game->story_line, "%s is hurt - a broken %s. The ambulance is called; out here it takes a while", hurt->name, limb(hurt->injured));
say(game, game->story_line);
game->message_time = 6.0f;
return;
}
case AMB_CALLED:
if ((a->t += w->game_dt) < AMB_COMES || !game_drivePath(game)) return;
{
Vec3 pos, dir;
game_driveAt(&game->arrival, 0.0f, &pos, &dir);
Object *car = Car_create(pos, yaw_facing(dir));
if (!car) return;
car->variant = 1;
Mesh_destroy(&car->mesh);
car->mesh = Shapes_ambulance();
snprintf(car->name, sizeof car->name, "Ambulance");
if (!World_add(w, car)) return;
a->car = car;
a->s = 0.0f;
a->stage = AMB_IN;
say(game, "Blue lights on the gravel road - the ambulance is here");
}
return;
case AMB_IN: case AMB_OUT: {
float stop = game->arrival.length - AMB_STOP;
a->s += (a->stage == AMB_IN ? 1.0f : -1.0f) * AMB_SPEED * dt;
if (a->stage == AMB_IN && a->s >= stop) { a->s = stop; a->stage = AMB_PARKED; a->t = 0.0f; }
Vec3 pos, dir;
game_driveAt(&game->arrival, a->s, &pos, &dir);
Car_place(w, a->car, pos, yaw_facing(a->stage == AMB_OUT ? vec3_scale(dir, -1.0f) : dir));
if (a->stage == AMB_OUT && a->s <= 0.0f) { /* (gone: to the hospital) */
Object *o = a->who;
if (o && o->riding == a->car) Car_getOut(o);
if (o && o->guest) { o->gone_home = true; o->inside_door = pos; o->indoors = 1e7f; o->injured = INJ_NONE; }
else if (o) {
o->hospital_until = game->story_hours + AWAY_HOURS;
o->position = vec3(BERLIN_X + BERLIN_BAR + 1.5f, 0.05f, 2.0f);
o->velocity = o->movement = vec3_zero();
o->ai.meeting = true;
Object_syncColliders(o);
}
Object_useUp(a->car);
memset(a, 0, sizeof *a);
}
return;
}
case AMB_PARKED: {
Object *o = a->who;
if ((a->t += dt) < AMB_LOADING) return;
if (o && !o->riding) {
o->body.down_time = 0.0f; /* (on the stretcher, in) */
o->body.pose = POSE_UP;
Car_getIn(a->car, o, 2);
snprintf(game->story_line, sizeof game->story_line, "The paramedics carry %s to the ambulance on a stretcher", o->name);
say(game, game->story_line);
}
a->stage = AMB_OUT;
return;
}
default: return;
}
}
void game_injury(Game *game, float dt) {
World *w = &game->world;
if (game->meeting.kind) return;
Object *you = game->player;
if (you->sprain > 0.0f && !game->sprain_told) { game->sprain_told = true; say(game, "Ow - you twisted your ankle. A few hours of limping"); }
else if (you->sprain <= 0.0f && game->sprain_told) { game->sprain_told = false; say(game, "Your ankle's fine again"); }
youHurt(game, dt);
ambulance(game, dt);
for (int i = 0; i < w->count; i++) {
Object *o = w->objects[i];
if (!o->is_character || o->type == OBJ_DOG) continue;
if (o->hospital_until > 0.0f) { /* at the hospital: back when it's time (or the next weekend brought them) */
if (!Game_inBerlin(o)) back(game, o, false);
else if (game->story_hours >= o->hospital_until) back(game, o, true);
}
if (o->look.cast && game->weekend >= o->cast_until && o->cast_until > 0) {
int kind = Injury_castKind(o), side = (o->look.cast - 1) % 2;
Injury_setCast(o, kind, side, false);
o->cast_until = 0;
if (!Game_inBerlin(o)) {
snprintf(game->story_line, sizeof game->story_line, "%s%s cast is off - good as new", o->type == OBJ_PLAYER ? "Your" : o->name, o->type == OBJ_PLAYER ? "" : "'s");
say(game, game->story_line);
}
}
}
}
/* Dev: all well again - out of the ambulance, back from the hospital, the cast and the sprain off. */
void game_injuryHeal(Game *game, Object *o) {
Ambulance *a = &game->ambulance;
if (a->who == o) {
if (a->car && o->riding == a->car) Car_getOut(o);
a->who = NULL;
if (a->stage == AMB_CALLED) { a->stage = AMB_NONE; a->t = 0.0f; } /* (not on its way yet: called off) */
}
if (o == game->player) game->you_hurt_t = 0.0f;
if (o->hospital_until > 0.0f) {
o->hospital_until = 0.0f;
o->ai.meeting = false;
if (Game_inBerlin(o) && !game->meeting.kind) putOnGround(game, o);
}
Injury_heal(o);
game->sprain_told = false;
}
bool game_ambulanceHere(const Game *game) { return game->ambulance.stage >= AMB_IN; }