Nimbin[12]?Games / Entropie / entropie/src/people/ai.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/ai.h 22.3 KB · 349 lines raw
#ifndef PEOPLE_AI_H
#define PEOPLE_AI_H

/*
 * Behaviour of the other people in the world.
 *
 *   idle   : stands around, turns towards the player when near
 *   wander : strolls to a random spot around home, avoiding obstacles
 *   help   : walks beside a leader; when the leader grabs something it finds
 *            a free spot at the object, grabs too and pushes / pulls along
 *   fetch  : walks to a beer bottle and picks it up
 *   drink  : takes a sip or two, then puts the bottle down
 *   wake   : someone passed out drunk for a while: goes over and shakes them awake
 *   needs  : sleeps when tired, eats and drinks (lying food and bottles, or
 *            at the apple crate and water barrel), walks off for a pee
 *   tidy   : people who like things clean pick up trash they pass and drop
 *            it in the container when they're not busy
 *   help   : (also) when it's not clear what to do: takes something like what
 *            the leader carries, walks along with it and does the same with it
 *            (puts it down next to theirs, into the fire, into the bin)
 *   help   : (also) understands the leader's wood work and carries it on:
 *            fells with them, takes the branches off, cuts and splits what
 *            lies around; fetches fitting tools; rests when worn out
 *   work   : an order of their own: makes firewood of the wood around a
 *            place (and fells more trees if asked), then stacks it on the
 *            woodpile they were shown; collects the trash with a garbage
 *            bag and takes it to the container; looks after the fire (keeps
 *            wood in it, lights it when it gets dark, sits by it)
 *   person : everyone has their own character: jobs they like or hate (they
 *            are quicker at what they like), how willing they are to do what
 *            they're asked, and a few words about themselves. Tired or drunk,
 *            they say no more often. They suggest jobs that need doing
 *   pace   : and their own way of working: quick or slow, thinking things
 *            over before starting on them or getting right to it, and breaks
 *            now and then (none, sitting down, a little walk, a chat)
 *   follow : being shown something: how to make firewood (watches until
 *            they get it) or where the woodpile goes (follows you there)
 *   talk   : walks up to the player to offer help, ask what to do, or ask
 *            where the firewood should go; how chatty depends on temperament.
 *            Out of work only because the player has the axe: the bold ask
 *            for it, the others wait for it to be put down
 *
 * Steering looks ahead along a few directions and takes the first free one,
 * so people walk around boxes, trees and each other instead of into them.
 */

#include <stdbool.h>

#include "math/linalg.h"

struct Object;

typedef enum {
    AI_IDLE,
    AI_WANDER,
    AI_HELP,
    AI_FETCH,
    AI_DRINK,
    AI_WAKE,     /* goes over to someone asleep and shakes them awake */
    AI_SUPPLY,   /* eats or drinks at the apple crate / water barrel */
    AI_PEE,      /* walks off a bit for a pee */
    AI_WORK,     /* on an order: firewood (and more trees) on their own */
    AI_FOLLOW,   /* being shown something by the player */
    AI_APPROACH, /* walks up to the player to say something */
    AI_TABLE,    /* over to a free chair at a table: sits a while, eats or drinks what they have there */
} AiMode;

typedef enum { ORDER_NONE, ORDER_FIREWOOD, ORDER_TREES, ORDER_TRASH, ORDER_FIRE, ORDER_COUNT } Order;

/* How someone takes a break from work */
typedef enum { BREAK_NONE, BREAK_SIT, BREAK_WALK, BREAK_CHAT, BREAK_COFFEE } BreakKind;

/* Who someone is */
typedef struct {
    float       likes[ORDER_COUNT]; /* -1 hates the job .. 1 loves it */
    float       willing;            /* 0 = only what they fancy .. 1 = whatever they're asked */
    float       skill[ORDER_COUNT];  /* how good they are at it to begin with (0..1) */
    const char *about;              /* a few words about themselves */
    /* How they work */
    float       tempo;              /* 1 = normal; quicker strokes and steps above, slower below */
    float       ponder;             /* seconds they think it over before starting on something */
    BreakKind   break_kind;         /* what they do for a break ... */
    float       break_every;        /* ... after about this many seconds of work ... */
    float       break_length;       /* ... for about this long */
} Character;
/* What someone walks up to the player to talk about */
typedef enum { TOPIC_NONE, TOPIC_OFFER, TOPIC_ASK, TOPIC_SUGGEST, TOPIC_WHERE, TOPIC_ASK_HAND, TOPIC_TOOL } Topic;
typedef enum { SHOW_NONE, SHOW_HOW, SHOW_PLACE } Showing;

