точно есть дэшм
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cf1nbn3eqdof8"
|
||||
path="res://.godot/imported/BulletHoleDecal.png-6f42066c913e5757391dce3d7b915fa9.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/Weapons/Images/BulletHoleDecal.png"
|
||||
dest_files=["res://.godot/imported/BulletHoleDecal.png-6f42066c913e5757391dce3d7b915fa9.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 300 B |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://jwucel52ti1u"
|
||||
path="res://.godot/imported/Crosshair.png-0a87b4824bf18c8e6a30d881e1ead75b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/Weapons/Images/Crosshair.png"
|
||||
dest_files=["res://.godot/imported/Crosshair.png-0a87b4824bf18c8e6a30d881e1ead75b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
@@ -0,0 +1,41 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://br3rf0u4bxs67"
|
||||
path.s3tc="res://.godot/imported/MuzzleFlash.png-0b80887bf51df0e0051d3a639d95f491.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/Weapons/Images/MuzzleFlash.png"
|
||||
dest_files=["res://.godot/imported/MuzzleFlash.png-0b80887bf51df0e0051d3a639d95f491.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
@@ -0,0 +1,57 @@
|
||||
[gd_resource type="Resource" script_class="WeaponResource" format=3 uid="uid://cbxau8flaoifg"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://x8oniabn746q" path="res://addons/Weapons/Scenes/MuzzleFlashParticleScene.tscn" id="2_4d7vg"]
|
||||
[ext_resource type="AudioStream" uid="uid://b88waak17hcaf" path="res://Sound/effect/reloading-weapons.mp3" id="2_wwj3m"]
|
||||
[ext_resource type="AudioStream" uid="uid://db15o7lfgctub" path="res://Sound/effect/ak.mp3" id="3_mqb0n"]
|
||||
[ext_resource type="Script" uid="uid://bnhfyt5sl8jcd" path="res://addons/Weapons/Scripts/WeaponResourcesScript.gd" id="4_i0hia"]
|
||||
|
||||
[sub_resource type="Curve" id="Curve_eo1mu"]
|
||||
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.097493, 1), 0.0, 0.0, 0, 0, Vector2(0.643454, 0.0704225), 0.0, 0.0, 0, 0, Vector2(1, 0.0492958), 0.0, 0.0, 0, 0]
|
||||
point_count = 4
|
||||
|
||||
[resource]
|
||||
script = ExtResource("4_i0hia")
|
||||
weaponName = "AssaultRifle"
|
||||
weaponId = 2
|
||||
type = 1
|
||||
animBlendTime = 0.2
|
||||
equipAnimName = "EquipAnimAssaultRifle"
|
||||
unequipAnimName = "UnequipAnimAssaultRifle"
|
||||
shootAnimName = "ShootAnimAssaultRifle"
|
||||
reloadAnimName = "ReloadAnimAssaultRifle"
|
||||
shootSound = ExtResource("3_mqb0n")
|
||||
reloadSound = ExtResource("2_wwj3m")
|
||||
totalAmmoInMag = 30
|
||||
totalAmmoInMagRef = 30
|
||||
ammoType = "MediumAmmo"
|
||||
equipTime = 0.2
|
||||
unequipTime = 0.2
|
||||
canAutoShoot = true
|
||||
nbProjShotsAtSameTime = 1
|
||||
nbProjShots = 1
|
||||
minSpread = -0.03
|
||||
maxSpread = 0.03
|
||||
maxRange = 290.0
|
||||
damagePerProj = 25.0
|
||||
damageDropoff = SubResource("Curve_eo1mu")
|
||||
headshotDamageMult = 2.0
|
||||
timeBetweenShots = 0.11
|
||||
reloadTimePerPart = 2.1
|
||||
baseRotSpeed = 7.0
|
||||
targetRotSpeed = 8.0
|
||||
recoilVal = Vector3(0.08, 0.04, 0)
|
||||
position = Array[Vector3]([Vector3(0.194412, -0.18, -0.144264), Vector3(0, 3.142, 0)])
|
||||
tiltRotSpeed = 7.0
|
||||
tiltRotAmount = 0.3
|
||||
minSwayVal = Vector2(-20, -20)
|
||||
maxSwayVal = Vector2(20, 20)
|
||||
swaySpeedPos = 0.1
|
||||
swaySpeedRot = 0.1
|
||||
swayAmountPos = 0.2
|
||||
swayAmountRot = 40.0
|
||||
bobFreq = 0.009
|
||||
bobAmount = 0.022
|
||||
bobSpeed = 10.0
|
||||
onIdleBobFreqDivider = 1.5
|
||||
muzzleFlashRef = ExtResource("2_4d7vg")
|
||||
showMuzzleFlash = true
|
||||
@@ -0,0 +1,58 @@
|
||||
[gd_resource type="Resource" script_class="WeaponResource" format=3 uid="uid://j42d6dl8qkaj"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://x8oniabn746q" path="res://addons/Weapons/Scenes/MuzzleFlashParticleScene.tscn" id="1_0bp1b"]
|
||||
[ext_resource type="Script" uid="uid://bnhfyt5sl8jcd" path="res://addons/Weapons/Scripts/WeaponResourcesScript.gd" id="2_0fmbw"]
|
||||
[ext_resource type="AudioStream" uid="uid://wqg8m4nlm87s" path="res://Sound/effect/pistol-loaded-to-fire.mp3" id="2_vx7n8"]
|
||||
[ext_resource type="AudioStream" uid="uid://dreqp22wgbfnn" path="res://Sound/effect/pistol.mp3" id="3_5tegi"]
|
||||
|
||||
[sub_resource type="Curve" id="Curve_eo1mu"]
|
||||
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.097493, 1), 0.0, 0.0, 0, 0, Vector2(0.643454, 0.0704225), 0.0, 0.0, 0, 0, Vector2(1, 0.0492958), 0.0, 0.0, 0, 0]
|
||||
point_count = 4
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_0fmbw")
|
||||
weaponName = "Pistol"
|
||||
weaponId = 1
|
||||
type = 1
|
||||
animBlendTime = 0.2
|
||||
equipAnimName = "EquipAnimPistol"
|
||||
unequipAnimName = "UnequipAnimPistol"
|
||||
shootAnimName = "ShootAnimPistol"
|
||||
reloadAnimName = "ReloadAnimPistol"
|
||||
shootSound = ExtResource("3_5tegi")
|
||||
reloadSound = ExtResource("2_vx7n8")
|
||||
totalAmmoInMag = 10
|
||||
totalAmmoInMagRef = 10
|
||||
ammoType = "LightAmmo"
|
||||
equipTime = 0.2
|
||||
unequipTime = 0.2
|
||||
canAutoShoot = true
|
||||
nbProjShotsAtSameTime = 1
|
||||
nbProjShots = 1
|
||||
minSpread = -0.01
|
||||
maxSpread = 0.01
|
||||
maxRange = 100.0
|
||||
damagePerProj = 10.0
|
||||
damageDropoff = SubResource("Curve_eo1mu")
|
||||
headshotDamageMult = 2.0
|
||||
timeBetweenShots = 0.19
|
||||
autoReload = false
|
||||
reloadTimePerPart = 1.1
|
||||
baseRotSpeed = 7.0
|
||||
targetRotSpeed = 8.0
|
||||
recoilVal = Vector3(0.04, 0.012, 0)
|
||||
position = Array[Vector3]([Vector3(0.20047, -0.153444, -0.150842), Vector3(0, 3.142, 0)])
|
||||
tiltRotSpeed = 4.04
|
||||
tiltRotAmount = 0.3
|
||||
minSwayVal = Vector2(-20, -20)
|
||||
maxSwayVal = Vector2(20, 20)
|
||||
swaySpeedPos = 0.1
|
||||
swaySpeedRot = 0.1
|
||||
swayAmountPos = 0.2
|
||||
swayAmountRot = 28.0
|
||||
bobFreq = 0.008
|
||||
bobAmount = 0.018
|
||||
bobSpeed = 10.0
|
||||
onIdleBobFreqDivider = 2.0
|
||||
muzzleFlashRef = ExtResource("1_0bp1b")
|
||||
showMuzzleFlash = true
|
||||
@@ -0,0 +1,54 @@
|
||||
[gd_resource type="Resource" script_class="WeaponResource" format=3 uid="uid://dn71dyben68oe"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://u4tj3ey6tjg8" path="res://addons/Weapons/Scenes/RocketScene.tscn" id="1_hdqr8"]
|
||||
[ext_resource type="PackedScene" uid="uid://x8oniabn746q" path="res://addons/Weapons/Scenes/MuzzleFlashParticleScene.tscn" id="1_icrwl"]
|
||||
[ext_resource type="Script" uid="uid://bnhfyt5sl8jcd" path="res://addons/Weapons/Scripts/WeaponResourcesScript.gd" id="4_ws8wg"]
|
||||
|
||||
[sub_resource type="Curve" id="Curve_8j8ql"]
|
||||
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.969231, 0.0578563), 0.0, 0.0, 0, 0]
|
||||
point_count = 2
|
||||
|
||||
[resource]
|
||||
script = ExtResource("4_ws8wg")
|
||||
weaponName = "RocketLauncher"
|
||||
weaponId = 5
|
||||
type = 2
|
||||
animBlendTime = 0.2
|
||||
equipAnimName = "EquipAnimRocketLauncher"
|
||||
unequipAnimName = "UnequipAnimRocketLauncher"
|
||||
shootAnimName = "ShootAnimRocketLancher"
|
||||
reloadAnimName = "ReloadAnimRocketLauncher"
|
||||
totalAmmoInMag = 1
|
||||
totalAmmoInMagRef = 1
|
||||
ammoType = "RocketAmmo"
|
||||
equipTime = 0.2
|
||||
unequipTime = 0.2
|
||||
canAutoShoot = true
|
||||
nbProjShotsAtSameTime = 1
|
||||
nbProjShots = 1
|
||||
damagePerProj = 340.0
|
||||
damageDropoff = SubResource("Curve_8j8ql")
|
||||
timeBetweenShots = 0.82
|
||||
reloadTimePerPart = 1.9
|
||||
baseRotSpeed = 3.0
|
||||
targetRotSpeed = 6.5
|
||||
recoilVal = Vector3(0.19, 0.03, 0)
|
||||
isProjExplosive = true
|
||||
projRef = ExtResource("1_hdqr8")
|
||||
projMoveSpeed = 25.0
|
||||
projTimeBeforeVanish = 10.0
|
||||
position = Array[Vector3]([Vector3(0.177288, -0.268151, -0.15469), Vector3(0, 3.14159, 0)])
|
||||
tiltRotSpeed = 7.0
|
||||
tiltRotAmount = 0.2
|
||||
minSwayVal = Vector2(-20, -20)
|
||||
maxSwayVal = Vector2(20, 20)
|
||||
swaySpeedPos = 0.1
|
||||
swaySpeedRot = 0.1
|
||||
swayAmountPos = 0.2
|
||||
swayAmountRot = 48.0
|
||||
bobFreq = 0.01
|
||||
bobAmount = 0.025
|
||||
bobSpeed = 10.0
|
||||
onIdleBobFreqDivider = 1.2
|
||||
muzzleFlashRef = ExtResource("1_icrwl")
|
||||
showMuzzleFlash = true
|
||||
@@ -0,0 +1,54 @@
|
||||
[gd_resource type="Resource" script_class="WeaponResource" format=3 uid="uid://bgb8htvjywlwm"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://x8oniabn746q" path="res://addons/Weapons/Scenes/MuzzleFlashParticleScene.tscn" id="2_lxpym"]
|
||||
[ext_resource type="Script" uid="uid://bnhfyt5sl8jcd" path="res://addons/Weapons/Scripts/WeaponResourcesScript.gd" id="5_ynmrh"]
|
||||
|
||||
[sub_resource type="Curve" id="Curve_eo1mu"]
|
||||
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.0991379, 1), 0.0, 0.0, 0, 0, Vector2(0.336207, 0.168539), 0.0, 0.0, 0, 0, Vector2(1, 0.0492958), 0.0, 0.0, 0, 0]
|
||||
point_count = 4
|
||||
|
||||
[resource]
|
||||
script = ExtResource("5_ynmrh")
|
||||
weaponName = "Shotgun"
|
||||
weaponId = 3
|
||||
type = 1
|
||||
animBlendTime = 0.2
|
||||
equipAnimName = "EquipAnimShotgun"
|
||||
unequipAnimName = "UnequipAnimShotgun"
|
||||
shootAnimName = "ShootAnimShotgun"
|
||||
reloadAnimName = "ReloadAnimShotgun"
|
||||
totalAmmoInMag = 64
|
||||
totalAmmoInMagRef = 64
|
||||
ammoType = "ShellAmmo"
|
||||
equipTime = 0.2
|
||||
unequipTime = 0.2
|
||||
canAutoShoot = true
|
||||
nbProjShotsAtSameTime = 8
|
||||
nbProjShots = 1
|
||||
minSpread = -0.7
|
||||
maxSpread = 0.7
|
||||
maxRange = 210.0
|
||||
damagePerProj = 25.0
|
||||
damageDropoff = SubResource("Curve_eo1mu")
|
||||
headshotDamageMult = 1.7
|
||||
timeBetweenShots = 0.28
|
||||
nbPartsNeeded = 8
|
||||
reloadTimePerPart = 0.3
|
||||
baseRotSpeed = 7.0
|
||||
targetRotSpeed = 8.0
|
||||
recoilVal = Vector3(0.13, 0.05, 0)
|
||||
position = Array[Vector3]([Vector3(0.196569, -0.209086, -0.0802836), Vector3(0, 3.14159, 0)])
|
||||
tiltRotSpeed = 7.0
|
||||
tiltRotAmount = 0.3
|
||||
minSwayVal = Vector2(-20, -20)
|
||||
maxSwayVal = Vector2(20, 20)
|
||||
swaySpeedPos = 0.1
|
||||
swaySpeedRot = 0.1
|
||||
swayAmountPos = 0.2
|
||||
swayAmountRot = 40.0
|
||||
bobFreq = 0.009
|
||||
bobAmount = 0.022
|
||||
bobSpeed = 10.0
|
||||
onIdleBobFreqDivider = 1.5
|
||||
muzzleFlashRef = ExtResource("2_lxpym")
|
||||
showMuzzleFlash = true
|
||||
@@ -0,0 +1,51 @@
|
||||
[gd_resource type="Resource" script_class="WeaponResource" format=3 uid="uid://b63lj0c7tash0"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://x8oniabn746q" path="res://addons/Weapons/Scenes/MuzzleFlashParticleScene.tscn" id="2_ijpj8"]
|
||||
[ext_resource type="Script" uid="uid://bnhfyt5sl8jcd" path="res://addons/Weapons/Scripts/WeaponResourcesScript.gd" id="5_kospc"]
|
||||
|
||||
[sub_resource type="Curve" id="Curve_eo1mu"]
|
||||
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.678639, 1), 0.0, 0.0, 0, 0, Vector2(1, 0.462132), 0.0, 0.0, 0, 0]
|
||||
point_count = 3
|
||||
|
||||
[resource]
|
||||
script = ExtResource("5_kospc")
|
||||
weaponName = "SniperRifle"
|
||||
weaponId = 4
|
||||
type = 1
|
||||
animBlendTime = 0.2
|
||||
equipAnimName = "EquipAnimSniperRifle"
|
||||
unequipAnimName = "UnequipAnimSniperRifle"
|
||||
shootAnimName = "ShootAnimSniperRifle"
|
||||
reloadAnimName = "ReloadAnimSniperRifle"
|
||||
totalAmmoInMag = 5
|
||||
totalAmmoInMagRef = 5
|
||||
ammoType = "HeavyAmmo"
|
||||
equipTime = 0.2
|
||||
unequipTime = 0.2
|
||||
canAutoShoot = true
|
||||
nbProjShotsAtSameTime = 1
|
||||
nbProjShots = 1
|
||||
maxRange = 490.0
|
||||
damagePerProj = 180.0
|
||||
damageDropoff = SubResource("Curve_eo1mu")
|
||||
headshotDamageMult = 2.0
|
||||
timeBetweenShots = 0.95
|
||||
reloadTimePerPart = 2.0
|
||||
baseRotSpeed = 5.0
|
||||
targetRotSpeed = 9.0
|
||||
recoilVal = Vector3(0.2, 0.04, 0)
|
||||
position = Array[Vector3]([Vector3(0.208089, -0.137525, -0.165069), Vector3(0, 3.14159, 0)])
|
||||
tiltRotSpeed = 7.0
|
||||
tiltRotAmount = 0.25
|
||||
minSwayVal = Vector2(-20, -20)
|
||||
maxSwayVal = Vector2(20, 20)
|
||||
swaySpeedPos = 0.07
|
||||
swaySpeedRot = 0.1
|
||||
swayAmountPos = 0.2
|
||||
swayAmountRot = 44.0
|
||||
bobFreq = 0.01
|
||||
bobAmount = 0.023
|
||||
bobSpeed = 10.0
|
||||
onIdleBobFreqDivider = 1.4
|
||||
muzzleFlashRef = ExtResource("2_ijpj8")
|
||||
showMuzzleFlash = true
|
||||
@@ -0,0 +1,32 @@
|
||||
[gd_scene format=3 uid="uid://pjv5ptit5tvg"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bp4miwy6defwl" path="res://addons/Weapons/Scripts/Ammunition/AmmoRefillerScript.gd" id="1_bsrep"]
|
||||
[ext_resource type="PackedScene" uid="uid://cyxdexqmowyvh" path="res://addons/Addon Assets/Weapon Models/AmmunitionBox/ammobox_low.glb" id="2_8nqyo"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_vfsrg"]
|
||||
size = Vector3(0.974533, 0.752262, 1.42589)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_diulm"]
|
||||
size = Vector3(1.90394, 1.28174, 2.08409)
|
||||
|
||||
[node name="AmmoRefiller" type="StaticBody3D" unique_id=1413490376]
|
||||
collision_layer = 64
|
||||
collision_mask = 121
|
||||
script = ExtResource("1_bsrep")
|
||||
|
||||
[node name="Hitbox" type="CollisionShape3D" parent="." unique_id=855968420]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0297165, -0.00481224, 0.00307465)
|
||||
shape = SubResource("BoxShape3D_vfsrg")
|
||||
|
||||
[node name="DetectArea" type="Area3D" parent="." unique_id=1561253085]
|
||||
collision_layer = 64
|
||||
collision_mask = 2
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="DetectArea" unique_id=834866130]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0385975, 0.274414, -0.0104526)
|
||||
shape = SubResource("BoxShape3D_diulm")
|
||||
|
||||
[node name="Model" parent="." unique_id=92899466 instance=ExtResource("2_8nqyo")]
|
||||
transform = Transform3D(-2.84124e-07, 0, 6.5, 0, 6.5, 0, -6.5, 0, -2.84124e-07, 0, -0.0915464, 0)
|
||||
|
||||
[connection signal="area_entered" from="DetectArea" to="." method="_on_detect_area_area_entered"]
|
||||
@@ -0,0 +1,9 @@
|
||||
[gd_scene format=3 uid="uid://0gq5270ogtxu"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cf1nbn3eqdof8" path="res://addons/Weapons/Images/BulletHoleDecal.png" id="1_d0hng"]
|
||||
|
||||
[node name="BulletDecal" type="Node3D" unique_id=1126630367]
|
||||
|
||||
[node name="Decal" type="Decal" parent="." unique_id=559746448]
|
||||
size = Vector3(0.2, 0.2, 0.2)
|
||||
texture_albedo = ExtResource("1_d0hng")
|
||||
@@ -0,0 +1,50 @@
|
||||
[gd_scene format=3 uid="uid://x8oniabn746q"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://br3rf0u4bxs67" path="res://addons/Weapons/Images/MuzzleFlash.png" id="1_f6nr6"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_64eh8"]
|
||||
transparency = 1
|
||||
albedo_texture = ExtResource("1_f6nr6")
|
||||
emission_enabled = true
|
||||
emission = Color(0.941176, 0.623529, 0, 1)
|
||||
|
||||
[sub_resource type="Curve" id="Curve_yutl4"]
|
||||
_data = [Vector2(0, 0.496705), 0.0, 0.0, 0, 0, Vector2(0.765351, 0.485997), 0.0, 0.0, 0, 0, Vector2(1, 0.0286427), 0.0, 0.0, 0, 0]
|
||||
point_count = 3
|
||||
|
||||
[sub_resource type="CurveTexture" id="CurveTexture_oq8qr"]
|
||||
curve = SubResource("Curve_yutl4")
|
||||
|
||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_3amic"]
|
||||
emission_shape_offset = Vector3(0, 0.05, 0)
|
||||
angle_min = -90.0
|
||||
angle_max = 90.0
|
||||
direction = Vector3(0, 0, 0)
|
||||
gravity = Vector3(0, 0, 0)
|
||||
scale_curve = SubResource("CurveTexture_oq8qr")
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3q3wu"]
|
||||
transparency = 4
|
||||
albedo_texture = ExtResource("1_f6nr6")
|
||||
emission_enabled = true
|
||||
emission = Color(0.811765, 0.313726, 0.0431373, 1)
|
||||
emission_energy_multiplier = 0.1
|
||||
billboard_mode = 3
|
||||
particles_anim_h_frames = 1
|
||||
particles_anim_v_frames = 1
|
||||
particles_anim_loop = false
|
||||
|
||||
[sub_resource type="QuadMesh" id="QuadMesh_hkd1h"]
|
||||
material = SubResource("StandardMaterial3D_3q3wu")
|
||||
size = Vector2(0.25, 0.25)
|
||||
|
||||
[node name="MuzzleFlashParticles" type="GPUParticles3D" unique_id=1820802449]
|
||||
material_override = SubResource("StandardMaterial3D_64eh8")
|
||||
emitting = false
|
||||
amount = 3
|
||||
lifetime = 0.04
|
||||
one_shot = true
|
||||
explosiveness = 0.6
|
||||
local_coords = true
|
||||
process_material = SubResource("ParticleProcessMaterial_3amic")
|
||||
draw_pass_1 = SubResource("QuadMesh_hkd1h")
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
||||
extends StaticBody3D
|
||||
|
||||
@export var ammoToRefill : Dictionary = {}
|
||||
|
||||
func _on_detect_area_area_entered(area: Area3D):
|
||||
if area.get_parent() is PlayerCharacter:
|
||||
var playChar = area.get_parent()
|
||||
var linkToAmmoRefill : Node3D = playChar.get_node("LinkComponent")
|
||||
|
||||
if linkToAmmoRefill != null:
|
||||
linkToAmmoRefill.ammoRefillLink(ammoToRefill)
|
||||
else:
|
||||
print("Player character can't refill ammunition")
|
||||
|
||||
queue_free()
|
||||
@@ -0,0 +1 @@
|
||||
uid://bp4miwy6defwl
|
||||
@@ -0,0 +1,20 @@
|
||||
extends Node3D
|
||||
|
||||
var ammoDict : Dictionary = { #key = ammo type, value = ammo start number
|
||||
"LightAmmo" : 90,
|
||||
"MediumAmmo" : 60,
|
||||
"HeavyAmmo" : 9,
|
||||
"ShellAmmo" : 128,
|
||||
"RocketAmmo" : 3,
|
||||
"GrenadeAmmo" : 12
|
||||
}
|
||||
|
||||
var maxNbPerAmmoDict : Dictionary = { #key = ammo type, value = ammo max number
|
||||
"LightAmmo" : 360,
|
||||
"MediumAmmo" : 360,
|
||||
"HeavyAmmo" : 50,
|
||||
"ShellAmmo" : 640,
|
||||
"RocketAmmo" : 15,
|
||||
"GrenadeAmmo" : 60
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://b45mr122adhlv
|
||||
@@ -0,0 +1,58 @@
|
||||
extends Node3D
|
||||
|
||||
var cW
|
||||
var cWModel : Node3D
|
||||
|
||||
@onready var cameraHolder : Node3D = %CameraHolder
|
||||
@onready var playChar : CharacterBody3D = $"../../../../.."
|
||||
@onready var animPlayer : AnimationPlayer = %AnimationPlayer
|
||||
@onready var weaponManager : Node3D = %WeaponManager
|
||||
|
||||
func getCurrentWeapon(currWeap, currweaponManagerodel):
|
||||
#get current weapon model and resources
|
||||
cW = currWeap
|
||||
cWModel = currweaponManagerodel
|
||||
|
||||
func _process(delta: float):
|
||||
if cW != null and cWModel != null:
|
||||
weaponTilt(playChar.inputDirection, delta)
|
||||
weaponSway(cameraHolder.mouseInput, delta)
|
||||
weaponBob(playChar.velocity.length(),delta)
|
||||
|
||||
func weaponTilt(playCharInput, delta):
|
||||
#rotate weapon model on the z axis depending on the player character direction orientation (left or right)
|
||||
cWModel.rotation.z = lerp(cWModel.rotation.z, playCharInput.x * cW.tiltRotAmount, cW.tiltRotSpeed * delta)
|
||||
|
||||
func weaponSway(mouseInput, delta):
|
||||
#clamp mouse movement
|
||||
mouseInput.x = clamp(mouseInput.x, cW.minSwayVal.x, cW.maxSwayVal.x)
|
||||
mouseInput.y = clamp(mouseInput.y, cW.minSwayVal.y, cW.maxSwayVal.y)
|
||||
|
||||
#lerp weapon position based on mouse movement, relative to the initial position
|
||||
cWModel.position.x = lerp(cWModel.position.x, cW.position[0].x + (mouseInput.x * cW.swayAmountPos) * delta, cW.swaySpeedPos)
|
||||
cWModel.position.y = lerp(cWModel.position.y, cW.position[0].y - (mouseInput.y * cW.swayAmountPos) * delta, cW.swaySpeedPos)
|
||||
|
||||
#lerp weapon rotation based on mouse movement, relative to the initial rotation
|
||||
#use of rad_to_deg here, because we rotate the model based on degrees, but the saved weapon rotation is in radians
|
||||
cWModel.rotation_degrees.y = lerp(cWModel.rotation_degrees.y, rad_to_deg(cW.position[1].y) - (mouseInput.x * cW.swayAmountRot) * delta, cW.swaySpeedRot)
|
||||
cWModel.rotation_degrees.x = lerp(cWModel.rotation_degrees.x, rad_to_deg(cW.position[1].x) + (mouseInput.y * cW.swayAmountRot) * delta, cW.swaySpeedRot)
|
||||
|
||||
func weaponBob(vel : float, delta):
|
||||
var bobFreq : float = cW.bobFreq
|
||||
|
||||
#change bob frequency for weapon idle
|
||||
if vel < 4.0:
|
||||
bobFreq /= cW.onIdleBobFreqDivider
|
||||
|
||||
#smoothly move the weapon model in the form of a curve (hence the use of sin)
|
||||
cWModel.position.y = lerp(cWModel.position.y, cW.bobPos[0].y + sin(Time.get_ticks_msec() * bobFreq) * cW.bobAmount * vel / 10, cW.bobSpeed * delta)
|
||||
cWModel.position.x = lerp(cWModel.position.x, cW.bobPos[0].x + sin(Time.get_ticks_msec() * bobFreq * 0.5) * cW.bobAmount * vel / 10, cW.bobSpeed * delta)
|
||||
|
||||
func playAnimation(animName : String, animSpeed : float, hasToRestartAnim : bool):
|
||||
if cW != null and animPlayer != null:
|
||||
#restart current anim if needed (for example restart shoot animation while still playing)
|
||||
if hasToRestartAnim and animPlayer.current_animation == animName:
|
||||
animPlayer.seek(0, true)
|
||||
#play animation
|
||||
animPlayer.play("%s" % animName, -1, animSpeed)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://bc64rms0gin6g
|
||||
@@ -0,0 +1,54 @@
|
||||
extends Node3D
|
||||
|
||||
var cW
|
||||
var cWModel : Node3D
|
||||
|
||||
# Безопасные относительные пути к телу моба, родителю и плееру анимаций
|
||||
@onready var mob_body : CharacterBody3D = $"../.."
|
||||
@onready var animPlayer : AnimationPlayer = $"../.."/AnimationPlayer
|
||||
@onready var weaponManager : Node3D = $".."
|
||||
|
||||
func getCurrentWeapon(currWeap, currweaponManagerodel):
|
||||
cW = currWeap
|
||||
cWModel = currweaponManagerodel
|
||||
|
||||
func _process(delta: float):
|
||||
if cW != null and cWModel != null and is_instance_valid(mob_body) and animPlayer != null:
|
||||
# КРИТИЧЕСКАЯ ЗАЩИТА ВСПЫШКИ: Если играет выстрел, код НЕ перекрывает координаты своей математикой!
|
||||
if animPlayer.is_playing() and animPlayer.current_animation == "ShootAnimPistol":
|
||||
return
|
||||
|
||||
# Если выстрела нет, плавно покачиваем и наклоняем пистолет при движении моба
|
||||
var movement_dir = mob_body.velocity.normalized()
|
||||
weaponTilt(movement_dir, delta)
|
||||
weaponBob(mob_body.velocity.length(), delta)
|
||||
|
||||
func weaponTilt(moveDir, delta):
|
||||
if "tiltRotAmount" in cW and "tiltRotSpeed" in cW:
|
||||
cWModel.rotation.z = lerp(cWModel.rotation.z, moveDir.x * cW.tiltRotAmount, cW.tiltRotSpeed * delta)
|
||||
|
||||
func weaponBob(vel : float, delta):
|
||||
if not ("bobFreq" in cW) or not ("bobAmount" in cW) or not ("bobSpeed" in cW): return
|
||||
var bobFreq : float = cW.bobFreq
|
||||
|
||||
if vel < 1.0:
|
||||
if "onIdleBobFreqDivider" in cW: bobFreq /= cW.onIdleBobFreqDivider
|
||||
else: bobFreq /= 2.0
|
||||
|
||||
var secure_vel = clamp(vel, 0.0, 10.0)
|
||||
if secure_vel < 0.2: secure_vel = 0.5
|
||||
|
||||
var time_tick = Time.get_ticks_msec() * bobFreq
|
||||
var target_y = cW.bobPos.y + sin(time_tick) * cW.bobAmount * secure_vel / 10
|
||||
var target_x = cW.bobPos.x + sin(time_tick * 0.5) * cW.bobAmount * secure_vel / 10
|
||||
|
||||
if is_finite(target_y) and is_finite(target_x):
|
||||
cWModel.position.y = lerp(cWModel.position.y, target_y, cW.bobSpeed * delta)
|
||||
cWModel.position.x = lerp(cWModel.position.x, target_x, cW.bobSpeed * delta)
|
||||
|
||||
# Резервная функция вызова
|
||||
func playAnimation(animName : String, animSpeed : float, hasToRestartAnim : bool):
|
||||
if animPlayer != null:
|
||||
if hasToRestartAnim and animPlayer.current_animation == animName:
|
||||
animPlayer.seek(0, true)
|
||||
animPlayer.play("%s" % animName, -1, animSpeed)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dgt4q3ev7fhh5
|
||||
@@ -0,0 +1,25 @@
|
||||
extends Node3D
|
||||
|
||||
#Camera recoil variables
|
||||
var currentRotation : Vector3
|
||||
var targetRotation : Vector3
|
||||
var baseRotationSpeed : float
|
||||
var targetRotationSpeed : float
|
||||
|
||||
func _process(delta):
|
||||
handleRecoil(delta)
|
||||
|
||||
func handleRecoil(delta):
|
||||
#first phase, the camera will aim according the recoil values
|
||||
#second phase, the camera back down to her initial rotation value
|
||||
targetRotation = lerp(targetRotation, Vector3.ZERO, baseRotationSpeed * delta)
|
||||
currentRotation = lerp(currentRotation, targetRotation, targetRotationSpeed * delta)
|
||||
|
||||
rotation = currentRotation
|
||||
|
||||
func setRecoilValues(baseRotSpeed : float, targRotSpeed : int):
|
||||
baseRotationSpeed = baseRotSpeed
|
||||
targetRotationSpeed = targRotSpeed
|
||||
|
||||
func addRecoil(recoilValue):
|
||||
targetRotation += Vector3(recoilValue.x, randf_range(-recoilValue.y, recoilValue.y), randf_range(-recoilValue.z, recoilValue.z))
|
||||
@@ -0,0 +1 @@
|
||||
uid://k7djd8c1xge2
|
||||
@@ -0,0 +1,7 @@
|
||||
extends SubViewport
|
||||
|
||||
var screenSize : Vector2
|
||||
|
||||
func _ready():
|
||||
screenSize = get_window().size
|
||||
size = screenSize
|
||||
@@ -0,0 +1 @@
|
||||
uid://bt4lvwbcabtef
|
||||
@@ -0,0 +1,6 @@
|
||||
extends Camera3D
|
||||
|
||||
@onready var mainCam : Camera3D = %Camera
|
||||
|
||||
func _process(_delta: float):
|
||||
if mainCam != null: global_transform = mainCam.global_transform
|
||||
@@ -0,0 +1 @@
|
||||
uid://dvfp5mk7fbsbl
|
||||
@@ -0,0 +1,65 @@
|
||||
extends RigidBody3D
|
||||
|
||||
#properties variables
|
||||
var isExplosive : bool = false
|
||||
var direction : Vector3
|
||||
var damage : float
|
||||
var timeBeforeVanish : float
|
||||
var bodiesList : Array = []
|
||||
|
||||
#references variables
|
||||
@onready var mesh = $Mesh
|
||||
@onready var hitbox = $Hitbox
|
||||
|
||||
@export_group("Sound variables")
|
||||
@onready var audioManager : PackedScene = preload("../../Misc/Scenes/AudioManagerScene.tscn")
|
||||
@export var explosionSound : AudioStream
|
||||
|
||||
@export_group("Particles variables")
|
||||
@onready var particlesManager : PackedScene = preload("../../Misc/Scenes/ParticlesManagerScene.tscn")
|
||||
|
||||
func _process(delta):
|
||||
if timeBeforeVanish > 0.0: timeBeforeVanish -= delta
|
||||
else: hit()
|
||||
|
||||
func _on_body_entered(body):
|
||||
hit()
|
||||
applyDamage(body)
|
||||
|
||||
func hit():
|
||||
mesh.visible = false
|
||||
hitbox.set_deferred("disabled", true)
|
||||
|
||||
if isExplosive: explode()
|
||||
|
||||
func applyDamage(body):
|
||||
if body.is_in_group("Enemies") and body.has_method("projectileHit"):
|
||||
body.projectileHit(damage, direction)
|
||||
|
||||
if body.is_in_group("HitableObjects") and body.has_method("projectileHit"):
|
||||
body.projectileHit(damage, direction)
|
||||
|
||||
func explode():
|
||||
#this function is visual and audio only, it doesn't affect the gameplay
|
||||
weaponSoundManagement(explosionSound)
|
||||
|
||||
var particlesIns : ParticlesManager
|
||||
if particlesIns == null:
|
||||
particlesIns = particlesManager.instantiate()
|
||||
particlesIns.particleToEmit = "Explosion"
|
||||
particlesIns.global_transform = global_transform
|
||||
get_tree().get_root().add_child.call_deferred(particlesIns)
|
||||
else:
|
||||
print("Projectile already has emit explosion particles")
|
||||
|
||||
queue_free()
|
||||
|
||||
func weaponSoundManagement(soundName):
|
||||
if soundName != null:
|
||||
var audioIns = audioManager.instantiate()
|
||||
audioIns.global_transform = global_transform
|
||||
get_tree().get_root().add_child(audioIns)
|
||||
audioIns.bus = "Sfx"
|
||||
audioIns.volume_db = 5.0
|
||||
audioIns.stream = soundName
|
||||
audioIns.play()
|
||||
@@ -0,0 +1 @@
|
||||
uid://bysswu6cmi0t4
|
||||
@@ -0,0 +1,109 @@
|
||||
extends Node3D
|
||||
|
||||
var reloadTime : float
|
||||
var startReloadTimer : bool = false #has to be initilated at start
|
||||
var currentPartIndex : int
|
||||
var playSoundAndAnim : bool
|
||||
var forceReloadStop : bool = false
|
||||
|
||||
var cW #current weapon
|
||||
@onready var weaponManager : Node3D = %WeaponManager #weapon manager
|
||||
|
||||
func getCurrentWeapon(currentWeapon):
|
||||
cW = currentWeapon
|
||||
|
||||
func _process(delta : float):
|
||||
if cW.isReloading and startReloadTimer and !forceReloadStop:
|
||||
reloadFollow(delta)
|
||||
elif forceReloadStop:
|
||||
cW.isReloading = false
|
||||
startReloadTimer = false
|
||||
return
|
||||
|
||||
func reload():
|
||||
reloadStart()
|
||||
|
||||
func reloadStart():
|
||||
if cW.hasToReload:
|
||||
if (!cW.isReloading and \
|
||||
#the type of ammunition the weapon is using still as reserve
|
||||
weaponManager.ammoManager.ammoDict[cW.ammoType] > cW.nbProjShotsAtSameTime and \
|
||||
#the magazine isn't full
|
||||
cW.totalAmmoInMag != cW.totalAmmoInMagRef and \
|
||||
!cW.isShooting):
|
||||
cW.isReloading = true
|
||||
|
||||
#for more than 1 part, you need to enter a multiple of total number of ammo the magazine can contain
|
||||
#for example, for a shotgun that can contain 8 shells, the number of parts to reload possible are : 1, 2, 4, 8
|
||||
#if you choose a number like 3, or 5, it will reload 3/8, or 5/8 at once, which is not possible, so be sure to enter a number of part allowing the weapon to reload ammunition units
|
||||
if (cW.totalAmmoInMagRef % cW.nbPartsNeeded) != 0:
|
||||
push_error("The number of parts set is not correct, cannot insert %d of ammunition" % (cW.nbPartsNeeded / cW.totalAmmoInMagRef))
|
||||
cW.isReloading = false
|
||||
else:
|
||||
currentPartIndex = 0
|
||||
reloadTime = cW.reloadTimePerPart
|
||||
forceReloadStop = false
|
||||
playSoundAndAnim = true
|
||||
startReloadTimer = true
|
||||
#the rest is been processed is reloadTimeProcess, then reloadFollow
|
||||
else:
|
||||
print("No need to reload")
|
||||
|
||||
func reloadFollow(delta : float):
|
||||
if playSoundAndAnim:
|
||||
playSoundAndAnim = false
|
||||
weaponManager.weaponSoundManagement(cW.reloadSound, cW.reloadSoundSpeed)
|
||||
|
||||
if cW.shootAnimName != "":
|
||||
weaponManager.animManager.playAnimation("ReloadAnim%s" % cW.weaponName, cW.reloadAnimSpeed, true)
|
||||
else:
|
||||
print("%s doesn't have a reload animation" % cW.weaponName)
|
||||
|
||||
if reloadTime > 0.0: reloadTime -= delta
|
||||
else:
|
||||
if currentPartIndex < cW.nbPartsNeeded: #-1, because if not it loop one extra time
|
||||
if cW.nbPartsNeeded == 1:
|
||||
onePartReloadCalculus()
|
||||
else:
|
||||
multiPartReloadCalculus()
|
||||
|
||||
currentPartIndex += 1
|
||||
|
||||
if currentPartIndex < cW.nbPartsNeeded:
|
||||
reloadTime = cW.reloadTimePerPart
|
||||
playSoundAndAnim = true
|
||||
else:
|
||||
print("Reload complete")
|
||||
cW.isReloading = false
|
||||
else:
|
||||
print("Reload complete")
|
||||
cW.isReloading = false
|
||||
|
||||
func onePartReloadCalculus():
|
||||
#explanation of the use of the min function here
|
||||
#case 1: if there's enough ammo to completely refill the magazine
|
||||
#case 2: if there's not enough ammo left, we refill the magazine with the remaining ammo.
|
||||
var nbnbAmmoToRefill : int = min(cW.totalAmmoInMagRef - cW.totalAmmoInMag, weaponManager.ammoManager.ammoDict[cW.ammoType])
|
||||
|
||||
if nbnbAmmoToRefill <= cW.totalAmmoInMagRef and nbnbAmmoToRefill >= cW.nbProjShotsAtSameTime:
|
||||
#refill the magazine, and subtract the number from the ammo manager
|
||||
cW.totalAmmoInMag += nbnbAmmoToRefill
|
||||
weaponManager.ammoManager.ammoDict[cW.ammoType] -= nbnbAmmoToRefill
|
||||
|
||||
func multiPartReloadCalculus():
|
||||
var nbAmmoToRefill = cW.totalAmmoInMagRef / cW.nbPartsNeeded
|
||||
if weaponManager.ammoManager.ammoDict[cW.ammoType] >= nbAmmoToRefill and \
|
||||
cW.totalAmmoInMag <= cW.totalAmmoInMagRef - nbAmmoToRefill:
|
||||
#add number of ammo to the magazine, and substract it from the ammo manager
|
||||
cW.totalAmmoInMag += nbAmmoToRefill
|
||||
weaponManager.ammoManager.ammoDict[cW.ammoType] -= nbAmmoToRefill
|
||||
else:
|
||||
print("Not enough ammunition in bag, or magazine complete")
|
||||
forceReloadStop = true
|
||||
|
||||
func autoReload():
|
||||
#auto reload the weapon if he can reload, has to reload, has auto reload enabled, has enought ammo in the ammo manager, and the magazine is empty
|
||||
if cW.autoReload and !cW.isReloading and \
|
||||
weaponManager.ammoManager.ammoDict[cW.ammoType] > 0 and \
|
||||
cW.totalAmmoInMag <= 0:
|
||||
reload()
|
||||
@@ -0,0 +1 @@
|
||||
uid://cfbsp443am2jd
|
||||
@@ -0,0 +1,219 @@
|
||||
extends Node3D
|
||||
|
||||
var cW #current weapon
|
||||
var pointOfCollision : Vector3 = Vector3.ZERO
|
||||
var rng : RandomNumberGenerator
|
||||
|
||||
@onready var weaponManager : Node3D = %WeaponManager #weapon manager
|
||||
@onready var blood_particles_scene: PackedScene = preload("res://addons/NPC/enemy/blood_particles.tscn") # Укажи точный путь к файлу из Шага 2
|
||||
|
||||
func getCurrentWeapon(currWeap):
|
||||
#get current weapon resources
|
||||
cW = currWeap
|
||||
|
||||
func shoot():
|
||||
# БЛОКИРОВКА СТРЕЛЬБЫ ДЛЯ ДИАЛОГОВ И СМЕНЫ ОРУЖИЯ:
|
||||
# Если менеджеру оружия запрещено стрелять — принудительно выходим из функции
|
||||
var dialogue_ui = get_tree().current_scene.find_child("DialogueUI", true, false)
|
||||
if dialogue_ui:
|
||||
var dialogue_box = dialogue_ui.find_child("DialogueBox", true, false)
|
||||
# Если окно с текстом диалога СЕЙЧАС открыто и видимо на экране — выстрел ЗАПРЕЩЕН
|
||||
if dialogue_box and dialogue_box.visible:
|
||||
return # Мгновенно выходим, не давая проиграться коду ниже
|
||||
|
||||
|
||||
|
||||
|
||||
if !cW.isShooting and (
|
||||
#magazine isn't empty, and has >= ammo than the number of projectiles required for a shot
|
||||
(cW.totalAmmoInMag > 0 and cW.totalAmmoInMag >= cW.nbProjShotsAtSameTime)
|
||||
or
|
||||
#has all ammos in the magazine, and number of ammo is positive
|
||||
(cW.allAmmoInMag and weaponManager.ammoManager.ammoDict[cW.ammoType] > 0 and
|
||||
#has >= ammo than the number of projectiles required for a shot
|
||||
weaponManager.ammoManager.ammoDict[cW.ammoType] >= cW.nbProjShotsAtSameTime)
|
||||
) and !cW.isReloading:
|
||||
cW.isShooting = true
|
||||
|
||||
#number of successive shots (for example if 3, the weapon will shot 3 times in a row)
|
||||
for i in range(cW.nbProjShots):
|
||||
#same conditions has before, are checked before every shot
|
||||
if ((cW.totalAmmoInMag > 0 and cW.totalAmmoInMag >= cW.nbProjShotsAtSameTime)
|
||||
or (cW.allAmmoInMag and weaponManager.ammoManager.ammoDict[cW.ammoType] > 0) and
|
||||
weaponManager.ammoManager.ammoDict[cW.ammoType] >= cW.nbProjShotsAtSameTime):
|
||||
|
||||
weaponManager.weaponSoundManagement(cW.shootSound, cW.shootSoundSpeed)
|
||||
|
||||
if cW.shootAnimName != "":
|
||||
weaponManager.animManager.playAnimation("ShootAnim%s" % cW.weaponName, cW.shootAnimSpeed, true)
|
||||
else:
|
||||
print("%s doesn't have a shoot animation" % cW.weaponName)
|
||||
|
||||
#number projectiles shots at the same time (for example,
|
||||
#a shotgun shell is constituted of ~ 20 pellets that are spread across the target,
|
||||
#so 20 projectiles shots at the same time)
|
||||
for j in range(0, cW.nbProjShotsAtSameTime):
|
||||
if cW.allAmmoInMag: weaponManager.ammoManager.ammoDict[cW.ammoType] -= 1
|
||||
else: cW.totalAmmoInMag -= 1
|
||||
|
||||
#get the collision point
|
||||
pointOfCollision = getCameraPOV()
|
||||
|
||||
#call the fonction corresponding to the selected type
|
||||
if cW.type == cW.types.HITSCAN: hitscanShot(pointOfCollision)
|
||||
elif cW.type == cW.types.PROJECTILE: projectileShot(pointOfCollision)
|
||||
|
||||
if cW.showMuzzleFlash: weaponManager.displayMuzzleFlash()
|
||||
|
||||
weaponManager.cameraRecoilHolder.setRecoilValues(cW.baseRotSpeed, cW.targetRotSpeed)
|
||||
weaponManager.cameraRecoilHolder.addRecoil(cW.recoilVal)
|
||||
|
||||
await get_tree().create_timer(cW.timeBetweenShots).timeout
|
||||
|
||||
else:
|
||||
print("Not enought ammunitions to shoot")
|
||||
|
||||
cW.isShooting = false
|
||||
|
||||
func getCameraPOV():
|
||||
var camera : Camera3D = %Camera
|
||||
var window : Window = get_window()
|
||||
var viewport : Vector2i
|
||||
|
||||
#match viewport to window size, to ensure that the raycast goes in the right direction
|
||||
match window.content_scale_mode:
|
||||
window.CONTENT_SCALE_MODE_VIEWPORT:
|
||||
viewport = window.content_scale_size
|
||||
window.CONTENT_SCALE_MODE_CANVAS_ITEMS:
|
||||
viewport = window.content_scale_size
|
||||
window.CONTENT_SCALE_MODE_DISABLED:
|
||||
viewport = window.get_size()
|
||||
|
||||
#Start raycast in camera position, and launch it in camera direction
|
||||
var raycastStart = camera.project_ray_origin(viewport/2)
|
||||
var raycastEnd
|
||||
if cW.type == cW.types.HITSCAN: raycastEnd = raycastStart + camera.project_ray_normal(viewport/2) * cW.maxRange
|
||||
if cW.type == cW.types.PROJECTILE: raycastEnd = raycastStart + camera.project_ray_normal(viewport/2) * 280
|
||||
|
||||
#Create intersection space to contain possible collisions
|
||||
var newIntersection = PhysicsRayQueryParameters3D.create(raycastStart, raycastEnd)
|
||||
var intersection = get_world_3d().direct_space_state.intersect_ray(newIntersection)
|
||||
|
||||
#If the raycast has collide with something, return collision point transform properties
|
||||
if !intersection.is_empty():
|
||||
var collisionPoint = intersection.position
|
||||
return collisionPoint
|
||||
#Else, return the end of the raycast (so nothing, because he hasn't collide with anything)
|
||||
else:
|
||||
return raycastEnd
|
||||
|
||||
|
||||
|
||||
|
||||
func hitscanShot(pointOfCollisionHitscan : Vector3):
|
||||
rng = RandomNumberGenerator.new()
|
||||
|
||||
#set up weapon shot sprad
|
||||
var spread = Vector3(rng.randf_range(cW.minSpread, cW.maxSpread), rng.randf_range(cW.minSpread, cW.maxSpread), rng.randf_range(cW.minSpread, cW.maxSpread))
|
||||
|
||||
#calculate direction of the hitscan bullet
|
||||
var hitscanBulletDirection = (pointOfCollisionHitscan - cW.weaponSlot.attackPoint.get_global_transform().origin).normalized()
|
||||
|
||||
#create new intersection space to contain possibe collisions
|
||||
var newIntersection = PhysicsRayQueryParameters3D.create(cW.weaponSlot.attackPoint.get_global_transform().origin, pointOfCollisionHitscan + spread + hitscanBulletDirection * 2)
|
||||
newIntersection.collide_with_areas = true
|
||||
newIntersection.collide_with_bodies = true
|
||||
var hitscanBulletCollision = get_world_3d().direct_space_state.intersect_ray(newIntersection)
|
||||
|
||||
#if the raycast has collide
|
||||
if hitscanBulletCollision:
|
||||
var collider = hitscanBulletCollision.collider
|
||||
var colliderPoint = hitscanBulletCollision.position
|
||||
var colliderNormal = hitscanBulletCollision.normal
|
||||
var finalDamage : int
|
||||
|
||||
# --- НАНЕСЕНИЕ УРОНА ВРАГАМ ---
|
||||
if collider.is_in_group("Enemies"):
|
||||
finalDamage = cW.damagePerProj * cW.damageDropoff.sample(pointOfCollisionHitscan.distance_to(global_position) / cW.maxRange)
|
||||
|
||||
# Ищем HealthComponent внутри врага
|
||||
var enemy_health = collider.find_child("HealthComponent", true, false)
|
||||
if enemy_health:
|
||||
enemy_health.take_damage(finalDamage)
|
||||
|
||||
# --- СПАВН КРАСНЫХ КВАДРАТИКОВ (ИМПАКТ) ---
|
||||
# Переменная blood_particles_scene должна быть объявлена в самом верху скрипта ShootManager
|
||||
if has_node("blood_particles_scene") or (typeof(blood_particles_scene) if "blood_particles_scene" in self else null):
|
||||
var particles_instance = blood_particles_scene.instantiate()
|
||||
get_tree().get_root().add_child(particles_instance)
|
||||
particles_instance.global_position = colliderPoint # Ставим в точку попадания
|
||||
|
||||
if collider.has_method("hitscanHit"):
|
||||
collider.hitscanHit(finalDamage, hitscanBulletDirection, hitscanBulletCollision.position)
|
||||
|
||||
elif collider.is_in_group("EnemiesHead"):
|
||||
finalDamage = cW.damagePerProj * cW.headshotDamageMult * cW.damageDropoff.sample(pointOfCollisionHitscan.distance_to(global_position) / cW.maxRange)
|
||||
|
||||
var enemy_health = collider.find_child("HealthComponent", true, false)
|
||||
if enemy_health:
|
||||
enemy_health.take_damage(finalDamage)
|
||||
|
||||
# --- СПАВН КРАСНЫХ КВАДРАТИКОВ (ИМПАКТ В ГОЛОВУ) ---
|
||||
if "blood_particles_scene" in self and blood_particles_scene != null:
|
||||
var particles_instance = blood_particles_scene.instantiate()
|
||||
get_tree().get_root().add_child(particles_instance)
|
||||
particles_instance.global_position = colliderPoint
|
||||
|
||||
if collider.has_method("hitscanHit"):
|
||||
collider.hitscanHit(finalDamage, hitscanBulletDirection, hitscanBulletCollision.position)
|
||||
|
||||
elif collider.is_in_group("HitableObjects"):
|
||||
finalDamage = cW.damagePerProj * cW.damageDropoff.sample(pointOfCollisionHitscan.distance_to(global_position) / cW.maxRange)
|
||||
|
||||
var enemy_health = collider.find_child("HealthComponent", true, false)
|
||||
if enemy_health:
|
||||
enemy_health.take_damage(finalDamage / 6.0)
|
||||
|
||||
if collider.has_method("hitscanHit"):
|
||||
collider.hitscanHit(finalDamage/6.0, hitscanBulletDirection, hitscanBulletCollision.position)
|
||||
weaponManager.displayBulletHole(colliderPoint, colliderNormal)
|
||||
|
||||
else:
|
||||
weaponManager.displayBulletHole(colliderPoint, colliderNormal)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func projectileShot(pointOfCollisionProjectile : Vector3):
|
||||
rng = RandomNumberGenerator.new()
|
||||
|
||||
#set up weapon shot sprad
|
||||
var spread = Vector3(rng.randf_range(cW.minSpread, cW.maxSpread), rng.randf_range(cW.minSpread, cW.maxSpread), rng.randf_range(cW.minSpread, cW.maxSpread))
|
||||
|
||||
#Calculate direction of the projectile
|
||||
var projectileDirection = ((pointOfCollisionProjectile - cW.weaponSlot.attackPoint.get_global_transform().origin).normalized() + spread)
|
||||
|
||||
#Instantiate projectile
|
||||
var projInstance = cW.projRef.instantiate()
|
||||
|
||||
#set projectile properties
|
||||
projInstance.global_transform = cW.weaponSlot.attackPoint.global_transform
|
||||
projInstance.direction = projectileDirection
|
||||
projInstance.damage = cW.damagePerProj
|
||||
projInstance.timeBeforeVanish = cW.projTimeBeforeVanish
|
||||
projInstance.gravity_scale = cW.projGravityVal
|
||||
projInstance.isExplosive = cW.isProjExplosive
|
||||
|
||||
get_tree().get_root().add_child(projInstance)
|
||||
|
||||
projInstance.set_linear_velocity(projectileDirection * cW.projMoveSpeed)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://pufyqjrkl22t
|
||||
@@ -0,0 +1,216 @@
|
||||
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)
|
||||
|
||||
func enterWeapon(nextWeapon : int):
|
||||
#this function manage the second part of the weapon switching mechanic
|
||||
#in this part, the next weapon is enabled (equiped and set up)
|
||||
cW = weaponList[nextWeapon]
|
||||
nextWeapon = 0
|
||||
cWModel = cW.weaponSlot.model
|
||||
cWModel.visible = true
|
||||
|
||||
shootManager.getCurrentWeapon(cW)
|
||||
reloadManager.getCurrentWeapon(cW)
|
||||
animManager.getCurrentWeapon(cW, cWModel)
|
||||
|
||||
weaponSoundManagement(cW.equipSound, cW.equipSoundSpeed)
|
||||
|
||||
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
|
||||
canUseWeapon = true
|
||||
canChangeWeapons = true
|
||||
|
||||
func _process(_delta : float):
|
||||
if cW != null and cWModel != null and canUseWeapon:
|
||||
weaponInputs()
|
||||
|
||||
reloadManager.autoReload()
|
||||
|
||||
displayStats()
|
||||
|
||||
func weaponInputs():
|
||||
if Input.is_action_pressed(shoot_action): shootManager.shoot()
|
||||
|
||||
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])
|
||||
|
||||
func displayStats():
|
||||
hud.displayWeaponStack(weaponStack.size())
|
||||
hud.displayWeaponName(cW.weaponName)
|
||||
hud.displayTotalAmmoInMag(cW.totalAmmoInMag, cW.nbProjShotsAtSameTime)
|
||||
hud.displayTotalAmmo(ammoManager.ammoDict[cW.ammoType], cW.nbProjShotsAtSameTime)
|
||||
|
||||
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
|
||||
|
||||
func displayBulletHole(colliderPoint : Vector3, colliderNormal : Vector3):
|
||||
#create a muzzle flash instance, and display it at the indicated point
|
||||
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)
|
||||
|
||||
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] Оружие полностью разблокировано.")
|
||||
@@ -0,0 +1 @@
|
||||
uid://d2jpda3mq5jpa
|
||||
@@ -0,0 +1,106 @@
|
||||
extends Resource
|
||||
|
||||
class_name WeaponResource
|
||||
|
||||
@export_group("General variables")
|
||||
@export var weaponName : String
|
||||
@export var weaponId : int
|
||||
var weaponSlot : WeaponSlot
|
||||
|
||||
@export_group("Type variables")
|
||||
enum types
|
||||
{
|
||||
NULL, HITSCAN, PROJECTILE
|
||||
}
|
||||
@export var type = types.NULL
|
||||
|
||||
@export_group("Animation variables")
|
||||
@export var animBlendTime : float
|
||||
@export var equipAnimName : String
|
||||
@export var equipAnimSpeed : float = 1.0
|
||||
@export var unequipAnimName : String
|
||||
@export var unequipAnimSpeed : float = 1.0
|
||||
@export var shootAnimName : String
|
||||
@export var shootAnimSpeed : float = 1.0
|
||||
@export var reloadAnimName : String
|
||||
@export var reloadAnimSpeed : float = 1.0
|
||||
|
||||
@export_group("Sound variables")
|
||||
@export var equipSound : AudioStream
|
||||
@export var equipSoundSpeed : float = 1.0
|
||||
@export var unequipSound : AudioStream
|
||||
@export var unequipSoundSpeed : float = 1.0
|
||||
@export var shootSound : AudioStream
|
||||
@export var shootSoundSpeed : float = 1.0
|
||||
@export var reloadSound : AudioStream
|
||||
@export var reloadSoundSpeed : float = 1.0
|
||||
|
||||
@export_group("Ammunition variables")
|
||||
@export var totalAmmoInMag : int
|
||||
@export var totalAmmoInMagRef : int
|
||||
@export var ammoType : String
|
||||
@export var allAmmoInMag : bool = false
|
||||
|
||||
@export_group("Equip variables")
|
||||
@export var equipTime : float
|
||||
|
||||
@export_group("Unequip variables")
|
||||
@export var unequipTime : float
|
||||
|
||||
@export_group("Shoot variables")
|
||||
var isShooting : bool = false
|
||||
@export var canAutoShoot : bool
|
||||
@export var nbProjShotsAtSameTime : int
|
||||
@export var nbProjShots : int
|
||||
@export var minSpread : float
|
||||
@export var maxSpread : float
|
||||
@export var maxRange : float
|
||||
@export var damagePerProj : float
|
||||
@export var damageDropoff : Curve
|
||||
@export_range(0.0, 15.0, 0.01) var headshotDamageMult : float = 1.0
|
||||
@export var timeBetweenShots : float
|
||||
|
||||
@export_group("Reload variables")
|
||||
var isReloading : bool = false
|
||||
@export var hasToReload : bool = true
|
||||
@export var autoReload : bool = true
|
||||
@export var nbPartsNeeded : int = 1
|
||||
@export var reloadTimePerPart : float
|
||||
|
||||
@export_group("Recoil variables")
|
||||
@export var baseRotSpeed : float = 0.0
|
||||
@export var targetRotSpeed : float = 0.0
|
||||
@export var recoilVal : Vector3 = Vector3.ZERO
|
||||
|
||||
@export_group("Projectile variables")
|
||||
@export var isProjExplosive : bool = false
|
||||
@export var projRef : PackedScene
|
||||
@export var projMoveSpeed : float
|
||||
@export var projTimeBeforeVanish : float
|
||||
@export var projGravityVal : float
|
||||
|
||||
@export_group("Position variables")
|
||||
@export var position : Array[Vector3] = [Vector3.ZERO, Vector3.ZERO]
|
||||
|
||||
@export_group("Tilt variables")
|
||||
@export_range(0.0, 20.0, 0.01) var tiltRotSpeed : float = 0.0
|
||||
@export_range(0.0, 1.0, 0.01) var tiltRotAmount : float = 0.0
|
||||
|
||||
@export_group("Sway variables")
|
||||
@export var minSwayVal : Vector2 = Vector2.ZERO
|
||||
@export var maxSwayVal : Vector2 = Vector2.ZERO
|
||||
@export_range(0, 0.2, 0.01) var swaySpeedPos: float = 0.0
|
||||
@export_range(0, 0.2, 0.01) var swaySpeedRot : float = 0.0
|
||||
@export_range(0, 0.5, 0.01) var swayAmountPos : float = 0.0
|
||||
@export_range(0, 100.0, 0.1) var swayAmountRot : float = 0.0
|
||||
|
||||
@export_group("Bob variables")
|
||||
var bobPos : Array[Vector3]
|
||||
@export_range(0.0, 0.1, 0.001) var bobFreq : float = 0.0
|
||||
@export_range(0.0, 0.1, 0.001) var bobAmount : float = 0.0
|
||||
@export_range(0.0, 50.0, 1.0) var bobSpeed : float = 0.0
|
||||
@export var onIdleBobFreqDivider : float = 0.0
|
||||
|
||||
@export_group("Muzzle flash variables")
|
||||
@export var muzzleFlashRef : PackedScene
|
||||
@export var showMuzzleFlash : bool
|
||||
@@ -0,0 +1 @@
|
||||
uid://bnhfyt5sl8jcd
|
||||
@@ -0,0 +1,8 @@
|
||||
extends Node
|
||||
|
||||
class_name WeaponSlot
|
||||
|
||||
@export var model : Node3D
|
||||
@export var weaponId : int
|
||||
@export var attackPoint : Marker3D
|
||||
@export var muzzleFlashSpawner : Marker3D
|
||||
@@ -0,0 +1 @@
|
||||
uid://bcka80usfl4am
|
||||
@@ -0,0 +1,46 @@
|
||||
extends StaticBody3D
|
||||
|
||||
# ID оружия из WeaponResource (например: 0 - пистолет, 1 - автомат)
|
||||
@export var weaponIdToGive : int = 0
|
||||
|
||||
func _on_detect_area_area_entered(area: Area3D):
|
||||
# Проверяем, что в зону вошел именно игрок
|
||||
if area.get_parent() is PlayerCharacter:
|
||||
var playChar = area.get_parent()
|
||||
|
||||
# 1. Сначала проверяем, есть ли вообще у игрока LinkComponent (как в вашем ящике)
|
||||
var linkComponent : Node3D = playChar.get_node_or_null("LinkComponent")
|
||||
|
||||
if linkComponent != null:
|
||||
# 2. Ищем WeaponManager напрямую внутри игрока (playChar) на любой глубине
|
||||
var weapon_manager = playChar.find_child("WeaponManager", true, false)
|
||||
|
||||
# Если по имени "WeaponManager" не нашло, попробуем найти скрипт, где есть weaponStack
|
||||
if weapon_manager == null:
|
||||
for child in playChar.get_children():
|
||||
if "weaponStack" in child:
|
||||
weapon_manager = child
|
||||
break
|
||||
|
||||
# 3. Если менеджер успешно найден, выполняем подбор
|
||||
if weapon_manager and "weaponStack" in weapon_manager:
|
||||
# Проверяем, нет ли этого оружия уже в инвентаре
|
||||
if not weapon_manager.weaponStack.has(weaponIdToGive):
|
||||
|
||||
# Добавляем ID оружия в стек игрока
|
||||
weapon_manager.weaponStack.append(weaponIdToGive)
|
||||
|
||||
# Обновляем текущий индекс оружия на только что подобранное
|
||||
weapon_manager.weaponIndex = weapon_manager.weaponStack.size() - 1
|
||||
|
||||
# Вызываем оригинальную функцию смены оружия
|
||||
weapon_manager.changeWeapon(weaponIdToGive)
|
||||
|
||||
# Удаляем объект оружия с земли
|
||||
queue_free()
|
||||
else:
|
||||
print("У игрока уже есть это оружие в weaponStack")
|
||||
else:
|
||||
print("КРИТИЧЕСКАЯ ОШИБКА: Узел WeaponManager вообще не найден внутри сцены игрока!")
|
||||
else:
|
||||
print("Player character can't pickup weapons (LinkComponent missing)")
|
||||
@@ -0,0 +1 @@
|
||||
uid://bh4dles0v0tn8
|
||||
Reference in New Issue
Block a user