extends CanvasLayer @onready var dialogue_box = $DialogueBox @onready var name_label = $DialogueBox/NameLabel @onready var text_label = $DialogueBox/TextLabel @onready var press_e_label = $PressE var current_dialogue_lines: Array = [] var current_line_index: int = 0 var player_ref: Node3D = null var is_active: bool = false # --- НАШИ НОВЫЕ ПЕРЕМЕННЫЕ ДЛЯ ЗАМОРОЗКИ ВЗГЛЯДА --- var camera_node: Camera3D = null var saved_camera_rotation: Vector3 = Vector3.ZERO var is_camera_locked: bool = false func _ready(): if dialogue_box: dialogue_box.visible = false if press_e_label: press_e_label.visible = false func start_dialogue(lines: Array): hide_prompt() current_dialogue_lines = lines current_line_index = 0 if dialogue_box: dialogue_box.visible = true is_active = true player_ref = get_tree().current_scene.find_child("PlayerCharacter", true, false) if player_ref: # Блокируем стрельбу var wm = player_ref.find_child("WeaponManager", true, false) if wm: if "canUseWeapon" in wm: wm.canUseWeapon = false if wm.has_method("disable_weapons_for_dialogue"): wm.disable_weapons_for_dialogue() # --- ЖЕСТКАЯ ФИКСАЦИЯ УГЛА КАМЕРЫ --- # Находим 3D-камеру внутри игрока camera_node = player_ref.find_child("Camera3D", true, false) if camera_node == null: camera_node = player_ref.find_child("PlayerCamera", true, false) if camera_node: # Запоминаем точный угол, куда смотрел игрок в момент нажатия Е saved_camera_rotation = camera_node.rotation is_camera_locked = true print("[UI] Угол камеры успешно сохранен: ", saved_camera_rotation) Input.mouse_mode = Input.MOUSE_MODE_VISIBLE show_current_line() # Физический цикл интерфейса, который работает пока открыто окно диалога func _process(_delta: float) -> void: # Пока диалог активен, мы КАЖДЫЙ КАДР принудительно возвращаем камере сохраненный угол, # полностью перебивая любые попытки ассета уронить взгляд в пол! if is_camera_locked and camera_node != null and is_instance_valid(camera_node): camera_node.rotation = saved_camera_rotation func show_current_line(): if current_line_index < current_dialogue_lines.size(): var line_data = current_dialogue_lines[current_line_index] if name_label: name_label.text = line_data.get("name", "NPC") if text_label: text_label.text = line_data.get("text", "") else: # Перед закрытием просим Сталкера обнулить статус активности var current_scene = get_tree().current_scene if current_scene: var npc = current_scene.find_child("StaticBody3D", true, false) if npc == null: npc = current_scene.find_child("bot", true, false) if npc and "_restore_player_control" in npc: npc._restore_player_control() if "is_dialogue_active" in npc: npc.is_dialogue_active = false end_dialogue() func _unhandled_input(event: InputEvent) -> void: if is_active and dialogue_box and dialogue_box.visible: var is_click = event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT var is_space = event is InputEventKey and event.pressed and event.keycode == KEY_SPACE if is_click or is_space: current_line_index += 1 show_current_line() get_viewport().set_input_as_handled() func end_dialogue(): is_active = false if dialogue_box: dialogue_box.visible = false if press_e_label: press_e_label.visible = false is_camera_locked = false # Даем игре фору в два физических кадра, чтобы финальный клик мышки полностью угас await get_tree().process_frame await get_tree().process_frame # --- БРОНЕБОЙНЫЙ РАЗБЛОК СТРЕЛЬБЫ, ПЕРЕЗАРЯДКИ И КОЛЕСИКА ОРУЖИЯ --- if player_ref: var wm = player_ref.find_child("WeaponManager", true, false) if wm: # 1. Возвращаем базовые флаги использования и смены пушек if "canUseWeapon" in wm: wm.canUseWeapon = true if "canChangeWeapons" in wm: wm.canChangeWeapons = true if "canReload" in wm: wm.canReload = true # 2. Вызываем ВСЕ возможные методы включения оружия, какие заложил автор ассета: if wm.has_method("enable_weapons_after_dialogue"): wm.enable_weapons_after_dialogue() elif wm.has_method("enable_weapons"): wm.enable_weapons() elif wm.has_method("activate_weapons"): wm.activate_weapons() # 3. Принудительно заставляем HUD и пушку обновиться, чтобы вернуть её в руки if wm.has_method("displayStats"): wm.displayStats() if "cW" in wm and wm.cW != null and wm.has_method("changeWeapon"): # Насильно заставляем персонажа достать текущее оружие обратно wm.changeWeapon(wm.weaponStack[wm.weaponIndex]) Input.mouse_mode = Input.MOUSE_MODE_CAPTURED print("[UI] Диалог чисто закрыт. Оружие, перезарядка и колесико принудительно возвращены в строй!") func show_prompt() -> void: if press_e_label and (dialogue_box == null or not dialogue_box.visible): press_e_label.visible = true func hide_prompt() -> void: if press_e_label: press_e_label.visible = false