#define AI_SPEECH_MAX 80
#define AI_SKIPS      4   /* things they remember they couldn't get at */
#define AI_PATH_MAX   24  /* waypoints (see world/nav.h) */

typedef struct {
    bool           ready;
    AiMode         mode;
    struct Object *leader;    /* AI_HELP */
    struct Object *target;    /* AI_FETCH / AI_DRINK: the bottle, AI_WAKE: the sleeper */
    bool           pushing;   /* AI_HELP: holding the leader's object */
    float          settled;   /* AI_HELP / AI_FOLLOW: arrived (or blocked close by): off again once the spot is further than this; 0 = not there */
    Vec3           home;
    Vec3           goal;      /* where we are walking to */
    float          timer;     /* pause left / time in this mode */
    float          side;      /* AI_HELP: -1 left of the leader, +1 right */
    float          detour;    /* side we last walked around something (-1 / 1) */
    Vec3           steer_dir; /* the way round an obstacle we're taking ... */
    float          steer_hold; /* ... for this much longer */
    float          boxed;      /* no way through just now: wait this long before trying again (no dithering) */
    Vec3           walk_dir;   /* the way they walk (turns smoothly) */
    const struct Object *steer_target; /* what we're walking up to ... */
    float          steer_best, steer_stall; /* ... closest so far, seconds without getting closer */
    Vec3           path[AI_PATH_MAX]; /* a way round fixed things (when walking straight leads into a corner) */
    int            path_len, path_at;
    Vec3           path_goal; /* ... where it leads */
    float          path_none; /* no way there: don't look again for this long */
    float          watch_time; /* watchdog: seconds without anything happening ... */
    Vec3           watch_pos;  /* ... since here ... */
    int            watch_mode; /* ... in this mode / order / with this target and these things in hand */
    const struct Object *watch_target, *watch_items[2];
    int            watch_count;
    float          watch_job;  /* job_time last frame (working on something counts as something happening) */
    int            watch_strikes; /* stuck again without anything happening in between */
    float          stuck;     /* seconds without getting closer to the goal */
    float          closest;
    int            sips_left; /* AI_DRINK: sips still wanted */
    float          table_stay; /* AI_TABLE: seconds they sit there ... */
    float          table_pause; /* ... till the next bite or sip ... */
    float          table_chat;  /* ... and the next word with the others there */
    bool           resting;   /* AI_HELP: worn out, catching breath */
    struct Object *tool;      /* AI_HELP: tool we are going to fetch for the leader's job */
    struct Object *copied;    /* AI_HELP: the leader's item we copy (got one like it, do the same with it) */
    int            copy_sort; /* ... what sort of thing it is */
    int            copy_step; /* ... 0 = carrying along, then putting it down / in the fire / in the bin */
    Vec3           copy_put;  /* ... where ours goes */
    unsigned       rng;

    /* Work orders and what this person knows */
    Order          order;       /* AI_WORK */
    Order          pending;     /* asked for, but first they need to be shown how */
    Vec3           work_area;
    bool           knows_wood;  /* knows how to make firewood */
    struct Object *woodpile;    /* the woodpile they were shown (NULL = don't know one) */
    bool           no_pile;     /* told to leave the firewood where it is */
    Showing        showing;     /* AI_FOLLOW */
    int            seen_jobs;   /* the player's finished jobs when the showing began */
    struct Object *job_target;  /* wood being worked on */
    float          job_time;
    struct Object *skip[AI_SKIPS];      /* didn't work out: leave these a while ... */
    float          skip_time[AI_SKIPS]; /* ... this much longer each */
    float          retry;       /* lost the grip: wait a moment before trying again */
    float          jam_time;    /* AI_HELP: the load doesn't move and we stand where it wants to go (seconds) */
    float          clear_time;  /* ... so we keep off that side a while */
    Vec3           clear_dir;   /* ... (the way the load wants to go) */
    Vec3           jam_from;    /* (where the load was when we started to wonder) */
    float          shove_time;  /* a pushed load has been shoving us this long (negative: a while not minding it) */
    float          dodge;       /* stepping out of its way (seconds left) ... */
    Vec3           dodge_dir;   /* ... this way */

    /* Talking */
    Topic          topic;       /* AI_APPROACH: what they want to talk about */
    bool           ready_to_talk;
    bool           talking;     /* in a conversation: stands still and listens */
    float          talk_cooldown;
    char           speech[AI_SPEECH_MAX];
    Character      character;
    Order          suggested;   /* TOPIC_SUGGEST: the job they suggest */
    Vec3           pee_cover;   /* AI_PEE: what they pee behind (face it, or squat with the back to it) ... */
    bool           pee_hidden;  /* ... if there is something */
    float          annoyed;     /* 0..1: left waiting for an answer, ignored; eases off over minutes */
    bool           wants_bag;   /* at the garbage bags: the world hands them one */
    struct Object *empty_tray;  /* at a full ashtray: the world tips it out into their hand */
    bool           tool_asked;  /* asked the player for their axe (once per order) */
    float          tidy_pause;  /* bending down for trash on the way (seconds left) */
    float          tray_time;   /* on the way to empty the ashtray this long */
    struct Object *sort_from;   /* sorting the crates (ai_help.c sortCrates): to this one for a bottle that doesn't belong ... */
    struct Object *sort_bottle; /* ... carrying this one over to its own crate ... */
    float          sort_time;   /* ... this long already ... */
    float          sort_look;   /* ... and looking again for one in this long */
    bool           want_jacket; /* cold, the pullover put down somewhere: off to get it */
    bool           want_smokes; /* out of cigarettes, nobody gives one: off to the machine */
    float          smokes_time; /* ... on the way this long */
    bool           asked_you;   /* asked the player for one (nothing came of it: the machine next time) */
    struct Object *take_from;   /* a bottle from this crate, or the next thing out of this car's boot: please (see car.c Car_serve) */
    bool           sheltering;  /* in out of the rain (ai.c shelter) */
    bool           rain_seated; /* ... sat down to wait it out (the garages' kitchen, the shelter) ... */
    int            rain_place;  /* ... which of those (Site_rainPlaces), + 1 (0: not chosen yet) */
    bool           greet;       /* just arrived: over to the fire, saying hello, sitting there till the work starts ... */
    bool           greet_stand; /* ... no room on the benches: standing with the others here instead ... */
    Vec3           greet_at;
    bool           greet_asked; /* ... asked those on a bench to move up */
    bool           drying;      /* wet through after the rain: sitting by the fire till dry */
    bool           timber;      /* felling: waiting for somebody to get out from where it'll come down */
    Vec3           dodge_to;    /* warned off (a tree coming down): out to here ... */
    float          dodge_t;     /* ... for this long */
    struct Object *umbrella;    /* rain: off to get this umbrella instead of going under a roof (ai.c shelter) */
    float          greet_left;  /* just turned up: this long at the fire, then on with the day (0: till told otherwise) */
    bool           on_project;  /* at work on their floor's stage (ai_project.c) ... */
    float          shift;       /* ... game s into this go at it (then a break) ... */
    float          project_off; /* ... game s till they go back to it ... */
    float          held_up;     /* ... game s it's been held up (material missing) ... */
    struct Object *fetch;       /* ... material they're bringing over to it (this long so far) */
    float          fetch_time;
    bool           errand;      /* off somewhere on purpose: errand_to (a shopping run: the car's driver door;
                                   showing the way: the spot) ... */
    bool           errand_there; /* ... and there */
    Vec3           errand_to;
    struct Object *errand_with; /* ... showing whoever this is the way: waiting for them when they fall behind */
    bool           meeting;     /* in Berlin: at a meeting (or there between weekends) - sitting, listening, nothing else */
    float          remark;      /* ... real s till the next remark about it */
    float          praised;     /* game s till a "great work" counts again */
    struct Object *share;       /* rain: walking under this one's umbrella, at their side ... */
    float share_time;           /* ... this long so far */
    struct Object *blown;       /* the wind took this out of their hand: after it (ai.c fetchBlown) ... */
    float          blown_t;     /* ... this long already */
    struct Object *hang_on;     /* warm, the pullover round the waist: over this (a railing, a chair) it goes ... */
    float          hang_wait;   /* ... and not thought of again for this long */
    bool           going_in;    /* a resident on the way into the house (ai.c goInside) */
    struct Object *tent_job;    /* lending a hand with this tent (ai.c pitchTents) ... */
    float          tent_time;   /* ... this long */
    bool           tent_said;   /* ... said so */
    bool           unload;      /* unloading the car (ai.c unloadCar) ... */
    bool           unload_rest; /* ... put it down for a breather */
    struct Object *unload_car;
    float          unload_time; /* ... on this trip this long */
    float          butt_time;   /* holding a finished cigarette (Object.butt_held) this long ... */
    bool           butt_asked;  /* ... and asked somebody for their pocket ashtray already */
    int            asking_you;  /* asked the player for this (PocketNeed: a paper, a filter, tobacco), 0: nothing */
    bool           filter_asked; /* asked for a filter this time already (none: rolls one without) */
    float          jacket_time; /* ... on the way this long */
    bool           tool_waiting; /* waiting for the player to put the axe down */
    unsigned char  banned;      /* tools (1 << ToolKind) they were told to leave alone ... */
    unsigned char  defies;      /* ... and those they use anyway ("I know what I'm doing") */
    unsigned char  warned;      /* tools they already said something about (using one they shouldn't) */
    float          risky;       /* seconds until the next close call with a tool they shouldn't use */
    float          speech_time;
    float          lighter_time; /* until they next think about lighters (give one back, ask for theirs) */
    float          lighter_ask;  /* until they ask anybody for a lighter again */
    struct Object *set_aside[2]; /* put down to pee: picked up again after */
    /* Getting the work place ready (ai_work.c prepareSpot) */
    struct Object *prep_for;    /* the piece it was looked at for ... */
    int            prep_stage;  /* ... PREP_* */
    Vec3           prep_spot;   /* ... where the work goes (moving it) */
    struct Object *prep_item;   /* ... what's being cleared away */
    struct Object *prep_helper; /* ... who was called over to help move it */
    float          prep_time;
    bool           chat_near;   /* on a chat break: close enough (left again only well beyond) */
    float          hold_idle;
    bool     hold_there;   /* ... at the spot (stands there till pushed well off it) */
    float          ladder_dir;  /* on a ladder: +1 going up, -1 down */
    float          ladder_seek; /* until they look for a way up / down again */
    Order          paused_order; /* called away from this job (to help): back to it after, or when reminded ... */
    Vec3           paused_area;  /* ... there */
    float          high_time;   /* seconds up high (a roof) ... */
    bool           high_said;   /* ... said something about it */
    bool           heights_said; /* told they won't go up there (once each time they're asked) */
    float          ladder_climb_t; /* seconds up a ladder that leads nowhere */   /* holding a ladder nobody is on: seconds of that (then they let go) */
    float          sun_heat;    /* seconds of hard work in the midday sun (the shirt comes off) */
    float          sniff_cooldown; /* until the next remark about a smell */
    AiMode         before;      /* mode to go back to after being shown something */

    /* Their way of working */
    const struct Object *task_seen; /* the last thing they thought over before starting on it */
    float          ponder;      /* thinking it over (seconds left) */
    float          streak;      /* seconds worked since the last break */
    float          on_break;    /* on a break (seconds left) */
    Vec3           break_from;  /* BREAK_WALK: where they set out from (and come back to) */
    bool           break_back;  /* ... on the way back */
    BreakKind      break_now;   /* this break: mostly their own kind, now and then another */
    struct Object *break_at;    /* BREAK_COFFEE: the stove (a coffee there) */
    float          break_sip;   /* ... until the next sip */
    struct Object *chat_with;   /* BREAK_CHAT: who they're chatting with */
    float          chat_line;   /* ... until the next thing said */
    int            chat_said;

    /* The festival (ai_fest.c) */
    int            fest_floor;  /* dancing at this floor (+1; 0 none) ... */
    Vec3           fest_spot;   /* ... their place on it ... */
    float          fest_time;   /* ... real s at it so far (negative: till they feel like dancing again) */
    struct Object *fest_who;    /* the storm: off to warn this one; the awareness team: off to see to this one */
    float          fest_walk;   /* ... on the way this long */

    /* People and people (ai_touch.c) */
    struct Object *step_in;     /* off to tell this one to stop (they bothered step_for) ... */
    struct Object *step_for;
    float          step_t;      /* ... on the way this long */
    struct Object *harass;      /* a drunk guest after this one (the festival) ... */
    float          harass_walk; /* ... on the way this long */
} Ai;

