extends Node3D ## Wiese-Zone innerhalb der Dorf-Hauptwelt (kein eigener Scene-Teleport). ## Glitzos leben nur in meadow_aabb; außerhalb → Pixel-Sprühnebel. @export var meadow_aabb: AABB = AABB(Vector3(20.0, -1.0, -18.0), Vector3(36.0, 8.0, 36.0)) var _glitzo_timer: float = 0.0 var _bear_saved: bool = false var _first_glitzo_done: bool = false func _ready() -> void: _bear_saved = bool(GameState.get_flag("bear_saved", false)) _first_glitzo_done = Achievements.is_unlocked("first_glitzo") var bear := get_node_or_null("Bear") if bear and bear.has_signal("interacted"): bear.interacted.connect(_on_bear) var snake := get_node_or_null("SnakePickup") if snake and snake.has_signal("interacted"): snake.interacted.connect(_on_snake_pickup) if Inventory.has_item("snake") or GameState.get_flag("snake_massaged", false): if snake: snake.queue_free() if GameState.get_flag("snake_massaged", false): _disable_mower() func _process(delta: float) -> void: ## Only tick while player is near the meadow (cheap). var player := get_tree().get_first_node_in_group("player") if player is Node3D: var pp: Vector3 = (player as Node3D).global_position if not _near_meadow(pp): _cull_glitzos_off_meadow() return _glitzo_timer += delta if _glitzo_timer >= 3.2: _glitzo_timer = 0.0 _spawn_glitzo() _cull_glitzos_off_meadow() func _near_meadow(p: Vector3) -> bool: var expanded := meadow_aabb.grow(8.0) return expanded.has_point(Vector3(p.x, 0.0, p.z)) func _cull_glitzos_off_meadow() -> void: for child in get_children(): if child is Node3D and (child.name.begins_with("Glitzo") or str(child.get("texture_path")).ends_with("glitzo.png")): var p: Vector3 = child.global_position if not meadow_aabb.has_point(Vector3(p.x, 0.0, p.z)): _pixel_spray(p) child.queue_free() func _pixel_spray(at: Vector3) -> void: var scene: PackedScene = load("res://scenes/prefabs/quirxel_projectile.tscn") if scene == null: return for i in range(5): var q: Node3D = scene.instantiate() get_parent().add_child(q) q.global_position = at + Vector3(0, 0.4, 0) var ang := randf() * TAU q.set("velocity", Vector3(cos(ang), 0.5, sin(ang)) * randf_range(3.0, 6.0)) q.set("lifetime", 0.7) q.set("hp", 99) func _spawn_glitzo() -> void: var scene: PackedScene = load("res://scenes/prefabs/enemy.tscn") if scene == null: return var g: Node3D = scene.instantiate() g.name = "GlitzoSpawn_%d" % Time.get_ticks_msec() g.set("max_hp", 4) g.set("texture_path", "res://assets/sprites/placeholders/glitzo.png") g.set("ai_enabled", true) g.set("glitzo_mode", true) g.set("move_speed", 2.6) g.set("attack_cooldown", 1.15) g.set("attack_range", 1.1) g.set("death_cause_key", "death_glitzo") g.set("billboard_height", 1.0) g.set("aggro_range", 22.0) if not _first_glitzo_done: g.set("achievement_on_defeat", "first_glitzo") add_child(g) ## Spawn inside meadow AABB (local to world coords used by export). var min_p := meadow_aabb.position var max_p := meadow_aabb.position + meadow_aabb.size g.global_position = Vector3( randf_range(min_p.x + 4.0, max_p.x - 4.0), 0.1, randf_range(min_p.z + 4.0, max_p.z - 4.0) ) var bill: Node = g.get_node_or_null("BillboardSprite") if bill and bill.has_method("set_texture"): var tex: Texture2D = load("res://assets/sprites/placeholders/glitzo.png") if tex: bill.set_texture(tex) if g.has_signal("defeated"): g.defeated.connect(_on_glitzo_killed) func _on_glitzo_killed() -> void: _first_glitzo_done = true func _on_bear(_npc: Node = null) -> void: var ui := get_node_or_null("/root/UIRoot") if _bear_saved: if ui and ui.has_method("show_dialog"): ui.show_dialog_key("dialog_bear_saved") return if Inventory.has_item("snake") and GameState.get_flag("snake_massaged", false): _save_bear() return if Inventory.has_item("snake"): if ui and ui.has_method("show_dialog"): ui.show_dialog_key("dialog_villager_snake") return if ui and ui.has_method("show_dialog"): ui.show_dialog_key("dialog_bear_help") func _on_snake_pickup(_npc: Node = null) -> void: var ui := get_node_or_null("/root/UIRoot") if ui and ui.has_method("show_dialog"): ui.show_dialog_key("dialog_snake_picked") func _save_bear() -> void: _bear_saved = true GameState.set_flag("bear_saved", true) if not Inventory.has_item("tooth"): Inventory.add_item("tooth", 1) _disable_mower() var ui := get_node_or_null("/root/UIRoot") if ui and ui.has_method("show_dialog"): ui.show_dialog_key("dialog_bear_saved", 4.5) func _disable_mower() -> void: var mower := get_node_or_null("MowerHazard") if mower: mower.queue_free() func notify_snake_massaged() -> void: if not _bear_saved: _save_bear()