/* * The why questions coming up on the ground: you see something that makes you * wonder - a woman peeing standing up with a Urinella, somebody down drunk * that nobody noticed, a guy working shirtless - and it goes into your * notebook (J) with who could tell you why. Asked (talk.c, about the * festival), it's understood; the Herberge decides (game_meeting.c). * * The notebook: the festival (its name, who leads what, the cash box, what * this weekend is for) and the why questions, as far as each has got. */ #include #include "game/game_internal.h" #include "world/cast.h" #include "world/why.h" #define WHY_CHECK 1.0f /* s between looks round */ #define SEE_NEAR 25.0f /* m: what you notice */ #define WHY_SHOWN 7.0f /* s it stays on screen */ static bool near(const Game *game, const Object *o) { return hypotf(o->position.x - game->player->position.x, o->position.z - game->player->position.z) < SEE_NEAR; } static void comeUp(Game *game, int k, const char *what) { game->world.why[k] = WHY_RAISED; snprintf(game->story_line, sizeof game->story_line, "%s (J: your notebook)", what); say(game, game->story_line); game->message_time = WHY_SHOWN; } void game_why(Game *game, float dt) { if ((game->why_check -= dt) > 0.0f || Game_inBerlin(game->player)) return; game->why_check = WHY_CHECK; World *w = &game->world; char what[128]; for (int i = 0; i < w->count; i++) { const Object *o = w->objects[i]; if (o->type != OBJ_HUMAN || !near(game, o)) continue; if (w->why[WHY_URINELLA] == WHY_UNKNOWN && o->female && o->urinella && o->urinellas > 0 && o->ai.mode == AI_PEE && Body_isBusy(&o->body)) { snprintf(what, sizeof what, "%s pees standing up with a Urinella. Why would a festival hand those out?", o->name); comeUp(game, WHY_URINELLA, what); return; } if (w->why[WHY_AWARENESS] == WHY_UNKNOWN && Body_isDown(&o->body) && (o->passed_out || o->drunk > 0.7f)) { snprintf(what, sizeof what, "%s is down, out cold - and nobody noticed. Who looks out for people at a festival?", o->name); comeUp(game, WHY_AWARENESS, what); return; } if (w->why[WHY_SHIRT] == WHY_UNKNOWN && !o->female && o->look.top == TOP_BARE) { snprintf(what, sizeof what, "%s works shirtless. Festival bars that say \"no shirt, no service\" - why?", o->name); comeUp(game, WHY_SHIRT, what); return; } } } /* ---------- The notebook (J) ---------- */ /* A long text into lines of at most `width` characters (at spaces); returns how many. */ static int wrap(const char *text, const char *indent, char lines[][128], int max, int width) { int n = 0; const char *p = text; while (*p && n < max) { int len = (int)strlen(p), take = len; if (take > width) { take = width; while (take > 0 && p[take] != ' ') take--; if (take == 0) take = width; } snprintf(lines[n++], 128, "%s%.*s", indent, take, p); p += take; while (*p == ' ') p++; } return n; } int Game_notesLines(const Game *game, char lines[][128], int max, const char **title) { static char head[128]; const World *w = &game->world; int n = 0; snprintf(head, sizeof head, "Your notebook - %s (J: close)", Game_festivalName(game)); *title = head; /* who leads the floors */ static const int FLOORS[] = { PROJECT_OBSTWIESE, PROJECT_HOFBUEHNE, PROJECT_KARTOFFELACKER, PROJECT_HIDDEN }; char who[128] = "Leading the floors:"; size_t len = strlen(who); for (int k = 0; k < 4 && len < sizeof who - 30; k++) { const Object *lead = Cast_leadOf(w->objects, w->count, (Project)FLOORS[k]); if (game->player->leads == FLOORS[k]) lead = game->player; static const char *const SHORT[] = { "Obstwiese", "Hofbuehne", "Kartoffelacker", "techno" }; snprintf(who + len, sizeof who - len, "%s %s %s", k ? "," : "", SHORT[k], lead ? (lead == game->player ? "you" : lead->name) : "nobody"); len = strlen(who); } if (n < max) snprintf(lines[n++], 128, "%s", who); static const char *const FOCUS[] = { "-", "the floors", "the side jobs", "a party" }; if (n < max) snprintf(lines[n++], 128, "Cash box: %d EUR Weekend %d, for: %s", (int)w->cash, game->weekend, FOCUS[(unsigned)game->focus < 4 ? game->focus : 0]); if (n < max && (w->bigtree.step > BT_STANDING || Cast_leadOf(w->objects, w->count, PROJECT_BIG_TREE))) snprintf(lines[n++], 128, "The big old tree (Enrico): %s", game_bigTreeStatus(game)); if (n < max) snprintf(lines[n++], 128, " "); if (n < max) snprintf(lines[n++], 128, "Why do festivals do that?"); for (int k = 0; k < WHY_COUNT && n < max; k++) { const WhyInfo *q = Why_get(k); switch (w->why[k]) { case WHY_UNKNOWN: snprintf(lines[n++], 128, "- ? (hasn't come up yet)"); break; case WHY_RAISED: snprintf(lines[n++], 128, "- %s", q->ask); if (n < max) { char heard[128]; snprintf(heard, sizeof heard, "%s asked it at the Herberge: \"%s\"", q->raiser, q->raise); n += wrap(w->why_heard & (1 << k) ? heard : q->seen, " ", lines + n, max - n, 100); } if (n < max) snprintf(lines[n++], 128, " Ask %s, %s, %s or %s (X, 4, then 5)", q->knowers[0], q->knowers[1], q->knowers[2], q->knowers[3]); break; case WHY_UNDERSTOOD: snprintf(lines[n++], 128, "- %s", q->ask); if (n < max) n += wrap(q->because, " ", lines + n, max - n, 100); if (n < max) snprintf(lines[n++], 128, " Decided at the next Herberge"); break; default: snprintf(lines[n++], 128, "- %s: %s", q->title, w->why[k] == WHY_YES ? "yes - we do it" : "not this year"); break; } } n += game_festivalNotes(game, lines + n, max - n); return n; }