Refactor stats

This commit is contained in:
2025-10-22 16:24:07 -07:00
parent 6ec45c4805
commit f0c4e65783
77 changed files with 565 additions and 372 deletions

View File

@@ -1,12 +1,10 @@
using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.Introspection;
using Chickensoft.SaveFileBuilder;
using Godot;
using SimpleInjector;
using System;
using Zennysoft.Game.Implementation.Components;
using Zennysoft.Ma.Adapter;
using Zennysoft.Ma.Adapter.Entity;
@@ -27,17 +25,19 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
public ISaveChunk<PlayerData> PlayerChunk { get; set; } = default!;
#endregion
public HealthComponent HealthComponent { get; private set; }
public IHealthComponent HealthComponent { get; private set; }
public VTComponent VTComponent { get; private set; }
public IVTComponent VTComponent { get; private set; }
public AttackComponent AttackComponent { get; private set; }
public IAttackComponent AttackComponent { get; private set; }
public DefenseComponent DefenseComponent { get; private set; }
public IDefenseComponent DefenseComponent { get; private set; }
public ExperiencePointsComponent ExperiencePointsComponent { get; private set; }
public IExperiencePointsComponent ExperiencePointsComponent { get; private set; }
public LuckComponent LuckComponent { get; private set; }
public ILuckComponent LuckComponent { get; private set; }
public IEquipmentComponent EquipmentComponent { get; private set; }
public Vector3 CurrentPosition => GlobalPosition;
@@ -45,15 +45,6 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
public IInventory Inventory { get; private set; } = default!;
public AutoProp<EquipableItem> EquippedWeapon => _equippedWeapon;
private AutoProp<EquipableItem> _equippedWeapon { get; set; } = new AutoProp<EquipableItem>(new Weapon());
public AutoProp<EquipableItem> EquippedArmor => _equippedArmor;
private AutoProp<EquipableItem> _equippedArmor { get; set; } = new AutoProp<EquipableItem>(new Armor());
public AutoProp<EquipableItem> EquippedAccessory => _equippedAccessory;
private AutoProp<EquipableItem> _equippedAccessory { get; set; } = new AutoProp<EquipableItem>(new Accessory());
private PlayerLogic.Settings Settings { get; set; } = default!;
private IPlayerLogic PlayerLogic { get; set; } = default!;
@@ -119,14 +110,16 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
private Vector3 _knockbackDirection = Vector3.Zero;
#region Initialization
public void InitializePlayerState()
public Player()
{
Inventory = new Inventory();
SetProcessInput(false);
SetPhysicsProcess(false);
HealthTimer.WaitTime = _healthTimerWaitTime;
HealthTimer.Timeout += OnHealthTimerTimeout;
HealthComponent = new HealthComponent(InitialHP);
VTComponent = new VTComponent(InitialVT);
AttackComponent = new AttackComponent(InitialAttack);
DefenseComponent = new DefenseComponent(InitialDefense);
ExperiencePointsComponent = new ExperiencePointsComponent();
LuckComponent = new LuckComponent(InitialLuck);
EquipmentComponent = new EquipmentComponent();
}
public void Setup()
@@ -138,9 +131,6 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
PlayerLogic.Set(this as IPlayer);
PlayerLogic.Set(Settings);
PlayerLogic.Set(_gameRepo);
Hitbox.AreaEntered += Hitbox_AreaEntered;
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
}
public void OnResolved()
@@ -150,11 +140,13 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
PlayerChunk = new SaveChunk<PlayerData>(
onSave: (chunk) => new PlayerData()
{
Inventory = Inventory
Inventory = (Inventory)Inventory,
HealthComponent = (HealthComponent)HealthComponent
},
onLoad: (chunk, data) =>
{
Inventory = data.Inventory;
HealthComponent = data.HealthComponent;
}
);
@@ -173,22 +165,18 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
PlayerLogic.Start();
this.Provide();
SetProcessInput(false);
SetPhysicsProcess(false);
}
public void OnReady()
{
Hitbox.AreaEntered += Hitbox_AreaEntered;
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
SwordSlashAnimation.Position = GetViewport().GetVisibleRect().Size / 2;
HealthComponent = new HealthComponent(InitialHP);
HealthComponent.HealthReachedZero += Die;
VTComponent = new VTComponent(InitialVT);
AttackComponent = new AttackComponent(InitialAttack);
DefenseComponent = new DefenseComponent(InitialDefense);
ExperiencePointsComponent = new ExperiencePointsComponent();
LuckComponent = new LuckComponent(InitialLuck);
HealthTimer.WaitTime = _healthTimerWaitTime;
HealthTimer.Timeout += OnHealthTimerTimeout;
SetProcessInput(false);
SetPhysicsProcess(false);
}
#endregion
@@ -206,20 +194,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
SetHealthTimerStatus(false);
}
public void Attack()
{
if (PlayerIsHittingGeometry())
{
AnimationPlayer.Play("hit_wall");
_gameRepo.OnPlayerAttackedWall();
}
else
{
PlayAttackAnimation();
}
}
public void SetHealthTimerStatus(bool isActive)
private void SetHealthTimerStatus(bool isActive)
{
if (isActive)
HealthTimer.Start();
@@ -227,22 +202,6 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
HealthTimer.Stop();
}
public void Move(float delta)
{
var rawInput = GlobalInputVector;
var strafeLeftInput = LeftStrafeInputVector;
var strafeRightInput = RightStrafeInputVector;
var transform = Transform;
transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis;
var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized();
var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration;
_knockbackStrength *= 0.9f;
Transform = Transform with { Basis = transform.Basis };
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
MoveAndSlide();
}
public void TeleportPlayer(Transform3D newTransform)
{
Transform = newTransform;
@@ -250,7 +209,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
public void TakeDamage(Damage damage)
{
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.TotalDefense, ((Armor)_equippedArmor.Value).Stats.ElementalResistanceSet);
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.TotalDefense, ((Armor)EquipmentComponent.EquippedArmor.Value).Stats.ElementalResistanceSet);
HealthComponent.Damage(damageReceived);
}
@@ -306,21 +265,21 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
if (equipable is Weapon weapon)
{
Unequip(_equippedWeapon.Value);
Unequip(EquipmentComponent.EquippedWeapon.Value);
weapon.IsEquipped = true;
_equippedWeapon.OnNext(weapon);
EquipmentComponent.Equip(weapon);
}
else if (equipable is Armor armor)
{
Unequip(_equippedArmor.Value);
Unequip(EquipmentComponent.EquippedArmor.Value);
armor.IsEquipped = true;
_equippedArmor.OnNext(armor);
EquipmentComponent.Equip(armor);
}
else if (equipable is Accessory accessory)
{
Unequip(_equippedAccessory.Value);
Unequip(EquipmentComponent.EquippedAccessory.Value);
accessory.IsEquipped = true;
_equippedAccessory.OnNext(accessory);
EquipmentComponent.Equip(accessory);
}
else
throw new NotImplementedException("Item type is not supported.");
@@ -331,17 +290,17 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
if (equipable is Weapon weapon)
{
weapon.IsEquipped = false;
_equippedWeapon.OnNext(new Weapon());
EquipmentComponent.Unequip(weapon);
}
else if (equipable is Armor armor)
{
armor.IsEquipped = false;
_equippedArmor.OnNext(new Armor());
EquipmentComponent.Unequip(armor);
}
else if (equipable is Accessory accessory)
{
accessory.IsEquipped = false;
_equippedAccessory.OnNext(new Accessory());
EquipmentComponent.Unequip(accessory);
}
else
throw new NotImplementedException("Item type is not supported.");
@@ -365,6 +324,19 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
private static float RightStrafeInputVector => Input.GetActionStrength(GameInputs.StrafeRight);
private void Attack()
{
if (PlayerIsHittingGeometry())
{
AnimationPlayer.Play("hit_wall");
_gameRepo.OnPlayerAttackedWall();
}
else
{
PlayAttackAnimation();
}
}
private void ThrowItem()
{
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
@@ -376,7 +348,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
private void PlayAttackAnimation()
{
var attackSpeed = ((Weapon)EquippedWeapon.Value).AttackSpeed;
var attackSpeed = ((Weapon)EquipmentComponent.EquippedWeapon.Value).AttackSpeed;
AnimationPlayer.SetSpeedScale((float)attackSpeed);
AnimationPlayer.Play("attack");
_gameRepo.OnPlayerAttack();
@@ -388,13 +360,29 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
PlayerBinding.Dispose();
}
private void Move(float delta)
{
var rawInput = GlobalInputVector;
var strafeLeftInput = LeftStrafeInputVector;
var strafeRightInput = RightStrafeInputVector;
var transform = Transform;
transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis;
var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized();
var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration;
_knockbackStrength *= 0.9f;
Transform = Transform with { Basis = transform.Basis };
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
MoveAndSlide();
}
private void OnPlayerPositionUpdated(Vector3 globalPosition) => GlobalPosition = globalPosition;
private void OnHealthTimerTimeout()
{
if (VTComponent.CurrentVT.Value > 0)
{
if (((Accessory)EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
if (((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
reduceOnTick = !reduceOnTick;
HealthComponent.Heal(1);
@@ -415,21 +403,21 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
private void HitEnemy(IEnemy enemy)
{
var ignoreElementalResistance = ((Weapon)EquippedWeapon.Value).WeaponTag == WeaponTag.IgnoreAffinity;
var ignoreElementalResistance = ((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.IgnoreAffinity;
var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value);
var element = ((Weapon)EquippedWeapon.Value).WeaponElement;
var element = ((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponElement;
var baseAttack = new Damage(
(int)(AttackComponent.TotalAttack * ((Weapon)EquippedWeapon.Value).ElementalDamageBonus),
(int)(AttackComponent.TotalAttack * ((Weapon)EquipmentComponent.EquippedWeapon.Value).ElementalDamageBonus),
element,
false,
false,
ignoreElementalResistance);
var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.TotalDefense, new ElementalResistanceSet(0, 0, 0, 0, 0));
enemy.TakeDamage(damageDealt);
enemy.HealthComponent.Damage(damageDealt);
if (((Weapon)EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable)
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable)
knockbackable.Knockback(0.3f, -CurrentBasis.Z.Normalized());
if (((Weapon)EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage)
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage)
TakeDamage(new Damage(5, ElementType.None, false, true, true));
_gameRepo.OnPlayerAttackedEnemy();