/* Starts helping the leader; drops a bottle if needed. */
void Ai_help(struct Object *self, struct Object *leader);
void Ai_stopHelping(struct Object *self);
bool Ai_isHelping(const struct Object *self);
/* Called away from a job and didn't go back to it on their own: back to it now (reminded). False: no such job. */
bool Ai_resumePaused(struct Object *self);

/* Says something (a speech bubble for a few seconds). */
void Ai_say(struct Object *self, const char *text);
/* Starts working on an order around area (they must know how). */
void Ai_order(struct Object *self, Order order, Vec3 area);
/* A tree felled falling that way: the first thing it would come down on (a house, a car, a tent ...), or NULL. */
const struct Object *Ai_fallsOnto(const struct Object *tree, Vec3 dir);
/* Somebody where it'll come down (falling that way): told to get out (they step aside). True if anybody is there. */
bool Ai_warnFellingRoom(struct Object *feller, struct Object *const *objects, int count, struct Object *tree, Vec3 dir);
void Ai_stopWork(struct Object *self);
/* Follows the player to be shown how to do the pending order, or where the woodpile goes. */
void Ai_show(struct Object *self, Showing what, const struct Object *player);
void Ai_stopShowing(struct Object *self);
/* Now knows this woodpile and stacks firewood there. */
void Ai_setWoodpile(struct Object *self, struct Object *woodpile);
/* In a conversation or not; done = it ended (no new chat for a while). */
void Ai_setTalking(struct Object *self, bool talking);

