Implemented battery weapons

This commit is contained in:
Marco 2025-08-13 16:51:56 +02:00
commit 54fa750bca
20 changed files with 372 additions and 264 deletions

View file

@ -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")

View file

@ -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"

View file

@ -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"

View file

@ -5,7 +5,6 @@
[resource]
script = ExtResource("2_p6a7h")
LevelId = 0
MapName = &"iso Test"
MapDescription = null
ScenePath = &"uid://ec4m3geediis"

View file

@ -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"

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -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")

View file

@ -6,5 +6,6 @@ public partial class IsoPlayerStateMachine : StateMachineBase<PlayerState,Charac
{
[Export] public override PlayerState InitialState { get; protected set; } = PlayerState.Init;
[Export] public IsoPlayerStorageModule Storage { get; private set; }
}

View file

@ -1,10 +1,14 @@
using Godot;
using Cirno.Scripts.Components.Actors;
using Godot;
namespace Cirno.Scripts.Components.FSM._3DPlayer;
public partial class IsoPlayerStorageModule : Node
{
[Export] public IsoPlayerFSMProxy Root { get; private set; }
[Export] public ActorResourceProvider Shield { get; private set; }
public Node RootAsNode => Root;
public Vector2 FacingDirection { get; set; } = Vector2.Down;

View file

@ -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;
}

View file

@ -36,6 +36,7 @@ public partial class Shooting : EnemyStateBase3D
//DamageReceiver.HealthProvider.ResourceDepleted += HealthProviderOnResourceDepleted;
EquippedWeapon.WeaponData = Storage.Root.EnemyResource.Weapon;
EquippedWeapon.Init();
_currentStrafeTarget = null;

View file

@ -0,0 +1,9 @@
namespace Cirno.Scripts.Enums;
public enum WeaponAmmoType
{
Infinite,
Ammo,
Shield,
Battery,
}

View file

@ -0,0 +1 @@
uid://0ouvmqwpq4xa

View file

@ -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;

View file

@ -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<Timer>("./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<Bullet3D>(WeaponData.BulletData);
//var bullet = WeaponData.BulletData.BulletScene.Instantiate<Bullet3D>()
bullet.GlobalPosition = Muzzle.GlobalPosition;
//var bullet = this.CreateChildOf<Bullet>(_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<Timer>("./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<Bullet3D>(WeaponData.BulletData);
//var bullet = WeaponData.BulletData.BulletScene.Instantiate<Bullet3D>()
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()
{
}
}

View file

@ -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