#include "tarot.h" #include "i18n.h" #include #include /* Card meanings are condensed from A. E. Waite, The Pictorial Key to the * Tarot (1911), Part III §3 "The Greater Arcana and their Divinatory * Meanings" (public domain). Waite gives several alternative readings * for some cards; these keep his own wording, trimmed to the core * clauses. */ typedef struct { const char *name; const char *image_file; const char *upright; const char *reversed; } TarotCardInfo; static const TarotCardInfo k_cards[TAROT_DECK_SIZE] = { [CARD_FOOL] = { "The Fool", "RWS_Tarot_00_Fool.jpeg", "Folly, mania, extravagance, intoxication, delirium, frenzy.", "Negligence, absence, carelessness, apathy, nullity, vanity." }, [CARD_MAGICIAN] = { "The Magician", "RWS_Tarot_01_Magician.jpeg", "Skill, diplomacy, address, subtlety; self-confidence, will.", "Physician, Magus, mental disease, disgrace, disquiet." }, [CARD_HIGH_PRIESTESS] = { "The High Priestess", "RWS_Tarot_02_High_Priestess.jpeg", "Secrets, mystery, the future as yet unrevealed; silence, tenacity, wisdom, science.", "Passion, moral or physical ardour, conceit, surface knowledge." }, [CARD_EMPRESS] = { "The Empress", "RWS_Tarot_03_Empress.jpeg", "Fruitfulness, action, initiative, length of days; also difficulty, doubt, ignorance.", "Light, truth, the unravelling of involved matters, public rejoicings; vacillation." }, [CARD_EMPEROR] = { "The Emperor", "RWS_Tarot_04_Emperor.jpeg", "Stability, power, protection, realization; aid, reason, conviction, authority and will.", "Benevolence, compassion, credit; also confusion to enemies, obstruction, immaturity." }, [CARD_HIEROPHANT] = { "The Hierophant", "RWS_Tarot_05_Hierophant.jpeg", "Marriage, alliance, captivity, servitude; by another account, mercy, goodness, inspiration.", "Society, good understanding, concord, over-kindness, weakness." }, [CARD_LOVERS] = { "The Lovers", "RWS_Tarot_06_Lovers.jpeg", "Attraction, love, beauty, trials overcome.", "Failure, foolish designs; marriage frustrated, contrarieties of all kinds." }, [CARD_CHARIOT] = { "The Chariot", "RWS_Tarot_07_Chariot.jpeg", "Succour, providence; also war, triumph, presumption, vengeance, trouble.", "Riot, quarrel, dispute, litigation, defeat." }, [CARD_STRENGTH] = { "Strength", "RWS_Tarot_08_Strength.jpeg", "Power, energy, action, courage, magnanimity; complete success and honours.", "Despotism, abuse of power, weakness, discord, sometimes even disgrace." }, [CARD_HERMIT] = { "The Hermit", "RWS_Tarot_09_Hermit.jpeg", "Prudence, circumspection; also, and especially, treason, dissimulation, roguery, corruption.", "Concealment, disguise, policy, fear, unreasoned caution." }, [CARD_WHEEL_OF_FORTUNE] = { "Wheel of Fortune", "RWS_Tarot_10_Wheel_of_Fortune.jpeg", "Destiny, fortune, success, elevation, luck, felicity.", "Increase, abundance, superfluity." }, [CARD_JUSTICE] = { "Justice", "RWS_Tarot_11_Justice.jpeg", "Equity, rightness, probity, executive; triumph of the deserving side in law.", "Law in all its departments, legal complications, bigotry, bias, excessive severity." }, [CARD_HANGED_MAN] = { "The Hanged Man", "RWS_Tarot_12_Hanged_Man.jpeg", "Wisdom, circumspection, discernment, trials, sacrifice, intuition, divination, prophecy.", "Selfishness, the crowd, body politic." }, [CARD_DEATH] = { "Death", "RWS_Tarot_13_Death.jpeg", "End, mortality, destruction, corruption; loss of a benefactor, or many contrarieties.", "Inertia, sleep, lethargy, petrifaction, somnambulism; hope destroyed." }, [CARD_TEMPERANCE] = { "Temperance", "RWS_Tarot_14_Temperance.jpeg", "Economy, moderation, frugality, management, accommodation.", "Things connected with churches, religions, sects, the priesthood; disunion, competing interests." }, [CARD_DEVIL] = { "The Devil", "RWS_Tarot_15_Devil.jpeg", "Ravage, violence, vehemence, extraordinary efforts, force, fatality.", "Evil fatality, weakness, pettiness, blindness." }, [CARD_TOWER] = { "The Tower", "RWS_Tarot_16_Tower.jpeg", "Misery, distress, indigence, adversity, calamity, disgrace, deception, ruin; unforeseen catastrophe.", "The same in a lesser degree; also oppression, imprisonment, tyranny." }, [CARD_STAR] = { "The Star", "RWS_Tarot_17_Star.jpeg", "Loss, theft, privation, abandonment; another reading says hope and bright prospects.", "Arrogance, haughtiness, impotence." }, [CARD_MOON] = { "The Moon", "RWS_Tarot_18_Moon.jpeg", "Hidden enemies, danger, calumny, darkness, terror, deception, occult forces, error.", "Instability, inconstancy, silence, lesser degrees of deception and error." }, [CARD_SUN] = { "The Sun", "RWS_Tarot_19_Sun.jpeg", "Material happiness, fortunate marriage, contentment.", "The same in a lesser sense." }, [CARD_JUDGEMENT] = { "Judgement", "RWS_Tarot_20_Judgement.jpeg", "Change of position, renewal, outcome; another account specifies total loss through lawsuit.", "Weakness, pusillanimity, simplicity; also deliberation, decision, sentence." }, [CARD_WORLD] = { "The World", "RWS_Tarot_21_World.jpeg", "Assured success, recompense, voyage, route, emigration, flight, change of place.", "Inertia, fixity, stagnation, permanence." }, }; /* Position names and one-line descriptions follow Waite's own account * of "An Ancient Celtic Method of Divination" (Part III §7), in his * original drawing order. Waite addresses the querent as "him" * throughout; that wording is kept verbatim as the GENDER_MALE variant * below, and GENDER_FEMALE/GENDER_UNSPECIFIED are original paraphrases * written for this project (not Waite's own text) so the reading can * address the person it's actually for. Each array is indexed by * Gender (tarot.h): [GENDER_UNSPECIFIED], [GENDER_MALE], [GENDER_FEMALE]. */ typedef struct { const char *name[3]; const char *description[3]; } PositionInfo; static const PositionInfo k_positions[TAROT_SPREAD_SIZE] = { [POSITION_PRESENT] = { { "The Present", "The Present", "The Present" }, { "This covers them: the general influence affecting the matter.", "This covers him: the general influence affecting the matter.", "This covers her: the general influence affecting the matter.", } }, [POSITION_CHALLENGE] = { { "The Challenge", "The Challenge", "The Challenge" }, { "This crosses them: the nature of the obstacle in the matter.", "This crosses him: the nature of the obstacle in the matter.", "This crosses her: the nature of the obstacle in the matter.", } }, [POSITION_CROWN] = { { "The Crown", "The Crown", "The Crown" }, { "This crowns them: the aim or ideal, the best that can be achieved.", "This crowns him: the aim or ideal, the best that can be achieved.", "This crowns her: the aim or ideal, the best that can be achieved.", } }, [POSITION_FOUNDATION] = { { "The Foundation", "The Foundation", "The Foundation" }, { "This is beneath them: the basis of the matter, already actual.", "This is beneath him: the basis of the matter, already actual.", "This is beneath her: the basis of the matter, already actual.", } }, [POSITION_RECENT_PAST] = { { "The Recent Past", "The Recent Past", "The Recent Past" }, { "This is behind them: the influence that is just passing away.", "This is behind him: the influence that is just passing away.", "This is behind her: the influence that is just passing away.", } }, [POSITION_NEAR_FUTURE] = { { "The Near Future", "The Near Future", "The Near Future" }, { "This is before them: the influence now coming into action.", "This is before him: the influence now coming into action.", "This is before her: the influence now coming into action.", } }, [POSITION_ATTITUDE] = { { "Themself", "Himself", "Herself" }, { "Their position or attitude in the circumstances.", "His position or attitude in the circumstances.", "Her position or attitude in the circumstances.", } }, [POSITION_ENVIRONMENT] = { { "Their House", "His House", "Her House" }, { "Their environment and the tendencies at work therein.", "His environment and the tendencies at work therein.", "Her environment and the tendencies at work therein.", } }, [POSITION_HOPES_AND_FEARS] = { { "Hopes and Fears", "Hopes and Fears", "Hopes and Fears" }, { "Their hopes or fears in the matter.", "His hopes or fears in the matter.", "Her hopes or fears in the matter.", } }, [POSITION_OUTCOME] = { { "The Outcome", "The Outcome", "The Outcome" }, { "What will come: the final result of the matter.", "What will come: the final result of the matter.", "What will come: the final result of the matter.", } }, }; /* Slugs used to build i18n.c lookup keys ("card..name", etc.) - * translation files key off these, not the enum names, so renaming a C * enumerator never silently breaks a .lang file. */ static const char *const k_card_slug[TAROT_DECK_SIZE] = { [CARD_FOOL] = "fool", [CARD_MAGICIAN] = "magician", [CARD_HIGH_PRIESTESS] = "high_priestess", [CARD_EMPRESS] = "empress", [CARD_EMPEROR] = "emperor", [CARD_HIEROPHANT] = "hierophant", [CARD_LOVERS] = "lovers", [CARD_CHARIOT] = "chariot", [CARD_STRENGTH] = "strength", [CARD_HERMIT] = "hermit", [CARD_WHEEL_OF_FORTUNE] = "wheel_of_fortune", [CARD_JUSTICE] = "justice", [CARD_HANGED_MAN] = "hanged_man", [CARD_DEATH] = "death", [CARD_TEMPERANCE] = "temperance", [CARD_DEVIL] = "devil", [CARD_TOWER] = "tower", [CARD_STAR] = "star", [CARD_MOON] = "moon", [CARD_SUN] = "sun", [CARD_JUDGEMENT] = "judgement", [CARD_WORLD] = "world", }; static const char *const k_position_slug[TAROT_SPREAD_SIZE] = { [POSITION_PRESENT] = "present", [POSITION_CHALLENGE] = "challenge", [POSITION_CROWN] = "crown", [POSITION_FOUNDATION] = "foundation", [POSITION_RECENT_PAST] = "recent_past", [POSITION_NEAR_FUTURE] = "near_future", [POSITION_ATTITUDE] = "attitude", [POSITION_ENVIRONMENT] = "environment", [POSITION_HOPES_AND_FEARS] = "hopes_and_fears", [POSITION_OUTCOME] = "outcome", }; static const char *card_field(const char *slug, const char *field, const char *fallback) { char key[64]; strcpy(key, "card."); strcat(key, slug); strcat(key, "."); strcat(key, field); return i18n_get(key, fallback); } /* Suffix appended to the i18n key for the male/female variants - the * unspecified/neutral variant uses the plain, unsuffixed key so it * matches the field name callers already know (e.g. "position. * attitude.name"), same convention as card_field()'s upright/reversed * field names above. */ static const char *const k_gender_suffix[3] = { [GENDER_UNSPECIFIED] = "", [GENDER_MALE] = ".male", [GENDER_FEMALE] = ".female", }; static const char *const k_gender_slug[3] = { [GENDER_UNSPECIFIED] = "unspecified", [GENDER_MALE] = "male", [GENDER_FEMALE] = "female", }; static const char *position_field(const char *slug, const char *field, Gender gender, const char *fallback) { char neutral_key[80]; strcpy(neutral_key, "position."); strcat(neutral_key, slug); strcat(neutral_key, "."); strcat(neutral_key, field); if (gender == GENDER_UNSPECIFIED) return i18n_get(neutral_key, fallback); /* Not every position's text actually varies by gender (e.g. "The * Outcome" has no pronoun) - the .lang files only define a ".male"/ * ".female" key where the wording differs. So look up the neutral key * first and use *that* (translated, if a catalog is loaded) as the * fallback for the gendered key, rather than jumping straight past a * loaded translation to the hardcoded English `fallback` whenever the * gendered key happens to be absent. */ const char *neutral_text = i18n_get(neutral_key, fallback); char key[88]; strcpy(key, neutral_key); strcat(key, k_gender_suffix[gender]); return i18n_get(key, neutral_text); } const char *tarot_card_name(TarotCard card) { return card_field(k_card_slug[card], "name", k_cards[card].name); } const char *tarot_card_image_file(TarotCard card) { /* Not translated - it's a filename, not display text. */ return k_cards[card].image_file; } const char *tarot_card_meaning(TarotCard card, bool reversed) { return card_field(k_card_slug[card], reversed ? "reversed" : "upright", reversed ? k_cards[card].reversed : k_cards[card].upright); } const char *tarot_position_name(CelticCrossPosition position, Gender gender) { return position_field(k_position_slug[position], "name", gender, k_positions[position].name[gender]); } const char *tarot_position_description(CelticCrossPosition position, Gender gender) { return position_field(k_position_slug[position], "desc", gender, k_positions[position].description[gender]); } const char *tarot_card_slug(TarotCard card) { return k_card_slug[card]; } const char *tarot_position_slug(CelticCrossPosition position) { return k_position_slug[position]; } const char *tarot_gender_slug(Gender gender) { return k_gender_slug[gender]; }