extends SceneTree ## Seeds the placeholder effect .tscn (and the gallery scene) once, headless. Those .tscn are the ## source of truth Siim edits in the inspector — this script only builds their first-draft defaults ## (ported from the old code-built particles). Re-run only to reset a placeholder from scratch: ## godot --headless --script fx/_seed_placeholders.gd const _EFFECT_SCRIPT := "res://fx/one_shot_effect.gd" const _GALLERY_SCRIPT := "res://fx/effect_gallery.gd" func _init() -> void: _seed_blood_burst() _seed_slam_dust() _seed_spark() _seed_hit_flash() _seed_gallery() print("Seeded FX placeholder scenes into res://fx/") quit() # ── shared builders ───────────────────────────────────────────────────────── func _unshaded() -> StandardMaterial3D: var m := StandardMaterial3D.new() m.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED m.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA m.vertex_color_use_as_albedo = true m.cull_mode = BaseMaterial3D.CULL_DISABLED return m func _sphere(radius: float) -> SphereMesh: var s := SphereMesh.new() s.radius = radius s.height = radius * 2.0 s.radial_segments = 4 s.rings = 2 s.material = _unshaded() return s func _ramp(c0: Color, c1: Color) -> Gradient: var g := Gradient.new() g.set_color(0, c0) g.set_color(1, c1) return g func _curve(points: Array) -> Curve: var c := Curve.new() for pt: Vector2 in points: c.add_point(pt) return c func _save(p: CPUParticles3D, path: String) -> void: p.set_script(load(_EFFECT_SCRIPT)) var packed := PackedScene.new() packed.pack(p) ResourceSaver.save(packed, path) p.free() # ── the placeholders (defaults ported from the old code-built particles) ───── func _seed_blood_burst() -> void: var p := CPUParticles3D.new() p.name = "blood_burst" p.mesh = _sphere(0.07) p.color_ramp = _ramp(Color(1.0, 0.02, 0.02, 1.0), Color(0.25, 0.0, 0.0, 0.0)) p.scale_amount_curve = _curve([Vector2(0.0, 1.0), Vector2(0.6, 0.5), Vector2(1.0, 0.0)]) p.emitting = false p.one_shot = true p.explosiveness = 0.9 p.amount = 25 p.lifetime = 1.1 p.randomness = 0.4 p.local_coords = false p.direction = Vector3(0.0, 1.0, 0.0) p.spread = 80.0 p.gravity = Vector3(0.0, -7.0, 0.0) p.initial_velocity_min = 4.0 p.initial_velocity_max = 11.0 p.scale_amount_min = 0.5 p.scale_amount_max = 1.6 _save(p, "res://fx/blood_burst.tscn") func _seed_slam_dust() -> void: var p := CPUParticles3D.new() p.name = "slam_dust" p.mesh = _sphere(0.16) p.color_ramp = _ramp(Color(0.72, 0.60, 0.40, 0.9), Color(0.55, 0.45, 0.30, 0.0)) p.scale_amount_curve = _curve([Vector2(0.0, 0.4), Vector2(0.35, 1.0), Vector2(1.0, 0.0)]) p.emitting = false p.one_shot = true p.explosiveness = 1.0 p.amount = 36 p.lifetime = 0.9 p.randomness = 0.5 p.local_coords = false p.emission_shape = CPUParticles3D.EMISSION_SHAPE_SPHERE p.emission_sphere_radius = 0.5 p.direction = Vector3(0.0, 1.0, 0.0) p.spread = 75.0 p.gravity = Vector3(0.0, -6.0, 0.0) p.initial_velocity_min = 2.5 p.initial_velocity_max = 6.5 p.scale_amount_min = 0.6 p.scale_amount_max = 1.4 _save(p, "res://fx/slam_dust.tscn") func _seed_spark() -> void: var p := CPUParticles3D.new() p.name = "spark" p.mesh = _sphere(0.03) p.color_ramp = _ramp(Color(1.0, 0.95, 0.6, 1.0), Color(1.0, 0.55, 0.1, 0.0)) p.scale_amount_curve = _curve([Vector2(0.0, 1.0), Vector2(1.0, 0.0)]) p.emitting = false p.one_shot = true p.explosiveness = 1.0 p.amount = 14 p.lifetime = 0.35 p.randomness = 0.6 p.local_coords = false p.direction = Vector3(0.0, 1.0, 0.0) p.spread = 45.0 p.gravity = Vector3(0.0, -9.0, 0.0) p.initial_velocity_min = 3.0 p.initial_velocity_max = 7.0 p.scale_amount_min = 0.4 p.scale_amount_max = 1.0 _save(p, "res://fx/spark.tscn") func _seed_hit_flash() -> void: var p := CPUParticles3D.new() p.name = "hit_flash" p.mesh = _sphere(0.05) p.color_ramp = _ramp(Color(1.0, 1.0, 1.0, 1.0), Color(1.0, 1.0, 1.0, 0.0)) p.scale_amount_curve = _curve([Vector2(0.0, 0.2), Vector2(0.3, 1.2), Vector2(1.0, 0.0)]) p.emitting = false p.one_shot = true p.explosiveness = 1.0 p.amount = 6 p.lifetime = 0.18 p.randomness = 0.2 p.local_coords = false p.spread = 180.0 p.gravity = Vector3.ZERO p.initial_velocity_min = 0.5 p.initial_velocity_max = 1.5 p.scale_amount_min = 0.8 p.scale_amount_max = 1.4 _save(p, "res://fx/hit_flash.tscn") func _seed_gallery() -> void: var root_node := Node3D.new() root_node.name = "EffectGallery" var cam := Camera3D.new() cam.name = "Camera3D" cam.transform = Transform3D(Basis.from_euler(Vector3(deg_to_rad(-18.0), 0.0, 0.0)), Vector3(0.0, 2.0, 4.5)) root_node.add_child(cam) cam.owner = root_node var light := DirectionalLight3D.new() light.name = "Sun" light.rotation_degrees = Vector3(-50.0, -30.0, 0.0) root_node.add_child(light) light.owner = root_node var ground := MeshInstance3D.new() ground.name = "Ground" var plane := PlaneMesh.new() plane.size = Vector2(12.0, 12.0) var gmat := StandardMaterial3D.new() gmat.albedo_color = Color(0.62, 0.53, 0.36) plane.material = gmat ground.mesh = plane root_node.add_child(ground) ground.owner = root_node var ui := CanvasLayer.new() ui.name = "UI" root_node.add_child(ui) ui.owner = root_node var label := Label.new() label.name = "Label" label.position = Vector2(24.0, 20.0) label.text = "FX gallery" label.add_theme_font_size_override("font_size", 28) ui.add_child(label) label.owner = root_node root_node.set_script(load(_GALLERY_SCRIPT)) var packed := PackedScene.new() packed.pack(root_node) ResourceSaver.save(packed, "res://fx/effect_gallery.tscn") root_node.free()