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/people/touch.c raw
#include "people/touch.h"
#include "render/figure.h"
#include <math.h>
#include <string.h>
static const char *const NAMES[TOUCH_PARTS] = { "hand", "arm", "shoulder", "back", "head", "waist", "leg", "chest", "bottom", "crotch" };
const char *Touch_partName(int part) { return NAMES[part < 0 || part >= TOUCH_PARTS ? 0 : part]; }
bool Touch_intimate(int part) { return part == TOUCH_CHEST || part == TOUCH_BUTT || part == TOUCH_GROIN || part == TOUCH_LEG; }
int Touch_part(const Object *whom, int joint, Vec3 hand) {
Vec3 local = Figure_toLocal(whom->position, Object_facing(whom), hand); /* (z: in front of them, x: their right) */
switch (joint) {
case JOINT_HAND_L: case JOINT_HAND_R: case JOINT_WRIST_L: case JOINT_WRIST_R: return TOUCH_HAND;
case JOINT_ELBOW_L: case JOINT_ELBOW_R: return TOUCH_ARM;
case JOINT_SHOULDER_L: case JOINT_SHOULDER_R: return TOUCH_SHOULDER;
case JOINT_NECK: case JOINT_HEAD: return TOUCH_HEAD;
case JOINT_CHEST: return local.z > 0.04f ? TOUCH_CHEST : local.z < -0.04f ? TOUCH_BACK : TOUCH_WAIST;
case JOINT_PELVIS: case JOINT_HIP_L: case JOINT_HIP_R:
if (local.z > 0.06f && fabsf(local.x) < 0.12f) return TOUCH_GROIN;
if (local.z < -0.04f) return TOUCH_BUTT;
return TOUCH_WAIST;
default: return TOUCH_LEG; /* (a knee, an ankle) */
}
}
/* Two who belong together (they share a tent). */
static bool couple(const Object *a, const Object *b) {
return (!strcmp(a->name, "Volkram") && !strcmp(b->name, "Jana")) || (!strcmp(a->name, "Jana") && !strcmp(b->name, "Volkram"));
}
void Touch_feelings(const Object *whom, const Object *by, float *like, float *love) {
if (by->type == OBJ_PLAYER) { *like = whom->like; *love = whom->love; return; }
if (couple(whom, by)) { *like = 0.9f; *love = 0.9f; return; }
bool known = whom->cast_id > 0 && by->cast_id > 0; /* (the crew know each other) */
*like = known ? 0.55f : 0.25f;
*love = 0.0f;
}
/* How much of each it takes for a touch there to be welcome (and its being just too much). */
static void needs(int part, float *like, float *love) {
*like = 2.0f; *love = 2.0f; /* (out of reach) */
switch (part) {
case TOUCH_ARM: case TOUCH_SHOULDER: case TOUCH_BACK: *like = 0.25f; break;
case TOUCH_HAND: *like = 0.5f; *love = 0.35f; break;
case TOUCH_HEAD: *like = 0.6f; *love = 0.45f; break;
case TOUCH_WAIST: *like = 0.85f; *love = 0.5f; break;
case TOUCH_LEG: *love = 0.6f; break;
default: *love = 0.8f; break; /* (the chest, the bottom, between the legs) */
}
}
static void note(World *world, Object *by, Object *whom, int what, int part) {
if (world->touched_n >= 8) return;
world->touched[world->touched_n].by = by;
world->touched[world->touched_n].whom = whom;
world->touched[world->touched_n].what = what;
world->touched[world->touched_n].part = part;
world->touched_n++;
}
static void sayIt(Object *whom, const char *line) { if (whom->type == OBJ_HUMAN) Ai_say(whom, line); }
int Touch_react(World *world, Object *whom, Object *by, int part) {
float like, love, need_like, need_love;
Touch_feelings(whom, by, &like, &love);
needs(part, &need_like, &need_love);
float mood = -0.15f * whom->ai.annoyed - 0.1f * fmaxf(whom->temperament.nerves, 0.0f) + 0.1f * fminf(whom->drunk, 1.0f) * (love > 0.2f ? 1.0f : 0.0f);
float margin = fmaxf(like + mood - need_like, love + mood - need_love); /* (either will do) */
bool you = by->type == OBJ_PLAYER;
int what;
if (margin >= 0.0f) {
what = TOUCHED_WELCOME;
if (you) { /* closeness that's welcome brings you closer */
whom->like = fminf(1.0f, whom->like + 0.01f);
if (part == TOUCH_HAND || part == TOUCH_WAIST || Touch_intimate(part)) whom->love = fminf(1.0f, whom->love + 0.025f);
}
static const char *const OK[TOUCH_PARTS] = { "Hey, you.", "Mm?", "What's up?", "Hm?", "Hey...", "Come here, you.", "Oh - hi.", "Mm...", "Cheeky.", "Not here - later." };
if (whom->ai.speech_time <= 0.0f) sayIt(whom, OK[part]);
} else if (margin > -0.15f && !Touch_intimate(part) && part != TOUCH_WAIST) {
what = TOUCHED_TOLERATED;
if (you) whom->like = fmaxf(0.0f, whom->like - 0.01f);
sayIt(whom, part == TOUCH_HAND ? "Uh... okay?" : "Can I help you?");
} else if (!Touch_intimate(part)) {
what = TOUCHED_UNWELCOME;
if (you) whom->like = fmaxf(0.0f, whom->like - 0.06f);
whom->ai.annoyed = fminf(1.0f, whom->ai.annoyed + 0.4f);
sayIt(whom, "Don't touch me, please.");
} else {
what = TOUCHED_HARASSED;
if (you) { whom->like = fmaxf(0.0f, whom->like - 0.3f); whom->love = fmaxf(0.0f, whom->love - 0.4f); }
whom->ai.annoyed = 1.0f;
whom->commitment = fmaxf(0.0f, whom->commitment - 0.1f);
if (whom->guest) whom->fun = fmaxf(0.0f, whom->fun - 0.2f);
static const char *const NO[] = { "Hey! Get your hands off me!", "What the hell?! Don't touch me!", "Back off! Seriously!" };
sayIt(whom, NO[(int)(fabsf(whom->position.x * 7.0f + whom->position.z)) % 3]);
}
note(world, by, whom, what, part);
return what;
}
bool Touch_calm(World *world, Object *whom, Object *by, int part) {
float like, love;
Touch_feelings(whom, by, &like, &love);
if (Touch_intimate(part) || like < 0.3f) return Touch_react(world, whom, by, part) == TOUCHED_WELCOME;
whom->ai.annoyed = fmaxf(0.0f, whom->ai.annoyed - 0.5f);
whom->temperament.nerves = fmaxf(-0.5f, whom->temperament.nerves - 0.05f);
if (by->type == OBJ_PLAYER) whom->like = fminf(1.0f, whom->like + 0.03f);
if (whom->guest) whom->fun = fminf(1.0f, whom->fun + 0.03f);
sayIt(whom, like > 0.6f ? "Thanks. I needed that." : "...Thanks. Better.");
note(world, by, whom, TOUCHED_WELCOME, -1); /* (a kind act: seen) */
return true;
}