Nimbin[12]?Games / Entropie / entropie/src/people/hands.h

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/people/hands.h 9.2 KB · 172 lines raw
#ifndef PEOPLE_HANDS_H
#define PEOPLE_HANDS_H

/*
 * What a character does with its hands: pick up and carry items (one per
 * hand, or one big item with both), and grab objects to push or pull them.
 * Works for any character; the player drives it from input.
 *
 * Rules
 *   one hand : up to ONE_HAND_MAX_WEIGHT kg and ONE_HAND_MAX_SIZE m
 *   two hands: up to TWO_HAND_MAX_WEIGHT kg and TWO_HAND_MAX_SIZE m, both hands free
 *   grab     : any loose object; uses every free hand. Several characters can
 *              grab the same object and their strength adds up.
 *
 * Grabbed objects can be lifted by everyone holding them together and carried
 * (Hands_toggleLift).
 *
 * While grabbing, the character faces the object along a fixed heading:
 * forward pushes, backward pulls, sideways drags it along. Looking around
 * does not move the object.
 */

#include <stdbool.h>

#include "math/linalg.h"

struct Object;

typedef enum {
    HAND_FREE,
    HAND_REACHING,  /* bending down / reaching for an item */
    HAND_HOLDING,   /* carrying an item */
    HAND_GRABBING,  /* holding on to an object to push or pull it */
    HAND_READY,     /* reaching out in front (E / Q): takes hold of whatever comes in reach */
    HAND_HOLD,      /* holding on to something fixed (a post, a wall, a tree) or somebody (a body part): hold, hold_local */
} HandState;

typedef struct {
    HandState      state[2];
    struct Object *item[2];        /* same item in both hands = carried with two hands */
    float          timer[2];
    float          item_yaw[2];    /* item rotation relative to the carrier */
    struct Object *grabbed;
    Vec3           grab_vector;    /* object position minus own position (world, fixed) */
    Vec3           grab_heading;   /* direction we face while grabbing (horizontal) */
    Vec3           grab_point[2];  /* hand contacts in object space (turn with the object) */
    float          grab_share;     /* how much the object follows (0..1, whole team) */
    float          throw_time[2];  /* > 0: arm follows through after a throw */
    bool           overhand[2];    /* ... that was thrown overhand */
    float          wind;           /* > 0: winding up for a throw (seconds held) */
    bool           winding;        /* ... still held this frame */
    bool           touching;       /* this frame: a hand reaches for touch_point */
    Vec3           touch_point;
    float          rope;           /* this frame: both hands on a rope at rope_at (0 none), leaning back into it this hard (0..1) */
    Vec3           rope_at, rope_dir; /* ... the near hand's grip, the way the rope runs (to where it's tied) */
    bool           on_edge;        /* this frame: both free hands hold on to an edge (climbing up) */
    Vec3           edge_point, edge_across;
    float          edge_crouch;
    int            edge_lead;      /* ... this hand gets there first ... */
    float          edge_trail;     /* ... the other still this far behind (1: down by the shoulder, 0: on it too) ... */
    float          edge_turn;      /* ... the shoulders turned this far, the first hand's side ahead (radians) */
    float          settle[2];      /* 0 -> 1 just after taking an item: it turns into the carry pose */
    bool           by_neck[2];     /* bottles: held at the neck (rare) instead of low around the body */
    float          miss_time;      /* grabbing: seconds the hands couldn't reach their grip */
    Vec3           settle_y[2];    /* item axes when it was taken (figure space) */
    Vec3           settle_z[2];
    int            drink_hand;     /* hand bringing a bottle to the mouth, -1 = none */
    float          drink_time;
    bool           drink_sipped;
    struct Object *hold[2];        /* HAND_HOLD: what (or who) this hand holds on to ... */
    Vec3           hold_local[2];  /* ... where on it (its own space; a person: unused) ... */
    int            hold_joint[2];  /* ... a person: the joint (Joint) held at, its part (people/touch.h) */
    int            hold_part[2];
} Hands;

/* E / Q: this hand reaches out in front and takes hold of whatever comes in reach - a thing to
   carry, something heavy to push, something fixed to hold on to, somebody. Again: lets go. */
void  Hands_reachOut(struct Object *who, int hand);
/* Lets go with this hand (whatever it holds on to, reaching out). */
void  Hands_letGo(struct Object *who, int hand);
/* A hand reaching out: what's in reach of it now taken hold of. Returns what (or NULL); *person: it's somebody. */
struct Object *Hands_catch(struct Object *who, int hand, struct Object *const *objects, int count, bool *person);
/* Holding on to this one (a hand on them), or -1. */
int   Hands_holding(const struct Object *who, const struct Object *whom);
/* Where a hand is held (world): the fixed point, or the person's joint now. */
Vec3  Hands_holdPoint(const struct Object *who, int hand);

