Rust
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
|
||||
using Chickensoft.Collections;
|
||||
using Godot;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
|
||||
public interface IStatusEffectComponent : IEntityComponent
|
||||
{
|
||||
[Export] public double RustDuration { get; set; }
|
||||
|
||||
public AutoProp<bool> Rust { get; }
|
||||
|
||||
public bool ImmuneToRust { get; set; }
|
||||
}
|
||||
@@ -31,6 +31,8 @@ namespace Zennysoft.Ma.Adapter.Entity
|
||||
|
||||
public IDefenseComponent DefenseComponent { get; }
|
||||
|
||||
public IStatusEffectComponent StatusEffectComponent { get; }
|
||||
|
||||
public ElementalResistanceSet ElementalResistanceSet { get; }
|
||||
|
||||
public int InitialHP { get; }
|
||||
|
||||
@@ -18,12 +18,6 @@ public interface IGameRepo : IDisposable
|
||||
|
||||
event Action<IBaseInventoryItem>? RemoveItemFromInventoryEvent;
|
||||
|
||||
event Action? PlayerAttack;
|
||||
|
||||
event Action? PlayerAttackedWall;
|
||||
|
||||
event Action? PlayerAttackedEnemy;
|
||||
|
||||
event Action<IEquipableItem>? EquippedItem;
|
||||
|
||||
event Action<IEquipableItem>? UnequippedItem;
|
||||
@@ -42,10 +36,6 @@ public interface IGameRepo : IDisposable
|
||||
|
||||
public void RemoveItemFromInventory(IBaseInventoryItem item);
|
||||
|
||||
public void OnPlayerAttack();
|
||||
|
||||
public void OnPlayerAttackedWall();
|
||||
|
||||
public void CloseInventory();
|
||||
|
||||
public void GameEnded();
|
||||
@@ -64,9 +54,6 @@ public class GameRepo : IGameRepo
|
||||
public event Action<string>? AnnounceMessageOnMainScreenEvent;
|
||||
public event Action<string>? AnnounceMessageInInventoryEvent;
|
||||
public event Action<IBaseInventoryItem>? RemoveItemFromInventoryEvent;
|
||||
public event Action? PlayerAttack;
|
||||
public event Action? PlayerAttackedWall;
|
||||
public event Action? PlayerAttackedEnemy;
|
||||
public event Action<IEquipableItem>? EquippedItem;
|
||||
public event Action<IEquipableItem>? UnequippedItem;
|
||||
public event Action<IEnemy>? EnemyDied;
|
||||
@@ -107,16 +94,6 @@ public class GameRepo : IGameRepo
|
||||
RemoveItemFromInventoryEvent?.Invoke(item);
|
||||
}
|
||||
|
||||
public void OnPlayerAttack()
|
||||
{
|
||||
PlayerAttack?.Invoke();
|
||||
}
|
||||
|
||||
public void OnPlayerAttackedWall()
|
||||
{
|
||||
PlayerAttackedWall?.Invoke();
|
||||
}
|
||||
|
||||
public void CloseInventory()
|
||||
{
|
||||
CloseInventoryEvent?.Invoke();
|
||||
|
||||
@@ -46,6 +46,8 @@ public interface IPlayer : IKillable, ICharacterBody3D
|
||||
|
||||
public IEquipmentComponent EquipmentComponent { get; }
|
||||
|
||||
public IStatusEffectComponent StatusEffectComponent { get; }
|
||||
|
||||
public void SetHealthTimerStatus(bool isActive);
|
||||
|
||||
public void ModifyHealthTimerSpeed(float newModifier);
|
||||
|
||||
20
Zennysoft.Game.Ma/src/Components/StatusEffectComponent.cs
Normal file
20
Zennysoft.Game.Ma/src/Components/StatusEffectComponent.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Chickensoft.Collections;
|
||||
|
||||
public class StatusEffectComponent : IStatusEffectComponent
|
||||
{
|
||||
public StatusEffectComponent(double rustDuration)
|
||||
{
|
||||
RustDuration = rustDuration;
|
||||
}
|
||||
|
||||
public double RustDuration { get; set; }
|
||||
|
||||
public AutoProp<bool> Rust { get; } = new AutoProp<bool>(false);
|
||||
|
||||
public bool ImmuneToRust { get; set; } = false;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Rust.OnNext(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://chhmivq4bntxf
|
||||
@@ -34,6 +34,8 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
|
||||
|
||||
public IDefenseComponent DefenseComponent { get; private set; }
|
||||
|
||||
public IStatusEffectComponent StatusEffectComponent { get; private set; }
|
||||
|
||||
public virtual IEnemyModelView EnemyModelView { get; set; } = default!;
|
||||
|
||||
public Vector3 TargetPosition { get; private set; }
|
||||
@@ -69,6 +71,9 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
|
||||
[Node] private AudioStreamPlayer3D _dieSFX { get; set; } = default!;
|
||||
[Node] private AudioStreamPlayer3D _aggroSFX { get; set; } = default!;
|
||||
|
||||
private Timer _rustTimer;
|
||||
private Timer _rustDuration;
|
||||
|
||||
protected bool _activated = false;
|
||||
private Vector3 _previousPosition = Vector3.Zero;
|
||||
|
||||
@@ -86,8 +91,22 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
|
||||
HealthComponent.HealthReachedZero += Die;
|
||||
HealthComponent.DamageTaken += TakeHit;
|
||||
|
||||
_rustTimer = new Timer();
|
||||
_rustDuration = new Timer();
|
||||
|
||||
_rustTimer.WaitTime = 3;
|
||||
_rustDuration.WaitTime = 30;
|
||||
_rustTimer.Timeout += _rustTimer_Timeout;
|
||||
_rustDuration.Timeout += _rustDuration_Timeout;
|
||||
|
||||
AddChild(_rustTimer);
|
||||
AddChild(_rustDuration);
|
||||
|
||||
AttackComponent = new AttackComponent(InitialAttack);
|
||||
DefenseComponent = new DefenseComponent(InitialDefense);
|
||||
StatusEffectComponent = new StatusEffectComponent(30);
|
||||
|
||||
StatusEffectComponent.Rust.Changed += OnRusted;
|
||||
|
||||
EnemyBinding
|
||||
.Handle((in EnemyLogic.Output.Activate _) =>
|
||||
@@ -160,6 +179,8 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
|
||||
public virtual void Die()
|
||||
{
|
||||
SetPhysicsProcess(false);
|
||||
_rustDuration.Stop();
|
||||
_rustTimer.Stop();
|
||||
_enemyLogic.Input(new EnemyLogic.Input.Defeated());
|
||||
_player.ExperiencePointsComponent.Gain(ExpGiven);
|
||||
EnemyModelView.PlayDeathAnimation();
|
||||
@@ -244,4 +265,28 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
|
||||
{
|
||||
_player.TakeDamage(new AttackData(AttackComponent.CurrentAttack.Value, ElementType.None));
|
||||
}
|
||||
|
||||
private void OnRusted(bool rustStatus)
|
||||
{
|
||||
if (rustStatus)
|
||||
{
|
||||
_rustTimer.Start();
|
||||
_rustDuration.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rustTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void _rustTimer_Timeout()
|
||||
{
|
||||
HealthComponent.Damage(3);
|
||||
TakeHit();
|
||||
}
|
||||
|
||||
private void _rustDuration_Timeout()
|
||||
{
|
||||
StatusEffectComponent.Rust.OnNext(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,9 @@ public partial class Game : Node3D, IGame
|
||||
|
||||
private Timer _doubleExpTimer;
|
||||
|
||||
private Timer _rustTimer;
|
||||
private Timer _rustDurationTimer;
|
||||
|
||||
[Signal] private delegate void OnLoadLevelRequestEventHandler();
|
||||
|
||||
public event Action<string> InventoryEventNotification;
|
||||
@@ -191,6 +194,19 @@ public partial class Game : Node3D, IGame
|
||||
_doubleExpTimer.Timeout += EndDoubleExpTimer;
|
||||
AddChild(_doubleExpTimer);
|
||||
|
||||
_player.StatusEffectComponent.Rust.Changed += RustStatusChanged;
|
||||
|
||||
_rustTimer = new Timer();
|
||||
_rustTimer.WaitTime = 2f;
|
||||
_rustTimer.Timeout += RustTimeout;
|
||||
|
||||
_rustDurationTimer = new Timer();
|
||||
_rustDurationTimer.WaitTime = _player.StatusEffectComponent.RustDuration;
|
||||
_rustDurationTimer.Timeout += RustWoreOff;
|
||||
|
||||
AddChild(_rustTimer);
|
||||
AddChild(_rustDurationTimer);
|
||||
|
||||
GameRepo.IsPaused.Sync += IsPaused_Sync;
|
||||
InGameUI.PlayerInfoUI.Activate();
|
||||
InGameUI.Show();
|
||||
@@ -414,16 +430,16 @@ public partial class Game : Node3D, IGame
|
||||
{
|
||||
var restorativeScene = GD.Load<PackedScene>("res://src/items/restorative/Restorative.tscn");
|
||||
var restorative = restorativeScene.Instantiate<Restorative>();
|
||||
restorative.GlobalPosition = new Vector3(vector.X, 2f, vector.Z) + (-_player.GetGlobalBasis().Z);
|
||||
AddChild(restorative);
|
||||
restorative.GlobalPosition = new Vector3(vector.X, 2f, vector.Z) + (-_player.GetGlobalBasis().Z);
|
||||
}
|
||||
|
||||
private void DropItem(Vector3 vector)
|
||||
{
|
||||
var randomItem = ItemDatabase.Instance.PickItem<IBaseInventoryItem>() as Node3D;
|
||||
var duplicated = randomItem.Duplicate((int)DuplicateFlags.UseInstantiation) as Node3D;
|
||||
duplicated.GlobalPosition = new Vector3(vector.X, 2f, vector.Z) + (-_player.GetGlobalBasis().Z);
|
||||
AddChild(duplicated);
|
||||
duplicated.GlobalPosition = new Vector3(vector.X, 2f, vector.Z) + (-_player.GetGlobalBasis().Z);
|
||||
}
|
||||
|
||||
private void UseTeleportPrompt_CloseTeleportPrompt()
|
||||
@@ -576,6 +592,12 @@ public partial class Game : Node3D, IGame
|
||||
SfxDatabase.Instance.Play(SoundEffect.HealVT);
|
||||
InventoryEventNotification.Invoke($"Restored {consumableItem.HealVTAmount} VT.");
|
||||
}
|
||||
|
||||
if (consumableItem.Stats.HealsStatusAilments)
|
||||
{
|
||||
_player.StatusEffectComponent.Reset();
|
||||
InventoryEventNotification.Invoke($"All status afflictments have faded.");
|
||||
}
|
||||
}
|
||||
|
||||
private void EnactEffectItemEffects(EffectItem effectItem)
|
||||
@@ -809,6 +831,29 @@ public partial class Game : Node3D, IGame
|
||||
_player.Activate();
|
||||
}
|
||||
|
||||
private void RustStatusChanged(bool rustStatus)
|
||||
{
|
||||
if (rustStatus)
|
||||
{
|
||||
_rustTimer.Start();
|
||||
_rustDurationTimer.Start();
|
||||
GameRepo.AnnounceMessageOnMainScreen("Afflicted with Rust.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_rustTimer.Stop();
|
||||
GameRepo.AnnounceMessageOnMainScreen("Rust affliction has faded.");
|
||||
}
|
||||
}
|
||||
|
||||
private void RustTimeout()
|
||||
{
|
||||
_player.HealthComponent.Damage(3);
|
||||
}
|
||||
|
||||
private void RustWoreOff() => _player.StatusEffectComponent.Rust.OnNext(false);
|
||||
|
||||
|
||||
public void NotifyInventory(string message) => InventoryEventNotification?.Invoke(message);
|
||||
|
||||
private void OnQuit() => GameExitRequested?.Invoke();
|
||||
|
||||
@@ -21,4 +21,7 @@ public partial class ConsumableItemStats : InventoryItemStats
|
||||
[Export]
|
||||
[Save("consumable_item_raise_vt")]
|
||||
public int PermanentRaiseVTAmount { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
public bool HealsStatusAilments { get; set; } = false;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
PermanentRaiseHPAmount = 0
|
||||
PermanentRaiseVTAmount = 0
|
||||
HealsStatusAilments = true
|
||||
Name = "Ancient Capsule"
|
||||
StatDescription = "Heals all status ailments."
|
||||
FlavorText = ""
|
||||
|
||||
@@ -8,7 +8,7 @@ height = 0.725098
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_wll7p"]
|
||||
radius = 0.470016
|
||||
|
||||
[node name="Ammo" type="RigidBody3D"]
|
||||
[node name="Weapon" type="RigidBody3D"]
|
||||
collision_layer = 0
|
||||
axis_lock_linear_x = true
|
||||
axis_lock_linear_z = true
|
||||
|
||||
@@ -125,6 +125,11 @@ unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Die"
|
||||
|
||||
[node name="RustButton" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer/VFlowContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Rust"
|
||||
|
||||
[node name="DebugInfoCheckbox" type="CheckBox" parent="MarginContainer/VBoxContainer/HBoxContainer/VFlowContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
@@ -21,6 +21,7 @@ public partial class DummyPlayer : CharacterBody3D, IPlayer
|
||||
public int HealthTimerHPRate { get; set; }
|
||||
public float HealthTimerSpeedModifier { get; }
|
||||
public bool AutoIdentifyItems { get; set; }
|
||||
public IStatusEffectComponent StatusEffectComponent { get; }
|
||||
|
||||
public event Action PlayerDied;
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
|
||||
|
||||
public IEquipmentComponent EquipmentComponent { get; private set; }
|
||||
|
||||
public IStatusEffectComponent StatusEffectComponent { get; private set; }
|
||||
|
||||
public Vector3 CurrentPosition => GlobalPosition;
|
||||
|
||||
public Basis CurrentBasis => Transform.Basis;
|
||||
@@ -70,6 +72,8 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
|
||||
|
||||
[Export(PropertyHint.Range, "1, 100, 1")] public int InitialLuck { get; set; } = 8;
|
||||
|
||||
[Export(PropertyHint.Range, "1, 60, 1")] public double RustDuration { get; set; } = 30;
|
||||
|
||||
[Export]
|
||||
private bool HealthTimerIsActive = false;
|
||||
#endregion
|
||||
@@ -149,6 +153,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
|
||||
ExperiencePointsComponent = new ExperiencePointsComponent();
|
||||
LuckComponent = new LuckComponent(InitialLuck);
|
||||
EquipmentComponent = new EquipmentComponent();
|
||||
StatusEffectComponent = new StatusEffectComponent(RustDuration);
|
||||
|
||||
_itemReroller = new ItemReroller(ItemDatabase.Instance);
|
||||
_playerEffectService = new PlayerEffectService(this);
|
||||
@@ -872,6 +877,19 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
|
||||
_playerEffectService.TakeSelfDamage(weapon.Stats.SelfDamage);
|
||||
if (weapon.WeaponTag == WeaponTag.Instakill)
|
||||
_playerEffectService.Instakill(enemy);
|
||||
if (weapon.WeaponTag == WeaponTag.RustChanceSelfAndEnemy)
|
||||
{
|
||||
var rustChance = 0.15f;
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
if (rng.Randf() <= rustChance)
|
||||
{
|
||||
if (rng.Randf() >= 0.5f && ((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag != AccessoryTag.StatusEffectImmunity)
|
||||
StatusEffectComponent.Rust.OnNext(true);
|
||||
else
|
||||
enemy.StatusEffectComponent.Rust.OnNext(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void CollisionDetector_AreaEntered(Area3D area)
|
||||
|
||||
@@ -26,6 +26,8 @@ public partial class PauseDebugMenu : Control, IDebugMenu
|
||||
|
||||
[Node] public Button LoadNextFloorButton { get; set; } = default!;
|
||||
|
||||
[Node] public Button RustButton { get; set; } = default!;
|
||||
|
||||
[Node] public Button DieButton { get; set; } = default!;
|
||||
|
||||
[Node] public CheckBox DebugInfoCheckbox { get; set; } = default!;
|
||||
@@ -42,6 +44,7 @@ public partial class PauseDebugMenu : Control, IDebugMenu
|
||||
{
|
||||
LoadNextFloorButton.Pressed += LoadNextFloorButton_Pressed;
|
||||
DieButton.Pressed += DieButton_Pressed;
|
||||
RustButton.Pressed += RustButton_Pressed;
|
||||
|
||||
_itemDatabase = ItemDatabase.Instance;
|
||||
_spawnableItems = _itemDatabase.Items;
|
||||
@@ -94,6 +97,8 @@ public partial class PauseDebugMenu : Control, IDebugMenu
|
||||
|
||||
private void DieButton_Pressed() => _player.Die();
|
||||
|
||||
private void RustButton_Pressed() => _player.StatusEffectComponent.Rust.OnNext(true);
|
||||
|
||||
private void FloorSelectDropDown_ItemSelected(long index)
|
||||
{
|
||||
var sceneName = FloorSelectDropDown.GetItemText((int)index);
|
||||
|
||||
Reference in New Issue
Block a user