2026-07-21 00:27:17 +07:00
|
|
|
|
extends Node3D
|
|
|
|
|
|
|
|
|
|
|
|
var weaponStack : Array[int] = [] #weapons current wielded by play char
|
|
|
|
|
|
var weaponList : Dictionary = {} #all weapons available in the game (key = weapon name, value = wepakn resource)
|
|
|
|
|
|
@export var weaponResources : Array[WeaponResource] #all weapon resources files
|
|
|
|
|
|
@export var startWeapons : Array[WeaponSlot] #the weapon the player character will start with
|
|
|
|
|
|
|
|
|
|
|
|
var cW = null #current weapon
|
|
|
|
|
|
var cWModel = null #current weapon model
|
|
|
|
|
|
var weaponIndex : int = 0
|
|
|
|
|
|
|
|
|
|
|
|
#weapon changes variables
|
|
|
|
|
|
var canChangeWeapons : bool = true
|
|
|
|
|
|
var canUseWeapon : bool = true
|
|
|
|
|
|
|
|
|
|
|
|
@export_group("Keybind variables")
|
|
|
|
|
|
@export var shoot_action : String
|
|
|
|
|
|
@export var reload_action : String
|
|
|
|
|
|
@export var weapon_wheel_up_action : String
|
|
|
|
|
|
@export var weapon_wheel_down_action : String
|
|
|
|
|
|
|
|
|
|
|
|
@onready var playChar : CharacterBody3D = $"../../../.."
|
|
|
|
|
|
@onready var cameraHolder : Node3D = %CameraHolder
|
|
|
|
|
|
@onready var cameraRecoilHolder : Node3D = %CameraRecoilHolder
|
|
|
|
|
|
@onready var camera : Camera3D = %Camera
|
|
|
|
|
|
@onready var weaponContainer : Node3D = %WeaponContainer
|
|
|
|
|
|
@onready var shootManager : Node3D = %ShootManager
|
|
|
|
|
|
@onready var reloadManager : Node3D = %ReloadManager
|
|
|
|
|
|
@onready var ammoManager : Node3D = %AmmunitionManager
|
|
|
|
|
|
@onready var animPlayer : AnimationPlayer = %AnimationPlayer
|
|
|
|
|
|
@onready var animManager : Node3D = %AnimationManager
|
|
|
|
|
|
@onready var audioManager : PackedScene = preload("../../Misc/Scenes/AudioManagerScene.tscn")
|
|
|
|
|
|
@onready var bulletDecal : PackedScene = preload("../../Weapons/Scenes/BulletDecalScene.tscn")
|
|
|
|
|
|
@onready var hud : CanvasLayer = %HUD
|
|
|
|
|
|
@onready var linkComponent : Node3D = %LinkComponent
|
|
|
|
|
|
|
|
|
|
|
|
func _ready():
|
|
|
|
|
|
initialize()
|
|
|
|
|
|
|
|
|
|
|
|
func initialize():
|
|
|
|
|
|
for weapon in weaponResources:
|
|
|
|
|
|
#create dict to refer weapons
|
|
|
|
|
|
weaponList[weapon.weaponId] = weapon
|
|
|
|
|
|
|
|
|
|
|
|
for weapo in weaponList.keys():
|
|
|
|
|
|
#weaponsEmplacements[weapo] = weaponIndex
|
|
|
|
|
|
cW = weaponList[weapo] #set each weapon to current, to acess properties useful to set up animations slicing and select correct weapon slot
|
|
|
|
|
|
|
|
|
|
|
|
for weaponSlot in weaponContainer.get_children():
|
|
|
|
|
|
if weaponSlot.weaponId == cW.weaponId: #id correspondant
|
|
|
|
|
|
|
|
|
|
|
|
#if weapon is in the predetermined start weapons list
|
|
|
|
|
|
for startWeapon in startWeapons:
|
|
|
|
|
|
if startWeapon.weaponId == cW.weaponId:
|
|
|
|
|
|
weaponStack.append(cW.weaponId)
|
|
|
|
|
|
|
|
|
|
|
|
cW.weaponSlot = weaponSlot #get weapon slot script ref from weapon list (allows to get access to model, attack point, ...)
|
|
|
|
|
|
cWModel = cW.weaponSlot.model
|
|
|
|
|
|
cWModel.visible = false
|
|
|
|
|
|
|
|
|
|
|
|
forceAttackPointTransformValues(cW.weaponSlot.attackPoint)
|
|
|
|
|
|
|
|
|
|
|
|
cW.bobPos = cW.position
|
|
|
|
|
|
|
|
|
|
|
|
if weaponStack.size() > 0:
|
|
|
|
|
|
#enable (equip and set up) the first weapon on the weapon stack
|
|
|
|
|
|
enterWeapon(weaponStack[0])
|
|
|
|
|
|
|
|
|
|
|
|
func exitWeapon(nextWeapon : int):
|
|
|
|
|
|
#this function manage the first part of the weapon switching mechanic
|
|
|
|
|
|
#in this part, the current weapon is disabled (unequiped and taked down)
|
|
|
|
|
|
if nextWeapon != cW.weaponId:
|
|
|
|
|
|
canChangeWeapons = false
|
|
|
|
|
|
canUseWeapon = false
|
|
|
|
|
|
if cW.isShooting: cW.isShooting = false
|
|
|
|
|
|
if cW.isReloading: cW.isReloading = false
|
|
|
|
|
|
|
|
|
|
|
|
if cW.unequipAnimName != "":
|
|
|
|
|
|
animManager.playAnimation("UnequipAnim%s" % cW.weaponName, cW.unequipAnimSpeed, false)
|
|
|
|
|
|
await get_tree().create_timer(cW.unequipTime).timeout
|
|
|
|
|
|
|
|
|
|
|
|
cWModel.visible = false
|
|
|
|
|
|
|
|
|
|
|
|
enterWeapon(nextWeapon)
|
|
|
|
|
|
|
2026-07-23 01:41:44 +07:00
|
|
|
|
func enterWeapon(nextWeapon):
|
2026-07-21 00:27:17 +07:00
|
|
|
|
#this function manage the second part of the weapon switching mechanic
|
|
|
|
|
|
#in this part, the next weapon is enabled (equiped and set up)
|
2026-07-23 01:41:44 +07:00
|
|
|
|
|
|
|
|
|
|
# --- СВЕРХ-ЗАЩИТА ОТ БАГОВ СЛОВАРЯ (DICTIONARY) ПРИ СМЕНЕ УРОВНЯ ---
|
|
|
|
|
|
# Раз движок уверен, что weaponList — это Dictionary, проверяем наличие ключа через .has()
|
|
|
|
|
|
var is_valid_weapon = false
|
|
|
|
|
|
|
|
|
|
|
|
if weaponList != null and weaponList.has(nextWeapon):
|
|
|
|
|
|
is_valid_weapon = true
|
|
|
|
|
|
|
|
|
|
|
|
# Если оружие еще не готово или ключ '0' отсутствует в словаре на новом уровне:
|
|
|
|
|
|
if not is_valid_weapon:
|
|
|
|
|
|
print("[ОРУЖИЕ] Предупреждение: Ключ ", nextWeapon, " еще не инициализирован в словарe weaponList. Ждем...")
|
|
|
|
|
|
# Даем ассету один кадр очухаться и наполнить свои словари пушками
|
|
|
|
|
|
await get_tree().process_frame
|
|
|
|
|
|
|
|
|
|
|
|
# Повторная проверка
|
|
|
|
|
|
if weaponList != null and weaponList.has(nextWeapon):
|
|
|
|
|
|
is_valid_weapon = true
|
|
|
|
|
|
|
|
|
|
|
|
# Если всё еще пусто — аварийно выходим, чтобы спасти игру от вылета
|
|
|
|
|
|
if not is_valid_weapon:
|
|
|
|
|
|
print("[ОРУЖИЕ] КРИТИЧЕСКИЙ СБОЙ: Оружие полностью утеряно при генерации сцены!")
|
|
|
|
|
|
canUseWeapon = true
|
|
|
|
|
|
canChangeWeapons = true
|
|
|
|
|
|
return
|
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
cW = weaponList[nextWeapon]
|
|
|
|
|
|
|
2026-07-23 01:41:44 +07:00
|
|
|
|
# Проверяем наличие модели оружия перед включением видимости
|
|
|
|
|
|
if cW and cW.weaponSlot and "model" in cW.weaponSlot:
|
|
|
|
|
|
cWModel = cW.weaponSlot.model
|
|
|
|
|
|
if cWModel:
|
|
|
|
|
|
cWModel.visible = true
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
2026-07-23 01:41:44 +07:00
|
|
|
|
# Передаем обновленное оружие в менеджеры, если они существуют
|
|
|
|
|
|
if shootManager: shootManager.getCurrentWeapon(cW)
|
|
|
|
|
|
if reloadManager: reloadManager.getCurrentWeapon(cW)
|
|
|
|
|
|
if animManager: animManager.getCurrentWeapon(cW, cWModel)
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
2026-07-23 01:41:44 +07:00
|
|
|
|
if cW:
|
|
|
|
|
|
weaponSoundManagement(cW.equipSound, cW.equipSoundSpeed)
|
|
|
|
|
|
if animPlayer:
|
|
|
|
|
|
animPlayer.playback_default_blend_time = cW.animBlendTime
|
|
|
|
|
|
|
|
|
|
|
|
if cW.equipAnimName != "" and animManager:
|
|
|
|
|
|
animManager.playAnimation("EquipAnim%s" % cW.weaponName, cW.equipAnimSpeed, false)
|
|
|
|
|
|
|
|
|
|
|
|
await get_tree().create_timer(cW.equipTime).timeout
|
|
|
|
|
|
|
|
|
|
|
|
if cW.isShooting: cW.isShooting = false
|
|
|
|
|
|
if cW.isReloading: cW.isReloading = false
|
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
canUseWeapon = true
|
|
|
|
|
|
canChangeWeapons = true
|
2026-07-23 01:41:44 +07:00
|
|
|
|
|
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
|
|
|
|
|
func _process(_delta : float):
|
|
|
|
|
|
if cW != null and cWModel != null and canUseWeapon:
|
|
|
|
|
|
weaponInputs()
|
|
|
|
|
|
|
|
|
|
|
|
reloadManager.autoReload()
|
|
|
|
|
|
|
|
|
|
|
|
displayStats()
|
|
|
|
|
|
|
|
|
|
|
|
func weaponInputs():
|
2026-07-24 01:57:55 +07:00
|
|
|
|
if Input.is_action_pressed(shoot_action):
|
|
|
|
|
|
# --- ПЕРЕХВАТ ДЛЯ БОНУСА SPEEDBOOSTER ---
|
|
|
|
|
|
|
|
|
|
|
|
if cW != null and cW.weaponName == "SpeedBooster":
|
|
|
|
|
|
# Проверяем, есть ли заряды и что мы его уже не используем прямо сейчас
|
|
|
|
|
|
if cW.totalAmmoInMag > 0 and not cW.isShooting:
|
|
|
|
|
|
cW.isShooting = true
|
|
|
|
|
|
# === НАШЕ ДОБАВЛЕНИЕ: ПРИНУДИТЕЛЬНО ИГРАЕМ ЗВУК ИЗ РЕСУРСА ПРЕДМЕТА ===
|
|
|
|
|
|
# Берем звук, который ты прикрепил в поле shot_sound (или shootSound)
|
|
|
|
|
|
if "shotSound" in cW and cW.shotSound != null:
|
|
|
|
|
|
weaponSoundManagement(cW.shotSound, 1.0)
|
|
|
|
|
|
elif "shootSound" in cW and cW.shootSound != null:
|
|
|
|
|
|
weaponSoundManagement(cW.shootSound, 1.0)
|
|
|
|
|
|
# Тратим одно использование бонуса
|
|
|
|
|
|
cW.totalAmmoInMag -= 1
|
|
|
|
|
|
displayStats() # Обновляем цифры на HUD (станет 0)
|
|
|
|
|
|
|
|
|
|
|
|
print("[БОНУС] Успешный клик! Активирую скорость на PlayerCharacter.")
|
|
|
|
|
|
|
|
|
|
|
|
# Отправляем команду на ускорение в скрипт твоего игрока
|
|
|
|
|
|
if playChar and playChar.has_method("activate_speed_boost"):
|
|
|
|
|
|
playChar.activate_speed_boost()
|
|
|
|
|
|
|
|
|
|
|
|
# Ждем кулдаун использования банки (1 секунда, чтобы проигралась анимация глотка/использования)
|
|
|
|
|
|
await get_tree().create_timer(1.0).timeout
|
|
|
|
|
|
|
|
|
|
|
|
# --- УДАЛЕНИЕ ИЗ ИНВЕНТАРЯ ПОСЛЕ ИСПОЛЬЗОВАНИЯ ---
|
|
|
|
|
|
print("[БОНУС] Энергетик пуст. Удаляю его из инвентаря игрока...")
|
|
|
|
|
|
|
|
|
|
|
|
# Находим, под каким номером в инвентаре (weaponStack) лежит наш SpeedBooster
|
|
|
|
|
|
var booster_stack_index = weaponStack.find(cW.weaponId)
|
|
|
|
|
|
if booster_stack_index != -1:
|
|
|
|
|
|
# Полностью выкидываем его из списка оружия игрока
|
|
|
|
|
|
weaponStack.remove_at(booster_stack_index)
|
|
|
|
|
|
|
|
|
|
|
|
# Принудительно прячем 3D-модельку пустой банки в руках
|
|
|
|
|
|
if cWModel:
|
|
|
|
|
|
cWModel.visible = false
|
|
|
|
|
|
|
|
|
|
|
|
# Переключаем инвентарь на самое первое доступное оружие (индекс 0 - автомат или пистолет)
|
|
|
|
|
|
weaponIndex = 0
|
|
|
|
|
|
if weaponStack.size() > 0:
|
|
|
|
|
|
changeWeapon(weaponStack[0])
|
|
|
|
|
|
else:
|
|
|
|
|
|
# Если у игрока вообще больше нет оружия, сбрасываем текущее оружие в null
|
|
|
|
|
|
cW = null
|
|
|
|
|
|
cWModel = null
|
|
|
|
|
|
canUseWeapon = false
|
|
|
|
|
|
|
|
|
|
|
|
# Возвращаем флаг стрельбы в исходное состояние
|
|
|
|
|
|
if cW != null:
|
|
|
|
|
|
cW.isShooting = false
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
# ОРИГИНАЛЬНАЯ СТРЕЛЬБА АССЕТА (Для автоматов и пистолетов)
|
|
|
|
|
|
shootManager.shoot()
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
|
|
|
|
|
if Input.is_action_just_pressed(reload_action): reloadManager.reload()
|
|
|
|
|
|
|
|
|
|
|
|
if Input.is_action_just_pressed(weapon_wheel_up_action):
|
|
|
|
|
|
if canChangeWeapons and !cW.isShooting and !cW.isReloading:
|
|
|
|
|
|
weaponIndex = min(weaponIndex + 1, weaponStack.size() - 1) #from first element of weapon stack to last element
|
|
|
|
|
|
changeWeapon(weaponStack[weaponIndex])
|
|
|
|
|
|
|
|
|
|
|
|
if Input.is_action_just_pressed(weapon_wheel_down_action):
|
|
|
|
|
|
if canChangeWeapons and !cW.isShooting and !cW.isReloading:
|
|
|
|
|
|
weaponIndex = max(weaponIndex - 1, 0) #from last element of weapon stack to first element
|
|
|
|
|
|
changeWeapon(weaponStack[weaponIndex])
|
2026-07-24 01:57:55 +07:00
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
|
|
|
|
|
func displayStats():
|
2026-07-23 01:41:44 +07:00
|
|
|
|
if hud == null or cW == null:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
hud.displayWeaponStack(weaponStack.size())
|
|
|
|
|
|
hud.displayWeaponName(cW.weaponName)
|
|
|
|
|
|
hud.displayTotalAmmoInMag(cW.totalAmmoInMag, cW.nbProjShotsAtSameTime)
|
|
|
|
|
|
|
2026-07-23 01:41:44 +07:00
|
|
|
|
# --- БРОНЕБОЙНАЯ ЗАЩИТА ОТ ВЫЛЕТА ИЗ-ЗА ПАТРОНОВ ПРИ СМЕНЕ СЦЕНЫ ---
|
|
|
|
|
|
# Используем метод .get() вместо квадратных скобок [...].
|
|
|
|
|
|
# Он никогда не уронит игру, даже если словарь ammoDict полностью пустой!
|
|
|
|
|
|
var total_ammo : int = 0
|
|
|
|
|
|
if ammoManager != null and ammoManager.ammoDict != null:
|
|
|
|
|
|
total_ammo = ammoManager.ammoDict.get(cW.ammoType, 0)
|
|
|
|
|
|
|
|
|
|
|
|
hud.displayTotalAmmo(total_ammo, cW.nbProjShotsAtSameTime)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- БРОНЕБОЙНАЯ ЗАЩИТА ОТ ВЫЛЕТА ПРИ ПЕРЕХОДЕ НА НОВЫЙ УРОВЕНЬ ---
|
|
|
|
|
|
# Проверяем, существует ли ammoManager и есть ли тип патронов текущего оружия в словаре
|
|
|
|
|
|
if ammoManager != null and ammoManager.ammoDict != null and ammoManager.ammoDict.has(cW.ammoType):
|
|
|
|
|
|
hud.displayTotalAmmo(ammoManager.ammoDict[cW.ammoType], cW.nbProjShotsAtSameTime)
|
|
|
|
|
|
else:
|
|
|
|
|
|
# Если словарь еще не загрузился, временно пишем 0, чтобы игра не вылетала
|
|
|
|
|
|
hud.displayTotalAmmo(0, cW.nbProjShotsAtSameTime)
|
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
func changeWeapon(nextWeapon : int):
|
|
|
|
|
|
if canChangeWeapons and !cW.isShooting and !cW.isReloading:
|
|
|
|
|
|
exitWeapon(nextWeapon)
|
|
|
|
|
|
else:
|
|
|
|
|
|
push_error("Can't change weapon now")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
func displayMuzzleFlash():
|
|
|
|
|
|
#create a muzzle flash instance, and display it at the indicated point
|
|
|
|
|
|
if cW.muzzleFlashRef != null:
|
|
|
|
|
|
var muzzleFlashInstance = cW.muzzleFlashRef.instantiate()
|
|
|
|
|
|
add_child(muzzleFlashInstance)
|
|
|
|
|
|
muzzleFlashInstance.global_position = cW.weaponSlot.muzzleFlashSpawner.global_position
|
|
|
|
|
|
muzzleFlashInstance.emitting = true
|
|
|
|
|
|
else:
|
|
|
|
|
|
push_error("%s doesn't have a muzzle flash reference" % cW.weaponName)
|
|
|
|
|
|
return
|
|
|
|
|
|
|
2026-07-25 23:26:07 +07:00
|
|
|
|
# НАЙДИ И ПОЛНОСТЬСТЬЮ ЗАМЕНИ ЭТУ ФУНКЦИЮ В WeaponManagerScript.gd:
|
|
|
|
|
|
|
|
|
|
|
|
# Сначала загружаем файл искр в самом верху скрипта (к остальным preload, если есть, или прямо перед функцией):
|
|
|
|
|
|
const SPARKS_SCENE = preload("res://addons/Weapons/bullet_sparks.tscn.tscn") # Укажи правильный путь к файлу из Шага 1!
|
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
func displayBulletHole(colliderPoint : Vector3, colliderNormal : Vector3):
|
2026-07-25 23:26:07 +07:00
|
|
|
|
# 1. Оригинальный код автора для спавна декали дырки от пули
|
|
|
|
|
|
if bulletDecal != null:
|
|
|
|
|
|
var bulletDecalInstance = bulletDecal.instantiate()
|
|
|
|
|
|
get_tree().get_root().add_child(bulletDecalInstance)
|
|
|
|
|
|
bulletDecalInstance.global_position = colliderPoint
|
|
|
|
|
|
bulletDecalInstance.look_at(colliderPoint - colliderNormal, Vector3.UP)
|
|
|
|
|
|
bulletDecalInstance.rotate_object_local(Vector3(1.0, 0.0, 0.0), 90)
|
|
|
|
|
|
|
|
|
|
|
|
# 2. НАШЕ НОВОЕ ДОБАВЛЕНИЕ: СПАВН ПАРТИКЛОВ ИСКР
|
|
|
|
|
|
if SPARKS_SCENE != null:
|
|
|
|
|
|
# Было: var sparks_instance = SPARKS_SCENE.instAPE()
|
|
|
|
|
|
# НАДО (СТРОГО ВОТ ТАК):
|
|
|
|
|
|
var sparks_instance = SPARKS_SCENE.instantiate()
|
|
|
|
|
|
|
|
|
|
|
|
get_tree().get_root().add_child(sparks_instance)
|
|
|
|
|
|
|
|
|
|
|
|
# Слегка смещаем искры назад от стены (на 0.05 метра вдоль нормали),
|
|
|
|
|
|
# чтобы они гарантированно не рендерились внутри текстуры стены!
|
|
|
|
|
|
sparks_instance.global_position = colliderPoint + (colliderNormal * 0.05)
|
|
|
|
|
|
|
|
|
|
|
|
if colliderNormal.length() > 0.01:
|
|
|
|
|
|
sparks_instance.look_at(sparks_instance.global_position + colliderNormal, Vector3.UP)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-21 00:27:17 +07:00
|
|
|
|
|
|
|
|
|
|
func weaponSoundManagement(soundName : AudioStream, soundSpeed : float):
|
|
|
|
|
|
var audioIns : AudioStreamPlayer3D = audioManager.instantiate()
|
|
|
|
|
|
get_tree().get_root().add_child.call_deferred(audioIns)
|
|
|
|
|
|
#makes sure the node is in the scene tree
|
|
|
|
|
|
await get_tree().process_frame
|
|
|
|
|
|
if audioIns.is_inside_tree():
|
|
|
|
|
|
audioIns.global_transform = cW.weaponSlot.attackPoint.global_transform
|
|
|
|
|
|
audioIns.bus = "Sfx"
|
|
|
|
|
|
audioIns.pitch_scale = soundSpeed
|
|
|
|
|
|
audioIns.stream = soundName
|
|
|
|
|
|
audioIns.play()
|
|
|
|
|
|
else:
|
|
|
|
|
|
print("The sound can't be played, AudioStreamPlayer3D instance is not in the scene tree")
|
|
|
|
|
|
|
|
|
|
|
|
func forceAttackPointTransformValues(attackPoint : Marker3D):
|
|
|
|
|
|
#reset the attack points rotation values, to ensure that the projectiles will be shot in the correct direction
|
|
|
|
|
|
if attackPoint.rotation != Vector3.ZERO: attackPoint.rotation = Vector3.ZERO
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Добавьте этот код в самый конец вашего скрипта WeaponManager
|
|
|
|
|
|
|
|
|
|
|
|
# Замените эти две функции в самом конце вашего WeaponManager
|
|
|
|
|
|
|
|
|
|
|
|
func disable_weapons_for_dialogue() -> void:
|
|
|
|
|
|
canUseWeapon = false
|
|
|
|
|
|
canChangeWeapons = false
|
|
|
|
|
|
|
|
|
|
|
|
# Принудительно сбрасываем флаги стрельбы
|
|
|
|
|
|
if cW != null:
|
|
|
|
|
|
cW.isShooting = false
|
|
|
|
|
|
cW.isReloading = false
|
|
|
|
|
|
|
|
|
|
|
|
# ВЫКЛЮЧАЕМ менеджеры стрельбы и перезарядки, чтобы они не видели мышь
|
|
|
|
|
|
if shootManager:
|
|
|
|
|
|
shootManager.process_mode = Node.PROCESS_MODE_DISABLED
|
|
|
|
|
|
if reloadManager:
|
|
|
|
|
|
reloadManager.process_mode = Node.PROCESS_MODE_DISABLED
|
|
|
|
|
|
|
|
|
|
|
|
print("[WeaponManager] Стрельба и перезарядка ПОЛНОСТЬСТЬЮ заморожены.")
|
|
|
|
|
|
|
|
|
|
|
|
func enable_weapons_after_dialogue() -> void:
|
|
|
|
|
|
canUseWeapon = true
|
|
|
|
|
|
canChangeWeapons = true
|
|
|
|
|
|
|
|
|
|
|
|
# ВКЛЮЧАЕМ менеджеры обратно в стандартный режим работы
|
|
|
|
|
|
if shootManager:
|
|
|
|
|
|
shootManager.process_mode = Node.PROCESS_MODE_INHERIT
|
|
|
|
|
|
if reloadManager:
|
|
|
|
|
|
reloadManager.process_mode = Node.PROCESS_MODE_INHERIT
|
|
|
|
|
|
|
|
|
|
|
|
print("[WeaponManager] Оружие полностью разблокировано.")
|