Fix Enemy logic

This commit is contained in:
2025-03-11 17:11:43 -07:00
parent 29af9062b5
commit 76b94f7be3
4 changed files with 315 additions and 326 deletions

View File

@@ -44,7 +44,7 @@ public partial class NavigationAgentClient : Node3D, INavigationAgentClient
if (!_canMove)
return;
var enemy = GetParent() as IEnemy;
var enemy = GetOwner() as IEnemy;
enemy.Move(safeVelocity);
}
@@ -71,7 +71,7 @@ public partial class NavigationAgentClient : Node3D, INavigationAgentClient
var rng = new RandomNumberGenerator();
rng.Randomize();
_patrolTimer.WaitTime = rng.RandfRange(5.0f, 10.0f);
var enemy = GetParent() as ICanPatrol;
var enemy = GetOwner() as ICanPatrol;
enemy.Patrol();
}
}

View File

@@ -124,7 +124,6 @@ public partial class InventoryMenu : Control, IInventoryMenu
private void ExpToNextLevel_Sync(int obj) => EXPValue.Text = $"{Player.Stats.CurrentExp.Value}/{obj}";
// TODO: Change font style when EXP Bonus effect is active
private void CurrentExp_Sync(double obj) => EXPValue.Text = $"{obj}/{Player.Stats.ExpToNextLevel.Value}";
private void MaxDefense_Sync(int obj) => DEFValue.Text = $"{Player.Stats.CurrentDefense.Value}/{obj}";

View File