/* Picks up the item in front with this hand (or both), or drops what it holds. */
bool  Hands_pickUpOrDrop(struct Object *who, int hand, struct Object *const *objects, int count);
void  Hands_drop(struct Object *who, int hand);
/* Puts whatever is in the hands down on the ground beside them (lets go of
   what they hold on to): the hands are free, for a pee. out: what was put down. */
void  Hands_setAside(struct Object *who, struct Object *out[2]);
/*
 * Takes whatever is in front: small things with a free hand, bigger ones with
 * both, and anything too heavy to carry is taken hold of (push, pull, or lift
 * it together). Returns 1 picked up, 2 holding on to it, 0 nothing there,
 * -1 hands full.
 */
int   Hands_takeInFront(struct Object *who, struct Object *const *objects, int count);

/* The loose object in front within reach, or NULL. */
struct Object *Hands_inFront(const struct Object *who, struct Object *const *objects, int count);

/* The hand to use first: the main hand if it is free, else the other, -1 if both are busy. */
int   Hands_freeHand(const struct Object *who);

/* Picks up a specific item if this hand is free and it is within reach (used by the AI). */
bool  Hands_pickUpObject(struct Object *who, int hand, struct Object *item);
/* Takes an item handed over by someone (one hand, no reaching for it). */
bool  Hands_receive(struct Object *who, int hand, struct Object *item);

/* Winding up to throw (call every frame while the key is held): a quick one
   goes underhand, held longer the arm comes back over the shoulder for a
   harder, further throw overhand. */
void  Hands_windUp(struct Object *who);
bool  Hands_isWindingUp(const struct Object *who);
/* Throws what the main (else the other) hand holds along dir, as wound up (not at all: a lob). */
bool  Hands_throw(struct Object *who, Vec3 dir);

/*
 * Team lifting: everybody holding the grabbed object lifts it off the ground
 * if their strength together carries its weight (about 40 kg per person),
 * and carries it where they walk. Again to put it down.
 * A long log too heavy for them but not for half its weight: one end comes
 * up, the other drags on the ground (slower).
 * Returns 1 lifted, 2 one end lifted, 0 put down, -1 too heavy for the people
 * holding it, -3 could lift one end but isn't held near one.
 */
int   Hands_toggleLift(struct Object *who, struct Object *const *objects, int count);

/* This frame, reach out and touch a point (e.g. to wake someone). */
void  Hands_touch(struct Object *who, Vec3 point);
/* This frame, the free hands hold on to an edge at point, a shoulder width apart along across. */
void  Hands_holdEdge(struct Object *who, Vec3 point, Vec3 across, float crouch);

/* Grabs the object in front with all free hands. */
bool  Hands_grab(struct Object *who, struct Object *const *objects, int count);
/* Grabs a specific object if it is within reach (used by the AI). */
bool  Hands_grabObject(struct Object *who, struct Object *target);
void  Hands_release(struct Object *who);
bool  Hands_isGrabbing(const struct Object *who);
/* Turns what who holds on to (with everybody holding it) about its middle, towards
   want radians (+: the way the heading angle grows), as fast as strength allows and
   only as far as nothing solid is in the way. Returns the angle turned. */
float Hands_turnGrabbed(struct Object *who, struct Object *const *objects, int count, float want, float dt);

/* Takes a sip from a carried bottle, or a bite of carried food (right hand first). */
bool  Hands_drink(struct Object *who);
bool  Hands_isDrinking(const struct Object *who);
/* Hand holding a bottle or food with something left, or -1. */
int   Hands_bottleHand(const struct Object *who);

/* Gap between a body standing at position and an object's surface (meters). */
float Hands_gapFrom(Vec3 position, float height, const struct Object *o);

/* Is an item of this type in the hands? */
bool  Hands_carries(const struct Object *who, int type);

/* Walking speed multiplier while carrying or pushing. */
float Hands_moveFactor(const struct Object *who);

/* After physics: moves grabbed objects with everybody holding them (strength adds up). */
void  Hands_solveGrabs(struct Object *const *objects, int count, float dt);

/* After physics: advances reaching and sets the body goals and hand targets. */
void  Hands_update(struct Object *who, float dt);

/* After the skeleton is solved: moves carried items into the hands. */
void  Hands_placeHeld(struct Object *who);

#endif /* PEOPLE_HANDS_H */