/* Tools: a tool someone shouldn't use (the chainsaw unpractised, the axe or
   the saw drunk) they use anyway, unless told not to - and the ignorant
   don't listen. tool: a ToolKind. Ai_banTool: true = they'll leave it. */
bool Ai_shouldntUse(const struct Object *self, int tool);
bool Ai_banTool(struct Object *self, int tool, bool ban);
bool Ai_mayUse(const struct Object *self, int tool);

/* Time of day (hours) for everybody's plans. */
void Ai_setHour(float hour);
/* Does this job need doing right now (not much firewood, trash lying around, dark and no fire)? */
bool Ai_needed(const struct Object *self, struct Object *const *objects, int count, Order order);
/* Asked to do a job: yes or no, and what they say. their_idea: they asked for something to do. */
bool Ai_willDo(struct Object *self, struct Object *const *objects, int count, Order order, bool their_idea,
               const char **reply);
/* How fast their work goes compared to normal: liking the job, condition, drink. */
float Ai_workRate(const struct Object *self);
/* The job someone is doing right now (ORDER_NONE: nothing). */
Order Ai_job(const struct Object *self);
/* Doing a job makes you better at it. */
void  Ai_practice(struct Object *self, Order job, float amount);
/* The player calls out to them: they come over (or say why not). False if they didn't hear. */
bool  Ai_call(struct Object *self, const struct Object *player);

/* Where things are (the world's cell grid): steering only looks at what's near. NULL: everything. */
struct Grid;
struct World;
void Ai_useGrid(struct Grid *grid);
/* The world (for climbing: ladders, edges). */
void Ai_useWorld(struct World *world);
/* Settled in (the car empty, the tents up): from now on they come to you with jobs (firewood, trees...). */
void Ai_setSettled(bool settled);

/* Before physics: chooses what to do and sets movement and facing. */
void Ai_update(struct Object *self, struct Object *const *objects, int count, float dt);

#endif /* PEOPLE_AI_H */