Files
GameJamDungeon/Zennysoft.Game.Ma/src/items/thrown/ThrownItem.cs
2026-02-13 15:59:10 -08:00

139 lines
4.0 KiB
C#

using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Zennysoft.Ma.Adapter;
using Zennysoft.Ma.Adapter.Entity;
namespace Zennysoft.Game.Ma;
[Meta(typeof(IAutoNode))]
public partial class ThrownItem : RigidBody3D, IThrownItem
{
public override void _Notification(int what) => this.Notify(what);
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
[Dependency] public IGame Game => this.DependOn<IGame>();
public IBaseInventoryItem ItemThatIsThrown { get; set; }
private EffectService _effectService;
private ItemReroller _itemReroller;
[Node] public Sprite2D Sprite { get; set; } = default!;
[Node] public Area3D Collision { get; set; } = default!;
public void OnResolved()
{
BodyEntered += ThrownItem_BodyEntered;
Collision.AreaEntered += Collision_AreaEntered;
GlobalPosition = Player.GlobalPosition;
Sprite.Texture = ItemThatIsThrown.GetTexture();
AddCollisionExceptionWith((Node)Player);
Collision.SetCollisionLayerValue(3, false);
_itemReroller = new ItemReroller(ItemDatabase.Instance);
}
private void Collision_AreaEntered(Area3D area)
{
if (area.GetOwner() is IEnemy enemy)
{
CalculateEffect(enemy);
QueueFree();
}
}
private void ThrownItem_BodyEntered(Node body)
{
if (ItemThatIsThrown is ThrowableItem)
{
QueueFree();
}
else
{
RemoveCollisionExceptionWith((Node)Player);
Collision.SetCollisionLayerValue(3, true);
LinearVelocity = Vector3.Zero;
AngularVelocity = Vector3.Zero;
GravityScale = 0.5f;
}
}
public void Throw(EffectService effectService)
{
_effectService = effectService;
ApplyCentralImpulse(-Player.GlobalBasis.Z.Normalized() * ItemThatIsThrown.ThrowSpeed);
}
public void RescueItem()
{
ContactMonitor = false;
Freeze = true;
PlayRescueAnimation();
Game.RescuedItems.Items.Add(ItemThatIsThrown);
}
private void PlayRescueAnimation()
{
LoadShader("res://src/vfx/shaders/PixelMelt.gdshader");
var tweener = GetTree().CreateTween();
SetShaderValue(true);
tweener.TweenMethod(Callable.From((float x) => SetShaderValue(x)), 0.0f, 0.3f, 2f);
tweener.TweenCallback(Callable.From(QueueFree));
}
private void LoadShader(string shaderPath)
{
var shader = GD.Load<Shader>(shaderPath);
Sprite.Material = new ShaderMaterial();
var shaderMaterial = (ShaderMaterial)Sprite.Material;
shaderMaterial.Shader = shader;
}
private void SetShaderValue(float shaderValue)
{
var shaderMaterial = (ShaderMaterial)Sprite.Material;
shaderMaterial.SetShaderParameter("progress", shaderValue);
}
private void SetShaderValue(bool shaderValue)
{
var shaderMaterial = (ShaderMaterial)Sprite.Material;
shaderMaterial.SetShaderParameter("reverse", shaderValue);
}
private void CalculateEffect(IEnemy enemy)
{
if (ItemThatIsThrown.ItemTag == ItemTag.MysteryItem)
ItemThatIsThrown = _itemReroller.RerollItem(ItemThatIsThrown, Player.Inventory, false);
if (ItemThatIsThrown is EffectItem usableItem)
{
switch (usableItem.UsableItemTag)
{
case UsableItemTag.LowerTargetTo1HP:
enemy.HealthComponent.SetCurrentHealth(1);
break;
case UsableItemTag.TeleportToRandomLocation:
_effectService.TeleportToRandomRoom(enemy);
break;
default:
var damageDealt = DamageCalculator.CalculateDamage(new AttackData(usableItem.ThrowDamage, ElementType.None), enemy.DefenseComponent.CurrentDefense.Value, enemy.ElementalResistanceSet);
enemy.HealthComponent.Damage(damageDealt);
break;
}
}
else
{
var damageDealt = DamageCalculator.CalculateDamage(new AttackData(ItemThatIsThrown.ThrowDamage, ElementType.None), enemy.DefenseComponent.CurrentDefense.Value, enemy.ElementalResistanceSet);
enemy.HealthComponent.Damage(damageDealt);
}
}
public void OnExitTree()
{
BodyEntered -= ThrownItem_BodyEntered;
Collision.AreaEntered -= Collision_AreaEntered;
}
}