#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 #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 */