2026-07-21 00:27:17 +07:00
|
|
|
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
|
2026-07-25 23:26:07 +07:00
|
|
|
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
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
|
|
|
func _ready():
|
2026-07-25 23:26:07 +07:00
|
|
|
if dialogue_box: dialogue_box.visible = false
|
|
|
|
|
if press_e_label: press_e_label.visible = false
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
|
|
|
func start_dialogue(lines: Array):
|
|
|
|
|
hide_prompt()
|
|
|
|
|
current_dialogue_lines = lines
|
|
|
|
|
current_line_index = 0
|
2026-07-25 23:26:07 +07:00
|
|
|
if dialogue_box: dialogue_box.visible = true
|
|
|
|
|
is_active = true
|
2026-07-21 00:27:17 +07:00
|
|
|
|
2026-07-25 23:26:07 +07:00
|
|
|
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)
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
|
|
|
|
show_current_line()
|
|
|
|
|
|
2026-07-25 23:26:07 +07:00
|
|
|
# Физический цикл интерфейса, который работает пока открыто окно диалога
|
|
|
|
|
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
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
func show_current_line():
|
|
|
|
|
if current_line_index < current_dialogue_lines.size():
|
|
|
|
|
var line_data = current_dialogue_lines[current_line_index]
|
2026-07-25 23:26:07 +07:00
|
|
|
if name_label: name_label.text = line_data.get("name", "NPC")
|
|
|
|
|
if text_label: text_label.text = line_data.get("text", "")
|
2026-07-21 00:27:17 +07:00
|
|
|
else:
|
2026-07-25 23:26:07 +07:00
|
|
|
# Перед закрытием просим Сталкера обнулить статус активности
|
|
|
|
|
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
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
end_dialogue()
|
|
|
|
|
|
2026-07-25 23:26:07 +07:00
|
|
|
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
|
2026-07-21 00:27:17 +07:00
|
|
|
|
2026-07-25 23:26:07 +07:00
|
|
|
if is_click or is_space:
|
2026-07-21 00:27:17 +07:00
|
|
|
current_line_index += 1
|
|
|
|
|
show_current_line()
|
|
|
|
|
get_viewport().set_input_as_handled()
|
|
|
|
|
|
|
|
|
|
func end_dialogue():
|
2026-07-25 23:26:07 +07:00
|
|
|
is_active = false
|
|
|
|
|
if dialogue_box:
|
|
|
|
|
dialogue_box.visible = false
|
|
|
|
|
if press_e_label:
|
2026-07-21 00:27:17 +07:00
|
|
|
press_e_label.visible = false
|
2026-07-25 23:26:07 +07:00
|
|
|
|
|
|
|
|
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
|