diff --git a/loreroll/data/npc.json b/loreroll/data/npc.json new file mode 100644 index 0000000..5d867b1 --- /dev/null +++ b/loreroll/data/npc.json @@ -0,0 +1 @@ +{"races": [{"v": "aasimar", "w": 0.5}, {"v": "bugbear", "w": 0.1}, {"v": "dragonborn", "w": 1.0}, {"v": "dwarf (hill)", "w": 0.5}, {"v": "dwarf (mountain)", "w": 0.5}, {"v": "elf (high)", "w": 0.5}, {"v": "elf (wood)", "w": 0.5}, {"v": "elf (dark - drow)", "w": 0.1}, {"v": "firbolg", "w": 0.5}, {"v": "gnome (forest)", "w": 0.5}, {"v": "gnome (rock)", "w": 0.5}, {"v": "goblin", "w": 0.1}, {"v": "goliath", "w": 0.5}, {"v": "half-elf", "w": 1.0}, {"v": "half-orc", "w": 1.0}, {"v": "halfling (lightfoot)", "w": 0.5}, {"v": "halfling (stout)", "w": 0.5}, {"v": "hobgoblin", "w": 0.1}, {"v": "human", "w": 2.0}, {"v": "kenku", "w": 0.5}, {"v": "kobold", "w": 0.1}, {"v": "lizardfolk", "w": 0.5}, {"v": "orc", "w": 0.1}, {"v": "tabaxi", "w": 0.5}, {"v": "triton", "w": 0.5}, {"v": "tiefling", "w": 1.0}, {"v": "tortle", "w": 0.1}, {"v": "yuan-ti pureblood", "w": 0.1}], "classes": ["barbarian", "bard", "cleric", "druid", "fighter", "monk", "paladin", "ranger", "rogue", "sorcerer", "warlock", "wizard"], "age": [{"v": "very young", "w": 0.2}, {"v": "young", "w": 0.7}, {"v": "adult", "w": 1.0}, {"v": "middle aged", "w": 1.0}, {"v": "older", "w": 1.0}, {"v": "old", "w": 0.7}, {"v": "very old", "w": 0.3}, {"v": "ancient", "w": 0.1}], "physical": ["abnormally fat", "abnormally short", "abnormally tall", "abnormally thin", "agile", "athletic", "brawny", "broad shoulders", "chubby", "clumsy", "crooked posture", "curvy", "fat", "feeble", "fit", "hourglass figure", "hunchback", "hunched", "lanky", "large butt", "large hips", "medium build", "muscular", "muscular arms", "muscular legs", "obese", "overweight", "plump", "robust", "sinewy", "skinny", "slender", "slim", "slumped shoulders", "stocky", "stout", "strong", "tall", "thin", "tough", "weak", "well built", "average height", "petite", "short", "tall", "towering", "albino", "dark", "fire-burnt skin", "freckles", "light", "pale", "pimples", "sagging", "scarred", "spots", "smallpox scars", "sunburnt", "tanned", "unusual skin color", "wrinkles", "afro", "bald", "beads in hair/beard", "beard", "braided beard", "braids", "bushy hair", "bushy beard", "clean-shaven", "colored hair/beard", "dreadlocks", "fake hair", "fake beard", "full beard", "glorious beard", "goatee", "greasy hair", "handlebar beard", "long beard", "long hair", "messy hair", "mohawk", "moustache", "mullet", "muttonchops", "ponytail", "receding hair", "short hair", "shoulder-length hair", "stubble", "thinning hair", "thin/sparse beard", "unusual hair color", "wig", "bright clothes", "clean clothes", "colorful clothes", "dark clothes", "dirty clothes", "flamboyant clothes", "formal clothes", "outlandish clothes", "ragged clothes", "vibrant clothes", "well dressed", "amulet", "bracelets", "circlet", "distinctive amulet", "distinctive bracelets", "distinctive circlet", "distinctive jewelry", "distinctive necklace", "distinctive piercing(s)", "distinctive ring(s)", "jewelry", "massive amulet", "massive bracelets", "massive circlet", "massive jewelry", "massive necklace", "massive piercing(s)", "massive ring(s)", "necklace", "piercing(s)", "ring(s)", "subtle amulet", "subtle bracelets", "subtle circlet", "subtle jewelry", "subtle necklace", "subtle piercing(s)", "subtle ring(s)", "acid burn", "acne scars", "almost blind", "almost deaf", "artificial arm", "artificial claw instead of hand", "artificial ear", "artificial eye", "artificial eyebrows", "artificial finger(s)", "artificial fingernail(s)", "artificial hand", "artificial leg", "artificial nose", "artificial teeth", "attractive", "bags under eyes", "big ears", "big eyes", "big nose", "birthmark", "black eye", "blackened teeth", "blind", "blushing", "broken nose", "broken jaw", "bruise(s)", "cain", "clean", "clean teeth", "crooked mouth", "crooked nose", "cross-eyed", "crutches", "cute", "deaf", "deep voice", "different arm length", "different foot size", "different hand size", "different leg length", "dimple in chin", "dimples in cheeks", "dirty", "distinctive nose", "earrings", "exceptionally beautiful", "exceptionally ugly", "extra finger", "extravagant", "eyes twitch", "fang(s)", "forked tongue", "fur on a part of body", "glass eye", "glasses", "golden front tooth", "handsome", "high forehead", "high-pitched voice", "hook instead of a hand", "hooked nose", "horn(s)", "huge scar", "limping", "long nails", "loud voice", "mismatched eyes color", "missing arm", "missing ear", "missing eye", "missing eyebrows", "missing finger(s)", "missing fingernail(s)", "missing hand", "missing leg", "missing nose", "missing teeth", "monocle", "mute", "overbite", "pointy chin", "pointy nose", "pointy teeth", "pretty", "ragged", "runes carved into skin", "scales on a part of body", "scar across face", "scar(s)", "sexy", "silent voice", "small ears", "small eyes", "small nose", "smokepipe", "spectacles", "swollen eye", "tail", "tattooed", "tattooed face", "thick eyebrows", "tusks", "twitch", "ugly", "unable to walk", "underbite", "unusual eye color", "visible Adam's apple", "whispers", "wooden leg"], "personality": ["able", "abrasive", "abrupt", "absent-minded", "abusive", "accepting", "accomodating", "accomplished", "active", "adaptable", "ADHD", "addict", "adorable", "adventurous", "affectionate", "affraid", "aggresive", "agnostic", "agreeable", "aimless", "alcoholic", "alert", "alluring", "altruistic", "always drunk", "always hungry", "always late", "amiable", "ambitious", "amoral", "analytical", "angry", "annoyed", "annoying", "anti-social", "anxious", "apathetic", "apologetic", "appreciative", "approachable", "argumentative", "arrogant", "articulate", "artistic", "ashamed", "asocial", "aspiring", "assertive", "attentive", "audacious", "austere", "authoritarian", "avant-garde", "average", "awkward", "babbling", "babyish", "bad loser", "barbaric", "bashful", "belligerent", "benevolent", "bewildered", "bigoted", "bites fingernails", "bitter", "bizarre", "blaming", "blunt", "boastful", "bold", "bookworm", "bored", "bossy", "brainy", "bratty", "brave", "brazen", "bright", "brilliant", "brittle", "brotherly", "brutal", "brutish", "bully", "businesslike", "busy", "calculating", "callous", "calm", "candid", "can-do attitude", "can't-do attitude", "capable", "careless", "caring", "casual", "cautious", "charismatic", "charitable", "charming", "chaste", "chatty", "cheater", "cheerful", "cheerless", "chewing", "childish", "chivalrous", "civilised", "classy", "clever", "clumsy", "coarse", "cocky", "coherent", "cold", "cold-hearted", "collector", "committed", "communicative", "compassionate", "competent", "competitive", "composed", "compulsive", "concerned", "condescending", "confident", "conformist", "confused", "conservative", "considerate", "consistent", "conspiracy theorist", "content", "conversational", "cooperative", "coquettish", "courageous", "courteous", "cowardly", "cowering", "coy", "crazy", "creative", "credible", "creepy", "critical", "crude", "cruel", "cryptic", "cuddly", "cultured", "cunning", "curious", "cursed", "cursing", "cutthroat", "cynical", "dainty", "dangerous", "daring", "dark", "dashing", "dauntless", "dazzling", "decadent", "deceitful", "decent", "deceptive", "decisive", "decorous", "dedicated", "deep", "defeated", "defiant", "delicate", "demanding", "dependable", "dependent", "depressed", "deranged", "desperate", "despicable", "destructive", "determined", "devious", "devoted", "dignified", "dilligent", "dim-witted", "diplomatic", "direct", "disagreeable", "disciplined", "discouraged", "discouraging", "discreet", "disgusting", "dishonest", "disillusioned", "disinterested", "disloyal", "disobedient", "disorderly", "disorganized", "disrespectful", "disruptive", "dissatisfied", "distant", "distrought", "disturbed", "dogmatic", "dominant", "dominating", "doom-sayer", "dorky", "doubtful", "dramatic", "dreamy", "dreary", "driven", "drunk", "dubious", "dull", "dumb", "dutiful", "dynamic", "dyslexic", "eager", "easily distracted", "easy-going", "eccentric", "educated", "efficient", "egocentric", "egoistical", "elated", "elegant", "eloquent", "embarrassed", "emotional", "empathetic", "encouraging", "energetic", "engaging", "enthusiastic", "envious", "erratic", "ethical", "evasive", "evil", "excited", "extravagant", "extrovert", "fabulous", "fair", "faithful", "faithless", "family person", "famous", "fanatical", "fascinated", "fast-talker", "fatalistic", "fearless", "feisty", "femme fatale", "ferocious", "fickle", "fidgety", "fierce", "fiery", "filthy", "finicky", "firm", "fixated", "flamboyant", "flexible", "flirty", "flustered", "focused", "folksy", "foolish", "forceful", "forgetful", "forgiving", "formal", "forthright", "foul", "frank", "frantic", "fretful", "friendly", "frightened", "frustrated", "fun-loving", "funny", "furious", "fussy", "gallant", "generous", "genial", "gentle", "genuine", "giving", "glamorous", "glum", "good-natured", "goofy", "gossipy", "glamorous", "gloomy", "gluttonous", "graceful", "gracious", "grandiose", "grateful", "greedy", "grieving", "grim", "growly", "gruesome", "gruff", "grumpy", "guarded", "guileless", "guilty", "gullible", "haggling", "happy", "hardened", "hardworking", "harsh", "hateful", "heartbroken", "heartless", "hedonistic", "helpful", "helpless", "hesitant", "high voice", "high-spirited", "hilarious", "hillbilly", "honest", "honorable", "hopeful", "hopeless", "hospitable", "hostile", "hot-headed", "hot-tempered", "humble", "humming", "humorous", "humourless", "hungry for fame", "hypochondriac", "hypocritical", "hysterical", "idealistic", "idiotic", "ignorant", "ill-mannered", "illiterate", "imaginative", "immature", "immodest", "impartial", "impatient", "impolite", "impractical", "impulsive", "inactive", "incompetent", "inconsiderate", "inconsistent", "incorruptible", "indecisive", "independent", "indifferent", "individualistic", "indulgent", "inept", "infamous", "innovative", "inquisitive", "insecure", "insensitive", "insightful", "insincere", "insistent", "inspiring", "insulting", "intellectual", "intelligent", "interested", "interrupting", "intimidating", "intollerant", "introspective", "introvert", "intuitive", "involved", "irrational", "irreligious", "irresolute", "irresponsible", "irritable", "irritating", "jack of all trades", "jackass", "jealous", "jerk", "joker", "jolly", "jovial", "joyful", "judgemental", "just", "keen", "kind", "knowledgeable", "know-it-all", "lascivious", "lazy", "leader", "lethargic", "lewd", "liar", "liberal", "likeable", "lively", "logical", "lovable", "love-struck", "loving", "low voice", "low confidence", "loyal", "lucky", "lunatic", "macho", "mad", "malicious", "manipulative", "mannered", "mannerless", "masochist", "materialistic", "mature", "mean", "meddlesome", "meek", "megalomaniac", "melancholic", "melodramatic", "merciful", "merciless", "mild", "militant", "misanthrope", "mischievous", "miserable", "misguided", "mistrusting", "modest", "money-minded", "moody", "moralistic", "mysterious", "mystical", "naive", "narcissistic", "narrow-minded", "nasty", "nationalist", "naughty", "neat", "negativistic", "neglectful", "nerd", "nervous", "neurotic", "neutral", "nice", "nihilistic", "nit picker", "noble", "noisy", "nonchalant", "noncommittal", "noncompetitive", "non-violent", "nosey", "nut", "obedient", "obliging", "oblivious", "obnoxious", "obscene", "observant", "obsessive", "odd", "old-fashioned", "open-minded", "opinionated", "opportunistic", "oppressor", "optimistic", "orderly", "ordinary", "organized", "ostentatious", "outgoing", "outrageous", "outspoken", "over-confident", "over-educated", "over-protective", "pacifist", "pacing", "panicky", "paranoid", "particular", "passionate", "passive", "passive-aggresive", "pathetic", "patient", "patriotic", "peaceful", "pedantic", "perceptive", "perfect", "perfect manners", "perfectionist", "performer", "persistent", "persuasive", "pert", "perverse", "pessimistic", "pest", "petty", "philosophical", "philantropic", "picky", "pious", "pitiful", "playful", "pleasant", "plotting", "polite", "pompous", "poor", "popular", "positive", "possessive", "power-hungry", "practical", "precise", "predictable", "prejudiced", "preoccupied", "pretentious", "primitive", "principled", "private", "procrastinating", "productive", "profane", "professional", "progressive", "promiscuous", "proper", "prophetic", "proselytizer", "protective", "provocative", "proud", "prudent", "psychotic", "punctual", "pure", "purposeful", "pushy", "puzzled", "quarrelsome", "quick", "quiet", "quirky", "racist", "rambunctious", "rational", "realistic", "reasonable", "rebel", "receptive", "reckless", "reflective", "regretful", "relaxed", "reliable", "religious", "reluctant", "remorseful", "remorseless", "resentful", "reserved", "resilient", "resolute", "respectful", "responsible", "restless", "revengeful", "rhetorical", "rigid", "rigorous", "risk-taking", "ritualistic", "romantic", "rough", "rowdy", "rude", "rugged", "ruthless", "sacrificing", "sad", "sadistic", "sagely", "saintly", "sarcastic", "sassy", "satisfied", "savage", "scandalous", "scared", "scary", "sceptical", "scheming", "scornful", "seclusive", "secretive", "secure", "seducer", "seductive", "selective", "self-centered", "self-confident", "self-conscious", "self-controlling", "self-critical", "self-destructive", "self-directed", "self-disciplined", "self-important", "self-pitying", "self-reliant", "self-righteous", "self-sacrificing", "selfish", "selfless", "senile", "sensitive", "sensual", "sentimental", "serene", "serious", "sexist", "sexual", "shallow", "shameful", "shameless", "sharing", "sharp", "sharp-tongued", "sharp-witted", "sheepish", "shifty", "shortsighted", "shrewd", "shy", "silent", "silly", "simple", "sincere", "singing", "skillful", "slacker", "sleazy", "slimy", "sloppy", "slow", "slutty", "sly", "small-minded", "smart", "smart ass", "smiling", "snarky", "sneaky", "snob", "sociable", "soft", "soft-hearted", "solemn", "solitary", "sophisticated", "sore", "speaks loudly", "speaks silently", "spineless", "spiritual", "spiteful", "spoiled", "spontaneous", "staring", "stern", "stimulating", "stingy", "stoic", "stupid", "strange", "strict", "strong-willed", "stubborn", "studious", "stupid", "stutters", "stylish", "submissive", "sullen", "sultry", "superstitious", "supportive", "surly", "suspicious", "sweet", "swindler", "sympathetic", "systematic", "tacky", "tactful", "tactless", "talented", "talkative", "taps fingers", "technophobic", "temperamental", "tense", "terrified", "thankful", "thankless", "theatrical", "thick-skinned", "thorough", "thoughtful", "thoughtless", "threatening", "thick", "thrilled", "tidy", "tight", "timid", "tired", "tireless", "tiresome", "tolerant", "touchy", "traditionalist", "transparent", "treacherous", "troubled", "troublemaker", "troublesome", "trusting", "trustworthy", "truthful", "tugs hair/beard", "twirls hair/beard", "unaggressive", "unambitious", "unappreciative", "unassuming", "unbiased", "uncaring", "uncertain", "unconcerned", "unconventional", "unconvincing", "uncooperative", "uncoordinated", "undependable", "understanding", "undisciplined", "unfocused", "unfriendly", "ungrateful", "unhappy", "unhelpful", "unimaginative", "unkind", "unlucky", "unmotivated", "unpredictable", "unprincipled", "unreliable", "unruly", "unscrupulous", "unselfish", "unsentimental", "unstable", "unsure", "unsympathetic", "unsystematic", "untrustworthy", "unwilling", "upright", "upset", "uptight", "useful", "vague", "vain", "valiant", "vegan", "vegetarian", "vengeful", "verbose", "vindictive", "violent", "virtuous", "vivacious", "volatile", "vulgar", "vulnerable", "warm", "wary", "weak-willed", "weird", "well-travelled", "whimsical", "whiny", "whispers", "whistling", "wicked", "wild", "wise", "wishful", "withdrawn", "witty", "worried", "wretched", "youthful", "xenophobic", "zealous"], "names": ["Abrielle", "Acalia", "Acele", "Acholate", "Ada", "Adara", "Adiannon", "Adorra", "Adriel", "Aeris", "Afia", "Agama", "Ahanna", "Aiyana", "Akara", "Akassa", "Akia", "Alissa", "Alixandra", "Amaerilde", "Amara", "Amarisa", "Amarizi", "Ana", "Anatola", "Andonna", "Ani", "Anika", "Annalyn", "Annihya", "Antia", "Anya", "Apollonia", "Arcadia", "Archane", "Ariadne", "Ariannona", "Arianwen", "Arina", "Arryn", "Asada", "Asralyn", "Aurelia", "Auristela", "Awnia", "Aylia", "Ayne", "Baakshi", "Basak", "Basete", "Bathelie", "Beatha", "Beela", "Belen", "Bethe", "Braithe", "Brana", "Breena", "Brianan", "Bridonna", "Brielle", "Brynhilde", "Calene", "Calina", "Cambria", "Cara", "Carys", "Cassia", "Cassiopeia", "Celeste", "Celestine", "Celoa", "Cephenrene", "Chani", "Chivahle", "Chrystyne", "Ciscra", "Cora", "Corda", "Cyelena", "Dalavesta", "Daria", "Desini", "Desmina", "Dessa", "Drusila", "Duella", "Dylena", "Ebatryne", "Ecematare", "Edeline", "Efari", "Eira", "Eliron", "Elysa", "Elysia", "Enaldie", "Enoka", "Enoona", "Errinaya", "Esmee", "Esther", "Estyn", "Evadne", "Everen", "Fayne", "Fidess", "Frederika", "Frida", "Gene", "Gessane", "Ginerva", "Gronalyn", "Guinevere", "Gvene", "Gwethana", "Hagar", "Halete", "Hannelore", "Harper", "Hartie", "Helenia", "Hermione", "Heron", "Herra", "Hildandi", "Hyza", "Ianthe", "Ibera", "Idona", "Ignacia", "Ikini", "Ilene", "Illia", "Indie", "Iona", "Isolde", "Jesi", "Jessalyn", "Jessika", "Jezzine", "Joanna", "Jonna", "Justalyne", "Kara", "Kassina", "Katriel", "Kerensa", "Kerstyn", "Kessa", "Ketra", "Kilayox", "Kilia", "Kilyne", "Kory", "Kressara", "Krynna", "Kye", "Kyra", "Kyrielle", "Laela", "Laenaya", "Larke", "Lassona", "Leala", "Leila", "Leira", "Lelani", "Lenala", "Leska", "Lilith", "Linovahle", "Linyah", "Liora", "Liriene", "Liris", "Lloyanda", "Lolinda", "Lunex", "Lyla", "Lyna", "Lynessa", "Lynorr", "Lynx", "Lyra", "Maarika", "Maeve", "Magaltie", "Maia", "Maylea", "Mehande", "Meira", "Melisande", "Melvina", "Merula", "Midiga", "Minha", "Mirayam", "Mireille", "Mireya", "Morwena", "Mylene", "Nachaloa", "Naima", "Naphtalia", "Naria", "Narisa", "Natania", "Neirin", "Nelenna", "Nerys", "Niraya", "Nita", "Nuriel", "Nymira", "Nyssa", "Ochala", "Oleisa", "Olivia", "Onathe", "Ondola", "Oralie", "Orett", "Orinthea", "Orwyne", "Ozara", "Palra", "Partha", "Parthinia", "Pascheine", "Pekka", "Pela", "Peregrine", "Peri\u2019el", "Persephone", "Petronela", "Pharysene", "Philadona", "Phlox", "Phressa", "Pret", "Prisane", "Pryderi", "Prysala", "Pyralia", "Pythe", "Qadira", "Q\u2019ara", "Q\u2019pala", "Quasee", "Quinevere", "Quintessa", "Raisa", "Ralia", "Rasy", "Razra", "Rei", "Renalee", "Renfrew", "Resha", "Reslyn", "Reyith", "Rhays", "Rhiannon", "Rhyanon", "Rictoria", "Riona", "Rivatha", "Rydna", "Ryiah", "Sage", "Saira", "Sanala", "Saoirse", "Sarai", "Sarielle", "Sathe", "Semet", "Senira", "Sennetta", "Sepherene", "Serane", "Seraphina", "S\u00e9verin", "Sevestra", "Shike", "Sidara", "Sidathe", "Silene", "Sina", "Soko", "Sonali", "Sorcha", "Sparrow", "Sunete", "Surane", "Synestra", "Syrana", "Sythini", "Szene", "Tabika", "Tabithi", "Taewen", "Tajule", "Talis", "Tamare", "Tamrin", "Temy", "Teresse", "Terra", "Tessel", "Tezani", "Thalia", "Theia", "Thesra", "Tisette", "Tiv", "Tolida", "Tonica", "Treka", "Tressa", "Trinsa", "Tristana", "Tryane", "Turi", "Tybressa", "Tycane", "Tysinni", "Ulyssia", "Undaria", "Uneste", "Urda", "Uriela", "Usara", "Useli", "Ussesa", "Vanora", "Varin", "Vemery", "Venessa", "Veseere", "Vespera", "Vieronica", "Vita", "Vixra", "Voladea", "Vysarane", "Vythica", "Wanera", "Welisarne", "Wellisa", "Wesolyne", "Wintress", "Wren", "Wyeta", "Xara", "Xavia", "Xylia", "Yadira", "Yakira", "Yarri", "Yeira", "Yelina", "Yilvoxe", "Ysane", "Yuni", "Yve", "Yviene", "Yvonnette", "Yysara", "Zaira", "Zana", "Zara", "Zathe", "Zecele", "Zenobia", "Zephale", "Zephere", "Zerma", "Zestia", "Zet", "Zilka", "Zora", "Zoura", "Zrye", "Zyneste", "Zynoa", "Abaet", "Abarden", "Aboloft", "Acamen", "Achard", "Ackmard", "Adair", "Adeen", "Adon", "Aerden", "Afflon", "Aghon", "Agnar", "Agro", "Ahalfar", "Ahburn", "Ahdun", "Aidan", "Airen", "Airis", "Alaire", "Albright", "Aldaren", "Alderman", "Aldren", "Alkirk", "Allso", "Altair", "Amerdan", "Amitel", "Anfar", "Anumi", "Anumil", "Arlo", "Asden", "Asdern", "Asen", "Aslan", "Atar", "Atgur", "Atlin", "Auchfor", "Auden", "Ault", "Aurelian", "Aurelius", "Austen", "Avalon", "Ayrie", "Aysen", "Azamarr", "Baashar", "Bacohl", "Badeek", "Baduk", "Balati", "Baradeer", "Barak", "Barkydle", "Barton", "Basden", "Baske", "Bastian", "Baxar", "Bayde", "Beck", "Bedic", "Beeron", "Bein", "Beson", "Besur", "Besurlde", "Bewul", "Biedgar", "Bildon", "Biston", "Bithon", "Blaiz", "Boal", "Boaldelr", "Bolrock", "Brakdern", "Breanon", "Bredere", "Bredin", "Bredock", "Breen", "Briallan", "Brighton", "Briseis", "Bristan", "Buchmeid", "Bue", "Busma", "Buthomar", "Bydern", "Caelan", "Caelholdt", "Cainon", "Calden", "Camchak", "Camilde", "Cardon", "Casden", "Caspian", "Cassian", "Cassiel", "Cassius", "Cayold", "Celbahr", "Celorn", "Celthric", "Cemark", "Cerdern", "Cespar", "Cether", "Cevelt", "Chamon", "Chaniel", "Chesmarn", "Chork", "Chidak", "Cid", "Cibrock", "Cipyar", "Ciroc", "Clawsen", "Codern", "Colborn", "Colthan", "Connell", "Corbin", "Cordale", "Cos", "Cosdeer", "Cuparun", "Cusmirk", "Cydare", "Cylmar", "Cyprian", "Cythnar", "Cyton", "Daburn", "Daermod", "Dagen", "Dagfinn", "Dagrod", "Daire", "Dak", "Dakamon", "Dakkone", "Dalburn", "Dalmarn", "Dapvhir", "Darius", "Darkboon", "Darkkon", "Darko", "Darkspur", "Darmor", "Darpick", "Dasbeck", "Dask", "Deathmar", "Defearon", "Derik", "Derrin", "Desil", "Dessfar", "Destin", "Devlin", "Devlyn", "Dimian", "Dinfar", "Dismer", "Doceon", "Dochrohan", "Dokoran", "Domenic", "Domnhar", "Dorn", "Dosoman", "Drake", "Drakoe", "Drakone", "Drandon", "Drit", "Dritz", "Drophar", "Dryden", "Dryn", "Drystan", "Duba", "Dukran", "Duran", "Durmark", "Dusaro", "Dyfar", "Dyten", "Eard", "Ebraheim", "Eckard", "Efamar", "Efar", "Egmardern", "Eirian", "Eiridan", "Ekgamut", "Eldermar", "Eli", "Elik", "Elson", "Elthin", "Embre", "Enbane", "Endor", "Enidin", "Enoon", "Enro", "Eoin", "Erikarn", "Erim", "Eritai", "Escariet", "Esdel", "Espardo", "Etar", "Etburn", "Etdar", "Ethen", "Etmere", "Etran", "Eune", "Evanth", "Eythil", "Fangar", "Faoturk", "Faowind", "Favroe", "Fearlock", "Fenrirr", "Feron", "Feston", "Fetmar", "Feturn", "Ficadon", "Fickfylo", "Fildon", "Fineas", "Finian", "Fintis", "Firedorn", "Firiro", "Floran", "Folmard", "Fraderk", "Fronar", "Fydar", "Fyn", "Fyodor", "Gaerwn", "Gafolern", "Gai", "Galain", "Galiron", "Gametris", "Gareth", "Gatlen", "Gatlin", "Gauthus", "Gavriel", "Gemardt", "Gemedern", "Gemedes", "Gentar", "Gerirr", "Geth", "Gethrod", "Gib", "Gibolock", "Gibolt", "Gith", "Gom", "Gosford", "Gothar", "Gothikar", "Graff", "Gresforn", "Griffin", "Grimie", "Gryn", "Gundir", "Gunnar", "Gustov", "Guthale", "Gybol", "Gybrush", "Gyin", "Hadriel", "Hagalbar", "Halmar", "Hamish", "Harkin", "Harrenhal", "Hasten", "Hawke", "Hectar", "Hecton", "Hemm", "Henndar", "Heramon", "Hermenze", "Hermuck", "Hesperos", "Hezak", "Hezra", "Hildale", "Hildar", "Hileict", "Hodus", "Hydale", "Hyten", "Iagan", "Iarmod", "Idon", "Ieli", "Ieserk", "Ignatius", "Ikar", "Ilgenar", "Illilorn", "Illium", "Ingel", "Ipedorn", "Irefist", "Ironmark", "Isen", "Iseult", "Ishmael", "Isil", "Ithric", "Jackson", "Jakrin", "Jalil", "Jamik", "Janus", "Jareth", "Jaris", "Jather", "Jayco", "Jaython", "Jerrick", "Jesco", "Jespar", "Jessop", "Jethil", "Jex", "Jib", "Jibar", "Jin", "Jinto", "Joz", "Juktar", "Julthor", "Jun", "Justal", "Kadric", "Kafar", "Kagran", "Kaldar", "Kellan", "Kent", "Keran", "Kesad", "Kesmon", "Kethren", "Khron", "Kib", "Kibidon", "Kiden", "Kilbas", "Kilburn", "Kildarien", "Kimdar", "Kinorn", "Kip", "Kirder", "Kodof", "Kolmorn", "Kontas", "Korbin", "Krinn", "Kyler", "Kyrad", "Lackus", "Lacspor", "Laderic", "Lafornon", "Lahorn", "Laracal", "Lassrin", "Ledale", "Leit", "Lenox", "Lephar", "Lephidiles", "Lerin", "Lesphares", "Lessard", "Letor", "Lidorn", "Lin", "Liphanes", "Liron", "Loban", "Lothe", "Lox", "Lucien", "Ludokrin", "Luphildern", "Lupin", "Lurd", "Lustros", "Lydan", "Macon", "Madarlon", "Mafar", "Marderdeen", "Mardin", "Marius", "Markard", "Markdoon", "Marklin", "Martyn", "Mashasen", "Mathar", "Mathieu", "Mavrek", "Medarin", "Medin", "Mellamo", "Meowol", "Merdon", "Meridan", "Merkesh", "Mesah", "Mes'ard", "Mesophan", "Mesoton", "Mezo", "Michael", "Mick", "Mickal", "Migorn", "Milo", "Miphates", "Mi'talrythin", "Mitar", "Modric", "Modum", "Moki", "Mudon", "Mufar", "Mujarin", "Mylo", "Mythik", "Mythil", "Nadeer", "Nalfar", "Namorn", "Naphates", "Nazim", "Neowyld", "Nesso", "Nidale", "Nikpal", "Nikrolin", "Niktohal", "Niro", "Noford", "Nothar", "Nuthor", "Nuwolf", "Nydale", "Nyfain", "Nythil", "Ocarin", "Occelot", "Occhi", "Odaren", "Odeir", "Ohethlic", "Oisin", "Okar", "Omaniron", "Omarn", "Ophni", "Orin", "Orion", "Orpheus", "Ospar", "Othelen", "O\u2019tho", "Oxbaren", "Padan", "Pakker", "Palid", "Papur", "Paquin", "Paskel", "Peitar", "Pelphides", "Pender", "Pendus", "Perder", "Perol", "Perseus", "Phairdon", "Phelan", "Phemedes", "Phexides", "Phoenix", "Picon", "Pictal", "Picumar", "Pike", "Pildoor", "Pixdale", "Ponith", "Poran", "Poscidion", "Prothalon", "Ptorik", "Puthor", "Pyder", "Pyralis", "Qeisan", "Qidan", "Quiad", "Quid", "Quintis", "Quiss", "Qupar", "Qysan", "Radag'mal", "Randar", "Rankar", "Raysdan", "Rayth", "Reaper", "Remus", "Renham", "Resboron", "Reth", "Rethik", "Revvyn", "Rhithik", "Rhithin", "Rhyan", "Rhydderch", "Rhysling", "Riandur", "Rickard", "Rictor", "Rikar", "Riordan", "Rismak", "Riss", "Ritic", "Rivik", "Rogeir", "Rogist", "Rogoth", "Rophan", "Rourke", "Roux", "Rulrindale", "Rydan", "Ryfar", "Ryodan", "Rysdan", "Rythen", "Rythern", "Ryven", "Sabal", "Sadareen", "Safilix", "Samon", "Samot", "Sarkin", "Sasic", "Scoth", "Scythe", "Sebastian", "Secor", "Sed", "Sedar", "Senick", "Senthyril", "Seraphim", "Serian", "Serin", "Sermak", "Seryth", "Sesmidat", "Seth", "Setlo", "Shade", "Shadowbane", "Shane", "Shard", "Shardo", "Shillen", "Silco", "Sildo", "Sil'forrin", "Silpal", "Sirius", "Sithik", "Soderman", "Sothale", "Staph", "Stenwulf", "Steven", "Straus", "Suktor", "Suth", "Sutlin", "Syr", "Syrin", "Syth", "Sythril", "Talberon", "Talon", "Tavish", "Tearlach", "Tekren", "Telpur", "Temil", "Temilfist", "Tempist", "Teslanar", "Tespar", "Tessino", "Tethran", "Tez", "Thaniel", "Thiltran", "Tholan", "Tibers", "Tibolt", "Ticharol", "Tilner", "Tithan", "Tobale", "Tolle", "Tolsar", "Tol\u2019Solie", "Toma", "Torian", "Torin", "Tothale", "Tousba", "Towerlock", "Tuk", "Turrek", "Tuscanar", "Tusdar", "Tyden", "Tyvrik", "Uerthe", "Ugmar", "Uhrd", "Undin", "Updar", "Urien", "Uther", "Vaccon", "Vacone", "Vadim", "Vale", "Valkeri", "Valynard", "Varog", "Vasilis", "Vectomon", "Veldahar", "Verssek", "Vespar", "Vethelot", "Victor", "Vider", "Vigoth", "Vilan", "Vildar", "Vinald", "Vinkolt", "Virde", "Voltain", "Volux", "Voudim", "Vythethi", "Wak\u2019dern", "Walkar", "Wanar", "Wekmar", "Werymn", "Weshin", "Weston", "Whit", "Wictor", "William", "Willican", "Wilte", "Wiltmar", "Wishane", "Witfar", "Wrathran", "Wraythe", "Wulfe", "Wuthmon", "Wyder", "Wyeth", "Wyvorn", "Xander", "Xanthus", "Xavier", "Xenil", "Xex", "Xithyl", "Xuio", "Yabaro", "Yepal", "Yeriel", "Yesirn", "Yestin", "Yorjan", "Y\u2019reth", "Yseult", "Yssik", "Yssith", "Zaden", "Zagaroth", "Zak", "Zakarn", "Zaniel", "Zarek", "Zecane", "Zeke", "Zenner", "Zephyr", "Zerin", "Zessfar", "Zidar", "Zigmal", "Zile", "Zilocke", "Zio", "Zorion", "Zoru", "Zotar", "Zutar", "Zyten"], "yaml_datafile_checksum": "e4111e14b23b80a1c008c0602d5eebab58641a5c7a303d56c94bbf340bafc978df0e158cee83a1378f39e3908144043df2fa6be098387fa6aa8f7e95f4f1e703"} \ No newline at end of file diff --git a/loreroll/npc.py b/loreroll/npc.py index d98acc6..9c2a491 100644 --- a/loreroll/npc.py +++ b/loreroll/npc.py @@ -1,5 +1,7 @@ """Module for generating NPCs.""" +import hashlib +import json import os import random from collections import namedtuple @@ -19,6 +21,7 @@ ) NPC_FILENAME = os.path.join(os.path.dirname(__file__), 'data/npc.yaml') +NPC_JSON_FILENAME = os.path.join(os.path.dirname(__file__), 'data/npc.json') NPC_SCHEMA = Map({ 'races': Seq(Map({'v': Str(), 'w': Float()})), @@ -31,9 +34,45 @@ def _read_data(): - """Read NPC data.""" - with open(NPC_FILENAME, 'r') as datafile: - return load(datafile.read(), NPC_SCHEMA) + """Read NPC data. + + Parsing StrictYAML turned out to be really slow -> The function attempts + to read the pre-parsed JSON version. If that fails or if it has been + generated for a different YAML data version, read the source YAML and try + and store the data in JSON format for future runs. + """ + + def _handle_caching_error(operation, error): + # Catch and ignore (just print warning) any error. This is just + # "caching" and we want to continue with the rest in any case. + print( + f'WARNING: Could not {operation} the cache JSON file ' + f'("{NPC_JSON_FILENAME}"): {error}' + ) + + with open(NPC_FILENAME, 'r') as yaml_datafile: + yaml_data = yaml_datafile.read() + yaml_data_checksum = hashlib.sha512(yaml_data.encode()).hexdigest() + + # Try to read NPC_JSON_FILENAME ("cached" version). + try: + with open(NPC_JSON_FILENAME, 'r') as json_datafile: + npc_data = json.load(json_datafile) + checksum = npc_data.pop('yaml_datafile_checksum') + if checksum == yaml_data_checksum: + return npc_data + except Exception as error: + _handle_caching_error('read', error) + + # At this point we indeed need to parse the YAML data. Let's do so and + # try and store the parsed data into a JSON file for future runs. + npc_data = load(yaml_data, NPC_SCHEMA).data + try: + npc_data['yaml_datafile_checksum'] = yaml_data_checksum + json.dump(npc_data, open(NPC_JSON_FILENAME, 'w')) + except Exception as error: + _handle_caching_error('store', error) + return npc_data NPC_DATA = _read_data()