"""Build two original low-poly creature bosses as animated runtime GLBs. Replaces weak chicken and frog visuals while keeping stable boss IDs in game data. Run with: /Applications/Blender.app/Contents/MacOS/Blender --background --factory-startup \ --python scripts/blender/build_replacement_creature_bosses.py """ from __future__ import annotations import json import math import sys from pathlib import Path import bpy sys.path.insert(0, str(Path(__file__).parent)) from build_iwt2_boss_trio import ( # noqa: E402 OUT_ROOT, actions, armature, cone, ellipsoid, export_asset, finish, join_parts, plate, prepare_materials, reset_scene, ) def add_metadata(asset_id: str, concept: str) -> None: metadata_path = OUT_ROOT / asset_id / f"{asset_id}.asset.json" metadata = json.loads(metadata_path.read_text()) metadata["sourceConcept"] = concept metadata["license"] = "Original project-owned asset" metadata["runtime"]["forward"] = "-Y" metadata["runtime"]["unit"] = "meters" metadata_path.write_text(json.dumps(metadata, indent=2) + "\n") def build_brassbeak_basilisk() -> None: """Six-legged forge basilisk replacing Cluckhorn's chicken-cow model.""" asset_id = "brassbeak-basilisk" reset_scene() mats = prepare_materials({ "Scale": {"color": (0.035, 0.105, 0.12, 1), "metallic": 0.14, "roughness": 0.62}, "Underbelly": {"color": (0.12, 0.19, 0.18, 1), "metallic": 0.05, "roughness": 0.72}, "Copper": {"color": (0.45, 0.16, 0.055, 1), "metallic": 0.48, "roughness": 0.33}, "Brass": {"color": (0.78, 0.48, 0.09, 1), "metallic": 0.62, "roughness": 0.25}, "Blade": {"color": (0.50, 0.58, 0.55, 1), "metallic": 0.72, "roughness": 0.2}, "Furnace": {"color": (0.02, 0.82, 0.72, 1), "roughness": 0.18, "emission": (0.01, 0.72, 0.64, 1), "strength": 5.5}, }) specs = [ ("Root", (0, 0, 0), (0, 0, 0.45), None), ("Body", (0, 0.06, 1.18), (0, 0.05, 2.05), "Root"), ("Head", (0, -1.0, 1.48), (0, -1.82, 1.38), "Body"), ("Jaw", (0, -1.42, 1.28), (0, -2.05, 1.12), "Head"), ("Wing.L", (-0.62, -0.08, 1.72), (-1.55, -0.28, 1.5), "Body"), ("Wing.R", (0.62, -0.08, 1.72), (1.55, -0.28, 1.5), "Body"), ("Leg.FL", (-0.62, -0.72, 1.12), (-0.88, -0.84, 0.24), "Body"), ("Leg.FR", (0.62, -0.72, 1.12), (0.88, -0.84, 0.24), "Body"), ("Leg.ML", (-0.78, 0.03, 1.06), (-1.0, 0.02, 0.22), "Body"), ("Leg.MR", (0.78, 0.03, 1.06), (1.0, 0.02, 0.22), "Body"), ("Leg.BL", (-0.66, 0.76, 1.12), (-0.9, 0.88, 0.24), "Body"), ("Leg.BR", (0.66, 0.76, 1.12), (0.9, 0.88, 0.24), "Body"), ("Tail.1", (0, 1.0, 1.3), (0, 1.85, 1.12), "Body"), ("Tail.2", (0, 1.8, 1.12), (0, 2.7, 0.92), "Tail.1"), ] rig = armature("BrassbeakBasilisk", specs) # Broad armored silhouette with glowing furnace seams. ellipsoid("BasiliskBody", (0, 0.08, 1.36), (1.08, 1.43, 0.72), mats["Scale"], "Body", 2) ellipsoid("FurnaceBelly", (0, -0.15, 1.08), (0.78, 1.08, 0.46), mats["Underbelly"], "Body", 2) for index, y in enumerate((-0.7, -0.22, 0.28, 0.76)): width = 0.82 + (0.12 if index in (1, 2) else 0) plate( f"BackPlate{index}", (0, y, 1.92 + 0.08 * math.sin(index)), (width, 0.55, 0.27), (math.radians(84), 0, 0), mats["Copper"] if index % 2 == 0 else mats["Brass"], "Body", ) cone( f"ChimneySpine{index}", (0, y, 2.02), (0, y + 0.03, 2.52 - index * 0.04), 0.13, 0, mats["Blade"], "Body", 5, ) for side in (-1, 1): cone( f"FurnaceSeam{side:+d}", (side * 0.58, -0.76, 1.34), (side * 0.72, 0.72, 1.34), 0.035, 0.022, mats["Furnace"], "Body", 5, ) # Hammerhead, brass beak, split jaw, and crown blades. ellipsoid("HammerHead", (0, -1.28, 1.5), (0.78, 0.74, 0.56), mats["Copper"], "Head", 2) ellipsoid("FaceMask", (0, -1.72, 1.5), (0.58, 0.34, 0.42), mats["Brass"], "Head", 1) cone("UpperBeak", (0, -1.68, 1.51), (0, -2.58, 1.34), 0.42, 0.035, mats["Brass"], "Head", 6) cone("LowerBeak", (0, -1.64, 1.3), (0, -2.32, 1.18), 0.3, 0.025, mats["Blade"], "Jaw", 6) for side, suffix in ((-1, "L"), (1, "R")): ellipsoid(f"Eye{suffix}", (side * 0.43, -1.72, 1.66), (0.09, 0.055, 0.09), mats["Furnace"], "Head", 1) cone( f"BrowHorn{suffix}", (side * 0.42, -1.38, 1.78), (side * 0.88, -1.7, 2.03), 0.13, 0, mats["Blade"], "Head", 5, ) for index, (x, z) in enumerate(((-0.34, 2.0), (0, 2.14), (0.34, 2.0))): cone(f"CrownBlade{index}", (x, -1.2, 1.8), (x * 1.35, -1.15, z + 0.54), 0.12, 0, mats["Brass"], "Head", 5) # Blade-like vestigial wings make lateral cleaves readable from camera. for side, suffix in ((-1, "L"), (1, "R")): bone = f"Wing.{suffix}" plate( f"WingShield{suffix}", (side * 1.05, -0.08, 1.62), (0.7, 0.56, 0.13), (math.radians(78), math.radians(side * 18), math.radians(side * 8)), mats["Copper"], bone, ) cone( f"WingBlade{suffix}", (side * 0.72, -0.24, 1.7), (side * 1.95, -0.58, 1.42), 0.19, 0.015, mats["Blade"], bone, 6, ) cone( f"WingGlow{suffix}", (side * 0.88, -0.3, 1.69), (side * 1.7, -0.52, 1.5), 0.05, 0.008, mats["Furnace"], bone, 5, ) # Six short piston legs: stable, strange, easy to read while scuttling. leg_rows = (("F", -0.72), ("M", 0.03), ("B", 0.76)) for row_index, (row, y) in enumerate(leg_rows): for side, suffix in ((-1, "L"), (1, "R")): bone = f"Leg.{row}{suffix}" hip_x = side * (0.64 if row != "M" else 0.78) foot_x = side * (0.98 if row != "M" else 1.1) ellipsoid(f"Hip{row}{suffix}", (hip_x, y, 1.05), (0.3, 0.34, 0.3), mats["Copper"], bone, 1) cone(f"Shin{row}{suffix}", (hip_x, y, 1.0), (foot_x, y - 0.04, 0.28), 0.22, 0.14, mats["Scale"], bone, 6) ellipsoid(f"Foot{row}{suffix}", (foot_x, y - 0.22, 0.2), (0.31, 0.48, 0.19), mats["Brass"], bone, 1) for toe_index, toe_x in enumerate((-0.13, 0.13)): cone( f"Toe{row}{suffix}{toe_index}", (foot_x + toe_x, y - 0.42, 0.2), (foot_x + toe_x * 1.4, y - 0.75, 0.1), 0.055, 0.004, mats["Blade"], bone, 5, ) cone("TailCore1", (0, 0.95, 1.3), (0, 1.85, 1.1), 0.48, 0.3, mats["Scale"], "Tail.1", 7) cone("TailCore2", (0, 1.78, 1.1), (0, 2.72, 0.88), 0.31, 0.07, mats["Copper"], "Tail.2", 7) cone("TailBladeTop", (0, 2.45, 0.9), (0, 3.18, 1.45), 0.2, 0.015, mats["Blade"], "Tail.2", 5) cone("TailBladeBottom", (0, 2.45, 0.9), (0, 3.15, 0.48), 0.18, 0.015, mats["Brass"], "Tail.2", 5) ellipsoid("TailCoreGlow", (0, 2.54, 0.91), (0.14, 0.17, 0.14), mats["Furnace"], "Tail.2", 1) body = join_parts("BrassbeakBasilisk", rig) clips = actions(rig, brassbeak_actions()) export_asset( asset_id, "Brassbeak Basilisk", rig, body, clips, [ ("Body", (0, 0, 1.25), (1.25, 1.55, 0.9)), ("Head", (0, -1.65, 1.42), (0.95, 1.05, 0.75)), ("Tail", (0, 2.08, 1.0), (0.55, 1.25, 0.78)), ], (0, 0, 1.25), 8.8, "FurnaceBurst", 20, ) add_metadata(asset_id, "Original six-legged forge basilisk designed for I Want to Heal") def brassbeak_actions(): return [ ("Idle", 60, True, [ {"frame": 1}, {"frame": 15, "locations": {"Root": (0, 0, 0.04)}, "rotations": {"Head": (3, 0, -3), "Jaw": (7, 0, 0), "Tail.2": (0, 0, 7), "Wing.L": (0, 0, -4), "Wing.R": (0, 0, 4)}}, {"frame": 30, "rotations": {"Head": (0, 0, 3), "Jaw": (0, 0, 0), "Tail.2": (0, 0, -7)}}, {"frame": 45, "locations": {"Root": (0, 0, 0.04)}, "rotations": {"Head": (3, 0, -3), "Jaw": (7, 0, 0), "Tail.2": (0, 0, 7), "Wing.L": (0, 0, -4), "Wing.R": (0, 0, 4)}}, {"frame": 60}, ]), ("Scuttle", 30, True, [ {"frame": 1, "rotations": {"Leg.FL": (-18, 0, -5), "Leg.MR": (-18, 0, 4), "Leg.BL": (-18, 0, -4), "Leg.FR": (18, 0, 5), "Leg.ML": (18, 0, -4), "Leg.BR": (18, 0, 4), "Tail.2": (0, 0, -9)}}, {"frame": 8, "locations": {"Root": (0, 0, 0.08)}, "rotations": {"Body": (-3, 0, 0)}}, {"frame": 16, "rotations": {"Leg.FL": (18, 0, 5), "Leg.MR": (18, 0, -4), "Leg.BL": (18, 0, 4), "Leg.FR": (-18, 0, -5), "Leg.ML": (-18, 0, 4), "Leg.BR": (-18, 0, -4), "Tail.2": (0, 0, 9)}}, {"frame": 23, "locations": {"Root": (0, 0, 0.08)}, "rotations": {"Body": (3, 0, 0)}}, {"frame": 30, "rotations": {"Leg.FL": (-18, 0, -5), "Leg.MR": (-18, 0, 4), "Leg.BL": (-18, 0, -4), "Leg.FR": (18, 0, 5), "Leg.ML": (18, 0, -4), "Leg.BR": (18, 0, 4), "Tail.2": (0, 0, -9)}}, ]), ("BeakRend", 34, False, [ {"frame": 1}, {"frame": 9, "locations": {"Root": (0, 0.12, -0.05)}, "rotations": {"Body": (-9, 0, 0), "Head": (-24, 0, 0), "Jaw": (24, 0, 0), "Wing.L": (0, -16, -10), "Wing.R": (0, 16, 10)}}, {"frame": 15, "locations": {"Root": (0, -0.2, 0.05)}, "rotations": {"Body": (15, 0, 0), "Head": (28, 0, 0), "Jaw": (-6, 0, 0)}}, {"frame": 23, "rotations": {"Head": (-8, 0, 0), "Jaw": (12, 0, 0)}}, {"frame": 34}, ]), ("FurnaceBurst", 46, False, [ {"frame": 1}, {"frame": 12, "locations": {"Root": (0, 0, 0.1)}, "scales": {"Body": (0.94, 0.94, 0.94)}, "rotations": {"Wing.L": (-18, 18, -22), "Wing.R": (-18, -18, 22), "Head": (-12, 0, 0), "Jaw": (18, 0, 0), "Tail.1": (-12, 0, 0)}}, {"frame": 20, "locations": {"Root": (0, -0.08, 0.22)}, "scales": {"Body": (1.1, 1.1, 1.1)}, "rotations": {"Wing.L": (18, -62, -64), "Wing.R": (18, 62, 64), "Head": (20, 0, 0), "Jaw": (30, 0, 0), "Tail.1": (18, 0, 0), "Tail.2": (-22, 0, 0)}}, {"frame": 30, "scales": {"Body": (0.97, 0.97, 0.97)}, "rotations": {"Wing.L": (4, -18, -20), "Wing.R": (4, 18, 20), "Jaw": (4, 0, 0), "Tail.2": (8, 0, 0)}}, {"frame": 46}, ]), ("Stagger", 28, False, [ {"frame": 1}, {"frame": 6, "locations": {"Root": (0.12, 0.12, -0.09)}, "rotations": {"Body": (-14, 0, 13), "Head": (22, 0, -12), "Wing.L": (24, 0, -18), "Wing.R": (-8, 0, 12)}}, {"frame": 15, "rotations": {"Body": (7, 0, -6), "Head": (-8, 0, 5)}}, {"frame": 28}, ]), ("Death", 72, False, [ {"frame": 1}, {"frame": 20, "locations": {"Root": (0.15, 0.08, -0.25)}, "rotations": {"Root": (0, 25, 32), "Body": (18, 0, 12), "Head": (24, 0, -10), "Jaw": (20, 0, 0), "Wing.L": (32, 0, -26), "Wing.R": (16, 0, 20)}}, {"frame": 46, "locations": {"Root": (0.28, 0.08, -0.78)}, "rotations": {"Root": (0, 52, 82), "Body": (30, 0, 20), "Head": (42, 0, -20), "Leg.FL": (30, 0, 0), "Leg.ML": (-24, 0, 0), "Leg.BL": (20, 0, 0), "Tail.1": (-32, 0, 0), "Tail.2": (-25, 0, 0)}}, {"frame": 72, "locations": {"Root": (0.28, 0.08, -0.82)}, "rotations": {"Root": (0, 52, 82), "Body": (30, 0, 20), "Head": (44, 0, -20), "Leg.FL": (30, 0, 0), "Leg.ML": (-24, 0, 0), "Leg.BL": (20, 0, 0), "Tail.1": (-32, 0, 0), "Tail.2": (-25, 0, 0)}}, ]), ] def build_bogbell_myconid() -> None: """Bell-capped fungal brute replacing Mirelord's frog model.""" asset_id = "bogbell-myconid" reset_scene() mats = prepare_materials({ "Bark": {"color": (0.12, 0.18, 0.095, 1), "roughness": 0.88}, "Root": {"color": (0.25, 0.31, 0.16, 1), "roughness": 0.8}, "Cap": {"color": (0.29, 0.055, 0.31, 1), "roughness": 0.6}, "CapEdge": {"color": (0.52, 0.15, 0.42, 1), "roughness": 0.52}, "Gill": {"color": (0.62, 0.55, 0.31, 1), "roughness": 0.7}, "Spore": {"color": (0.48, 1.0, 0.32, 1), "roughness": 0.16, "emission": (0.22, 0.92, 0.16, 1), "strength": 4.8}, }) specs = [ ("Root", (0, 0, 0), (0, 0, 0.5), None), ("Body", (0, 0, 1.15), (0, 0, 2.25), "Root"), ("Cap", (0, -0.05, 2.18), (0, -0.05, 3.18), "Body"), ("Arm.L", (-0.58, -0.15, 1.72), (-1.28, -0.62, 0.7), "Body"), ("Arm.R", (0.58, -0.15, 1.72), (1.28, -0.62, 0.7), "Body"), ("Leg.L", (-0.38, 0.08, 1.08), (-0.58, -0.1, 0.2), "Body"), ("Leg.R", (0.38, 0.08, 1.08), (0.58, -0.1, 0.2), "Body"), ("Tendril.L", (-0.42, 0.58, 1.45), (-1.05, 1.45, 0.82), "Body"), ("Tendril.R", (0.42, 0.58, 1.45), (1.05, 1.45, 0.82), "Body"), ] rig = armature("BogbellMyconid", specs) # Gnarled trunk and hanging bell cap. ellipsoid("Trunk", (0, 0.05, 1.48), (0.82, 0.68, 1.05), mats["Bark"], "Body", 2) ellipsoid("ChestKnot", (0, -0.5, 1.62), (0.58, 0.28, 0.62), mats["Root"], "Body", 1) cone("NeckStalk", (0, -0.02, 1.95), (0, -0.04, 2.65), 0.48, 0.36, mats["Gill"], "Cap", 8) plate("BellCap", (0, -0.04, 2.78), (1.55, 1.38, 0.55), (0, 0, 0), mats["Cap"], "Cap", 9) ellipsoid("CapCrown", (0, 0.02, 3.04), (1.25, 1.08, 0.42), mats["CapEdge"], "Cap", 2) plate("GillBell", (0, -0.03, 2.58), (1.28, 1.12, 0.28), (0, 0, math.radians(180)), mats["Gill"], "Cap", 9) for index, angle in enumerate(range(0, 360, 45)): radians = math.radians(angle) x, y = math.cos(radians) * 1.02, math.sin(radians) * 0.87 cone( f"CapHorn{index}", (x * 0.9, y * 0.9, 3.12), (x * 1.38, y * 1.35, 3.34 + 0.08 * (index % 2)), 0.11, 0, mats["CapEdge"], "Cap", 5, ) for side, suffix in ((-1, "L"), (1, "R")): ellipsoid(f"Eye{suffix}", (side * 0.29, -0.65, 2.18), (0.095, 0.055, 0.11), mats["Spore"], "Cap", 1) cone( f"FaceRoot{suffix}", (side * 0.25, -0.52, 2.03), (side * 0.42, -0.78, 1.72), 0.07, 0.015, mats["Root"], "Cap", 5, ) ellipsoid("MouthHollow", (0, -0.68, 1.94), (0.22, 0.055, 0.13), mats["Cap"], "Cap", 1) # Root arms end in broad knuckles for readable pummel animation. for side, suffix in ((-1, "L"), (1, "R")): bone = f"Arm.{suffix}" cone(f"UpperArm{suffix}", (side * 0.55, -0.12, 1.78), (side * 1.04, -0.45, 1.05), 0.3, 0.22, mats["Bark"], bone, 7) cone(f"Forearm{suffix}", (side * 1.02, -0.44, 1.06), (side * 1.34, -0.84, 0.58), 0.24, 0.18, mats["Root"], bone, 7) ellipsoid(f"Knuckle{suffix}", (side * 1.38, -0.91, 0.48), (0.43, 0.38, 0.32), mats["Bark"], bone, 1) for finger in (-0.16, 0, 0.16): cone( f"Finger{suffix}{finger}", (side * 1.36 + finger, -1.02, 0.43), (side * 1.46 + finger, -1.35, 0.22), 0.065, 0.012, mats["Root"], bone, 5, ) for side, suffix in ((-1, "L"), (1, "R")): bone = f"Leg.{suffix}" ellipsoid(f"Hip{suffix}", (side * 0.4, 0.08, 1.0), (0.42, 0.46, 0.5), mats["Bark"], bone, 1) cone(f"RootLeg{suffix}", (side * 0.4, 0.06, 0.95), (side * 0.62, -0.12, 0.25), 0.34, 0.22, mats["Root"], bone, 7) for toe_index, toe_x in enumerate((-0.22, 0, 0.22)): cone( f"RootToe{suffix}{toe_index}", (side * 0.62 + toe_x, -0.2, 0.25), (side * 0.72 + toe_x * 1.25, -0.78 - abs(toe_x), 0.08), 0.095, 0.015, mats["Bark"], bone, 6, ) # Rear tendrils drag through mire. Spore sacs pulse during eruption. for side, suffix in ((-1, "L"), (1, "R")): bone = f"Tendril.{suffix}" cone(f"TendrilBase{suffix}", (side * 0.4, 0.5, 1.38), (side * 0.78, 1.22, 0.82), 0.22, 0.12, mats["Root"], bone, 7) cone(f"TendrilTip{suffix}", (side * 0.76, 1.18, 0.84), (side * 1.28, 1.85, 0.3), 0.13, 0.018, mats["Bark"], bone, 6) ellipsoid(f"SporeSac{suffix}", (side * 0.82, 0.72, 1.25), (0.24, 0.31, 0.3), mats["Spore"], bone, 1) for index, (x, y, z, size) in enumerate(((-0.5, 0.45, 1.88, 0.16), (0.48, 0.5, 1.72, 0.2), (-0.28, 0.62, 1.35, 0.13))): ellipsoid(f"BodySpore{index}", (x, y, z), (size, size * 0.82, size * 1.1), mats["Spore"], "Body", 1) body = join_parts("BogbellMyconid", rig) clips = actions(rig, bogbell_actions()) export_asset( asset_id, "Bogbell Myconid", rig, body, clips, [ ("Body", (0, 0, 1.45), (1.05, 0.95, 1.35)), ("Cap", (0, 0, 2.82), (1.68, 1.48, 0.72)), ("Roots", (0, 0.38, 0.62), (1.58, 1.75, 0.72)), ], (0, 0, 1.65), 8.5, "SporeEruption", 21, ) add_metadata(asset_id, "Original bell-capped fungal mire creature designed for I Want to Heal") def bogbell_actions(): return [ ("Idle", 60, True, [ {"frame": 1}, {"frame": 15, "locations": {"Root": (0, 0, 0.04)}, "scales": {"Cap": (1.03, 1.03, 0.98)}, "rotations": {"Cap": (2, 0, -3), "Arm.L": (0, 0, -3), "Arm.R": (0, 0, 3), "Tendril.L": (0, 0, 7), "Tendril.R": (0, 0, -7)}}, {"frame": 30, "scales": {"Cap": (0.98, 0.98, 1.03)}, "rotations": {"Cap": (-1, 0, 3), "Tendril.L": (0, 0, -7), "Tendril.R": (0, 0, 7)}}, {"frame": 45, "locations": {"Root": (0, 0, 0.04)}, "scales": {"Cap": (1.03, 1.03, 0.98)}, "rotations": {"Cap": (2, 0, -3), "Arm.L": (0, 0, -3), "Arm.R": (0, 0, 3), "Tendril.L": (0, 0, 7), "Tendril.R": (0, 0, -7)}}, {"frame": 60}, ]), ("BurrowRush", 32, True, [ {"frame": 1, "locations": {"Root": (0, 0, -0.12)}, "rotations": {"Body": (10, 0, 0), "Arm.L": (26, 0, -12), "Arm.R": (26, 0, 12), "Leg.L": (-16, 0, 0), "Leg.R": (16, 0, 0), "Tendril.L": (-18, 0, -12), "Tendril.R": (-18, 0, 12)}}, {"frame": 9, "locations": {"Root": (0, 0, -0.26)}, "rotations": {"Cap": (-9, 0, 0), "Leg.L": (16, 0, 0), "Leg.R": (-16, 0, 0), "Tendril.L": (14, 0, 10), "Tendril.R": (14, 0, -10)}}, {"frame": 17, "locations": {"Root": (0, 0, -0.12)}, "rotations": {"Body": (10, 0, 0), "Arm.L": (26, 0, -12), "Arm.R": (26, 0, 12), "Leg.L": (-16, 0, 0), "Leg.R": (16, 0, 0), "Tendril.L": (-18, 0, -12), "Tendril.R": (-18, 0, 12)}}, {"frame": 25, "locations": {"Root": (0, 0, -0.26)}, "rotations": {"Cap": (-9, 0, 0), "Leg.L": (16, 0, 0), "Leg.R": (-16, 0, 0), "Tendril.L": (14, 0, 10), "Tendril.R": (14, 0, -10)}}, {"frame": 32, "locations": {"Root": (0, 0, -0.12)}, "rotations": {"Body": (10, 0, 0), "Arm.L": (26, 0, -12), "Arm.R": (26, 0, 12), "Leg.L": (-16, 0, 0), "Leg.R": (16, 0, 0), "Tendril.L": (-18, 0, -12), "Tendril.R": (-18, 0, 12)}}, ]), ("RootPummel", 36, False, [ {"frame": 1}, {"frame": 10, "locations": {"Root": (0, 0.1, 0.06)}, "rotations": {"Body": (-12, 0, 0), "Cap": (-8, 0, 0), "Arm.L": (-42, 0, -30), "Arm.R": (-42, 0, 30)}}, {"frame": 17, "locations": {"Root": (0, -0.12, -0.14)}, "rotations": {"Body": (22, 0, 0), "Cap": (18, 0, 0), "Arm.L": (58, 0, 16), "Arm.R": (58, 0, -16)}}, {"frame": 25, "rotations": {"Body": (-5, 0, 0), "Arm.L": (12, 0, -6), "Arm.R": (12, 0, 6)}}, {"frame": 36}, ]), ("SporeEruption", 48, False, [ {"frame": 1}, {"frame": 13, "locations": {"Root": (0, 0, -0.12)}, "scales": {"Cap": (0.88, 0.88, 1.16)}, "rotations": {"Body": (-13, 0, 0), "Cap": (-15, 0, 0), "Arm.L": (-26, 0, -28), "Arm.R": (-26, 0, 28), "Tendril.L": (-28, 0, -24), "Tendril.R": (-28, 0, 24)}}, {"frame": 21, "locations": {"Root": (0, -0.04, 0.24)}, "scales": {"Cap": (1.18, 1.18, 0.9), "Body": (1.08, 1.08, 1.08)}, "rotations": {"Body": (18, 0, 0), "Cap": (19, 0, 0), "Arm.L": (18, 0, 62), "Arm.R": (18, 0, -62), "Tendril.L": (32, 0, 48), "Tendril.R": (32, 0, -48)}}, {"frame": 32, "scales": {"Cap": (0.97, 0.97, 1.04), "Body": (0.97, 0.97, 0.97)}, "rotations": {"Cap": (-5, 0, 0), "Arm.L": (4, 0, 12), "Arm.R": (4, 0, -12)}}, {"frame": 48}, ]), ("Stagger", 28, False, [ {"frame": 1}, {"frame": 6, "locations": {"Root": (0.14, 0.1, -0.08)}, "rotations": {"Body": (-15, 0, 13), "Cap": (24, 0, -18), "Arm.L": (20, 0, -18), "Arm.R": (-8, 0, 12)}}, {"frame": 15, "rotations": {"Body": (7, 0, -6), "Cap": (-8, 0, 7)}}, {"frame": 28}, ]), ("Death", 74, False, [ {"frame": 1}, {"frame": 20, "locations": {"Root": (0.14, 0.1, -0.3)}, "rotations": {"Root": (0, 24, 30), "Body": (20, 0, 12), "Cap": (28, 0, -18), "Arm.L": (30, 0, -26), "Arm.R": (16, 0, 20), "Tendril.L": (-24, 0, -14), "Tendril.R": (-16, 0, 18)}}, {"frame": 48, "locations": {"Root": (0.28, 0.1, -0.86)}, "rotations": {"Root": (0, 54, 84), "Body": (34, 0, 24), "Cap": (48, 0, -30), "Arm.L": (52, 0, -42), "Arm.R": (28, 0, 34), "Leg.L": (24, 0, 0), "Leg.R": (-18, 0, 0), "Tendril.L": (-40, 0, -24), "Tendril.R": (-34, 0, 26)}}, {"frame": 74, "locations": {"Root": (0.28, 0.1, -0.9)}, "rotations": {"Root": (0, 54, 84), "Body": (34, 0, 24), "Cap": (50, 0, -30), "Arm.L": (52, 0, -42), "Arm.R": (28, 0, 34), "Leg.L": (24, 0, 0), "Leg.R": (-18, 0, 0), "Tendril.L": (-40, 0, -24), "Tendril.R": (-34, 0, 26)}}, ]), ] def main() -> None: bpy.context.preferences.filepaths.save_version = 0 OUT_ROOT.mkdir(parents=True, exist_ok=True) build_brassbeak_basilisk() build_bogbell_myconid() if __name__ == "__main__": main()