From 54fa750bca0665331f78421d6a30f5c689bf670f Mon Sep 17 00:00:00 2001 From: Marco Date: Wed, 13 Aug 2025 16:51:56 +0200 Subject: [PATCH] Implemented battery weapons --- 3D/MapScenes/TestLevel2.tscn | 24 +- Resources/Items/IcicleGun.tres | 5 - Resources/Items/LaserWeapon.tres | 9 +- Resources/Maps/IsoMapTest2.tres | 1 - Resources/StartData/Pistol_Start.tres | 1 - Resources/Weapons/IcicleGun.tres | 5 - Resources/Weapons/IcicleGun_3D.tres | 17 +- Resources/Weapons/IcicleRepeater_t0.tres | 6 - Resources/Weapons/LaserWeapon_3D.tres | 20 + Scenes/Actors/IsoPlayer_FSM.tscn | 6 +- Scenes/Weapons/BaseWeapon_3D.tscn | 6 +- .../FSM/3DPlayer/IsoPlayerStateMachine.cs | 1 + .../FSM/3DPlayer/IsoPlayerStorageModule.cs | 6 +- .../FSM/3DPlayer/PlayerWeaponProvider3D.cs | 2 +- Scripts/Components/FSM/Enemy/3D/Shooting.cs | 1 + Scripts/Enums/WeaponAmmoType.cs | 9 + Scripts/Enums/WeaponAmmoType.cs.uid | 1 + Scripts/Resources/WeaponResource.cs | 5 + Scripts/Weapons/Weapon3D.cs | 454 ++++++++++-------- Sprites/Items/LaserWeapon.png.import | 19 +- 20 files changed, 353 insertions(+), 245 deletions(-) create mode 100644 Resources/Weapons/LaserWeapon_3D.tres create mode 100644 Scripts/Enums/WeaponAmmoType.cs create mode 100644 Scripts/Enums/WeaponAmmoType.cs.uid diff --git a/3D/MapScenes/TestLevel2.tscn b/3D/MapScenes/TestLevel2.tscn index 13c93e1f..57232155 100644 --- a/3D/MapScenes/TestLevel2.tscn +++ b/3D/MapScenes/TestLevel2.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=645 format=4 uid="uid://cupulrjeeivxm"] +[gd_scene load_steps=647 format=4 uid="uid://cupulrjeeivxm"] [ext_resource type="Script" uid="uid://kno58homctew" path="res://addons/func_godot/src/map/func_godot_map.gd" id="1_amw6e"] [ext_resource type="Resource" uid="uid://cx41lsryg5wpm" path="res://3D/TrenchBroom/map_settings.tres" id="2_smtsr"] @@ -30,7 +30,7 @@ [ext_resource type="Material" uid="uid://c47ulvm6n2tgk" path="res://textures/Floors/Floor228.tres" id="19_ue087"] [ext_resource type="Material" uid="uid://bchj40rv0q85g" path="res://textures/Floors/Floor255.tres" id="20_4fwvw"] [ext_resource type="Material" uid="uid://dnegblycwcpc8" path="res://textures/Manual/Blue_Panel_Wall.tres" id="20_aae8v"] -[ext_resource type="Material" path="res://textures/Manual/Chevron.tres" id="20_r2p4f"] +[ext_resource type="Material" uid="uid://dfs1tc2ry78pb" path="res://textures/Manual/Chevron.tres" id="20_r2p4f"] [ext_resource type="Material" uid="uid://bh0uo0cm3cr15" path="res://textures/Various/Various6.tres" id="21_81m4u"] [ext_resource type="Material" uid="uid://crk5xgfn3svey" path="res://textures/Floors/Floor178.tres" id="21_cr7d0"] [ext_resource type="Material" uid="uid://qbhdbykuieqn" path="res://textures/Manual/Floor_Mine_001.tres" id="21_v7uwt"] @@ -111,6 +111,8 @@ [ext_resource type="PackedScene" uid="uid://yath5bvxo3cn" path="res://3D/Scenes/Props/Wall_Emitter_3D.tscn" id="105_64qw8"] [ext_resource type="PackedScene" uid="uid://djm3rsc7ul5jb" path="res://3D/Scenes/Props/Tube_3D_Emitter.tscn" id="106_upccm"] [ext_resource type="Resource" uid="uid://ct1fa2huvy34n" path="res://Resources/Items/Ammo1.tres" id="107_0njqu"] +[ext_resource type="Resource" uid="uid://ckfqrq8a0uj1t" path="res://Resources/Items/LaserWeapon.tres" id="108_r6j3v"] +[ext_resource type="Resource" uid="uid://bgcgeg187vg1h" path="res://Resources/Items/IcicleRepeater.tres" id="109_gbc0s"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0njqu"] albedo_texture = ExtResource("3_bryct") @@ -5594,6 +5596,24 @@ Billboard = true PixelSize = 0.05 metadata/_edit_group_ = true +[node name="Weapon" type="Marker3D" parent="Props"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14.340561, 1.3534348, 29.91616) +script = ExtResource("76_bin7h") +Item = ExtResource("108_r6j3v") +AutoSpawn = true +Billboard = true +PixelSize = 0.05 +metadata/_edit_group_ = true + +[node name="Weapon2" type="Marker3D" parent="Props"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13.757989, 1.3534348, 28.568409) +script = ExtResource("76_bin7h") +Item = ExtResource("109_gbc0s") +AutoSpawn = true +Billboard = true +PixelSize = 0.05 +metadata/_edit_group_ = true + [node name="Ammo3" type="Marker3D" parent="Props"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15.25383, 1.3534348, 28.412422) script = ExtResource("76_bin7h") diff --git a/Resources/Items/IcicleGun.tres b/Resources/Items/IcicleGun.tres index 9379dc4d..d4e6876d 100644 --- a/Resources/Items/IcicleGun.tres +++ b/Resources/Items/IcicleGun.tres @@ -12,17 +12,12 @@ ShortName = &"IC-9" ItemDescription = &"Cirno\'s custom gun, shoots ice pellets and never runs out of ammo" ItemKey = &"ICICLE_GUN" Item = 9 -Tier = 0 -Price = 0 WeaponData = ExtResource("1_itajb") WeaponData3D = ExtResource("3_nh721") Amount = 1 Max = 1 -PickupIfMaxed = false -ConsumeOnUse = false UiType = 14 Selectable = true -AutoPickup = false InventorySprite = ExtResource("2_eaoas") DropScenePath = &"res://Scenes/Items/GenericItem.tscn" DropScenePath3D = &"uid://cnot7sft7lpf3" diff --git a/Resources/Items/LaserWeapon.tres b/Resources/Items/LaserWeapon.tres index c58f28bb..30be5dd1 100644 --- a/Resources/Items/LaserWeapon.tres +++ b/Resources/Items/LaserWeapon.tres @@ -1,8 +1,9 @@ -[gd_resource type="Resource" script_class="LootItem" load_steps=4 format=3 uid="uid://ckfqrq8a0uj1t"] +[gd_resource type="Resource" script_class="LootItem" load_steps=5 format=3 uid="uid://ckfqrq8a0uj1t"] [ext_resource type="Texture2D" uid="uid://d04hnwyg3sqlu" path="res://Sprites/Items/LaserWeapon.png" id="1_h548w"] [ext_resource type="Resource" uid="uid://do0jwf5jhx1i5" path="res://Resources/Weapons/LaserWeapon.tres" id="2_rec72"] [ext_resource type="Script" uid="uid://epnwjptvks3t" path="res://Scripts/Resources/LootItem.cs" id="3_2blkp"] +[ext_resource type="Resource" uid="uid://d2tgk8rnd4sfs" path="res://Resources/Weapons/LaserWeapon_3D.tres" id="3_rec72"] [resource] script = ExtResource("3_2blkp") @@ -11,16 +12,12 @@ ShortName = &"Laser" ItemDescription = &"Laser" ItemKey = &"LASER_WEAPON" Item = 9 -Tier = 0 -Price = 0 WeaponData = ExtResource("2_rec72") +WeaponData3D = ExtResource("3_rec72") Amount = 1 Max = 1 -PickupIfMaxed = false -ConsumeOnUse = false UiType = 22 Selectable = true -AutoPickup = false InventorySprite = ExtResource("1_h548w") DropScenePath = &"res://Scenes/Items/GenericItem.tscn" DropScenePath3D = &"uid://cnot7sft7lpf3" diff --git a/Resources/Maps/IsoMapTest2.tres b/Resources/Maps/IsoMapTest2.tres index 582ad8f1..d8dfaaa8 100644 --- a/Resources/Maps/IsoMapTest2.tres +++ b/Resources/Maps/IsoMapTest2.tres @@ -5,7 +5,6 @@ [resource] script = ExtResource("2_p6a7h") -LevelId = 0 MapName = &"iso Test" MapDescription = null ScenePath = &"uid://ec4m3geediis" diff --git a/Resources/StartData/Pistol_Start.tres b/Resources/StartData/Pistol_Start.tres index aa1efdc5..287cb780 100644 --- a/Resources/StartData/Pistol_Start.tres +++ b/Resources/StartData/Pistol_Start.tres @@ -11,7 +11,6 @@ [resource] script = ExtResource("1_fmydh") -EggIndex = 0 StartingEquipment = Array[ExtResource("1_xjbmv")]([ExtResource("1_juefn"), ExtResource("2_xjbmv")]) RemoveEquipment = Array[ExtResource("1_xjbmv")]([ExtResource("1_wchkt"), ExtResource("2_2v4s6"), ExtResource("3_73lvc"), ExtResource("4_vnxsw")]) metadata/_custom_type_script = "uid://mja0rk7n2kln" diff --git a/Resources/Weapons/IcicleGun.tres b/Resources/Weapons/IcicleGun.tres index 9b164786..b8f7b272 100644 --- a/Resources/Weapons/IcicleGun.tres +++ b/Resources/Weapons/IcicleGun.tres @@ -10,17 +10,12 @@ script = ExtResource("2_m8dps") Name = &"Icicle Gun" BulletData = ExtResource("1_sd6j2") Priority = 1 -AmmoPerShot = 1 RateOfFire = 0.1 BulletCapacity = 100 ReloadTime = 0.1 -AutoReload = true -InfiniteAmmo = true ItemKey = &"ICICLE_GUN" AmmoKey = &"" -BulletsPerShot = 1 SpreadAngle = 5.0 RandomSpread = 2.5 -_rotationOffset = 0.0 ReloadSound = ExtResource("2_sd6j2") ShootSound = ExtResource("3_sd6j2") diff --git a/Resources/Weapons/IcicleGun_3D.tres b/Resources/Weapons/IcicleGun_3D.tres index 3051b165..f0eb0052 100644 --- a/Resources/Weapons/IcicleGun_3D.tres +++ b/Resources/Weapons/IcicleGun_3D.tres @@ -9,18 +9,17 @@ script = ExtResource("4_ld57e") Name = &"Icicle Gun" BulletData = ExtResource("1_d2kl0") -Priority = 1 -AmmoPerShot = 1 -RateOfFire = 0.1 +Priority = 10 +AmmoPerShot = 5 +RateOfFire = 0.052999999999883585 BulletCapacity = 100 -ReloadTime = 0.1 -AutoReload = true -InfiniteAmmo = true +ReloadTime = 0.5 +InfiniteAmmo = false ItemKey = &"ICICLE_GUN" -AmmoKey = &"" -BulletsPerShot = 1 +AmmoKey = &"BATTERY" +RechargeTime = 0.19999999999708962 +RechargeAmount = 5 SpreadAngle = 5.0 RandomSpread = 2.5 -_rotationOffset = 0.0 ReloadSound = ExtResource("2_sdmjb") ShootSound = ExtResource("3_hj8fq") diff --git a/Resources/Weapons/IcicleRepeater_t0.tres b/Resources/Weapons/IcicleRepeater_t0.tres index 18743e48..57146909 100644 --- a/Resources/Weapons/IcicleRepeater_t0.tres +++ b/Resources/Weapons/IcicleRepeater_t0.tres @@ -10,17 +10,11 @@ script = ExtResource("4_ai75q") Name = &"Icicle Repeater" BulletData = ExtResource("1_2567x") Priority = 10 -AmmoPerShot = 1 RateOfFire = 0.05 BulletCapacity = 6 ReloadTime = 0.5 -AutoReload = true InfiniteAmmo = false ItemKey = &"ICICLE_REPEATER_T0" AmmoKey = &"ICE_AMMO" -BulletsPerShot = 1 -SpreadAngle = 0.0 -RandomSpread = 0.0 -_rotationOffset = 0.0 ReloadSound = ExtResource("2_2sfo4") ShootSound = ExtResource("3_3qbca") diff --git a/Resources/Weapons/LaserWeapon_3D.tres b/Resources/Weapons/LaserWeapon_3D.tres new file mode 100644 index 00000000..dae9aa9c --- /dev/null +++ b/Resources/Weapons/LaserWeapon_3D.tres @@ -0,0 +1,20 @@ +[gd_resource type="Resource" script_class="WeaponResource" load_steps=4 format=3 uid="uid://d2tgk8rnd4sfs"] + +[ext_resource type="Resource" uid="uid://csmq6hngkx41e" path="res://Resources/Bullets/3D/icicle_gun_bullets_3D.tres" id="1_boxvv"] +[ext_resource type="AudioStream" uid="uid://c1au3v0mynil8" path="res://SFX/Weapons/Laser_shoot 7.wav" id="2_f21bu"] +[ext_resource type="Script" uid="uid://b6fmrnipv88bk" path="res://Scripts/Resources/WeaponResource.cs" id="4_wga0n"] + +[resource] +script = ExtResource("4_wga0n") +Name = &"Laser" +BulletData = ExtResource("1_boxvv") +Priority = 1 +AmmoPerShot = 2 +RateOfFire = 0.3000000000029104 +BulletCapacity = 5 +ReloadTime = 0.6000000000058208 +ItemKey = &"LASER_WEAPON" +AmmoKey = &"SHIELD" +SpreadAngle = 5.0 +RandomSpread = 2.5 +ShootSound = ExtResource("2_f21bu") diff --git a/Scenes/Actors/IsoPlayer_FSM.tscn b/Scenes/Actors/IsoPlayer_FSM.tscn index 2e43f68b..7baabbf6 100644 --- a/Scenes/Actors/IsoPlayer_FSM.tscn +++ b/Scenes/Actors/IsoPlayer_FSM.tscn @@ -202,8 +202,9 @@ collision_mask = 17 script = ExtResource("1_cc7e7") PlayerFSM = NodePath("StateMachine") -[node name="StateMachine" type="Node" parent="."] +[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("Storage")] script = ExtResource("1_vsywg") +Storage = NodePath("../Storage") [node name="Init" type="Node" parent="StateMachine"] script = ExtResource("2_3oyrx") @@ -288,9 +289,10 @@ Deceleration = 20.0 Gravity = -20.0 FallSpeed = 4.0 -[node name="Storage" type="Node" parent="." node_paths=PackedStringArray("Root")] +[node name="Storage" type="Node" parent="." node_paths=PackedStringArray("Root", "Shield")] script = ExtResource("6_habpy") Root = NodePath("..") +Shield = NodePath("../DamageReceiver/ShieldProvider") [node name="MouseAimProvider" type="Node3D" parent="."] script = ExtResource("9_2ffwi") diff --git a/Scenes/Weapons/BaseWeapon_3D.tscn b/Scenes/Weapons/BaseWeapon_3D.tscn index 32936ce3..1522a3ca 100644 --- a/Scenes/Weapons/BaseWeapon_3D.tscn +++ b/Scenes/Weapons/BaseWeapon_3D.tscn @@ -1,12 +1,10 @@ -[gd_scene load_steps=4 format=3 uid="uid://cfgc6ik8vb08c"] +[gd_scene load_steps=3 format=3 uid="uid://cfgc6ik8vb08c"] [ext_resource type="Script" uid="uid://dutroqc0grqyv" path="res://Scripts/Weapons/Weapon3D.cs" id="1_gdxml"] -[ext_resource type="Resource" uid="uid://b8apu0l5fm4k" path="res://Resources/Weapons/IcicleGun.tres" id="2_s6td3"] [ext_resource type="Texture2D" uid="uid://duwiasewxvcb5" path="res://Sprites/Items/Icicle_Gun.png" id="3_6jcxd"] [node name="Weapon" type="Node3D" node_paths=PackedStringArray("Muzzle", "Pivot", "Sprite")] script = ExtResource("1_gdxml") -WeaponData = ExtResource("2_s6td3") Muzzle = NodePath("Muzzle") Pivot = NodePath("Pivot") Sprite = NodePath("Sprite3D") @@ -19,6 +17,8 @@ Sprite = NodePath("Sprite3D") one_shot = true [node name="Sprite3D" type="Sprite3D" parent="."] +visible = false +pixel_size = 0.05 billboard = 1 texture_filter = 0 texture = ExtResource("3_6jcxd") diff --git a/Scripts/Components/FSM/3DPlayer/IsoPlayerStateMachine.cs b/Scripts/Components/FSM/3DPlayer/IsoPlayerStateMachine.cs index 90a13e4a..350dee66 100644 --- a/Scripts/Components/FSM/3DPlayer/IsoPlayerStateMachine.cs +++ b/Scripts/Components/FSM/3DPlayer/IsoPlayerStateMachine.cs @@ -6,5 +6,6 @@ public partial class IsoPlayerStateMachine : StateMachineBase Root; public Vector2 FacingDirection { get; set; } = Vector2.Down; diff --git a/Scripts/Components/FSM/3DPlayer/PlayerWeaponProvider3D.cs b/Scripts/Components/FSM/3DPlayer/PlayerWeaponProvider3D.cs index 5bed6303..6616daaf 100644 --- a/Scripts/Components/FSM/3DPlayer/PlayerWeaponProvider3D.cs +++ b/Scripts/Components/FSM/3DPlayer/PlayerWeaponProvider3D.cs @@ -229,7 +229,7 @@ public partial class PlayerWeaponProvider3D : Node weapon.WeaponData = startingItem.WeaponData3D; weapon.Sprite.Texture = startingItem.InventorySprite; - + weapon.Init(); this.AddWeapon(weapon); return weapon; } diff --git a/Scripts/Components/FSM/Enemy/3D/Shooting.cs b/Scripts/Components/FSM/Enemy/3D/Shooting.cs index 5d00c861..91ba3303 100644 --- a/Scripts/Components/FSM/Enemy/3D/Shooting.cs +++ b/Scripts/Components/FSM/Enemy/3D/Shooting.cs @@ -36,6 +36,7 @@ public partial class Shooting : EnemyStateBase3D //DamageReceiver.HealthProvider.ResourceDepleted += HealthProviderOnResourceDepleted; EquippedWeapon.WeaponData = Storage.Root.EnemyResource.Weapon; + EquippedWeapon.Init(); _currentStrafeTarget = null; diff --git a/Scripts/Enums/WeaponAmmoType.cs b/Scripts/Enums/WeaponAmmoType.cs new file mode 100644 index 00000000..5d3f8834 --- /dev/null +++ b/Scripts/Enums/WeaponAmmoType.cs @@ -0,0 +1,9 @@ +namespace Cirno.Scripts.Enums; + +public enum WeaponAmmoType +{ + Infinite, + Ammo, + Shield, + Battery, +} \ No newline at end of file diff --git a/Scripts/Enums/WeaponAmmoType.cs.uid b/Scripts/Enums/WeaponAmmoType.cs.uid new file mode 100644 index 00000000..567ceac5 --- /dev/null +++ b/Scripts/Enums/WeaponAmmoType.cs.uid @@ -0,0 +1 @@ +uid://0ouvmqwpq4xa diff --git a/Scripts/Resources/WeaponResource.cs b/Scripts/Resources/WeaponResource.cs index 571ffdf5..43a34ed0 100644 --- a/Scripts/Resources/WeaponResource.cs +++ b/Scripts/Resources/WeaponResource.cs @@ -34,6 +34,11 @@ public partial class WeaponResource : Resource [Export] public StringName ItemKey; [Export] public StringName AmmoKey; + + [ExportCategory("Battery Recharge")] + [Export] public double RechargeTime = 0.5d; + [Export]public int RechargeAmount = 1; + #region Bullet spawn data [ExportCategory("Bullet Spawn Data")] [Export] public int BulletsPerShot = 1; diff --git a/Scripts/Weapons/Weapon3D.cs b/Scripts/Weapons/Weapon3D.cs index 0c9b01f5..29d640e5 100644 --- a/Scripts/Weapons/Weapon3D.cs +++ b/Scripts/Weapons/Weapon3D.cs @@ -1,4 +1,5 @@ using Cirno.Scripts.Controllers; +using Cirno.Scripts.Enums; using Cirno.Scripts.Resources; using Cirno.Scripts.Utils; using Godot; @@ -7,220 +8,279 @@ namespace Cirno.Scripts.Weapons; public partial class Weapon3D : Node3D { - [Export] - public WeaponResource WeaponData { get; set; } + [Export] public WeaponResource WeaponData { get; set; } - [Export] - public PackedScene BulletScene { get; set; } - - [Export] - public Marker3D Muzzle { get; set; } - - [Export] - public Marker3D Pivot { get; set; } - - [Export] - public Sprite3D Sprite { get; private set; } + [Export] public PackedScene BulletScene { get; set; } - [Export] public StringName PowerKey { get; set; } = "POWER"; - - [Signal] - public delegate void ShootingEventHandler(); + [Export] public Marker3D Muzzle { get; set; } - [Signal] - public delegate void ReloadingEventHandler(); - - [Signal] public delegate void EmptyEventHandler(); - - public int Ammo { get; set; } = 0; + [Export] public Marker3D Pivot { get; set; } - private int _loadedAmmo; - public int LoadedAmmo - { - get => _loadedAmmo; - private set - { - _loadedAmmo = value; - InventoryManager.Instance?.NotifyLoadedAmmoChange(WeaponData?.ItemKey, _loadedAmmo); - } - } - - public Vector2 ShootDirection { get; set; } = Vector2.Zero; - - private Timer _cooldownTimer; - - private GameManager _gameManager; + [Export] public Sprite3D Sprite { get; private set; } - private readonly StringName _shieldAmmoType = "SHIELD"; - private bool UsesBattery => WeaponData.AmmoKey == _shieldAmmoType; - - // Called when the node enters the scene tree for the first time. - public override void _Ready() - { - _cooldownTimer = GetNode("./ShootTimer"); - - // Start full - if (WeaponData != null) - { - LoadedAmmo = WeaponData.BulletCapacity; - } - } + [Export] public StringName PowerKey { get; set; } = "POWER"; - public void Reload() - { - EmitSignalReloading(); - - _cooldownTimer.Start(WeaponData.ReloadTime); - - if (WeaponData.InfiniteAmmo || string.IsNullOrWhiteSpace(WeaponData.AmmoKey)) - { - LoadedAmmo = WeaponData.BulletCapacity; - } - else - { - var ammoToLoad = InventoryManager.Instance.RemoveItem(WeaponData.AmmoKey, WeaponData.BulletCapacity - LoadedAmmo); - - if (ammoToLoad > 0) - { - LoadedAmmo = ammoToLoad; - } - else - { - EmitSignalEmpty(); - //GD.Print("Out of ammo"); - } - } - } + [Signal] + public delegate void ShootingEventHandler(); - public void Shoot(BulletOwner? ownerOverride = null) - { - // Waiting on reload or Rate of Fire cooldown? - if (!_cooldownTimer.IsStopped()) - { - return; - } + [Signal] + public delegate void ReloadingEventHandler(); - // Check for battery if it's used - // if (UsesBattery) - // { - // if (GameManager.Instance.Player.Shield.CurrentResource >= WeaponData.AmmoPerShot) - // { - // GameManager.Instance.Player.Shield.CurrentResource -= WeaponData.AmmoPerShot; - // } - // else - // { - // EmitSignalEmpty(); - // return; - // } - // } - - // Out of ammo? - if (LoadedAmmo < WeaponData.AmmoPerShot) - { - if (WeaponData.AutoReload) - { - Reload(); - } - EmitSignalEmpty(); - return; - } - - EmitSignalShooting(); - - // TODO: Shoot at muzzle position, need to provide a way to turn it, on a radius? + [Signal] + public delegate void EmptyEventHandler(); - float halfSpread = WeaponData.SpreadAngle / 2f; - float spreadStep = WeaponData.BulletsPerShot > 1 ? WeaponData.SpreadAngle / (WeaponData.BulletsPerShot - 1) : 0; - - for (int i = 0; i < WeaponData.BulletsPerShot; i++) - { - // Calculate angle offset for this bullet - float spreadOffset = -halfSpread + (spreadStep * i); + public int Ammo { get; set; } = 0; - // Add random spread - if (WeaponData.RandomSpread > 0) - { - // Gaussian with mean = 0, stddev = WeaponData.RandomSpread - spreadOffset += RandomStuff.GaussianClamped( - mean: 0f, - stdDev: WeaponData.RandomSpread, // tuning knob - min: -halfSpread, - max: halfSpread - ); - } - - // Rotate the ShootDirection by the spread angle - Vector2 spreadDirection = ShootDirection.Rotated(Mathf.DegToRad(spreadOffset)); + private int _loadedAmmo; - // Restore pooling - var bullet = PoolingManager.Instance.SpawnBullet(WeaponData.BulletData); - - //var bullet = WeaponData.BulletData.BulletScene.Instantiate() - - bullet.GlobalPosition = Muzzle.GlobalPosition; - - //var bullet = this.CreateChildOf(_gameManager.BulletsContainer, WeaponData.BulletData.BulletScene, _muzzle.GlobalPosition); + public int LoadedAmmo + { + get => _loadedAmmo; + private set + { + _loadedAmmo = value; + InventoryManager.Instance?.NotifyLoadedAmmoChange(WeaponData?.ItemKey, _loadedAmmo); + } + } - if (bullet == null) - { - GD.PrintErr("Bullet is null, not shooting"); - return; - }; - - var bulletData = WeaponData.MakeBullet(Muzzle.GlobalPosition.ToVector2()); // TODO: Fix for 3D - if (ownerOverride.HasValue) - { - bulletData.Owner = ownerOverride.Value; - } + public Vector2 ShootDirection { get; set; } = Vector2.Zero; - if (bulletData.Owner is BulletOwner.Player || ownerOverride is BulletOwner.Player) - { - // Apply the P multiplier - bulletData.Damage *= - GetBulletStrengthMultiplier(bulletData.Damage, bulletData.OriginalBulletResource.MaxDamage, 20); - } - - bullet.Initialize(bulletData); - - //bullet.SetDirection(ShootDirection); - bullet.SetDirection(spreadDirection); - bullet.Speed = WeaponData.BulletData.BulletSpeed; - } + private Timer _cooldownTimer; + private Timer _rechargeTimer; - if (!UsesBattery) - { - LoadedAmmo -= WeaponData.AmmoPerShot; - } - - //_inventoryManager.NotifyLoadedAmmoChange(WeaponData.ItemKey, LoadedAmmo); - // if (!string.IsNullOrWhiteSpace(WeaponData?.AmmoKey)) - // { - // // Notify hud to decrease weapon - // - // } - - _cooldownTimer.Start(WeaponData?.RateOfFire ?? 0); - } + private GameManager _gameManager; - private float GetBulletStrengthMultiplier(float baseDamage, float maxDamage, float maxPower) - { - var p = InventoryManager.Instance.GetItemCount(PowerKey); + private readonly StringName _shieldAmmoType = "SHIELD"; + private readonly StringName _batteryAmmoType = "BATTERY"; + //private bool UsesBattery => WeaponData.AmmoKey == _shieldAmmoType; - float minMultiplier = 1.0f; - float maxMultiplier = maxDamage / baseDamage; + private WeaponAmmoType _ammoType = WeaponAmmoType.Infinite; - float normalizedPower = Mathf.Clamp((float)p / maxPower, 0f, 1f); - return Mathf.Lerp(minMultiplier, maxMultiplier, normalizedPower); - } - public void Hide() - { - - } + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + _cooldownTimer = GetNode("./ShootTimer"); + + //Init(); + } - public void Show() - { - - } - + public void Init() + { + SetAmmoType(); + + if (_ammoType is WeaponAmmoType.Battery && _rechargeTimer is null) + { + _rechargeTimer = new Timer(); + this.AddChild(_rechargeTimer); + _rechargeTimer.Timeout += RechargeTimerOnTimeout; + + _rechargeTimer.Start(WeaponData.RechargeTime); + } + + // Start full + if (WeaponData != null) + { + LoadedAmmo = WeaponData.BulletCapacity; + } + } + + private void RechargeTimerOnTimeout() + { + if (LoadedAmmo < WeaponData.BulletCapacity) + { + LoadedAmmo += WeaponData.RechargeAmount; + } + + _rechargeTimer.Start(WeaponData.RechargeTime); + } + + private void SetAmmoType() + { + if (WeaponData.InfiniteAmmo || string.IsNullOrWhiteSpace(WeaponData.AmmoKey)) + { + _ammoType = WeaponAmmoType.Infinite; + return; + } + + if (WeaponData.AmmoKey == _shieldAmmoType) + { + _ammoType = WeaponAmmoType.Shield; + return; + } + + if (WeaponData.AmmoKey == _batteryAmmoType) + { + _ammoType = WeaponAmmoType.Battery; + return; + } + + _ammoType = WeaponAmmoType.Ammo; + } + + public void Reload() + { + EmitSignalReloading(); + + _cooldownTimer.Start(WeaponData.ReloadTime); + + if (_ammoType is WeaponAmmoType.Infinite) + { + LoadedAmmo = WeaponData.BulletCapacity; + } + else + { + var ammoToLoad = + InventoryManager.Instance.RemoveItem(WeaponData.AmmoKey, WeaponData.BulletCapacity - LoadedAmmo); + + if (ammoToLoad > 0) + { + LoadedAmmo = ammoToLoad; + } + else + { + EmitSignalEmpty(); + //GD.Print("Out of ammo"); + } + } + } + + private bool HandlePreShoot() + { + // Waiting on reload or Rate of Fire cooldown? + if (!_cooldownTimer.IsStopped()) + { + return false; + } + + // Handle Shield powered weapons + if (_ammoType is WeaponAmmoType.Shield) + { + if (GameController.Instance.Player.Storage.Shield.CurrentResource >= WeaponData.AmmoPerShot) + { + GameController.Instance.Player.Storage.Shield.CurrentResource -= WeaponData.AmmoPerShot; + } + else + { + EmitSignalEmpty(); + } + _cooldownTimer.Start(WeaponData?.RateOfFire ?? 0); + return false; + } + + // Out of ammo? + if (LoadedAmmo < WeaponData.AmmoPerShot) + { + if (_ammoType is WeaponAmmoType.Ammo && WeaponData.AutoReload) + { + Reload(); + } + + EmitSignalEmpty(); + return false; + } + + if (_ammoType is WeaponAmmoType.Ammo or WeaponAmmoType.Battery) + { + LoadedAmmo -= WeaponData.AmmoPerShot; + } + + return true; + } + + public void Shoot(BulletOwner? ownerOverride = null) + { + if (!HandlePreShoot()) return; + + EmitSignalShooting(); + + // TODO: Shoot at muzzle position, need to provide a way to turn it, on a radius? + + float halfSpread = WeaponData.SpreadAngle / 2f; + float spreadStep = WeaponData.BulletsPerShot > 1 ? WeaponData.SpreadAngle / (WeaponData.BulletsPerShot - 1) : 0; + + for (int i = 0; i < WeaponData.BulletsPerShot; i++) + { + // Calculate angle offset for this bullet + float spreadOffset = -halfSpread + (spreadStep * i); + + // Add random spread + if (WeaponData.RandomSpread > 0) + { + // Gaussian with mean = 0, stddev = WeaponData.RandomSpread + spreadOffset += RandomStuff.GaussianClamped( + mean: 0f, + stdDev: WeaponData.RandomSpread, // tuning knob + min: -halfSpread, + max: halfSpread + ); + } + + // Rotate the ShootDirection by the spread angle + Vector2 spreadDirection = ShootDirection.Rotated(Mathf.DegToRad(spreadOffset)); + + // Restore pooling + var bullet = PoolingManager.Instance.SpawnBullet(WeaponData.BulletData); + + //var bullet = WeaponData.BulletData.BulletScene.Instantiate() + + bullet.GlobalPosition = Muzzle.GlobalPosition; + + var bulletData = WeaponData.MakeBullet(Muzzle.GlobalPosition.ToVector2()); // TODO: Fix for 3D + if (ownerOverride.HasValue) + { + bulletData.Owner = ownerOverride.Value; + } + + if (bulletData.Owner is BulletOwner.Player || ownerOverride is BulletOwner.Player) + { + // Apply the P multiplier + bulletData.Damage *= + GetBulletStrengthMultiplier(bulletData.Damage, bulletData.OriginalBulletResource.MaxDamage, 20); + } + + bullet.Initialize(bulletData); + + //bullet.SetDirection(ShootDirection); + bullet.SetDirection(spreadDirection); + bullet.Speed = WeaponData.BulletData.BulletSpeed; + } + + + + //_inventoryManager.NotifyLoadedAmmoChange(WeaponData.ItemKey, LoadedAmmo); + // if (!string.IsNullOrWhiteSpace(WeaponData?.AmmoKey)) + // { + // // Notify hud to decrease weapon + // + // } + + if (_ammoType is WeaponAmmoType.Ammo && WeaponData.AutoReload) + { + Reload(); + } + else + { + _cooldownTimer.Start(WeaponData?.RateOfFire ?? 0); + } + } + + private float GetBulletStrengthMultiplier(float baseDamage, float maxDamage, float maxPower) + { + var p = InventoryManager.Instance.GetItemCount(PowerKey); + + float minMultiplier = 1.0f; + float maxMultiplier = maxDamage / baseDamage; + + float normalizedPower = Mathf.Clamp((float)p / maxPower, 0f, 1f); + return Mathf.Lerp(minMultiplier, maxMultiplier, normalizedPower); + } + + public void Hide() + { + } + + public void Show() + { + } } \ No newline at end of file diff --git a/Sprites/Items/LaserWeapon.png.import b/Sprites/Items/LaserWeapon.png.import index 13196ecc..ded3a9d4 100644 --- a/Sprites/Items/LaserWeapon.png.import +++ b/Sprites/Items/LaserWeapon.png.import @@ -3,32 +3,39 @@ importer="texture" type="CompressedTexture2D" uid="uid://d04hnwyg3sqlu" -path="res://.godot/imported/LaserWeapon.png-e292e12aa34e57d3d32457a4c9af747e.ctex" +path.s3tc="res://.godot/imported/LaserWeapon.png-e292e12aa34e57d3d32457a4c9af747e.s3tc.ctex" metadata={ -"vram_texture": false +"imported_formats": ["s3tc_bptc"], +"vram_texture": true } [deps] source_file="res://Sprites/Items/LaserWeapon.png" -dest_files=["res://.godot/imported/LaserWeapon.png-e292e12aa34e57d3d32457a4c9af747e.ctex"] +dest_files=["res://.godot/imported/LaserWeapon.png-e292e12aa34e57d3d32457a4c9af747e.s3tc.ctex"] [params] -compress/mode=0 +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=false +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=1 +detect_3d/compress_to=0