""" Part library and per-type weights for generate_sprite.py. How picking works ----------------- 1. A body plan is picked using PLAN_WEIGHTS[type]. 2. Each slot in PICK_ORDER (generate_sprite.py) is filled with one part. A part is a candidate only if: - the chosen body plan is in its `plans` - if it has `requires`, at least one of those tags was added by an earlier pick - none of its `tags` were excluded by an earlier pick, and none of its `excludes` match an earlier pick's tags 3. Candidate weight = types.get(type, other). Higher = more likely. 0 = never. "none" entries are real choices, so their weight controls how often a slot is empty. Bodies are complete base creatures (body, head and face drawn together); the other slots vary them. Tags ending in "_head" (head family, gates head_top parts) and tags starting with "_" (used only so a base can exclude one specific part shape) are internal plumbing. All other tags show up as the sprite's "attributes" (beaked, finned, fluffy, tailed...). Editing this file changes which parts existing businesses get, since every pick draws from the same seeded random sequence. """ TYPES = [ "normal", "fire", "water", "grass", "electric", "ice", "fighting", "poison", "ground", "flying", "psychic", "bug", "rock", "ghost", "dragon", ] # Signature color per type. Used for the "type" palette (flames, leaves, sparks...) # and as a fallback when a logo has no usable second color. TYPE_COLORS = { "normal": "#A8A878", "fire": "#F08030", "water": "#6890F0", "grass": "#78C850", "electric": "#F8D030", "ice": "#98D8D8", "fighting": "#C03028", "poison": "#A040A0", "ground": "#E0C068", "flying": "#A890F0", "psychic": "#F85888", "bug": "#A8B820", "rock": "#B8A038", "ghost": "#705898", "dragon": "#7038F8", } PLANS = ["quadruped", "biped", "serpentine", "avian", "aquatic", "blob", "insectoid"] ALL = PLANS LEGGED = ["quadruped", "biped"] PLAN_WEIGHTS = { "normal": {"quadruped": 5, "biped": 4, "avian": 2, "blob": 1, "serpentine": 0.5}, "fire": {"quadruped": 5, "biped": 3, "serpentine": 1.5, "avian": 1.5, "blob": 1}, "water": {"aquatic": 5, "serpentine": 2.5, "quadruped": 2, "biped": 1.5, "blob": 1}, "grass": {"quadruped": 4, "biped": 3, "blob": 2, "serpentine": 1, "insectoid": 1}, "electric": {"quadruped": 4, "biped": 3, "blob": 2, "avian": 1, "insectoid": 1}, "ice": {"quadruped": 3, "biped": 2, "aquatic": 2, "avian": 1.5, "blob": 1.5, "serpentine": 1}, "fighting": {"biped": 7, "quadruped": 2, "insectoid": 0.5}, "poison": {"blob": 4, "serpentine": 3, "quadruped": 2, "biped": 2, "insectoid": 2}, "ground": {"quadruped": 5, "biped": 3, "serpentine": 2, "insectoid": 0.5}, "flying": {"avian": 7, "quadruped": 1, "serpentine": 1, "insectoid": 1}, "psychic": {"biped": 4, "quadruped": 3, "blob": 2, "avian": 1.5}, "bug": {"insectoid": 7, "serpentine": 1, "avian": 0.5}, "rock": {"biped": 3, "quadruped": 3, "serpentine": 2, "blob": 2}, "ghost": {"blob": 6, "serpentine": 2, "biped": 1, "avian": 0.5}, "dragon": {"serpentine": 4, "quadruped": 3, "biped": 3, "avian": 0.5}, } # Procedural markings: painted onto the body's main-color pixels in the accent color. # No sprites needed. "_other" is the weight for types not listed. The belly patch is # centred on the body's aura anchor (its visual centre), so it lands on the tummy # rather than across a big baked-in head. MARKINGS = { "none": {"_other": 4}, "spots": {"grass": 3, "poison": 3, "bug": 2, "water": 2, "electric": 2, "normal": 1.5, "_other": 0.5}, "speckles": {"ground": 3, "rock": 3, "ice": 1.5, "normal": 1, "_other": 0.3}, "belly": {"normal": 3, "water": 2, "fire": 2, "dragon": 2, "ice": 2, "fighting": 2, "ground": 2, "_other": 1}, } # Combination rules for the variation slots. # - At most MAX_FEATURES of head_top/back/tail are filled (picked in that order), so a creature # gets one or two signature features instead of a pile of unrelated parts. # - Each feature part has a visual motif. Once a motif is on the creature, more parts of the # same motif are boosted (x MOTIF_SAME) and parts of an unrelated motif are damped # (x MOTIF_CLASH), unless the pair is listed in MOTIF_PAIRS. Parts without a motif (plain fur # ears and tails) go with anything. # Slots skipped during generation (their art stays in the library). Remove "aura" to bring # the floating aura effects back. DISABLED_SLOTS = {"aura"} FEATURE_SLOTS = ("head_top", "back", "tail") MAX_FEATURES = 2 MOTIF_SAME, MOTIF_CLASH = 2.5, 0.08 MOTIFS = { # feathers "crest_feather": "feather", "wings_feather": "feather", "wings_feather_small": "feather", "tail_feather_fan": "feather", # plants "leaf_sprout": "plant", "flower_bloom": "plant", "mushroom_cap": "plant", "plant_bulb": "plant", "leaf_cape": "plant", "flower_back": "plant", "mushroom_back": "plant", "tail_leaf": "plant", # fire "crest_flame": "fire", "flame_mane": "fire", "tail_flame_tip": "fire", # spooky "wisp_flame": "spooky", "wings_bat": "spooky", "ghost_tatters": "spooky", "tail_wispy": "spooky", # crystal / ice "ice_crown": "crystal", "crystal_spikes": "crystal", "gem_forehead": "crystal", "crystal_cluster": "crystal", "icicle_spikes": "crystal", "tail_ice_shard": "crystal", "tail_crystal": "crystal", # water "ears_fin": "water", "water_spout": "water", "dorsal_fin": "water", "tail_fish_fin": "water", # electric "ears_bolt": "electric", "coil_spikes": "electric", "tail_lightning": "electric", # armour / rock "horn_single": "armor", "horns_ram": "armor", "shell_round": "armor", "shell_spiked": "armor", "spikes_back": "armor", "rock_plates": "armor", "tail_club": "armor", "tail_spiked": "armor", # dragon "horns_dragon": "dragon", "wings_dragon": "dragon", "sail_fin": "dragon", "tail_dragon": "dragon", # bug "antennae": "bug", "wings_bug": "bug", "tail_stinger": "bug", # sky "cloud_tuft": "sky", "cloud_puffs": "sky", } MOTIF_PAIRS = {frozenset(p) for p in [ ("dragon", "armor"), ("dragon", "fire"), ("crystal", "armor"), ("crystal", "water"), ("plant", "bug"), ("feather", "sky"), ("fire", "armor"), ("water", "armor"), ("spooky", "crystal"), ("electric", "armor"), ("sky", "electric"), ("sky", "crystal"), ("feather", "fire"), ("dragon", "water"), ]} def part(name, plans=ALL, types=None, other=0.25, tags=(), requires=(), excludes=(), deny=(), palette="main", size=None, z=None, desc=""): return { "name": name, "plans": list(plans), "types": dict(types or {}), "other": other, "tags": list(tags), "requires": list(requires), "excludes": list(excludes), "deny": list(deny), "palette": palette, "size": size, "z": z, "desc": desc, } def none(types=None, other=1.0, plans=ALL, requires=()): return part("none", plans, types, other, requires=requires, desc="(empty slot, no sprite)") # Head-family tags carried by each base body. head_top parts use them in `requires`. MAMMAL = ["mammal_head"] ANY_FACE = ["mammal_head", "reptile_head", "integrated_head"] NOT_BEAK = ["mammal_head", "reptile_head", "rock_head", "insect_head", "integrated_head", "ghost_head"] INTEGRATED = ["integrated_head"] def base(name, plan, types, head, size, desc, tags=(), excludes=(), deny=()): """A complete designed creature (body + head + face in one sprite). head: head-family tag(s) gating head_top parts. excludes: tags of variation parts that clash with features already drawn into the base (e.g. "eared" when it has ears). deny: specific variation part names that don't sit well on this base.""" heads = [head] if isinstance(head, str) else list(head) return part(name, [plan], types, 0.3, tags=heads + list(tags), excludes=excludes, deny=deny, size=size, desc=desc) # --------------------------------------------------------------------------- body (base creatures) BODY = [ # quadruped base("base_fox", "quadruped", {"fire": 3, "electric": 3, "psychic": 3, "normal": 2, "ice": 2}, "mammal_head", (42, 36), "Chibi fox/cat critter with cheek tufts, big pointed ears and a fluffy bib", excludes=["eared"], deny=["ears_fin", "horns_ram", "horns_dragon", "crystal_spikes", "tail_fish_fin"]), base("base_cub", "quadruped", {"ground": 4, "rock": 3, "fighting": 3, "normal": 2, "grass": 2}, "mammal_head", (40, 34), "Chunky bear-cub on all fours, round ears, sturdy paws", excludes=["eared", "_side_horns"], deny=["ears_fin", "horns_dragon", "crystal_spikes", "mane_fluffy", "tail_fish_fin"]), base("base_pup", "quadruped", {"normal": 4, "fire": 3, "fighting": 2, "water": 1.5}, "mammal_head", (42, 34), "Bouncy puppy with floppy ears and a happy open mouth", excludes=["eared", "_side_horns"], deny=["ears_fin", "horns_dragon", "tail_fish_fin"]), base("base_salamander", "quadruped", {"fire": 3, "water": 3, "poison": 3, "dragon": 2, "grass": 1}, "reptile_head", (47, 27), "Low chibi salamander/newt with a wide smile and frilly cheeks", excludes=["_head_fins"], deny=["horns_ram", "tail_fluffy", "mane_fluffy"]), base("base_drake", "quadruped", {"dragon": 5, "fire": 3, "rock": 2, "ground": 1}, "reptile_head", (42, 38), "Cool baby dragon on four legs, nub horns, confident grin", excludes=["horned", "_headband"], deny=["ears_fin", "crest_feather", "crystal_spikes", "tail_fluffy"]), base("base_fawn", "quadruped", {"grass": 4, "psychic": 3, "ice": 3, "normal": 1}, "mammal_head", (42, 35), "Dainty chibi fawn in 3/4 view: big leaf ears, gentle eyes, spotted back", excludes=["eared", "_side_horns"], deny=["ears_fin", "crystal_spikes", "mane_fluffy", "tail_fish_fin", "horns_dragon", "wings_bat", "wings_dragon", "mushroom_back"]), # biped base("base_imp", "biped", {"electric": 4, "normal": 3, "psychic": 2, "ghost": 1}, "mammal_head", (40, 40), "Upright mouse-imp with big round ears and a cheeky fanged grin", excludes=["eared"], deny=["ears_fin", "crystal_spikes", "shell_round", "shell_spiked", "rock_plates", "tail_fish_fin"]), base("base_brawler", "biped", {"fighting": 5, "rock": 3, "ground": 3, "normal": 1}, "mammal_head", (42, 43), "Stout little fighter with big fists and a determined face", excludes=["eared"], deny=["ears_fin", "spiky_hair", "crystal_spikes", "flame_mane", "tail_stub", "tail_fish_fin", "tail_feather_fan"]), base("base_bunny", "biped", {"normal": 4, "grass": 3, "ice": 2, "psychic": 2}, "mammal_head", (36, 45), "Upright chibi bunny with long ears and a fluffy chest", excludes=["eared"], deny=["ears_fin", "horn_single", "horns_dragon", "antennae", "crest_flame", "crystal_spikes", "spiky_hair", "water_spout", "wings_dragon", "flame_mane", "tail_fish_fin", "tail_feather_fan"]), base("base_dino", "biped", {"dragon": 4, "fire": 3, "ground": 2, "water": 1}, "reptile_head", (36, 44), "Little upright dino with a big head, tiny arms and a toothy grin", excludes=["_headband"], deny=["flame_mane"]), base("base_pixie", "biped", {"psychic": 4, "ghost": 3, "grass": 2, "poison": 2}, "mammal_head", (42, 39), "Leaf-elf pixie with sweeping pointed ears, round torso, stubby legs and a mischievous grin", excludes=["eared"], deny=["ears_fin", "wings_dragon", "shell_spiked", "rock_plates", "tail_feather_fan"]), # avian base("base_chick", "avian", {"normal": 4, "ice": 3, "electric": 2, "water": 2, "flying": 2}, "beak_head", (36, 35), "Egg-round chick with a feather tuft, wing nubs and a tiny beak", deny=["crest_feather", "wings_bat"]), base("base_owl", "avian", {"psychic": 4, "flying": 3, "ghost": 3, "normal": 1}, "beak_head", (36, 36), "Round owlet with huge eyes and ear tufts", excludes=["eared"], deny=["crest_feather", "crest_flame", "crystal_spikes", "ice_crown", "wisp_flame", "wings_feather", "wings_bat"]), base("base_hawk", "avian", {"flying": 5, "fire": 3, "fighting": 3, "dragon": 1}, "beak_head", (38, 37), "Cool young hawk, puffed chest, sharp brow and hooked beak", deny=["crest_feather", "wisp_flame", "wings_feather", "wings_bat"]), base("base_penguin", "avian", {"ice": 5, "water": 4, "normal": 1}, "beak_head", (36, 38), "Chubby penguin chick with flipper wings and a bib", deny=["wings_feather", "wings_feather_small", "wings_bat", "tail_wispy", "ghost_tatters"]), # aquatic base("base_guppy", "aquatic", {"water": 5, "poison": 2, "ice": 2, "dragon": 1}, "integrated_head", (46, 33), "Round bubbly fish with big eyes and frilly fins", deny=["ears_round", "ears_long", "ears_floppy", "shell_round"]), base("base_otter", "aquatic", {"ice": 4, "water": 4, "normal": 2}, "mammal_head", (49, 30), "Chubby seal/otter pup lying on its flippers", excludes=["eared"], deny=["shell_round", "tail_fish_fin"]), base("base_axolotl", "aquatic", {"water": 4, "poison": 3, "dragon": 2, "grass": 1}, "reptile_head", (51, 30), "Smiling axolotl with feathery gill fronds", excludes=["_head_fins"], deny=["horns_ram", "shell_round"]), # serpentine base("base_noodle", "serpentine", {"poison": 4, "ground": 3, "normal": 2, "grass": 2}, "reptile_head", (44, 40), "Cute coiled snake with a big round head and a sly smile", deny=["dorsal_fin"]), base("base_eel", "serpentine", {"water": 4, "ice": 3, "electric": 2, "dragon": 2}, "reptile_head", (45, 46), "Rising sea-serpent with fin frills and big eyes", excludes=["finned"], deny=["horns_ram", "wings_bat", "wings_dragon", "spikes_back", "leaf_cape", "crystal_cluster", "rock_plates", "cloud_puffs", "ghost_tatters", "icicle_spikes"]), base("base_wyrm", "serpentine", {"dragon": 4, "ghost": 3, "psychic": 1, "ice": 1}, "reptile_head", (43, 44), "Cool coiled young wyrm with whisker barbels and a proud look", excludes=["horned", "feathered"], deny=["ears_fin", "crystal_spikes", "spiky_hair", "dorsal_fin"]), # blob base("base_blob", "blob", {"normal": 4, "grass": 3, "ice": 3, "electric": 2}, "integrated_head", (40, 33), "Squishy mochi blob with a curl on top and a big smile", deny=["horn_single", "horns_ram", "ears_bolt", "ears_fin", "flower_back"]), base("base_slime", "blob", {"poison": 5, "water": 3, "ghost": 1}, "integrated_head", (40, 34), "Drippy goo blob with a cheeky tongue-out face", deny=["ears_floppy", "mushroom_back"]), base("base_wisp", "blob", {"ghost": 5, "psychic": 3, "fire": 1, "flying": 1}, ["integrated_head", "ghost_head"], (36, 40), "Floating ghost wisp with a curly tail-end and a spooky-cute grin", excludes=["tailed"], deny=["ears_floppy", "flower_back"]), base("base_pebble", "blob", {"rock": 5, "ground": 3, "fighting": 1}, "integrated_head", (38, 32), "Round rock lump creature with a sturdy little face and stubby feet", deny=["ears_floppy", "mushroom_back"]), # insectoid base("base_beetle", "insectoid", {"bug": 4, "rock": 2, "ground": 2, "poison": 1}, "insect_head", (42, 30), "Round shiny beetle bug with a horn and stubby legs", excludes=["horned"], deny=["crystal_spikes", "shell_spiked"]), base("base_grub", "insectoid", {"bug": 4, "grass": 3, "poison": 3}, "insect_head", (44, 27), "Plump caterpillar with a big happy face and tufted segments", deny=["shell_spiked", "coil_spikes"]), base("base_bee", "insectoid", {"bug": 4, "flying": 2, "fighting": 2, "electric": 1}, "insect_head", (38, 35), "Fuzzy round bee/bug with tiny wings and antennae", excludes=["winged", "antennae"], deny=["horns_ram", "horns_dragon", "shell_spiked", "tail_leaf", "tail_stinger", "coil_spikes"]), ] # --------------------------------------------------------------------------- head_top HEAD_TOP = [ none({"normal": 4, "poison": 2.5, "fighting": 2.5, "water": 2.5, "ghost": 2.5}, 2), part("ears_pointed", types={"electric": 4, "normal": 3, "fire": 3, "psychic": 3, "grass": 1.5}, other=0.5, requires=MAMMAL + INTEGRATED, tags=["eared"], desc="Pair of tall pointed ears"), part("ears_round", types={"normal": 4, "electric": 2, "ground": 2, "ice": 2, "water": 1.5}, other=0.5, requires=MAMMAL + INTEGRATED, tags=["eared"], desc="Pair of round mouse/bear ears"), part("ears_long", types={"normal": 3, "psychic": 3, "grass": 2, "flying": 1.5, "ice": 1}, other=0.3, requires=MAMMAL + INTEGRATED, tags=["eared"], size=(18, 20), z=25, desc="Long rabbit ears (drawn behind the creature)"), part("ears_floppy", types={"normal": 4, "water": 2, "ground": 1.5, "grass": 1}, other=0.3, requires=MAMMAL + INTEGRATED, tags=["eared"], size=(26, 12), z=25, desc="Droopy hanging ears (drawn behind the creature)"), part("ears_bolt", types={"electric": 7}, other=0.05, requires=MAMMAL + INTEGRATED, tags=["eared"], desc="Zigzag lightning-bolt ears, type-colored tips"), part("ears_fin", types={"water": 5, "ice": 2, "dragon": 1.5}, other=0.1, requires=ANY_FACE, tags=["finned", "eared", "_head_fins"], palette="accent", desc="Fin-shaped ear frills"), part("horn_single", types={"rock": 3, "ground": 3, "bug": 3, "dragon": 2, "fighting": 2, "poison": 2}, other=0.3, requires=NOT_BEAK, tags=["horned"], palette="accent", size=(10, 14), desc="One forehead horn (rhino/beetle)"), part("horns_ram", types={"rock": 4, "ground": 4, "fighting": 3, "normal": 1.5}, other=0.2, requires=NOT_BEAK, tags=["horned", "_side_horns"], palette="accent", size=(26, 14), desc="Curled ram horns"), part("horns_dragon", types={"dragon": 7, "fire": 2, "ghost": 1}, other=0.1, requires=NOT_BEAK, tags=["horned"], palette="accent", size=(22, 16), desc="Swept-back dragon horns"), part("antennae", types={"bug": 7, "electric": 2, "psychic": 1.5, "poison": 1}, other=0.1, requires=["insect_head", "mammal_head", "integrated_head"], tags=["antennae"], size=(16, 16), desc="Two thin antennae with tips"), part("crest_feather", types={"flying": 6, "fire": 2, "fighting": 1.5, "psychic": 1}, other=0.2, requires=["beak_head", "reptile_head"], tags=["feathered"], palette="accent", desc="Swept feather crest"), part("crest_flame", types={"fire": 8}, other=0.05, palette="type", desc="Flickering flame on top of head"), part("leaf_sprout", types={"grass": 8}, other=0.05, palette="type", size=(14, 14), desc="Leaf/sprout growing from head"), part("flower_bloom", types={"grass": 5, "poison": 2, "psychic": 1.5}, other=0.1, palette="accent", tags=["floral"], desc="Small flower on head"), part("mushroom_cap", types={"poison": 4, "grass": 3, "bug": 2, "ghost": 1}, other=0.05, palette="accent", size=(20, 12), desc="Mushroom cap worn like a hat"), part("ice_crown", types={"ice": 8}, other=0.05, palette="type", size=(18, 12), desc="Ring of small icicles"), part("crystal_spikes", types={"rock": 5, "ice": 3, "psychic": 2}, other=0.05, palette="accent", tags=["crystal"], desc="Cluster of crystal shards"), part("gem_forehead", types={"psychic": 6, "dragon": 2, "rock": 1.5, "ghost": 1}, other=0.05, palette="accent", tags=["gem"], size=(8, 8), desc="Gem set in forehead"), part("spiky_hair", types={"fighting": 3, "electric": 3, "poison": 2, "normal": 1, "fire": 1}, other=0.2, requires=ANY_FACE, tags=["spiky"], size=(20, 12), desc="Spiky tuft of fur/hair"), part("headband", types={"fighting": 6, "normal": 0.5}, other=0.02, requires=["mammal_head", "reptile_head", "rock_head", "ghost_head"], tags=["_headband"], palette="accent", size=(24, 10), desc="Tied headband with trailing ends"), part("wisp_flame", types={"ghost": 6, "fire": 1.5, "psychic": 1}, other=0.02, palette="type", desc="Ghostly floating flame wisp"), part("water_spout", types={"water": 5, "ice": 1}, other=0.02, palette="type", desc="Water droplet/fountain crest"), part("cloud_tuft", types={"flying": 3, "electric": 2, "ice": 1.5}, other=0.05, palette="type", tags=["fluffy"], size=(20, 12), desc="Puffy cloud tuft"), ] # (Faces are baked into the base creatures; there are no head, snout or eyes slots.) # --------------------------------------------------------------------------- back BACK = [ none({"normal": 5, "fighting": 4, "water": 3, "electric": 3, "psychic": 3, "poison": 3, "ground": 3, "fire": 3, "ghost": 3, "ice": 2.5, "rock": 2, "grass": 2, "dragon": 1.5, "bug": 1, "flying": 0.5}, 2), part("wings_feather", ["avian", "biped", "quadruped"], {"flying": 8, "fire": 2, "normal": 1.5, "psychic": 1.5, "ice": 1}, 0.3, tags=["winged", "feathered"], palette="accent", size=(44, 30), desc="Full feathered wings, spread"), part("wings_feather_small", ["avian", "biped", "quadruped", "blob"], {"flying": 4, "normal": 2, "ice": 2, "psychic": 1, "water": 1}, 0.3, tags=["winged", "feathered"], palette="accent", size=(30, 14), desc="Tiny stubby wings"), part("wings_bat", ["biped", "quadruped", "avian", "blob", "serpentine"], {"ghost": 4, "poison": 4, "dragon": 2, "flying": 2, "psychic": 1}, 0.1, tags=["winged"], palette="accent", size=(44, 26), desc="Membrane bat wings"), part("wings_bug", ["insectoid", "biped", "blob"], {"bug": 6, "grass": 2, "poison": 2, "psychic": 1.5, "electric": 1}, 0.1, tags=["winged"], palette="accent", size=(40, 28), desc="Translucent veined insect wings"), part("wings_dragon", ["quadruped", "biped", "serpentine"], {"dragon": 6, "fire": 3, "flying": 2, "rock": 1}, 0.1, tags=["winged"], palette="accent", size=(48, 32), desc="Large clawed dragon wings"), part("shell_round", ["quadruped", "biped", "aquatic"], {"water": 5, "ground": 3, "rock": 2, "grass": 1}, 0.2, tags=["shelled"], palette="accent", size=(40, 26), desc="Domed turtle shell"), part("shell_spiked", ["quadruped", "biped", "insectoid"], {"rock": 4, "ground": 3, "poison": 2, "water": 2, "fighting": 1}, 0.1, tags=["shelled", "spiky"], palette="accent", size=(40, 28), desc="Armored shell with spikes"), part("spikes_back", ["quadruped", "biped", "serpentine", "aquatic", "blob"], {"ground": 4, "poison": 3, "rock": 3, "dragon": 2, "ice": 2, "fire": 1.5}, 0.2, tags=["spiky"], palette="accent", size=(36, 14), desc="Row of spikes along the spine"), part("sail_fin", ["quadruped", "biped", "serpentine"], {"fire": 4, "dragon": 3, "water": 2, "electric": 1.5}, 0.1, tags=["finned"], palette="accent", size=(34, 20), desc="Tall dimetrodon-style back sail"), part("dorsal_fin", ["aquatic", "serpentine", "quadruped"], {"water": 7, "ice": 2, "dragon": 1.5}, 0.05, tags=["finned"], palette="accent", size=(20, 16), desc="Shark-style dorsal fin"), part("plant_bulb", ["quadruped", "biped", "blob"], {"grass": 6, "poison": 2}, 0.02, tags=["leafy"], palette="type", size=(30, 26), desc="Large seed pod/bulb with leaves"), part("leaf_cape", ["quadruped", "biped", "serpentine", "insectoid"], {"grass": 6, "bug": 2, "flying": 1}, 0.02, tags=["leafy"], palette="type", size=(38, 20), desc="Overlapping leaves along the back"), part("flower_back", ["quadruped", "biped", "blob"], {"grass": 5, "poison": 2, "psychic": 1.5}, 0.02, tags=["floral"], palette="accent", size=(32, 26), desc="Big blooming flower"), part("mushroom_back", ["quadruped", "insectoid", "blob"], {"grass": 3, "poison": 3, "bug": 3, "ghost": 1}, 0.02, palette="accent", size=(30, 22), desc="Cluster of mushrooms growing on back"), part("flame_mane", LEGGED, {"fire": 8, "dragon": 1}, 0.02, tags=["fiery"], palette="type", size=(36, 28), desc="Mane/collar of fire"), part("crystal_cluster", ["quadruped", "biped", "blob", "serpentine"], {"rock": 5, "ice": 3, "psychic": 3}, 0.02, tags=["crystal"], palette="accent", size=(30, 24), desc="Crystals jutting from back"), part("rock_plates", ["quadruped", "biped", "serpentine"], {"rock": 6, "ground": 3, "fighting": 1}, 0.02, tags=["armored"], palette="accent", size=(38, 20), desc="Boulder armor plates"), part("icicle_spikes", ["quadruped", "biped", "aquatic", "avian", "blob"], {"ice": 8, "water": 1}, 0.02, tags=["spiky"], palette="type", size=(29, 24), desc="Tight fan of icicles rising from the back"), part("mane_fluffy", LEGGED, {"normal": 4, "fighting": 3, "electric": 2, "fire": 1.5, "ice": 1.5}, 0.2, tags=["fluffy"], size=(34, 26), desc="Big fluffy fur collar/mane"), part("coil_spikes", ["quadruped", "biped", "blob", "insectoid"], {"electric": 7, "normal": 0.3}, 0.02, tags=["electric"], palette="type", size=(26, 24), desc="Chunky coil/battery prongs with a spark"), part("cloud_puffs", ["blob", "avian", "quadruped", "serpentine"], {"flying": 4, "ice": 2, "psychic": 2, "electric": 1.5, "normal": 1}, 0.05, tags=["fluffy"], palette="type", size=(30, 20), desc="Fluffy cloud hugging the back"), part("ghost_tatters", ["biped", "blob", "serpentine", "avian"], {"ghost": 6, "psychic": 1, "poison": 1}, 0.02, palette="accent", size=(26, 24), desc="Short ghostly shroud draped from the shoulders"), ] # --------------------------------------------------------------------------- tail TAIL = [ none({"fighting": 3, "bug": 3, "ghost": 3, "psychic": 2, "normal": 2}, 1.5, plans=ALL), part("tail_stub", ["quadruped", "biped", "avian"], {"normal": 4, "ground": 2, "ice": 2, "rock": 1.5, "fighting": 1.5}, 0.5, tags=["tailed"], size=(10, 10), desc="Short round stub tail"), part("tail_fluffy", LEGGED, {"normal": 4, "ice": 3, "electric": 2, "psychic": 2, "fire": 1.5}, 0.4, tags=["tailed", "fluffy"], size=(26, 20), desc="Big fluffy fox/squirrel tail"), part("tail_long_thin", LEGGED, {"psychic": 3, "normal": 2, "poison": 2, "electric": 2, "ghost": 1}, 0.4, tags=["tailed"], size=(30, 12), desc="Long thin tail with tuft"), part("tail_curly", LEGGED, {"normal": 3, "psychic": 3, "grass": 1.5, "poison": 1}, 0.3, tags=["tailed"], size=(16, 16), desc="Spiral curly tail"), part("tail_flame_tip", ["quadruped", "biped", "serpentine"], {"fire": 8}, 0.05, tags=["tailed", "fiery"], palette="type", size=(28, 20), desc="Tail ending in a flame"), part("tail_lightning", LEGGED, {"electric": 8}, 0.05, tags=["tailed"], palette="type", size=(26, 22), desc="Zigzag lightning-bolt tail"), part("tail_leaf", ["quadruped", "biped", "insectoid", "serpentine"], {"grass": 7, "bug": 1.5}, 0.05, tags=["tailed", "leafy"], palette="type", size=(24, 16), desc="Tail ending in a big leaf"), part("tail_fish_fin", ["aquatic", "serpentine", "quadruped", "biped"], {"water": 7, "ice": 2, "dragon": 1.5}, 0.05, tags=["tailed", "finned"], palette="accent", size=(22, 22), desc="Forked fish/mermaid tail fin"), part("tail_club", LEGGED, {"rock": 5, "ground": 4, "fighting": 1.5}, 0.05, tags=["tailed"], size=(28, 16), desc="Heavy club-ended tail"), part("tail_spiked", ["quadruped", "biped", "serpentine"], {"ground": 3, "rock": 3, "dragon": 3, "poison": 2, "ice": 1.5}, 0.1, tags=["tailed", "spiky"], size=(28, 14), desc="Tail with spikes"), part("tail_stinger", ["insectoid", "serpentine", "quadruped", "biped"], {"bug": 5, "poison": 5}, 0.05, tags=["tailed", "stinger"], palette="accent", size=(22, 18), desc="Curved stinger tail"), part("tail_feather_fan", ["avian", "biped"], {"flying": 7, "fire": 2, "psychic": 1.5, "normal": 1}, 0.1, tags=["tailed", "feathered"], palette="accent", size=(22, 22), desc="Fanned tail feathers"), part("tail_wispy", ["blob", "serpentine", "biped", "avian"], {"ghost": 7, "psychic": 1.5, "fire": 1}, 0.05, tags=["tailed"], size=(24, 16), desc="Fading smoky wisp tail"), part("tail_ice_shard", ["quadruped", "biped", "aquatic", "serpentine"], {"ice": 8}, 0.05, tags=["tailed", "crystal"], palette="type", size=(24, 16), desc="Tail ending in an ice shard"), part("tail_dragon", ["quadruped", "biped", "serpentine"], {"dragon": 6, "fire": 2, "ground": 1.5, "water": 1}, 0.1, tags=["tailed"], size=(30, 16), desc="Thick tapered tail with small fin"), part("tail_rattle", ["serpentine"], {"poison": 4, "ground": 4, "normal": 1}, 0.2, tags=["tailed"], palette="accent", size=(14, 12), desc="Rattlesnake rattle tip"), part("tail_crystal", ["quadruped", "biped", "serpentine"], {"psychic": 4, "rock": 3, "ice": 2}, 0.05, tags=["tailed", "crystal"], palette="accent", size=(24, 16), desc="Tail tipped with a crystal"), ] # --------------------------------------------------------------------------- aura _AURA_SIZE = (84, 84) AURA = [ none(other=8), part("aura_embers", types={"fire": 3}, other=0, palette="type", size=_AURA_SIZE, desc="Floating embers"), part("aura_sparks", types={"electric": 3}, other=0, palette="type", size=_AURA_SIZE, desc="Crackling sparks"), part("aura_bubbles", types={"water": 3, "poison": 0.5}, other=0, palette="type", size=_AURA_SIZE, desc="Rising bubbles"), part("aura_leaves", types={"grass": 3, "flying": 0.5, "bug": 0.5}, other=0, palette="type", size=_AURA_SIZE, desc="Drifting leaves"), part("aura_snowflakes", types={"ice": 3}, other=0, palette="type", size=_AURA_SIZE, desc="Snowflakes"), part("aura_wisps", types={"ghost": 3, "psychic": 0.5}, other=0, palette="type", size=_AURA_SIZE, desc="Ghost wisps"), part("aura_rings", types={"psychic": 3}, other=0, palette="type", size=_AURA_SIZE, desc="Psychic rings/ripples"), part("aura_dust", types={"ground": 3, "rock": 1.5, "fighting": 1}, other=0, palette="type", size=_AURA_SIZE, desc="Dust cloud at the feet"), part("aura_toxic", types={"poison": 3}, other=0, palette="type", size=_AURA_SIZE, desc="Toxic bubbles and drips"), part("aura_sparkle", types={"dragon": 2, "normal": 1, "psychic": 1, "flying": 0.5}, other=0, palette="type", size=_AURA_SIZE, desc="Twinkling sparkles"), part("aura_gusts", types={"flying": 3, "dragon": 0.5}, other=0, palette="type", size=_AURA_SIZE, desc="Wind swirls"), part("aura_pebbles", types={"rock": 3, "ground": 1, "psychic": 0.5}, other=0, palette="type", size=_AURA_SIZE, desc="Floating pebbles"), part("aura_power", types={"fighting": 3}, other=0, palette="type", size=_AURA_SIZE, desc="Power-up energy lines"), part("aura_spores", types={"bug": 2, "grass": 1.5, "poison": 1.5}, other=0, palette="type", size=_AURA_SIZE, desc="Floating spores"), ] SLOTS = {"body": BODY, "back": BACK, "tail": TAIL, "head_top": HEAD_TOP, "aura": AURA}