class_name AnimalAppearance extends RefCounted ## Disposable woodland identities, rebuilt from stable NPC IDs. No simulation RNG. const CEL_SHADER := preload("res://world/presentation/materials/storybook_cel.gdshader") const SPECIES: Array[StringName] = [&"fox", &"rabbit", &"badger", &"otter"] const MODELS: Array[PackedScene] = [ preload("res://assets/storybook/fox.glb"), preload("res://assets/storybook/rabbit.glb"), preload("res://assets/storybook/badger.glb"), preload("res://assets/storybook/otter.glb"), ] const PARTS: Array[StringName] = [ &"Body", &"Head", &"Hair", &"ArmLeft", &"ArmRight", &"LegLeft", &"LegRight", &"Tail" ] static func apply_to(root: Node3D, identity: int, npc_body := false) -> void: var index := posmod(identity, MODELS.size()) var source := MODELS[index].instantiate() var material := ShaderMaterial.new() material.shader = CEL_SHADER root.set_meta("animal_species", SPECIES[index]) for part in PARTS: var source_mesh := source.find_child(String(part), true, false) as MeshInstance3D var target_name := "MeshInstance3D" if npc_body and part == &"Body" else String(part) var target := root.get_node(target_name) as MeshInstance3D assert(source_mesh != null, "Missing Blender animation part: " + String(part)) target.mesh = source_mesh.mesh target.material_override = material source.free() static func set_profession_color(root: Node3D, color: Color) -> void: var body := root.get_node("MeshInstance3D") as MeshInstance3D var material := body.material_override as ShaderMaterial material.set_shader_parameter("coat_color", color) material.set_shader_parameter("profession_tint", 0.28)