@@ -106,518 +106,508 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
#region Initialization
public void Initialize()
{
AnimationPlayer.AnimationFinished += OnAnimationFinished;
_expToNextLevel = new Dictionary<int, int>
{
{ 2, 12 },
{ 3, 39 },
{ 4, 87 },
{ 5, 162 },
{ 6, 270 },
{ 7, 417 },
{ 8, 609 }
};
AnimationPlayer.AnimationFinished += OnAnimationFinished;
_expToNextLevel = new Dictionary<int, int>
{
{ 2, 12 },
{ 3, 39 },
{ 4, 87 },
{ 5, 162 },
{ 6, 270 },
{ 7, 417 },
{ 8, 609 }
};
}
public void Setup()
{
var container = new SimpleInjector.Container();
container.Register<IPlayerLogic, PlayerLogic>(Lifestyle.Singleton);
container.Verify();
var container = new SimpleInjector.Container();
container.Register<IPlayerLogic, PlayerLogic>(Lifestyle.Singleton);
container.Verify();
Settings = new PlayerLogic.Settings() { RotationSpeed = PlayerStatResource.RotationSpeed, MoveSpeed = PlayerStatResource.MoveSpeed, Acceleration = PlayerStatResource.Acceleration };
Stats = new PlayerStatController();
Stats.Init(
new PlayerStats
{
CurrentHP = PlayerStatResource.CurrentHP,
MaximumHP = PlayerStatResource.MaximumHP,
CurrentVT = PlayerStatResource.CurrentVT,
MaximumVT = PlayerStatResource.MaximumVT,
CurrentAttack = PlayerStatResource.CurrentAttack,
BonusAttack = PlayerStatResource.BonusAttack,
MaxAttack = PlayerStatResource.MaxAttack,
CurrentDefense = PlayerStatResource.CurrentDefense,
BonusDefense = PlayerStatResource.BonusDefense,
MaxDefense = PlayerStatResource.MaxDefense,
CurrentExp = PlayerStatResource.CurrentExp,
CurrentLevel = PlayerStatResource.CurrentLevel,
ExpToNextLevel = PlayerStatResource.ExpToNextLevel,
Luck = PlayerStatResource.Luck
});
Settings = new PlayerLogic.Settings() { RotationSpeed = PlayerStatResource.RotationSpeed, MoveSpeed = PlayerStatResource.MoveSpeed, Acceleration = PlayerStatResource.Acceleration };
Stats = new PlayerStatController();
Stats.Init(
new PlayerStats
{
CurrentHP = PlayerStatResource.CurrentHP,
MaximumHP = PlayerStatResource.MaximumHP,
CurrentVT = PlayerStatResource.CurrentVT,
MaximumVT = PlayerStatResource.MaximumVT,
CurrentAttack = PlayerStatResource.CurrentAttack,
BonusAttack = PlayerStatResource.BonusAttack,
MaxAttack = PlayerStatResource.MaxAttack,
CurrentDefense = PlayerStatResource.CurrentDefense,
BonusDefense = PlayerStatResource.BonusDefense,
MaxDefense = PlayerStatResource.MaxDefense,
CurrentExp = PlayerStatResource.CurrentExp,
CurrentLevel = PlayerStatResource.CurrentLevel,
ExpToNextLevel = PlayerStatResource.ExpToNextLevel,
Luck = PlayerStatResource.Luck
});
Inventory = new Inventory();
Inventory = new Inventory();
PlayerLogic = container.GetInstance<IPlayerLogic>();
PlayerLogic.Set(this as IPlayer);
PlayerLogic.Set(Settings);
PlayerLogic.Set(Stats);
PlayerLogic.Set(_gameRepo);
PlayerLogic = container.GetInstance<IPlayerLogic>();
PlayerLogic.Set(this as IPlayer);
PlayerLogic.Set(Settings);
PlayerLogic.Set(Stats);
PlayerLogic.Set(_gameRepo);
var defaultWeapon = new Weapon();
defaultWeapon.Stats = _defaultWeapon;
var defaultArmor = new Armor();
defaultArmor.Stats = _defaultArmor;
Inventory.TryAdd(defaultWeapon);
Inventory.TryAdd(defaultArmor);
var defaultWeapon = new Weapon();
defaultWeapon.Stats = _defaultWeapon;
var defaultArmor = new Armor();
defaultArmor.Stats = _defaultArmor;
Inventory.TryAdd(defaultWeapon);
Inventory.TryAdd(defaultArmor);
EquippedWeapon.Sync += EquippedWeapon_Sync;
EquippedArmor.Sync += EquippedArmor_Sync;
EquippedAccessory.Sync += EquippedAccessory_Sync;
Stats.CurrentHP.Sync += CurrentHP_Sync;
Stats.CurrentExp.Sync += CurrentEXP_Sync;
EquippedWeapon.Sync += EquippedWeapon_Sync;
EquippedArmor.Sync += EquippedArmor_Sync;
EquippedAccessory.Sync += EquippedAccessory_Sync;
Stats.CurrentHP.Sync += CurrentHP_Sync;
Stats.CurrentExp.Sync += CurrentEXP_Sync;
Equip(defaultWeapon);
Equip(defaultArmor);
Equip(defaultWeapon);
Equip(defaultArmor);
HealthTimer.WaitTime = _healthTimerWaitTime;
HealthTimer.Timeout += OnHealthTimerTimeout;
Hitbox.AreaEntered += Hitbox_AreaEntered;
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
HealthTimer.WaitTime = _healthTimerWaitTime;
HealthTimer.Timeout += OnHealthTimerTimeout;
Hitbox.AreaEntered += Hitbox_AreaEntered;
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
}
public void OnResolved()
{
PlayerChunk = new SaveChunk<PlayerData>(
onSave: (chunk) => new PlayerData()
{
PlayerStats = new PlayerStats()
{
CurrentHP = Stats.CurrentHP.Value,
MaximumHP = Stats.MaximumHP.Value,
CurrentVT = Stats.CurrentVT.Value,
MaximumVT = Stats.MaximumVT.Value,
CurrentAttack = Stats.CurrentAttack.Value,
BonusAttack = Stats.BonusAttack.Value,
MaxAttack = Stats.MaxAttack.Value,
CurrentDefense = Stats.CurrentDefense.Value,
BonusDefense = Stats.BonusDefense.Value,
MaxDefense = Stats.MaxDefense.Value,
CurrentExp = Stats.CurrentExp.Value,
CurrentLevel = Stats.CurrentLevel.Value,
ExpToNextLevel = Stats.ExpToNextLevel.Value,
Luck = Stats.Luck.Value
},
Inventory = Inventory
},
onLoad: (chunk, data) =>
{
Stats.Init(data.PlayerStats);
Inventory = data.Inventory;
}
);
PlayerChunk = new SaveChunk<PlayerData>(
onSave: (chunk) => new PlayerData()
{
PlayerStats = new PlayerStats()
{
CurrentHP = Stats.CurrentHP.Value,
MaximumHP = Stats.MaximumHP.Value,
CurrentVT = Stats.CurrentVT.Value,
MaximumVT = Stats.MaximumVT.Value,
CurrentAttack = Stats.CurrentAttack.Value,
BonusAttack = Stats.BonusAttack.Value,
MaxAttack = Stats.MaxAttack.Value,
CurrentDefense = Stats.CurrentDefense.Value,
BonusDefense = Stats.BonusDefense.Value,
MaxDefense = Stats.MaxDefense.Value,
CurrentExp = Stats.CurrentExp.Value,
CurrentLevel = Stats.CurrentLevel.Value,
ExpToNextLevel = Stats.ExpToNextLevel.Value,
Luck = Stats.Luck.Value
},
Inventory = Inventory
},
onLoad: (chunk, data) =>
{
Stats.Init(data.PlayerStats);
Inventory = data.Inventory;
}
);
PlayerBinding = PlayerLogic.Bind();
PlayerBinding = PlayerLogic.Bind();
PlayerBinding
.Handle((in PlayerLogic.Output.Animations.Attack output) =>
{
if (PlayerIsHittingGeometry())
{
AnimationPlayer.Play("hit_wall");
_gameRepo.OnPlayerAttackedWall();
}
else
{
var attackSpeed = ((Weapon)EquippedWeapon.Value).AttackSpeed;
AnimationPlayer.SetSpeedScale((float)attackSpeed);
AnimationPlayer.Play("attack");
_gameRepo.OnPlayerAttack();
}
})
.Handle((in PlayerLogic.Output.ThrowItem output) =>
{
})
.Handle((in PlayerLogic.Output.Move output) =>
{
Move(output.delta);
});
PlayerBinding
.Handle((in PlayerLogic.Output.Animations.Attack output) =>
{
if (PlayerIsHittingGeometry())
{
AnimationPlayer.Play("hit_wall");
_gameRepo.OnPlayerAttackedWall();
}
else
{
var attackSpeed = ((Weapon)EquippedWeapon.Value).AttackSpeed;
AnimationPlayer.SetSpeedScale((float)attackSpeed);
AnimationPlayer.Play("attack");
_gameRepo.OnPlayerAttack();
}
})
.Handle((in PlayerLogic.Output.ThrowItem output) =>
{
})
.Handle((in PlayerLogic.Output.Move output) =>
{
Move(output.delta);
});
GameChunk.AddChunk(PlayerChunk);
GameChunk.AddChunk(PlayerChunk);
PlayerLogic.Start();
this.Provide();
PlayerLogic.Start();
this.Provide();
}
public void OnReady()
{
SetPhysicsProcess(true);
SwordSlashAnimation.Position = GetViewport().GetVisibleRect().Size / 2;
SetPhysicsProcess(true);
SwordSlashAnimation.Position = GetViewport().GetVisibleRect().Size / 2;
}
#endregion
public void Attack()
{
PlayerLogic.Input(new PlayerLogic.Input.Attack());
PlayerLogic.Input(new PlayerLogic.Input.Attack());
}
public void PlayerPause()
{
Game.TogglePause();
Game.TogglePause();
}
public void RaiseHP(int amountToRaise)
{
Stats.SetMaximumHP(Stats.MaximumHP.Value + amountToRaise);
Stats.SetCurrentHP(Stats.MaximumHP.Value);
_gameRepo.AnnounceMessageInInventory($"{amountToRaise}MAXHP Up.");
Stats.SetMaximumHP(Stats.MaximumHP.Value + amountToRaise);
Stats.SetCurrentHP(Stats.MaximumHP.Value);
_gameRepo.AnnounceMessageInInventory($"{amountToRaise}MAXHP Up.");
}
public void HealHP(int amountToRestore)
{
Stats.SetCurrentHP(Stats.CurrentHP.Value + amountToRestore);
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
_gameRepo.AnnounceMessageInInventory($"{raiseString}HP Restored.");
Stats.SetCurrentHP(Stats.CurrentHP.Value + amountToRestore);
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
_gameRepo.AnnounceMessageInInventory($"{raiseString}HP Restored.");
}
public void RaiseVT(int amountToRaise)
{
if (Stats.CurrentVT == Stats.MaximumVT)
{
Stats.SetMaximumVT(Stats.MaximumVT.Value + amountToRaise);
Stats.SetCurrentVT(Stats.MaximumVT.Value);
_gameRepo.AnnounceMessageInInventory($"{amountToRaise}MAXVT Up.");
}
if (Stats.CurrentVT == Stats.MaximumVT)
{
Stats.SetMaximumVT(Stats.MaximumVT.Value + amountToRaise);
Stats.SetCurrentVT(Stats.MaximumVT.Value);
_gameRepo.AnnounceMessageInInventory($"{amountToRaise}MAXVT Up.");
}
}
public void HealVT(int amountToRestore)
{
Stats.SetCurrentVT(Stats.CurrentVT.Value + amountToRestore);
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
_gameRepo.AnnounceMessageInInventory($"{raiseString}VT Restored.");
Stats.SetCurrentVT(Stats.CurrentVT.Value + amountToRestore);
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
_gameRepo.AnnounceMessageInInventory($"{raiseString}VT Restored.");
}
public void ModifyBonusAttack(int amount)
{
Stats.SetBonusAttack(Stats.BonusAttack.Value + amount);
Stats.SetBonusAttack(Stats.BonusAttack.Value + amount);
}
public void ModifyBonusDefense(int amount)
{
Stats.SetBonusDefense(Stats.BonusDefense.Value + amount);
Stats.SetBonusDefense(Stats.BonusDefense.Value + amount);
}
public void ModifyMaximumHP(int amount)
{
Stats.SetMaximumHP(Stats.MaximumHP.Value + amount);
Stats.SetMaximumHP(Stats.MaximumHP.Value + amount);
}
public void ModifyMaximumVT(int amount)
{
Stats.SetMaximumVT(Stats.MaximumVT.Value + amount);
Stats.SetMaximumVT(Stats.MaximumVT.Value + amount);
}
public void ModifyBonusLuck(double amount)
{
Stats.SetLuck(Stats.Luck.Value + amount);
Stats.SetLuck(Stats.Luck.Value + amount);
}
public void Move(float delta)
{
var rawInput = GlobalInputVector;
var strafeLeftInput = LeftStrafeInputVector;
var strafeRightInput = RightStrafeInputVector;
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 = _knockbackStrength * 0.9f;
Transform = Transform with { Basis = transform.Basis };
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
MoveAndSlide();
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 = _knockbackStrength * 0.9f;
Transform = Transform with { Basis = transform.Basis };
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
MoveAndSlide();
}
public void TeleportPlayer(Transform3D newTransform)
{
Transform = newTransform;
Transform = newTransform;
}
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false)
{
if (Stats.CurrentHP.Value > 0)
{
damage = CalculateDefenseResistance(damage);
if (isCriticalHit)
damage *= 2;
Stats.SetCurrentHP(Stats.CurrentHP.Value - (int)damage);
}
if (Stats.CurrentHP.Value > 0)
{
damage = CalculateDefenseResistance(damage);
if (isCriticalHit)
damage *= 2;
Stats.SetCurrentHP(Stats.CurrentHP.Value - (int)damage);
}
}
public void Knockback(float impulse)
{
_knockbackStrength = impulse;
_knockbackDirection = GlobalBasis.Z.Normalized();
_knockbackStrength = impulse;
_knockbackDirection = GlobalBasis.Z.Normalized();
}
public void GainExp(double expGained)
{
Stats.SetCurrentExp(Stats.CurrentExp.Value + expGained);
Stats.SetCurrentExp(Stats.CurrentExp.Value + expGained);
}
public void LevelUp()
{
var nextLevel = Stats.CurrentLevel.Value + 1;
var expToNextLevel = _expToNextLevel[nextLevel];
var newCurrentExp = Mathf.Max(Stats.CurrentExp.Value - Stats.ExpToNextLevel.Value, 0);
Stats.SetCurrentLevel(nextLevel);
Stats.SetExpToNextLevel(expToNextLevel);
Stats.SetCurrentExp(newCurrentExp);
var nextLevel = Stats.CurrentLevel.Value + 1;
var expToNextLevel = _expToNextLevel[nextLevel];
var newCurrentExp = Mathf.Max(Stats.CurrentExp.Value - Stats.ExpToNextLevel.Value, 0);
Stats.SetCurrentLevel(nextLevel);
Stats.SetExpToNextLevel(expToNextLevel);
Stats.SetCurrentExp(newCurrentExp);
}
public void Die() => PlayerLogic.Input(new PlayerLogic.Input.Die());
public override void _UnhandledInput(InputEvent @event)
{
if (@event.IsActionPressed(GameInputs.Pause))
PlayerPause();
if (@event.IsActionPressed(GameInputs.Pause))
PlayerPause();
if (@event.IsActionPressed(GameInputs.Attack))
Attack();
if (@event.IsActionPressed(GameInputs.Attack))
Attack();
}
public void OnPhysicsProcess(double delta)
{
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform));
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform));
}
public void Equip(EquipableItem equipable)
{
if (string.IsNullOrEmpty(equipable.ItemName))
return;
if (equipable is Weapon weapon)
{
Unequip(_equippedWeapon.Value);
weapon.IsEquipped = true;
_equippedWeapon.OnNext(weapon);
}
else if (equipable is Armor armor)
{
Unequip(_equippedArmor.Value);
armor.IsEquipped = true;
_equippedArmor.OnNext(armor);
}
else if (equipable is Accessory accessory)
{
Unequip(_equippedAccessory.Value);
accessory.IsEquipped = true;
_equippedAccessory.OnNext(accessory);
}
else
throw new NotImplementedException("Item type is not supported.");
_gameRepo.OnEquippedItem(equipable);
if (equipable is Weapon weapon)
{
Unequip(_equippedWeapon.Value);
weapon.IsEquipped = true;
_equippedWeapon.OnNext(weapon);
}
else if (equipable is Armor armor)
{
Unequip(_equippedArmor.Value);
armor.IsEquipped = true;
_equippedArmor.OnNext(armor);
}
else if (equipable is Accessory accessory)
{
Unequip(_equippedAccessory.Value);
accessory.IsEquipped = true;
_equippedAccessory.OnNext(accessory);
}
else
throw new NotImplementedException("Item type is not supported.");
}
public void Unequip(EquipableItem equipable)
{
if (string.IsNullOrEmpty(equipable.ItemName))
return;
if (equipable is Weapon weapon)
{
weapon.IsEquipped = false;
ModifyBonusAttack(-weapon.Damage);
_equippedWeapon.OnNext(new Weapon());
}
else if (equipable is Armor armor)
{
armor.IsEquipped = false;
ModifyBonusDefense(-armor.Defense);
_equippedArmor.OnNext(new Armor());
}
else if (equipable is Accessory accessory)
{
accessory.IsEquipped = false;
ModifyMaximumHP(-accessory.MaxHPUp);
ModifyMaximumVT(-accessory.MaxVTUp);
ModifyBonusAttack(-accessory.ATKUp);
ModifyBonusDefense(-accessory.DEFUp);
ModifyBonusLuck(-accessory.LuckUp);
_equippedAccessory.OnNext(new Accessory());
}
else
throw new NotImplementedException("Item type is not supported.");
if (equipable is Weapon weapon)
{
weapon.IsEquipped = false;
ModifyBonusAttack(-weapon.Damage);
_equippedWeapon.OnNext(new Weapon());
}
else if (equipable is Armor armor)
{
armor.IsEquipped = false;
ModifyBonusDefense(-armor.Defense);
_equippedArmor.OnNext(new Armor());
}
else if (equipable is Accessory accessory)
{
accessory.IsEquipped = false;
ModifyMaximumHP(-accessory.MaxHPUp);
ModifyMaximumVT(-accessory.MaxVTUp);
ModifyBonusAttack(-accessory.ATKUp);
ModifyBonusDefense(-accessory.DEFUp);
ModifyBonusLuck(-accessory.LuckUp);
_equippedAccessory.OnNext(new Accessory());
}
else
throw new NotImplementedException("Item type is not supported.");
if (equipable.ItemTag == ItemTag.BreaksOnChange)
Inventory.Remove(equipable);
_gameRepo.OnUnequippedItem(equipable);
if (equipable.ItemTag == ItemTag.BreaksOnChange)
Inventory.Remove(equipable);
}
private static Vector3 GlobalInputVector
{
get
{
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
var input = new Vector3
{
X = rawInput.X,
Z = rawInput.Y
};
return input with { Y = 0f };
}
get
{
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
var input = new Vector3
{
X = rawInput.X,
Z = rawInput.Y
};
return input with { Y = 0f };
}
}
private static float LeftStrafeInputVector
{
get
{
return Input.GetActionStrength(GameInputs.StrafeLeft);
}
get
{
return Input.GetActionStrength(GameInputs.StrafeLeft);
}
}
private static float RightStrafeInputVector
{
get
{
return Input.GetActionStrength(GameInputs.StrafeRight);
}
get
{
return Input.GetActionStrength(GameInputs.StrafeRight);
}
}
private void ThrowItem()
{
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
var throwItem = itemScene.Instantiate<ThrowableItem>();
GetTree().Root.AddChildEx(throwItem);
throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0);
throwItem.GlobalRotation = GlobalRotation;
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
var throwItem = itemScene.Instantiate<ThrowableItem>();
GetTree().Root.AddChildEx(throwItem);
throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0);
throwItem.GlobalRotation = GlobalRotation;
}
private void OnAnimationFinished(StringName animation)
{
PlayerLogic.Input(new PlayerLogic.Input.AttackAnimationFinished());
PlayerLogic.Input(new PlayerLogic.Input.AttackAnimationFinished());
}
private void OnExitTree()
{
PlayerLogic.Stop();
PlayerBinding.Dispose();
AnimationPlayer.AnimationFinished -= OnAnimationFinished;
PlayerLogic.Stop();
PlayerBinding.Dispose();
AnimationPlayer.AnimationFinished -= OnAnimationFinished;
}
private void OnPlayerPositionUpdated(Vector3 globalPosition) => GlobalPosition = globalPosition;
private void OnHealthTimerTimeout()
{
if (Stats.CurrentHP.Value <= 0)
return;
if (Stats.CurrentHP.Value <= 0)
return;
if (Stats.CurrentVT.Value > 0)
{
if (((Accessory)EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
{
reduceOnTick = !reduceOnTick;
}
Stats.SetCurrentHP(Stats.CurrentHP.Value + 1);
if (reduceOnTick)
Stats.SetCurrentVT(Stats.CurrentVT.Value - 1);
}
else
Stats.SetCurrentHP(Stats.CurrentHP.Value - 1);
if (Stats.CurrentVT.Value > 0)
{
if (((Accessory)EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
{
reduceOnTick = !reduceOnTick;
}
Stats.SetCurrentHP(Stats.CurrentHP.Value + 1);
if (reduceOnTick)
Stats.SetCurrentVT(Stats.CurrentVT.Value - 1);
}
else
Stats.SetCurrentHP(Stats.CurrentHP.Value - 1);
}
private void EquippedWeapon_Sync(EquipableItem obj)
{
ModifyBonusAttack(((Weapon)obj).Damage);
ModifyBonusAttack(((Weapon)obj).Damage);
}
private void EquippedArmor_Sync(EquipableItem obj)
{
ModifyBonusDefense(((Armor)obj).Defense);
ModifyBonusDefense(((Armor)obj).Defense);
}
private void EquippedAccessory_Sync(EquipableItem accessory)
{
ModifyMaximumHP(((Accessory)accessory).MaxHPUp);
ModifyMaximumVT(((Accessory)accessory).MaxVTUp);
ModifyBonusAttack(((Accessory)accessory).ATKUp);
ModifyBonusDefense(((Accessory)accessory).DEFUp);
ModifyBonusLuck(((Accessory)accessory).LuckUp);
ModifyMaximumHP(((Accessory)accessory).MaxHPUp);
ModifyMaximumVT(((Accessory)accessory).MaxVTUp);
ModifyBonusAttack(((Accessory)accessory).ATKUp);
ModifyBonusDefense(((Accessory)accessory).DEFUp);
ModifyBonusLuck(((Accessory)accessory).LuckUp);
}
private void CurrentHP_Sync(int newHealth)
{
if (newHealth <= 0)
Die();
if (newHealth <= 0)
Die();
}
private void CurrentEXP_Sync(double newExp)
{
if (Stats.CurrentExp.Value >= Stats.ExpToNextLevel.Value)
LevelUp();
if (Stats.CurrentExp.Value >= Stats.ExpToNextLevel.Value)
LevelUp();
}
private double CalculateDefenseResistance(double incomingDamage)
{
return Mathf.Max(incomingDamage - Stats.CurrentDefense.Value - Stats.BonusDefense.Value, 0.0);
return Mathf.Max(incomingDamage - Stats.CurrentDefense.Value - Stats.BonusDefense.Value, 0.0);
}
private void Hitbox_AreaEntered(Area3D area)
{
var target = area.GetOwner();
if (target is IEnemy enemy)
HitEnemy(enemy);
var target = area.GetOwner();
if (target is IEnemy enemy)
HitEnemy(enemy);
}
private void HitEnemy(IEnemy enemy)
{
var attackValue = Stats.CurrentAttack.Value + Stats.BonusAttack.Value;
var ignoreElementalResistance = ((Weapon)EquippedWeapon.Value).WeaponTag == WeaponTag.IgnoreAffinity;
var isCriticalHit = BattleExtensions.IsCriticalHit(Stats.Luck.Value);
var element = ((Weapon)EquippedWeapon.Value).WeaponElement;
var attackValue = Stats.CurrentAttack.Value + Stats.BonusAttack.Value;
var ignoreElementalResistance = ((Weapon)EquippedWeapon.Value).WeaponTag == WeaponTag.IgnoreAffinity;
var isCriticalHit = BattleExtensions.IsCriticalHit(Stats.Luck.Value);
var element = ((Weapon)EquippedWeapon.Value).WeaponElement;
enemy.TakeDamage(
attackValue * ((Weapon)EquippedWeapon.Value).ElementalDamageBonus,
element,
isCriticalHit,
false,
ignoreElementalResistance);
enemy.TakeDamage(
attackValue * ((Weapon)EquippedWeapon.Value).ElementalDamageBonus,
element,
isCriticalHit,
false,
ignoreElementalResistance);
if (((Weapon)EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback)
enemy.Knockback(0.3f, -CurrentBasis.Z.Normalized());
if (((Weapon)EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback)
enemy.Knockback(0.3f, -CurrentBasis.Z.Normalized());
_gameRepo.OnPlayerAttackedEnemy();
_gameRepo.OnPlayerAttackedEnemy();
}
private void CollisionDetector_AreaEntered(Area3D area)
{
if (area.GetParent() is InventoryItem inventoryItem)
{
var isAdded = Inventory.TryAdd(inventoryItem);
if (isAdded)
{
_gameRepo.AnnounceMessageOnMainScreen($"{inventoryItem.ItemName} picked up.");
inventoryItem.QueueFree();
}
else
_gameRepo.AnnounceMessageOnMainScreen($"Could not pick up {inventoryItem.ItemName}.");
}
if (area.GetParent() is DroppedItem droppedItem)
{
var isAdded = Inventory.TryAdd(droppedItem.Item);
if (isAdded)
{
_gameRepo.AnnounceMessageOnMainScreen($"{droppedItem.Item.ItemName} picked up.");
droppedItem.QueueFree();
}
else
_gameRepo.AnnounceMessageOnMainScreen($"Could not pick up {droppedItem.Item.ItemName}.");
}
if (area.GetParent() is InventoryItem inventoryItem)
{
var isAdded = Inventory.TryAdd(inventoryItem);
if (isAdded)
{
_gameRepo.AnnounceMessageOnMainScreen($"{inventoryItem.ItemName} picked up.");
inventoryItem.QueueFree();
}
else
_gameRepo.AnnounceMessageOnMainScreen($"Could not pick up {inventoryItem.ItemName}.");
}
if (area.GetParent() is DroppedItem droppedItem)
{
var isAdded = Inventory.TryAdd(droppedItem.Item);
if (isAdded)
{
_gameRepo.AnnounceMessageOnMainScreen($"{droppedItem.Item.ItemName} picked up.");
droppedItem.QueueFree();
}
else
_gameRepo.AnnounceMessageOnMainScreen($"Could not pick up {droppedItem.Item.ItemName}.");
}
}
private bool PlayerIsHittingGeometry()
{
var collisions = WallCheck.GetCollidingBodies();
return collisions.Count > 0;
var collisions = WallCheck.GetCollidingBodies();
return collisions.Count > 0;
}
private void WallCheck_BodyEntered(Node body)
{
PlayerLogic.Input(new PlayerLogic.Input.AttackAnimationFinished());
GD.Print("Hit wall");
AnimationPlayer.Stop();
PlayerLogic.Input(new PlayerLogic.Input.AttackAnimationFinished());
GD.Print("Hit wall");
AnimationPlayer.Stop();
}
}