Files
deck_in_a_dash/interpreter/src/guidance.h
T
ml 1a654da3e9
build / build (push) Successful in 30s
Introduces watch/, a real Pebble watchapp (built via pebble build) that
shows the daily tarot/astrology reading on-device: persistence, reading
computation, and UI screens, driven by the existing engine/interpreter
code linked in unchanged where possible.

Required engine-side changes to make that linking work:
- A compact low-precision ephemeris (lowprec_ephemeris.c) replacing the
  vendored ~127KB Astronomy Engine, which doesn't fit the watch's ~64KB
  app budget.
- Hand-rolled sqrt/atan2/sin/cos replacements for that ephemeris and
  astro.c's Ascendant calculation - Pebble's statically-linked libm
  hard-faults on real hardware under this app's -fPIE link for all four.
- narrative.c/guidance.c refactored from FILE*/fprintf onto snprintf-
  based buffers, since Pebble's SDK blocks fprintf at compile time.
2026-07-14 17:10:22 +02:00

74 lines
3.8 KiB
C

#ifndef DECK_GUIDANCE_H
#define DECK_GUIDANCE_H
#include <stddef.h>
/* Header-only dependency on the engine for struct/enum *definitions*,
* same policy as narrative.h/significance.h - see their comments for
* why. Unlike those, though, the root Makefile *does* link
* engine/src/tarot_data.c's *implementation* (tarot_card_name()/
* tarot_card_meaning()) into the interpreter binary - a deliberate,
* narrow exception; see the Makefile's own comment on
* INTERP_TAROT_TEXT_OBJS for why that doesn't compromise this module's
* independent testability. */
#include "../../engine/src/tarot.h"
#include "significance.h"
/* Generous upper bound on guidance_write()'s output (intro/stance line
* + Attitude line + Outcome line, each ending in a newline, including
* the longest tarot_card_meaning() strings) across every language this
* project ships a translation for - see narrative.h's NARRATIVE_TEXT_MAX
* for the same reasoning. */
#define GUIDANCE_TEXT_MAX 1024
/* Ties the day's single most significant transit
* (interp->top_items[0]) to the Celtic Cross spread, and prints a short
* paragraph of concrete guidance on how to meet the day - the "combined
* storytelling" piece docs/reading.md flags as future work, now built.
* Prints on every day, quiet or major, tailored to interp->day_level -
* callers can invoke it unconditionally after every
* interpret_daily_reading() call.
*
* The core guidance keys off two things: the character of the top
* transit's aspect (harmonious/discordant/neutral, same classification
* narrative.c uses) and whether the spread's Attitude position - Waite's
* "Himself: his position or attitude in the circumstances", the
* position most directly about how the reader is meeting the day - fell
* upright or reversed. That crossing (3 x 2 = 6 combinations) is
* original text written for this project, not drawn from Waite or
* Sepharial, since neither source discusses combining astrology and
* tarot; it stays valid regardless of the day's intensity. What *does*
* vary with interp->day_level is only the sentence introducing the top
* transit (e.g. "With Saturn as today's dominant influence" on a Major
* day vs. "Saturn is only faintly active today, but for what it's
* worth" on a Quiet one). A day with no aspects in orb at all
* (interp->top_item_count == 0, always DAY_QUIET) has no transiting
* planet to introduce, so it falls back to a stance keyed on the
* Attitude card's orientation alone.
*
* The paragraph also names the Attitude and Outcome cards and, via
* tarot_card_meaning(), states their actual Waite meaning for the
* orientation they landed in (e.g. what Wheel of Fortune reversed
* means) - not a duplicated table, the real thing, since tarot_data.c
* is linked (see above).
*
* Every piece of this module's own text (stance/intro/no-transit/label
* strings) is looked up via i18n_get() under "guidance.*" keys
* (engine/i18n's .lang files) before falling back to the English text baked
* into guidance.c, so it respects whatever --lang the caller loaded
* with i18n_load()/i18n_load_table() (main.c does so before calling
* this). The German guidance.intro.* templates are deliberately phrased
* so the planet name placeholder is always the sentence's grammatical
* subject (nominative case) across all four day levels - see
* guidance.c's own comment on k_intro_fallback.
*
* Writes into `buf` (a caller-supplied buffer of `buf_size` bytes,
* always left null-terminated - GUIDANCE_TEXT_MAX is a safe size)
* instead of a FILE*, using only snprintf() internally (never
* fprintf/sprintf/vsnprintf, all of which Pebble's SDK blocks at compile
* time), so this function links into the watch app unchanged. */
void guidance_write(char *buf, size_t buf_size, const char *indent, const DailyInterpretation *interp,
const CelticCrossSpread *spread);
#endif