extends Node3D ## Cheap Compatibility-safe Xen arrival: rotating rings, CPU wisps, cyan flash. signal materialized const Audio = preload("res://scripts/hl_audio.gd") const ARRIVAL_TIME := 1.5 var elapsed := 0.0 var announced := false var rings: Array[MeshInstance3D] = [] var light: OmniLight3D func _ready() -> void: name = "BossTeleport" Audio.play(self, "ambience/port_suckin1.wav", true, -9) var material := StandardMaterial3D.new() material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA material.blend_mode = BaseMaterial3D.BLEND_MODE_ADD material.albedo_color = Color(0.12, 1.0, 0.65, 0.8) for i in range(3): var ring := MeshInstance3D.new() ring.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF var mesh := TorusMesh.new() mesh.inner_radius = 0.91 mesh.outer_radius = 1.0 mesh.rings = 32 mesh.ring_segments = 8 mesh.material = material ring.mesh = mesh ring.position.y = 0.10 + i * 0.72 add_child(ring) rings.append(ring) light = OmniLight3D.new() light.light_color = Color(0.12, 1.0, 0.65) light.light_energy = 3 light.omni_range = 6 light.shadow_enabled = false light.position.y = 1.1 add_child(light) var particles := CPUParticles3D.new() particles.amount = 40 particles.lifetime = 1.0 particles.emitting = true particles.emission_shape = CPUParticles3D.EMISSION_SHAPE_SPHERE particles.emission_sphere_radius = 0.9 particles.position.y = 0.5 particles.direction = Vector3.UP particles.spread = 20 particles.initial_velocity_min = 1 particles.initial_velocity_max = 2.2 particles.gravity = Vector3.ZERO var quad := QuadMesh.new() quad.size = Vector2(0.22, 0.4) var mist := material.duplicate() as StandardMaterial3D mist.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED mist.albedo_texture = preload("res://assets/effects/flame.png") quad.material = mist particles.mesh = quad var colors := Gradient.new() colors.set_color(0, Color(0.1, 1, 0.65, 0.8)) colors.set_color(1, Color(0.05, 0.3, 0.25, 0)) particles.color_ramp = colors add_child(particles) get_tree().create_timer(ARRIVAL_TIME).timeout.connect(func(): particles.emitting = false) func _process(dt: float) -> void: elapsed += dt for i in rings.size(): var size := maxf(0.05, sin(minf(elapsed / 2.2, 1.0) * PI)) rings[i].scale = Vector3.ONE * size * (1.0 + 0.12 * sin(elapsed * 11 + i)) rings[i].rotation = Vector3(sin(elapsed * 4 + i) * 0.2, elapsed * 3, 0) light.light_energy = 3 * maxf(0, 1.0 - maxf(0, elapsed - ARRIVAL_TIME) / 0.7) if elapsed >= ARRIVAL_TIME and not announced: announced = true Audio.play(self, "ambience/port_suckout1.wav", true, -9) materialized.emit() if elapsed >= 2.2: # Sound players belong to this node; leave them time to finish. for ring in rings: ring.hide() light.hide() set_process(false) get_tree().create_timer(3).timeout.connect(queue_free)