From 0d03c06854d21a738a7625270f910bb000d088bc Mon Sep 17 00:00:00 2001 From: worm Date: Thu, 23 Jul 2026 01:41:44 +0700 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D0=BD=D1=86=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=D1=8F=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC=D0=B0=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B5=D1=81=D0=B0=D0=B0=20=D0=B8?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=86=D0=B0=20=D1=83=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=BD=D0=B5=20=D1=81=20=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D0=BC=20=D0=B8=20=D0=BA=D0=BE=D0=BD=D1=86=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/Maps/Scenes/TemplateMapScene.tscn | 7 ++ addons/Maps/Scenes/world2.tscn | 7 ++ addons/Misc/Scenes/level_trigger.tscn | 27 ++++++ addons/Misc/Scenes/results_screen.tscn | 57 ++++++++++++ addons/Misc/Scripts/GameTransfer.gd | 65 ++++++++++++++ addons/Misc/Scripts/GameTransfer.gd.uid | 1 + addons/Misc/Scripts/LevelStats.gd | 30 +++++++ addons/Misc/Scripts/LevelStats.gd.uid | 1 + addons/Misc/Scripts/level_trigger.gd | 55 ++++++++++++ addons/Misc/Scripts/level_trigger.gd.uid | 1 + addons/Misc/Scripts/results_screen.gd | 79 +++++++++++++++++ addons/Misc/Scripts/results_screen.gd.uid | 1 + addons/NPC/script/enemy_mob.gd | 1 + .../StateMachine/PlayerCharacterScript.gd | 17 ++-- addons/Weapons/Scripts/WeaponManagerScript.gd | 88 +++++++++++++++---- prog.tscn | 8 +- project.godot | 3 + 17 files changed, 422 insertions(+), 26 deletions(-) create mode 100644 addons/Misc/Scenes/level_trigger.tscn create mode 100644 addons/Misc/Scenes/results_screen.tscn create mode 100644 addons/Misc/Scripts/GameTransfer.gd create mode 100644 addons/Misc/Scripts/GameTransfer.gd.uid create mode 100644 addons/Misc/Scripts/LevelStats.gd create mode 100644 addons/Misc/Scripts/LevelStats.gd.uid create mode 100644 addons/Misc/Scripts/level_trigger.gd create mode 100644 addons/Misc/Scripts/level_trigger.gd.uid create mode 100644 addons/Misc/Scripts/results_screen.gd create mode 100644 addons/Misc/Scripts/results_screen.gd.uid diff --git a/addons/Maps/Scenes/TemplateMapScene.tscn b/addons/Maps/Scenes/TemplateMapScene.tscn index 8d68e1c..f5b8038 100644 --- a/addons/Maps/Scenes/TemplateMapScene.tscn +++ b/addons/Maps/Scenes/TemplateMapScene.tscn @@ -9,6 +9,8 @@ [ext_resource type="Script" uid="uid://c8a2kystypxdm" path="res://addons/Targets/Scripts/ShootingRangeTargetManagerScript.gd" id="6_nmj7y"] [ext_resource type="PackedScene" uid="uid://cjhibfe5567xa" path="res://addons/Targets/Scenes/ShootingRangeTargetScene.tscn" id="7_wwbpl"] [ext_resource type="PackedScene" uid="uid://d27xhk2ygjsbr" path="res://addons/Targets/Scenes/HitableBoxScene.tscn" id="8_2mjpe"] +[ext_resource type="PackedScene" uid="uid://cxckcssgallbx" path="res://addons/Misc/Scenes/level_trigger.tscn" id="10_v12cc"] +[ext_resource type="PackedScene" uid="uid://c1v246tyt6bng" path="res://addons/Misc/Scenes/results_screen.tscn" id="11_rode7"] [sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_k1n2p"] panorama = ExtResource("5_k1n2p") @@ -395,3 +397,8 @@ dash_speed = 12.11 jumpHeight = 1.0 [node name="NamingConventionConverter" type="Node" parent="." unique_id=1842485999] + +[node name="LevelTrigger" parent="." unique_id=549172302 instance=ExtResource("10_v12cc")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -11.757071, 3.444125, -127.8315) +next_scene_path = "uid://blus2wf5ps3i7" +results_screen_scene = ExtResource("11_rode7") diff --git a/addons/Maps/Scenes/world2.tscn b/addons/Maps/Scenes/world2.tscn index 53754d7..c79a440 100644 --- a/addons/Maps/Scenes/world2.tscn +++ b/addons/Maps/Scenes/world2.tscn @@ -15,6 +15,8 @@ [ext_resource type="PackedScene" uid="uid://blxd132vgsdle" path="res://addons/custmode/larek.tscn" id="11_n3seu"] [ext_resource type="PackedScene" uid="uid://muvkocbhln75" path="res://addons/custmode/car_2.tscn" id="12_n3seu"] [ext_resource type="PackedScene" uid="uid://dwlnmn50e7r2p" path="res://showflake.tscn" id="15_6tfqi"] +[ext_resource type="PackedScene" uid="uid://cxckcssgallbx" path="res://addons/Misc/Scenes/level_trigger.tscn" id="16_ld5ws"] +[ext_resource type="PackedScene" uid="uid://c1v246tyt6bng" path="res://addons/Misc/Scenes/results_screen.tscn" id="17_83ltg"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pj53b"] albedo_color = Color(0.24777229, 0.24777214, 0.24777214, 1) @@ -547,3 +549,8 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -23.237055, 0, -22.500967) [node name="Node3D4" parent="snow2" unique_id=1755887601 instance=ExtResource("15_6tfqi")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.309002, 0, -19.343246) + +[node name="LevelTrigger" parent="." unique_id=549172302 instance=ExtResource("16_ld5ws")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -210.60919, 2.6160936, -0.4971075) +next_scene_path = "uid://51xf0fd3ibnb" +results_screen_scene = ExtResource("17_83ltg") diff --git a/addons/Misc/Scenes/level_trigger.tscn b/addons/Misc/Scenes/level_trigger.tscn new file mode 100644 index 0000000..97dd6e9 --- /dev/null +++ b/addons/Misc/Scenes/level_trigger.tscn @@ -0,0 +1,27 @@ +[gd_scene format=3 uid="uid://cxckcssgallbx"] + +[ext_resource type="Script" uid="uid://dux8o5uwin1sy" path="res://addons/Misc/Scripts/level_trigger.gd" id="1_1g6t3"] +[ext_resource type="ArrayMesh" uid="uid://dflmd4037fdqa" path="res://addons/custmode/untitled.obj" id="1_tam0r"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_pmktt"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_a2m1y"] +radius = 6.0 + +[node name="LevelTrigger" type="StaticBody3D" unique_id=549172302] +script = ExtResource("1_1g6t3") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1715081297] +transform = Transform3D(6.355, 0, 0, 0, 6.355, 0, 0, 0, 6.355, 0, 0, 0) +shape = SubResource("SphereShape3D_pmktt") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CollisionShape3D" unique_id=1423996988] +transform = Transform3D(0.06, 0, 0, 0, 0.06, 0, 0, 0, 0.06, 0, -0.47206923, 0) +mesh = ExtResource("1_tam0r") + +[node name="DetectArea" type="Area3D" parent="." unique_id=1314234424] +collision_layer = 0 +collision_mask = 15 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="DetectArea" unique_id=1390638580] +shape = SubResource("SphereShape3D_a2m1y") diff --git a/addons/Misc/Scenes/results_screen.tscn b/addons/Misc/Scenes/results_screen.tscn new file mode 100644 index 0000000..d91d75a --- /dev/null +++ b/addons/Misc/Scenes/results_screen.tscn @@ -0,0 +1,57 @@ +[gd_scene format=3 uid="uid://c1v246tyt6bng"] + +[ext_resource type="Script" uid="uid://bojftnghiqd2g" path="res://addons/Misc/Scripts/results_screen.gd" id="1_esv6s"] + +[node name="ResultsScreen" type="CanvasLayer" unique_id=2101110637] +layer = 1000000000 +script = ExtResource("1_esv6s") + +[node name="TitleLabel" type="Label" parent="." unique_id=864255331] +anchors_preset = -1 +anchor_left = 0.586 +anchor_top = 0.45200002 +anchor_right = 0.586 +anchor_bottom = 0.45200002 +offset_left = -84.07202 +offset_top = -113.89603 +offset_right = 82.92798 +offset_bottom = -90.89603 +text = "УРОВЕНЬ ЗАВЕРШЕН" + +[node name="KillsLabel" type="Label" parent="." unique_id=1676098116] +anchors_preset = -1 +anchor_left = 0.56700003 +anchor_top = 0.43300003 +anchor_right = 0.56700003 +anchor_bottom = 0.43300003 +offset_left = -69.18402 +offset_top = 62.415985 +offset_right = 68.81598 +offset_bottom = 85.415985 +text = "Убито врагов: 0\"." + +[node name="TimeLabel" type="Label" parent="." unique_id=466879962] +anchors_preset = -1 +anchor_left = 0.60200006 +anchor_top = 0.46500003 +anchor_right = 0.60200006 +anchor_bottom = 0.46500003 +offset_left = -108.50409 +offset_top = 84.67999 +offset_right = 108.49591 +offset_bottom = 107.67999 +text = "Время прохождения: 00:00" + +[node name="ContinueButton" type="Button" parent="." unique_id=1156988049] +anchors_preset = -1 +anchor_left = 0.586 +anchor_top = 0.5 +anchor_right = 0.586 +anchor_bottom = 0.5 +offset_left = -92.07202 +offset_top = 122.0 +offset_right = 57.92798 +offset_bottom = 180.0 +text = "Далее" + +[connection signal="pressed" from="ContinueButton" to="." method="_on_continue_button_pressed"] diff --git a/addons/Misc/Scripts/GameTransfer.gd b/addons/Misc/Scripts/GameTransfer.gd new file mode 100644 index 0000000..1b1b40b --- /dev/null +++ b/addons/Misc/Scripts/GameTransfer.gd @@ -0,0 +1,65 @@ +extends Node + +# Хранилище данных, которое живет между уровнями +var saved_health: float = 100.0 +var saved_weapons: Array = [] +var saved_weapon_index: int = 0 +var saved_ammo_dict: Dictionary = {} + +var is_transfer_ready: bool = false # Флаг, что у нас есть сохраненные данные + +# --- ФУНКЦИЯ 1: СОХРАНЕНИЕ ДАННЫХ ПЕРЕД СМЕНОЙ СЦЕНЫ --- +func save_player_data(player: Node) -> void: + if player == null: return + + # 1. Запоминаем Здоровье + var health_comp = player.find_child("HealthComponent", true, false) + if health_comp: + saved_health = health_comp.current_health + + # 2. Запоминаем Оружие и Патроны +# Найди этот блок внутри save_player_data в GameTransfer.gd: + var weapon_manager = player.find_child("WeaponManager", true, false) + if weapon_manager: + saved_weapons = weapon_manager.weaponStack.duplicate() + saved_weapon_index = weapon_manager.weaponIndex + + # ИСПРАВЛЕНО: Более глубокий поиск менеджера патронов, если автор спрятал его в детях + var ammo_manager = weapon_manager.find_child("AmmoManager", true, false) + if ammo_manager == null and "ammoManager" in weapon_manager: + ammo_manager = weapon_manager.ammoManager + + if ammo_manager and "ammoDict" in ammo_manager: + saved_ammo_dict = ammo_manager.ammoDict.duplicate() + + + is_transfer_ready = true + print("[ПЕРЕНОС] Данные игрока успешно сохранены в кэш!") + +# --- ФУНКЦИЯ 2: ВОССТАНОВЛЕНИЕ ДАННЫХ НА НОВОМ УРОВНЕ --- +func load_player_data(player: Node) -> void: + if player == null or not is_transfer_ready: return + + # 1. Возвращаем Здоровье + var health_comp = player.find_child("HealthComponent", true, false) + if health_comp: + health_comp.current_health = saved_health + # Обновляем цифры на новом HUD + var health_ui = player.find_child("PlayerHealthUI", true, false) + if health_ui and health_ui.has_method("_process"): + health_ui.notification(NOTIFICATION_PROCESS) + + # 2. Возвращаем Оружие и Патроны + var weapon_manager = player.find_child("WeaponManager", true, false) + if weapon_manager: + weapon_manager.weaponStack = saved_weapons.duplicate() + weapon_manager.weaponIndex = saved_weapon_index + + if "ammoManager" in weapon_manager and weapon_manager.ammoManager: + weapon_manager.ammoManager.ammoDict = saved_ammo_dict.duplicate() + + # Принудительно заставляем ассет достать правильное оружие из памяти + if weapon_manager.has_method("changeWeapon"): + weapon_manager.changeWeapon(saved_weapon_index) + + print("[ПЕРЕНОС] Снаряжение и ХП успешно возвращены игроку на новом уровне!") diff --git a/addons/Misc/Scripts/GameTransfer.gd.uid b/addons/Misc/Scripts/GameTransfer.gd.uid new file mode 100644 index 0000000..8781dc5 --- /dev/null +++ b/addons/Misc/Scripts/GameTransfer.gd.uid @@ -0,0 +1 @@ +uid://dbnkrmxycgjrl diff --git a/addons/Misc/Scripts/LevelStats.gd b/addons/Misc/Scripts/LevelStats.gd new file mode 100644 index 0000000..fe80e8b --- /dev/null +++ b/addons/Misc/Scripts/LevelStats.gd @@ -0,0 +1,30 @@ +extends Node + +var current_kills: int = 0 +var level_time: float = 0.0 +var is_timer_running: bool = false + +func _ready() -> void: + start_level_tracking() + +func _process(delta: float) -> void: + if is_timer_running: + level_time += delta + +func start_level_tracking() -> void: + current_kills = 0 + level_time = 0.0 + is_timer_running = true + +func stop_level_tracking() -> void: + is_timer_running = false + +func register_kill() -> void: + current_kills += 1 + print("[СТАТИСТИКА] Моб уничтожен! Всего убийств: ", current_kills) + +# Функция для красивого форматирования времени (например, 01:23) +func get_formatted_time() -> String: + var minutes = int(level_time) / 60 + var seconds = int(level_time) % 60 + return "%02d:%02d" % [minutes, seconds] diff --git a/addons/Misc/Scripts/LevelStats.gd.uid b/addons/Misc/Scripts/LevelStats.gd.uid new file mode 100644 index 0000000..e91d7f4 --- /dev/null +++ b/addons/Misc/Scripts/LevelStats.gd.uid @@ -0,0 +1 @@ +uid://jbvxvnmbrhe8 diff --git a/addons/Misc/Scripts/level_trigger.gd b/addons/Misc/Scripts/level_trigger.gd new file mode 100644 index 0000000..635fe81 --- /dev/null +++ b/addons/Misc/Scripts/level_trigger.gd @@ -0,0 +1,55 @@ +extends StaticBody3D + +@export_file("*.tscn") var next_scene_path: String = "" +var is_triggered: bool = false +var detect_area: Area3D = null + +@export var results_screen_scene: PackedScene + +func _ready() -> void: + detect_area = $DetectArea + +func _physics_process(delta: float) -> void: + if is_triggered or detect_area == null: + return + + var overlapping_stuff: Array = [] + overlapping_stuff.append_array(detect_area.get_overlapping_bodies()) + overlapping_stuff.append_array(detect_area.get_overlapping_areas()) + + for node in overlapping_stuff: + if node == self or node == detect_area or node is StaticBody3D or "CSG" in node.name: + continue + + var is_real_player = node.name == "PlayerCharacter" + if not is_real_player and node.get_parent(): + is_real_player = node.get_parent().name == "PlayerCharacter" + + if is_real_player: + is_triggered = true + print("[УРОВЕНЬ] МГНОВЕННЫЙ ФИНИШ! Полностью блокирую камеру и открываю курсор...") + + # Отключаем сам триггер + set_physics_process(false) + + # Находим корневой узел игрока + var main_player = node if node.name == "PlayerCharacter" else node.get_parent() + + # --- МГНОВЕННАЯ ЗАМОРОЗКА ИНПУТОВ КАМЕРЫ И ОРУЖИЯ --- + # Переводим игрока в режим PROCESS_MODE_DISABLED. + # Это мгновенно отключает у него функции _process, _physics_process и ВСЕ _input функции мыши! + # Камера намертво каменеет в ту же секунду, без необходимости кликать кнопками. + if main_player: + main_player.process_mode = Node.PROCESS_MODE_DISABLED + # ---------------------------------------------------- + + # Аппаратно освобождаем мышь для клика по кнопке "Далее" + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + + # Спавним экран результатов в корень игры + if results_screen_scene: + var results_instance = results_screen_scene.instantiate() + get_tree().get_root().add_child(results_instance) + if results_instance.has_method("show_results"): + results_instance.show_results(next_scene_path) + return diff --git a/addons/Misc/Scripts/level_trigger.gd.uid b/addons/Misc/Scripts/level_trigger.gd.uid new file mode 100644 index 0000000..03159a4 --- /dev/null +++ b/addons/Misc/Scripts/level_trigger.gd.uid @@ -0,0 +1 @@ +uid://dux8o5uwin1sy diff --git a/addons/Misc/Scripts/results_screen.gd b/addons/Misc/Scripts/results_screen.gd new file mode 100644 index 0000000..19a178a --- /dev/null +++ b/addons/Misc/Scripts/results_screen.gd @@ -0,0 +1,79 @@ +extends CanvasLayer + +var target_scene_path: String = "" + +func _ready() -> void: + # Ставим максимальный слой отрисовки, чтобы HUD игры не перекрывал меню + layer = 120 + if has_node("Panel"): + $Panel.visible = true + print("[РЕЗУЛЬТАТЫ] Экран итогов успешно создан прямо на карте!") + +func show_results(next_scene: String) -> void: + target_scene_path = next_scene + print("[РЕЗУЛЬТАТЫ] Данные получены. Путь к следующей сцене: ", target_scene_path) + + # Останавливаем таймер уровня + if LevelStats: + LevelStats.stop_level_tracking() + + # БРОНЕБОЙНОЕ ОБНОВЛЕНИЕ ТЕКСТА: Ищем узлы прямо в момент вызова функции + var kills_label = find_child("KillsLabel", true, false) + if kills_label == null: kills_label = find_child("kills_label", true, false) + if kills_label: + kills_label.text = "Убито врагов: " + str(LevelStats.current_kills) + print("[РЕЗУЛЬТАТЫ] Текст убийств обновлен: ", kills_label.text) + + var time_label = find_child("TimeLabel", true, false) + if time_label == null: time_label = find_child("time_label", true, false) + if time_label: + time_label.text = "Время прохождения: " + LevelStats.get_formatted_time() + print("[РЕЗУЛЬТАТЫ] Текст времени обновлен: ", time_label.text) + + # ПРИНУДИТЕЛЬНО РАЗРЕШАЕМ ДВИГАТЬ КУРСОР МЫШИ + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + +func _on_continue_button_pressed() -> void: + print("[РЕЗУЛЬТАТЫ] Кнопка 'Далее' зафиксирована! Запускаю плавное затемнение...") + + if target_scene_path == "": + print("[РЕЗУЛЬТАТЫ] ОШИБКА: Путь к следующей сцене пустой!") + return + + # --- НАШЕ КРИТИЧЕСКОЕ ДОБАВЛЕНИЕ: СОХРАНЯЕМ ИГРОКА ПЕРЕД УХОДОМ В ЗАТЕМНЕНИЕ --- + var player = get_tree().current_scene.find_child("PlayerCharacter", true, false) + if player and GameTransfer: + GameTransfer.save_player_data(player) + # -------------------------------------------------------------------------------- + + # Твой старый код затемнения и смены сцены... + var fade_rect = find_child("FadeRect", true, false) + if fade_rect and "visible" in fade_rect: + fade_rect.visible = true + fade_rect.modulate.a = 0.0 + var tween = create_tween() + tween.tween_property(fade_rect, "modulate:a", 1.0, 1.0) + await tween.finished + + _set_ui_elements_visible(false) + if LevelStats: LevelStats.start_level_tracking() + + queue_free() + get_tree().change_scene_to_file(target_scene_path) + +# Полностью замени функцию в самом конце results_screen.gd на этот код: +func _set_ui_elements_visible(is_visible: bool) -> void: + # Находим и переключаем надпись убийств + var k_label = find_child("KillsLabel", true, false) + if k_label == null: k_label = find_child("kills_label", true, false) + if k_label: k_label.visible = is_visible + + # Находим и переключаем надпись времени + var t_label = find_child("TimeLabel", true, false) + if t_label == null: t_label = find_child("time_label", true, false) + if t_label: t_label.visible = is_visible + + # Находим и переключаем кнопку продолжения + var c_button = find_child("ContinueButton", true, false) + if c_button == null: c_button = find_child("continue_button", true, false) + if c_button: c_button.visible = is_visible diff --git a/addons/Misc/Scripts/results_screen.gd.uid b/addons/Misc/Scripts/results_screen.gd.uid new file mode 100644 index 0000000..b14484a --- /dev/null +++ b/addons/Misc/Scripts/results_screen.gd.uid @@ -0,0 +1 @@ +uid://bojftnghiqd2g diff --git a/addons/NPC/script/enemy_mob.gd b/addons/NPC/script/enemy_mob.gd index 32b860b..e89399b 100644 --- a/addons/NPC/script/enemy_mob.gd +++ b/addons/NPC/script/enemy_mob.gd @@ -89,6 +89,7 @@ func die() -> void: if custom_battle_music and is_currently_seeing_player and has_node("/root/MusicManager"): get_node("/root/MusicManager").unregister_enemy_vision(self, custom_battle_music) queue_free() + if LevelStats: LevelStats.register_kill() # --- ФИЗИКА, ПРИЦЕЛИВАНИЕ И СТРЕЛЬБА --- diff --git a/addons/PlayerCharacter/Scripts/StateMachine/PlayerCharacterScript.gd b/addons/PlayerCharacter/Scripts/StateMachine/PlayerCharacterScript.gd index 06bd36a..9af8cac 100644 --- a/addons/PlayerCharacter/Scripts/StateMachine/PlayerCharacterScript.gd +++ b/addons/PlayerCharacter/Scripts/StateMachine/PlayerCharacterScript.gd @@ -96,12 +96,10 @@ var coyoteJumpOn : bool = false @onready var ceilingCheck : RayCast3D = $Raycasts/CeilingCheck @onready var floorCheck : RayCast3D = $Raycasts/FloorCheck +# НАЙДИ ЭТУ ФУНКЦИЮ ВНУТРИ СKРИПТА PlayerCharacter.gd И ЗАМЕНИ ЕЁ: + func _ready(): - # Запоминаем дефолтный FOV камеры, если она подключена - if player_camera: - normal_fov = player_camera.fov - - #set move variables, and value references + # Твой старый оригинальный код ready из ассета... moveSpeed = walkSpeed moveAccel = walkAccel moveDeccel = walkDeccel @@ -111,6 +109,15 @@ func _ready(): nbJumpsInAirAllowedRef = nbJumpsInAirAllowed coyoteJumpCooldownRef = coyoteJumpCooldown + # --- НАШЕ НОВОЕ ДОБАВЛЕНИЕ: ЗАБИРАЕМ КЭШ СНАРЯЖЕНИЯ И ХП НА НОВОЙ КАРТЕ --- + # Даем ассету фору в один кадр, чтобы его WeaponManager успел создаться, + # прежде чем мы принудительно перезапишем его инвентарь данными с прошлого уровня + await get_tree().create_timer(0.1).timeout + + if GameTransfer: + GameTransfer.load_player_data(self) + # ------------------------------------------------------------------------- + func _process(_delta: float): displayProperties() diff --git a/addons/Weapons/Scripts/WeaponManagerScript.gd b/addons/Weapons/Scripts/WeaponManagerScript.gd index 3391df2..093f7cc 100644 --- a/addons/Weapons/Scripts/WeaponManagerScript.gd +++ b/addons/Weapons/Scripts/WeaponManagerScript.gd @@ -83,30 +83,64 @@ func exitWeapon(nextWeapon : int): enterWeapon(nextWeapon) -func enterWeapon(nextWeapon : int): +func enterWeapon(nextWeapon): #this function manage the second part of the weapon switching mechanic #in this part, the next weapon is enabled (equiped and set up) + + # --- СВЕРХ-ЗАЩИТА ОТ БАГОВ СЛОВАРЯ (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 + cW = weaponList[nextWeapon] - nextWeapon = 0 - cWModel = cW.weaponSlot.model - cWModel.visible = true - shootManager.getCurrentWeapon(cW) - reloadManager.getCurrentWeapon(cW) - animManager.getCurrentWeapon(cW, cWModel) + # Проверяем наличие модели оружия перед включением видимости + if cW and cW.weaponSlot and "model" in cW.weaponSlot: + cWModel = cW.weaponSlot.model + if cWModel: + cWModel.visible = true - weaponSoundManagement(cW.equipSound, cW.equipSoundSpeed) + # Передаем обновленное оружие в менеджеры, если они существуют + if shootManager: shootManager.getCurrentWeapon(cW) + if reloadManager: reloadManager.getCurrentWeapon(cW) + if animManager: animManager.getCurrentWeapon(cW, cWModel) - animPlayer.playback_default_blend_time = cW.animBlendTime - - if cW.equipAnimName != "": - 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 + 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 + canUseWeapon = true canChangeWeapons = true + + func _process(_delta : float): if cW != null and cWModel != null and canUseWeapon: @@ -132,11 +166,31 @@ func weaponInputs(): changeWeapon(weaponStack[weaponIndex]) func displayStats(): + if hud == null or cW == null: + return + hud.displayWeaponStack(weaponStack.size()) hud.displayWeaponName(cW.weaponName) hud.displayTotalAmmoInMag(cW.totalAmmoInMag, cW.nbProjShotsAtSameTime) - hud.displayTotalAmmo(ammoManager.ammoDict[cW.ammoType], cW.nbProjShotsAtSameTime) + # --- БРОНЕБОЙНАЯ ЗАЩИТА ОТ ВЫЛЕТА ИЗ-ЗА ПАТРОНОВ ПРИ СМЕНЕ СЦЕНЫ --- + # Используем метод .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) + func changeWeapon(nextWeapon : int): if canChangeWeapons and !cW.isShooting and !cW.isReloading: exitWeapon(nextWeapon) diff --git a/prog.tscn b/prog.tscn index 532d4af..b8c302b 100644 --- a/prog.tscn +++ b/prog.tscn @@ -1,9 +1,9 @@ [gd_scene format=3 uid="uid://blus2wf5ps3i7"] -[ext_resource type="PackedScene" uid="uid://bwggrf7sbmkcv" path="res://addons/PlayerCharacter/Scenes/PlayerCharacterScene.tscn" id="2_58joc"] [ext_resource type="PackedScene" uid="uid://beqxcfcv7jhpg" path="res://капсула_вагона.tscn" id="3_0pxd3"] [ext_resource type="Texture2D" uid="uid://mdxrv585rfcv" path="res://addons/custmode/test.png" id="3_58joc"] [ext_resource type="Texture2D" uid="uid://b26ir1ccbj3f1" path="res://addons/texture_custom/Timeline 1_00086400.png" id="4_0pxd3"] +[ext_resource type="PackedScene" uid="uid://bwggrf7sbmkcv" path="res://addons/PlayerCharacter/Scenes/PlayerCharacterScene.tscn" id="4_r6sk8"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0pxd3"] albedo_texture = ExtResource("3_58joc") @@ -27,9 +27,6 @@ ssr_fade_in = 2.2392774 [node name="Node3D" type="Node3D" unique_id=1418886085] -[node name="PlayerCharacter" parent="." unique_id=1059654044 instance=ExtResource("2_58joc")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.3088503, 2.1988652, 0.17686236) - [node name="CSGBox3D" type="CSGBox3D" parent="." unique_id=1252647284] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.4910154, -0.16952014, -4.4346185) material_override = SubResource("StandardMaterial3D_0pxd3") @@ -57,3 +54,6 @@ shadow_normal_bias = 1.97 shadow_reverse_cull_face = true shadow_transmittance_bias = -0.05 shadow_blur = 1.15 + +[node name="PlayerCharacter" parent="." unique_id=1059654044 instance=ExtResource("4_r6sk8")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.682482, 1.3198853, -1.3838298) diff --git a/project.godot b/project.godot index df29eeb..172750e 100644 --- a/project.godot +++ b/project.godot @@ -18,6 +18,9 @@ config/icon="res://icon.svg" [autoload] MusicManager="*uid://dgg3biwjhbaeo" +LevelStats="*uid://jbvxvnmbrhe8" +ResultsScreen="*uid://bojftnghiqd2g" +GameTransfer="*uid://dbnkrmxycgjrl" [editor]