mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-09 05:55:54 +00:00
Weapon evolution
This commit is contained in:
parent
8492c3644b
commit
f58b9646df
10 changed files with 209 additions and 68 deletions
|
|
@ -2,6 +2,7 @@
|
|||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Utils;
|
||||
using Cirno.Scripts.Weapons;
|
||||
using Cirno.Scripts.Components.FSM.Enemy._3D;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
|
|
@ -55,14 +56,24 @@ public partial class DamageReceiver3D : Area3D, IHittable
|
|||
return;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
if (BulletGroup is BulletOwner.None)
|
||||
{
|
||||
this.Hit(bullet.Damage, bullet.DamageType);
|
||||
|
||||
EmitSignalBulletHit(bullet, area.GlobalPosition, (this.GlobalPosition - area.GlobalPosition).Normalized());
|
||||
|
||||
// Attribute XP if this hit was lethal
|
||||
if (HealthProvider.CurrentResource <= 0 && bullet.BulletInfo?.SourceWeapon != null)
|
||||
{
|
||||
int xp = 0;
|
||||
if (GetParent() is EnemyProxy3D enemyProxy && enemyProxy.EnemyResource is not null)
|
||||
{
|
||||
xp = (int)System.Math.Round(enemyProxy.EnemyResource.MotivationReward);
|
||||
}
|
||||
|
||||
bullet.BulletInfo.SourceWeapon.GainExperience(xp);
|
||||
}
|
||||
|
||||
bullet.RequestCollisionDestruction();
|
||||
return;
|
||||
}
|
||||
|
|
@ -73,6 +84,18 @@ public partial class DamageReceiver3D : Area3D, IHittable
|
|||
|
||||
EmitSignalBulletHit(bullet, area.GlobalPosition, (this.GlobalPosition - area.GlobalPosition).Normalized());
|
||||
|
||||
// Attribute XP on lethal hit
|
||||
if (HealthProvider.CurrentResource <= 0 && bullet.BulletInfo?.SourceWeapon != null)
|
||||
{
|
||||
int xp = 0;
|
||||
if (GetParent() is EnemyProxy3D enemyProxy && enemyProxy.EnemyResource is not null)
|
||||
{
|
||||
xp = (int)System.Math.Round(enemyProxy.EnemyResource.MotivationReward);
|
||||
}
|
||||
|
||||
bullet.BulletInfo.SourceWeapon.GainExperience(xp);
|
||||
}
|
||||
|
||||
bullet.RequestCollisionDestruction();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,15 @@ public partial class DamageReceiverActorModule : ActorModule, IHittable
|
|||
if (BulletGroup is BulletOwner.None)
|
||||
{
|
||||
this.Hit(bullet.Damage, bullet.DamageType);
|
||||
|
||||
// If this hit killed the actor, attribute XP to the source weapon if present
|
||||
if (HealthProvider.CurrentResource <= 0 && bullet.BulletInfo?.SourceWeapon != null)
|
||||
{
|
||||
// Award XP equal to actor's MotivationReward rounded to int, or a fixed value.
|
||||
var xp = (int)System.Math.Round(_actor.EnemyData?.MotivationReward ?? 0f);
|
||||
bullet.BulletInfo.SourceWeapon.GainExperience(xp);
|
||||
}
|
||||
|
||||
bullet.RequestCollisionDestruction();
|
||||
return;
|
||||
}
|
||||
|
|
@ -55,6 +64,14 @@ public partial class DamageReceiverActorModule : ActorModule, IHittable
|
|||
if (bullet.BulletInfo.Owner == BulletGroup) return;
|
||||
|
||||
this.Hit(bullet.Damage, bullet.DamageType);
|
||||
|
||||
// Attribute XP on lethal hit
|
||||
if (HealthProvider.CurrentResource <= 0 && bullet.BulletInfo?.SourceWeapon != null)
|
||||
{
|
||||
var xp = (int)System.Math.Round(_actor.EnemyData?.MotivationReward ?? 0f);
|
||||
bullet.BulletInfo.SourceWeapon.GainExperience(xp);
|
||||
}
|
||||
|
||||
bullet.RequestCollisionDestruction();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using Cirno.Scripts.Actors._3D;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Utils;
|
||||
using Cirno.Scripts.Weapons;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Components;
|
||||
|
|
@ -49,4 +50,9 @@ public class BulletInfo(BulletResource originalBulletResource)
|
|||
public Color PreFireColor { get; set; } = new Color(1, 0, 0, 0.5f);
|
||||
public Color LethalColor { get; set; } = new Color(1, 0, 0, 1.0f);
|
||||
#endregion
|
||||
|
||||
// Runtime: reference to the Weapon instance that fired this bullet.
|
||||
// This is NOT a Resource and will not be serialized; it simply lets
|
||||
// hit handlers attribute kills to a particular weapon instance.
|
||||
public Weapon3D SourceWeapon { get; set; }
|
||||
}
|
||||
|
|
@ -8,44 +8,47 @@ namespace Cirno.Scripts.Resources;
|
|||
|
||||
[GlobalClass]
|
||||
[Tool]
|
||||
public partial class WeaponResource : Resource
|
||||
public partial class WeaponResource : Resource
|
||||
{
|
||||
[Export]
|
||||
public StringName Name { get; set; }
|
||||
|
||||
[Export] public StringName Name { get; set; }
|
||||
|
||||
[Export] public BulletResource BulletData { get; private set; }
|
||||
|
||||
|
||||
//[Export]
|
||||
//public PackedScene BulletScene { get; set; }
|
||||
|
||||
//[Export] public PackedScene DestructionParticlesScene { get; set; }
|
||||
[Export] public int Priority { get; set; } = 0;
|
||||
[Export] public int AmmoPerShot { get; set; } = 1;
|
||||
//public PackedScene BulletScene { get; set; }
|
||||
|
||||
//[Export] public PackedScene DestructionParticlesScene { get; set; }
|
||||
[Export] public int Priority { get; set; } = 0;
|
||||
[Export] public int AmmoPerShot { get; set; } = 1;
|
||||
|
||||
[Export] public double RateOfFire = 0.4f;
|
||||
|
||||
[Export] public int BulletCapacity = 20;
|
||||
|
||||
[Export] public double ReloadTime = 1.0f;
|
||||
|
||||
[Export] public bool AutoReload = true;
|
||||
|
||||
[Export] public bool InfiniteAmmo = true;
|
||||
|
||||
|
||||
[Export] public int BulletCapacity = 20;
|
||||
|
||||
[Export] public double ReloadTime = 1.0f;
|
||||
|
||||
[Export] public bool AutoReload = true;
|
||||
|
||||
[Export] public bool InfiniteAmmo = true;
|
||||
|
||||
[Export] public StringName ItemKey;
|
||||
[Export] public StringName AmmoKey;
|
||||
|
||||
[ExportCategory("Battery Recharge")]
|
||||
[Export] public double RechargeTime = 0.5d;
|
||||
[Export]public int RechargeAmount = 1;
|
||||
[Export] public bool StopToShoot = false;
|
||||
|
||||
#region Bullet spawn data
|
||||
[ExportCategory("Bullet Spawn Data")]
|
||||
[Export] public int BulletsPerShot = 1;
|
||||
[ExportCategory("Battery Recharge")] [Export]
|
||||
public double RechargeTime = 0.5d;
|
||||
|
||||
[Export] public int RechargeAmount = 1;
|
||||
[Export] public bool StopToShoot = false;
|
||||
|
||||
#region Bullet spawn data
|
||||
|
||||
[ExportCategory("Bullet Spawn Data")] [Export]
|
||||
public int BulletsPerShot = 1;
|
||||
|
||||
[Export] public float SpreadAngle = 0f;
|
||||
|
||||
[Export] public float RandomSpread = 0f;
|
||||
|
||||
[Export] public float SpreadAngle = 0f;
|
||||
[Export] public float RandomSpread = 0f;
|
||||
//[Export] public float BulletSpeed = 100f;
|
||||
//[Export] public float BulletDamage = 1;
|
||||
//[Export] public float LifeTime = 10f;
|
||||
|
|
@ -56,33 +59,43 @@ public partial class WeaponResource : Resource
|
|||
//[Export] private Array<Resource> _timeModifiers;
|
||||
|
||||
#endregion
|
||||
|
||||
[ExportCategory("Sounds")]
|
||||
[Export] public AudioStream ReloadSound { get; set; }
|
||||
|
||||
[ExportCategory("Sounds")] [Export] public AudioStream ReloadSound { get; set; }
|
||||
[Export] public AudioStream ShootSound { get; set; }
|
||||
[Export] public AudioStream EmptySound { get; set; }
|
||||
|
||||
// --------------------------------------------------
|
||||
// Upgrade / progression blueprint data
|
||||
// Resources must remain blueprint-only; these fields describe
|
||||
// how this weapon progresses to the next tier.
|
||||
// --------------------------------------------------
|
||||
|
||||
[Export]
|
||||
public int ExperienceToNextLevel { get; set; } = 0; // XP required to evolve to NextLevelWeapon (0 = no progression)
|
||||
|
||||
[Export] public WeaponResource NextLevelWeapon { get; set; } // Reference to the next-tier weapon resource
|
||||
|
||||
public BulletInfo MakeBullet(Vector2 position)
|
||||
{
|
||||
return BulletData.MakeBullet(position, BulletsPerShot, SpreadAngle, _rotationOffset);
|
||||
|
||||
// return new BulletInfo()
|
||||
// {
|
||||
// Position = position,
|
||||
// Direction = Vector2.Right,
|
||||
// Speed = BulletSpeed,
|
||||
// Owner = owner,
|
||||
// DamageType = _damageType,
|
||||
// Damage = BulletDamage,
|
||||
// BulletCount = BulletsPerShot,
|
||||
// Spread = SpreadAngle,
|
||||
// BulletScene = BulletScene,
|
||||
// RotationOffset = _rotationOffset,
|
||||
// Modifier = _modifier as IBulletModifier,
|
||||
// LifeTime = LifeTime,
|
||||
// DestructionParticlesScene = DestructionParticlesScene,
|
||||
// TimeModifiers = _timeModifiers?.Where(mod => mod is TimeModifier).Cast<TimeModifier>().ToList() ??
|
||||
// new List<TimeModifier>()
|
||||
// };
|
||||
return BulletData.MakeBullet(position, BulletsPerShot, SpreadAngle, _rotationOffset);
|
||||
|
||||
// return new BulletInfo()
|
||||
// {
|
||||
// Position = position,
|
||||
// Direction = Vector2.Right,
|
||||
// Speed = BulletSpeed,
|
||||
// Owner = owner,
|
||||
// DamageType = _damageType,
|
||||
// Damage = BulletDamage,
|
||||
// BulletCount = BulletsPerShot,
|
||||
// Spread = SpreadAngle,
|
||||
// BulletScene = BulletScene,
|
||||
// RotationOffset = _rotationOffset,
|
||||
// Modifier = _modifier as IBulletModifier,
|
||||
// LifeTime = LifeTime,
|
||||
// DestructionParticlesScene = DestructionParticlesScene,
|
||||
// TimeModifiers = _timeModifiers?.Where(mod => mod is TimeModifier).Cast<TimeModifier>().ToList() ??
|
||||
// new List<TimeModifier>()
|
||||
// };
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,9 @@ public partial class Weapon3D : Node3D
|
|||
[Signal]
|
||||
public delegate void InitializedEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void EvolvedEventHandler(WeaponResource newWeaponResource);
|
||||
|
||||
public int Ammo { get; set; } = 0;
|
||||
|
||||
private int _loadedAmmo;
|
||||
|
|
@ -59,6 +62,9 @@ public partial class Weapon3D : Node3D
|
|||
|
||||
private WeaponAmmoType _ammoType = WeaponAmmoType.Infinite;
|
||||
|
||||
// Runtime experience for this weapon instance (NOT stored in resources)
|
||||
private int _currentExperience = 0;
|
||||
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
|
|
@ -150,6 +156,42 @@ public partial class Weapon3D : Node3D
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add experience to this weapon instance. When reaching the threshold defined on the WeaponResource,
|
||||
/// evolve into the configured NextLevelWeapon. Resources are not mutated; the instance swaps its reference
|
||||
/// to the next-tier Resource to reflect the new behavior.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount of experience to add (positive integer)</param>
|
||||
public void GainExperience(int amount)
|
||||
{
|
||||
if (amount <= 0) return;
|
||||
if (WeaponData == null) return;
|
||||
|
||||
// If weapon has no progression, ignore
|
||||
if (WeaponData.ExperienceToNextLevel <= 0 || WeaponData.NextLevelWeapon == null) return;
|
||||
|
||||
_currentExperience += amount;
|
||||
|
||||
while (WeaponData.ExperienceToNextLevel > 0 && _currentExperience >= WeaponData.ExperienceToNextLevel)
|
||||
{
|
||||
// Evolve
|
||||
_currentExperience -= WeaponData.ExperienceToNextLevel;
|
||||
|
||||
var next = WeaponData.NextLevelWeapon;
|
||||
if (next == null) break;
|
||||
|
||||
WeaponData = next;
|
||||
|
||||
// Re-init to apply new capacities / rates
|
||||
Init();
|
||||
|
||||
EmitSignalEvolved(next);
|
||||
|
||||
// Continue loop in case the new tier also has immediate threshold
|
||||
if (WeaponData.ExperienceToNextLevel <= 0 || WeaponData.NextLevelWeapon == null) break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandlePreShoot()
|
||||
{
|
||||
// Waiting on reload or Rate of Fire cooldown?
|
||||
|
|
@ -243,6 +285,9 @@ public partial class Weapon3D : Node3D
|
|||
GetBulletStrengthMultiplier(bulletData.Damage, bulletData.OriginalBulletResource.MaxDamage, 20);
|
||||
}
|
||||
|
||||
// Associate the bullet with this weapon instance so kills can be attributed
|
||||
bulletData.SourceWeapon = this;
|
||||
|
||||
bullet.Initialize(bulletData);
|
||||
|
||||
//bullet.SetDirection(ShootDirection);
|
||||
|
|
@ -252,12 +297,6 @@ public partial class Weapon3D : Node3D
|
|||
|
||||
|
||||
|
||||
//_inventoryManager.NotifyLoadedAmmoChange(WeaponData.ItemKey, LoadedAmmo);
|
||||
// if (!string.IsNullOrWhiteSpace(WeaponData?.AmmoKey))
|
||||
// {
|
||||
// // Notify hud to decrease weapon
|
||||
//
|
||||
// }
|
||||
|
||||
if (_ammoType is WeaponAmmoType.Ammo && WeaponData.AutoReload && LoadedAmmo < WeaponData.AmmoPerShot)
|
||||
{
|
||||
|
|
@ -280,11 +319,11 @@ public partial class Weapon3D : Node3D
|
|||
return Mathf.Lerp(minMultiplier, maxMultiplier, normalizedPower);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
public new void Hide()
|
||||
{
|
||||
}
|
||||
|
||||
public void Show()
|
||||
public new void Show()
|
||||
{
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue