1a654da3e9
build / build (push) Successful in 30s
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.
183 lines
6.9 KiB
C
183 lines
6.9 KiB
C
#include "narrative.h"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
/* i18n_get() only - narrative.h already pulls in astro.h; this is the
|
|
* one additional engine header needed to route k_narratives/
|
|
* k_house_area through the same translation catalog tarot_data.c uses
|
|
* (see the Makefile's INTERP_TAROT_TEXT_OBJS comment for why i18n.c is
|
|
* linked into this binary). */
|
|
#include "../../engine/src/i18n.h"
|
|
|
|
typedef struct {
|
|
const char *slug; /* builds "narrative.<slug>.*" i18n keys */
|
|
const char *base; /* always relevant, may be "" (see the Sun) */
|
|
const char *harmonious; /* shown only under a trine/sextile; may be "" */
|
|
const char *discordant; /* shown only under a square/opposition; may be "" */
|
|
} TransitNarrative;
|
|
|
|
/* Fallback (English) text, also the source of truth when no translation
|
|
* catalog is loaded - see narrative.h's doc comment for sourcing
|
|
* (Sepharial, "Transits and Planetary Periods", 1920, Chapter VIII) and
|
|
* the Moon/Pluto exception. German translations live in
|
|
* engine/i18n/de.lang under the same "narrative.<slug>.*" keys. */
|
|
static const TransitNarrative k_narratives[NUM_BODIES] = {
|
|
[PLANET_SUN] = {
|
|
"sun", "",
|
|
"Benefits from superiors and advancement in your sphere of "
|
|
"life and work - honours, emoluments, and successful new "
|
|
"associations.",
|
|
"Degradation and dishonour, loss of position, and adverse "
|
|
"judgement from superiors.",
|
|
},
|
|
[PLANET_MOON] = {
|
|
/* Original text, not from Sepharial - see narrative.h. */
|
|
"moon",
|
|
"Colours the everyday and domestic sphere of life, often "
|
|
"coinciding with the opening of new avenues.",
|
|
"These changes tend to be advantageous.",
|
|
"These changes tend to be adverse, with some indisposition "
|
|
"or domestic friction.",
|
|
},
|
|
[PLANET_MERCURY] = {
|
|
"mercury",
|
|
"Affects writings, journeys, commerce, and everyday activities - "
|
|
"a neutral messenger whose effect follows the nature of the "
|
|
"aspect it makes.",
|
|
"", "",
|
|
},
|
|
[PLANET_VENUS] = {
|
|
"venus",
|
|
"Brings domestic and social affairs to the fore - happiness, "
|
|
"comforts, and favours.",
|
|
"Success in love affairs and artistic pursuits is likely.",
|
|
"Grief and disappointment are more likely.",
|
|
},
|
|
[PLANET_MARS] = {
|
|
"mars",
|
|
"A strenuous time of quarrels, contention, strife and anger, with "
|
|
"some risk of hurts or injuries depending on the sign it "
|
|
"occupies.",
|
|
"Can bring benefits from doctors, surgeons, or new projects "
|
|
"and enterprises.",
|
|
"",
|
|
},
|
|
[PLANET_JUPITER] = {
|
|
"jupiter",
|
|
"Brings increase and expansion - fullness of fortune and health, "
|
|
"and a generally fortunate time.",
|
|
"", "",
|
|
},
|
|
[PLANET_SATURN] = {
|
|
"saturn",
|
|
"Brings depression, stagnation, hindrances and obstacles, and "
|
|
"some deprivation of the usual benefits.",
|
|
"Favours from older connections and past associations are "
|
|
"still possible.",
|
|
"",
|
|
},
|
|
[PLANET_URANUS] = {
|
|
"uranus",
|
|
"Brings separations, estrangements, sudden dislocations and "
|
|
"violent upsets.",
|
|
"Success through official or civic channels, and "
|
|
"beneficial changes or appointments, are possible.",
|
|
"",
|
|
},
|
|
[PLANET_NEPTUNE] = {
|
|
"neptune",
|
|
"Brings a state of chaos and confusion - an involved, uncertain "
|
|
"condition of affairs, with plots, subtlety, or unseen "
|
|
"influences at work.",
|
|
"", "",
|
|
},
|
|
[PLANET_PLUTO] = {
|
|
/* Original text, not from Sepharial - see narrative.h. */
|
|
"pluto",
|
|
"Brings deep, often hidden transformation - the surfacing or "
|
|
"dismantling of something that has outgrown its old form.",
|
|
"", "",
|
|
},
|
|
};
|
|
|
|
static bool aspect_is_harmonious(AspectType type) {
|
|
return type == ASPECT_TRINE || type == ASPECT_SEXTILE;
|
|
}
|
|
|
|
static bool aspect_is_discordant(AspectType type) {
|
|
return type == ASPECT_SQUARE || type == ASPECT_OPPOSITION;
|
|
}
|
|
|
|
/* Traditional whole-sign house significations - the "area of life" each
|
|
* house governs. This is centuries-old, uncredited astrological
|
|
* convention (the same status as the sign/aspect names already baked
|
|
* into engine/src/astro.c), not text drawn from Sepharial or any other
|
|
* single source. Indexed house - 1; fallback (English) text only, keyed
|
|
* as "narrative.house.<1-12>" in engine/i18n's .lang files. */
|
|
static const char *const k_house_area[12] = {
|
|
"your sense of self, identity, and outward appearance",
|
|
"money, possessions, and personal values",
|
|
"communication, siblings, and everyday learning",
|
|
"home, family, and your roots",
|
|
"romance, creativity, and children",
|
|
"daily work, routine, and health",
|
|
"partnerships and close relationships",
|
|
"shared resources, intimacy, and transformation",
|
|
"travel, higher learning, and beliefs",
|
|
"career, reputation, and public standing",
|
|
"friendships, community, and hopes for the future",
|
|
"solitude, the subconscious, and hidden matters",
|
|
};
|
|
|
|
static const char *narrative_field(const char *slug, const char *field, const char *fallback) {
|
|
char key[48];
|
|
snprintf(key, sizeof key, "narrative.%s.%s", slug, field);
|
|
return i18n_get(key, fallback);
|
|
}
|
|
|
|
void narrative_write(char *buf, size_t buf_size, const char *indent, const Aspect *aspect,
|
|
int transiting_house) {
|
|
if (buf_size == 0) return;
|
|
buf[0] = '\0';
|
|
|
|
const TransitNarrative *n = &k_narratives[aspect->transiting_planet];
|
|
const char *base = narrative_field(n->slug, "base", n->base);
|
|
|
|
const char *extra = "";
|
|
if (aspect_is_harmonious(aspect->type)) extra = narrative_field(n->slug, "harmonious", n->harmonious);
|
|
else if (aspect_is_discordant(aspect->type)) extra = narrative_field(n->slug, "discordant", n->discordant);
|
|
|
|
if (base[0] == '\0' && extra[0] == '\0') return;
|
|
|
|
/* Chained snprintf() calls, each bounds-checked against the running
|
|
* length before the next one runs - never fprintf/sprintf/vsnprintf,
|
|
* all of which Pebble's SDK blocks at compile time (see narrative.h's
|
|
* doc comment). Once `len` reaches buf_size (truncated), every
|
|
* subsequent call is skipped rather than computing buf_size - len,
|
|
* which would underflow. */
|
|
size_t len = (size_t)snprintf(buf, buf_size, "%s", indent);
|
|
if (len >= buf_size) return;
|
|
|
|
if (transiting_house >= 1 && transiting_house <= 12) {
|
|
char house_key[24];
|
|
snprintf(house_key, sizeof house_key, "narrative.house.%d", transiting_house);
|
|
const char *area = i18n_get(house_key, k_house_area[transiting_house - 1]);
|
|
|
|
char frame[256];
|
|
snprintf(frame, sizeof frame, i18n_get("narrative.house_frame", "In matters of %s (house %d)."),
|
|
area, transiting_house);
|
|
len += (size_t)snprintf(buf + len, buf_size - len, "%s ", frame);
|
|
if (len >= buf_size) return;
|
|
}
|
|
if (base[0] != '\0') {
|
|
len += (size_t)snprintf(buf + len, buf_size - len, "%s", base);
|
|
if (len >= buf_size) return;
|
|
}
|
|
if (extra[0] != '\0') {
|
|
len += (size_t)snprintf(buf + len, buf_size - len, "%s%s", base[0] != '\0' ? " " : "", extra);
|
|
if (len >= buf_size) return;
|
|
}
|
|
snprintf(buf + len, buf_size - len, "\n");
|
|
}
|