extends GPUParticles3D # Bioluminescent floating particles — only active in abyss zone (player y < -30) const ABYSS_DEPTH_THRESHOLD: float = -30.0 var _player: Node3D = null func _ready() -> void: amount = 200 lifetime = 12.0 one_shot = false explosiveness = 0.0 randomness = 1.0 visibility_aabb = AABB(Vector3(-30, -25, -30), Vector3(60, 50, 60)) var process_mat := ParticleProcessMaterial.new() process_mat.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX process_mat.emission_box_extents = Vector3(28.0, 20.0, 28.0) process_mat.direction = Vector3(0.0, 1.0, 0.0) process_mat.spread = 120.0 process_mat.initial_velocity_min = 0.0 process_mat.initial_velocity_max = 0.08 process_mat.linear_accel_min = -0.03 process_mat.linear_accel_max = 0.03 process_mat.radial_accel_min = -0.02 process_mat.radial_accel_max = 0.02 process_mat.damping_min = 0.4 process_mat.damping_max = 0.9 process_mat.scale_min = 0.03 process_mat.scale_max = 0.12 # Cyan-green bioluminescent color var grad := Gradient.new() grad.set_color(0, Color(0.0, 0.8, 0.9, 0.0)) grad.set_color(1, Color(0.0, 0.8, 0.9, 0.0)) grad.add_point(0.1, Color(0.1, 0.9, 0.8, 0.7)) grad.add_point(0.85, Color(0.2, 0.7, 1.0, 0.6)) var grad_tex := GradientTexture1D.new() grad_tex.gradient = grad process_mat.color_ramp = grad_tex process_mat.color = Color(0.1, 0.9, 0.8, 0.7) process_material = process_mat var quad := QuadMesh.new() quad.size = Vector2(0.08, 0.08) var mat := StandardMaterial3D.new() mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA mat.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED mat.emission_enabled = true mat.emission = Color(0.2, 0.8, 1.0) mat.emission_energy_multiplier = 3.0 mat.albedo_color = Color(0.1, 0.9, 0.8, 0.7) quad.surface_set_material(0, mat) draw_pass_1 = quad # Start inactive until we detect depth emitting = false _find_player() func _find_player() -> void: var players := get_tree().get_nodes_in_group("player") if players.size() > 0: _player = players[0] as Node3D func _process(_delta: float) -> void: if _player == null: _find_player() return var in_abyss: bool = _player.global_position.y < ABYSS_DEPTH_THRESHOLD if in_abyss != emitting: emitting = in_abyss # Follow player horizontally, float at player depth if in_abyss: global_position = _player.global_position