Give the interpreter real Celtic Cross meanings and --format/--lang support
- guidance.c now prints last, after the full spread; both it and main.c's new Celtic Cross readout pull real Waite card meanings via tarot_data.c instead of just naming cards. - interpreter-cli gains --format text|html|json and --lang en|de, matching deck-engine - required linking engine/src/tarot_data.c and i18n.c into the interpreter binary (a narrow, documented exception to its earlier "no engine .c files" policy) and writing German translations for narrative.c's/guidance.c's own text.
This commit is contained in:
@@ -22,6 +22,20 @@ static const char *const k_sign_slug[12] = {
|
||||
"libra", "scorpio", "sagittarius", "capricorn", "aquarius", "pisces",
|
||||
};
|
||||
|
||||
/* Mirrors tarot_data.c's own k_card_slug/k_position_slug, same
|
||||
* duplication policy as k_body_slug above. */
|
||||
static const char *const k_card_slug[TAROT_DECK_SIZE] = {
|
||||
"fool", "magician", "high_priestess", "empress", "emperor", "hierophant",
|
||||
"lovers", "chariot", "strength", "hermit", "wheel_of_fortune", "justice",
|
||||
"hanged_man", "death", "temperance", "devil", "tower", "star", "moon",
|
||||
"sun", "judgement", "world",
|
||||
};
|
||||
|
||||
static const char *const k_position_slug[TAROT_SPREAD_SIZE] = {
|
||||
"present", "challenge", "crown", "foundation", "recent_past",
|
||||
"near_future", "attitude", "environment", "hopes_and_fears", "outcome",
|
||||
};
|
||||
|
||||
static bool body_from_slug(const char *slug, Body *out) {
|
||||
for (int i = 0; i < NUM_BODIES; i++) {
|
||||
if (strcmp(slug, k_body_slug[i]) == 0) {
|
||||
@@ -77,6 +91,48 @@ static bool aspect_type_from_slug(const char *slug, AspectType *out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool card_from_slug(const char *slug, TarotCard *out) {
|
||||
for (int i = 0; i < TAROT_DECK_SIZE; i++) {
|
||||
if (strcmp(slug, k_card_slug[i]) == 0) {
|
||||
*out = (TarotCard)i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool position_from_slug(const char *slug, CelticCrossPosition *out) {
|
||||
for (int i = 0; i < TAROT_SPREAD_SIZE; i++) {
|
||||
if (strcmp(slug, k_position_slug[i]) == 0) {
|
||||
*out = (CelticCrossPosition)i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Fills out->positions[] from a "spread"."positions" JSON array. Used only
|
||||
* for guidance_print()'s Attitude/Outcome framing, never for scoring, so
|
||||
* this is deliberately lenient like parse_bodies(): an entry with an
|
||||
* unrecognized/missing "position" or "card" slug is skipped, and a
|
||||
* missing "spread" key entirely just leaves every position zeroed
|
||||
* (card = the first enum value, reversed = false) rather than failing
|
||||
* the whole load. */
|
||||
static void parse_spread(const JsonValue *positions, CelticCrossSpread *out) {
|
||||
int count = json_array_count(positions);
|
||||
for (int i = 0; i < count; i++) {
|
||||
const JsonValue *item = json_array_get(positions, i);
|
||||
CelticCrossPosition position;
|
||||
TarotCard card;
|
||||
if (!position_from_slug(json_as_string(json_object_get(item, "position")), &position)) continue;
|
||||
if (!card_from_slug(json_as_string(json_object_get(item, "card")), &card)) continue;
|
||||
|
||||
out->positions[position].card = card;
|
||||
const JsonValue *reversed = json_object_get(item, "reversed");
|
||||
out->positions[position].reversed = reversed && reversed->type == JSON_BOOL && reversed->as.boolean;
|
||||
}
|
||||
}
|
||||
|
||||
bool reading_load_json(const char *text, size_t length, DailyReading *out) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
@@ -122,6 +178,9 @@ bool reading_load_json(const char *text, size_t length, DailyReading *out) {
|
||||
parse_bodies(natal ? json_object_get(natal, "bodies") : NULL, out->natal.bodies);
|
||||
parse_bodies(json_object_get(transits, "bodies"), out->transits.bodies);
|
||||
|
||||
const JsonValue *spread = json_object_get(root, "spread");
|
||||
parse_spread(spread ? json_object_get(spread, "positions") : NULL, &out->spread);
|
||||
|
||||
json_free(root);
|
||||
return ok;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user