extends Node2D # 🛠️ BARU: Sinyal untuk memberi tahu Stage kalau boss masuk Fase 2 signal fase_dua_dimulai @export var roda_berputar : bool = true @export var sprite_rusak_tahap1 : Texture2D @export var sprite_rusak_tahap2 : Texture2D @export var sprite_hancur_total : Texture2D @export var peluru_fase1 : PackedScene = preload("res://pelururiflemusuh.tscn") @export var peluru_fase2 : PackedScene = preload("res://pelurumusuhfase_2.tscn") # 🎛️ SETELAN VOLUME AUDIO FASE 2 (+10 dB) @export var VOLUME_TEMBAKAN_KUAT: float = 10.0 var health = 100 var is_destroyed = false # 🛠️ BARU: Pengaman agar sinyal tutorial Fase 2 hanya dikirim sekali saja var tutorial_fase2_sudah_dikirim: bool = false @onready var body_sprite = $StaticBody2D/body @onready var anim_player = $AnimationPlayer @onready var titik_tembak = $TitikTembak # 🎵 AUDIO STREAM 1: Tembakan Biasa (Fase 1) @onready var audio_tembakan = $AudioStreamPlayer # 🎵 AUDIO STREAM 2: Tembakan Diperkuat / Meriam (Fase 2) @onready var audio_tembakan_kuat = $AudioStreamPlayer2 # Variabel untuk referensi player agar bisa diincar var player_ref = null func _ready(): if roda_berputar and anim_player: anim_player.play("berputar") # Cari player di dalam scene player_ref = get_tree().current_scene.find_child("Player", true, false) func mulai_menembak(): if is_destroyed: return await get_tree().create_timer(5.0).timeout _loop_tembakan() func _loop_tembakan(): while not is_destroyed and visible: if health > 50: for i in range(5): if is_destroyed or health <= 50: break _eksekusi_tembak_bertarget(peluru_fase1, 5) await get_tree().create_timer(0.15).timeout await get_tree().create_timer(5.0).timeout else: if is_destroyed: break _eksekusi_tembak_bertarget(peluru_fase2, 40.0) await get_tree().create_timer(7.0).timeout func _eksekusi_tembak_bertarget(scene_peluru, nilai_damage): if scene_peluru and titik_tembak: # 🎵 MAINKAN AUDIO BERDASARKAN FASE NYAWA BOSS if health > 50: if audio_tembakan: audio_tembakan.play() else: if audio_tembakan_kuat: audio_tembakan_kuat.volume_db = VOLUME_TEMBAKAN_KUAT audio_tembakan_kuat.play() var peluru = scene_peluru.instantiate() # 1. Tentukan posisi muncul peluru var spawn_pos = titik_tembak.global_position peluru.global_position = spawn_pos peluru.damage = nilai_damage # --- Atur Kecepatan Peluru --- if "speed" in peluru: if health > 50: peluru.speed = 600.0 # Kecepatan peluru Fase 1 else: peluru.speed = 1000.0 # Kecepatan peluru Fase 2 (lebih ngebut!) # 2. Tentukan target (Default ke kiri jauh) var target_pos = spawn_pos + Vector2(-1000, 0) if is_instance_valid(player_ref): target_pos = player_ref.global_position if player_ref.get("is_menunduk") == true: target_pos.y -= 220 # Meleset ke atas else: target_pos.y -= 50 # Bidik badan # 3. Hitung Arah var diff = target_pos - spawn_pos if diff.x > 0: diff.x = -100 # Paksa arah tetap ke kiri var arah = diff.normalized() # 4. Terapkan Arah dan Rotasi if "direction" in peluru: peluru.direction = arah peluru.rotation = arah.angle() get_tree().current_scene.add_child(peluru) func kurangi_nyawa(_jumlah): if is_destroyed: return if health <= 50: health -= 1.5 else: health -= 0.5 print("HP Boss: ", health) # 🛠️ BARU: Deteksi Transisi ke HP <= 50 untuk memicu Sinyal Tutorial if health <= 50 and not tutorial_fase2_sudah_dikirim and not is_destroyed: tutorial_fase2_sudah_dikirim = true emit_signal("fase_dua_dimulai") # Ledakkan sinyal ke skrip Stage! if health <= 0: hancurkan_mobil() elif health <= 25: body_sprite.texture = sprite_rusak_tahap2 body_sprite.scale = Vector2(1.79, 2.022) elif health <= 50: body_sprite.texture = sprite_rusak_tahap1 body_sprite.scale = Vector2(1.79, 2.022) func hancurkan_mobil(): is_destroyed = true if anim_player: anim_player.stop() if sprite_hancur_total: body_sprite.texture = sprite_hancur_total body_sprite.scale = Vector2(1.79, 2.022) var body = get_node_or_null("StaticBody2D") if body: for child in body.get_children(): if child is CollisionPolygon2D or child is CollisionShape2D: child.set_deferred("disabled", true)