using Godot; using System; using Chickensoft.AutoInject; using Chickensoft.Introspection; using Gamesmiths.Forge.Abilities; using Gamesmiths.Forge.Core; using Gamesmiths.Forge.Cues; using Gamesmiths.Forge.Effects; using Gamesmiths.Forge.Events; using Gamesmiths.Forge.Godot.Resources.Abilities; using Gamesmiths.Forge.Statescript; using Gamesmiths.Forge.Tags; using Movementtests.interfaces; using Movementtests.tools; using Node = Godot.Node; [GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_bullet.png"), Meta(typeof(IAutoNode))] public partial class Projectile : RigidBody3D, IForgeEntity, ITargetable, IKillable, ISpawnable { public override void _Notification(int what) => this.Notify(what); #region Dependencies [Dependency] public TagsManager TagsManager => this.DependOn(); [Dependency] public CuesManager CuesManager => this.DependOn(); #endregion #region IForgeEntity // Perfectly forward the IForgeEntity interface to the ForgeEntity component public EntityAttributes Attributes { get => ForgeEntity.Attributes; set => ForgeEntity.Attributes = value; } public EntityTags Tags { get => ForgeEntity.Tags; set => ForgeEntity.Tags = value; } public EffectsManager EffectsManager { get => ForgeEntity.EffectsManager; set => ForgeEntity.EffectsManager = value; } public EntityAbilities Abilities { get => ForgeEntity.Abilities; set => ForgeEntity.Abilities = value; } public EventManager Events { get => ForgeEntity.Events; set => ForgeEntity.Events = value; } public Variables SharedVariables { get => ForgeEntity.SharedVariables; set => ForgeEntity.SharedVariables = value; } #endregion [Node("ForgeEntityNode")] public required ForgeEntityNode ForgeEntity { get; set;} [Export] public float Damage = 10f; [Export] public float Speed = 10f; [Export] public float HomingFactor = 0.2f; public Node3D? Target { get; set; } public void Init() { ApplyCentralImpulse(ComputeImpulseToTarget()); } public Vector3 ComputeImpulseToTarget() { if (Target == null) return Vector3.Zero; return Vector3.Up * Speed; var targetDir = GlobalPosition.DirectionTo(Target.GlobalPosition); var hDir = new Vector3(targetDir.X, 0, targetDir.Z).Normalized(); var throwDir = (hDir + 3*Vector3.Up).Normalized(); var distanceTo = GlobalPosition.DistanceTo(Target.GlobalPosition); return throwDir * distanceTo*0.8f; } public override void _IntegrateForces(PhysicsDirectBodyState3D state) { if (Target == null) return; var targetPos = Target is ITargetable targetable ? targetable.GetTargetGlobalPosition() : Target.GlobalPosition; var targetVel = state.LinearVelocity + GlobalPosition.DirectionTo(targetPos) * HomingFactor; if (targetVel.Length() > Speed) targetVel = targetVel.Normalized() * Speed; state.LinearVelocity = targetVel; // var targetDir = GlobalPosition.DirectionTo(targetPos); // var hDir = new Vector3(targetDir.X, 0, targetDir.Z).Normalized(); // var currentVelocityHDir = new Vector3(state.LinearVelocity.X, 0, state.LinearVelocity.Z); // var finalHDir = hDir*HomingFactor + currentVelocityHDir; // var combinedVelocity = new Vector3(finalHDir.X, state.LinearVelocity.Y, finalHDir.Z); // if (combinedVelocity.Length() > Speed) combinedVelocity = combinedVelocity.Normalized() * Speed; // state.LinearVelocity = combinedVelocity; // state.LinearVelocity += targetDir/5.0f; } public void OnResolved() { BodyEntered += OnProjectileHit; // Events.Subscribe(Tag.RequestTag(TagsManager, "events.weapon.flyingtick"), data => { GD.Print("tick"); }); } private void OnProjectileHit(Node body) { if (body is IForgeEntity entity) { Events.Raise(new EventData { EventTags = Tag.RequestTag(TagsManager, "events.combat.hit").GetSingleTagContainer()!, Source = this, Target = entity, EventMagnitude = Damage }); } Events.Raise(new EventData { EventTags = Tag.RequestTag(TagsManager, "events.weapon.planted").GetSingleTagContainer()!, Source = this, EventMagnitude = Damage }); Kill(); } public Vector3 GetTargetGlobalPosition() { return GlobalPosition; } public void Kill() { QueueFree(); // If thrown offmap } }