using Cirno.Scripts.Interactables; using Cirno.Scripts.Resources.ItemEffects; using Godot; namespace Cirno.Scripts.Resources; [GlobalClass] [Tool] public partial class LootItem : Resource { [Export] public StringName ItemName { get; set; } [Export] public StringName ShortName { get; set; } [Export] public StringName ItemDescription { get; set; } [Export] public StringName ItemKey { get; set; } [Export] public ItemTypes Item; [Export] public int Tier { get; set; } = 0; [Export] public int Price { get; set; } [Export] public ItemEffectResource ItemEffect { get; private set; } [Export] public WeaponResource WeaponData { get; set; } [Export] public WeaponResource WeaponData3D { get; set; } [Export] public int Amount; [Export] public int Max; [Export] public bool PickupIfMaxed; [Export] public bool ConsumeOnUse; [Export(PropertyHint.Flags, "Icon,Count,Ammo,Energy")] public UiItemType UiType { get; set; } = 0; [Export] public bool Selectable; [Export] public bool AutoPickup { get; private set; } = false; [Export] public Texture2D InventorySprite; //[Export] public SpriteFrames WorldSprite; //[Export] public PackedScene HudItemScene; [Export(PropertyHint.File)] public StringName DropScenePath { get; private set; } // Has to be a string path to avoid recursion issues [Export(PropertyHint.File)] public StringName DropScenePath3D { get; private set; } // Has to be a string path to avoid recursion issues public ItemPickup Spawn(Node2D sibling, bool dropAsChild = false) { if (string.IsNullOrWhiteSpace(DropScenePath)) return null; var itemScene = GD.Load(DropScenePath); var spawnedItem = dropAsChild ? sibling.CreateChild(itemScene) : sibling.CreateSibling(itemScene); spawnedItem.Name = this.ItemKey; spawnedItem.LootTable.Add(this); spawnedItem.SetSprite(InventorySprite); return spawnedItem; } /// /// Spawns this item as an in the 3D world. /// /// Reference node used to determine parent and default spawn position. /// If true, spawns as a child of ; otherwise as a sibling. /// /// Optional world-space position override. When null, the position of is used. /// Pass a custom value to scatter drops instead of stacking them all at the same point. /// /// Optional initial velocity applied to the pickup so it arcs and falls to the floor. public ItemPickup3D Spawn3D(Node3D sibling, bool dropAsChild = false, Vector3? spawnPosition = null, Vector3? launchVelocity = null) { if (string.IsNullOrWhiteSpace(DropScenePath3D)) return null; var itemScene = GD.Load(DropScenePath3D); var spawnedItem = itemScene.Instantiate(); spawnedItem.Name = this.ItemKey; var position = spawnPosition ?? sibling.GlobalPosition; if (dropAsChild) { CallDeferred(MethodName.DeferredSpawn3D, sibling, spawnedItem, position); } else { CallDeferred(MethodName.DeferredSpawn3D, sibling.GetParentNode3D(), spawnedItem, position); } spawnedItem.LootTable.Add(this); spawnedItem.SetSprite(InventorySprite); if (launchVelocity.HasValue) { spawnedItem.Launch(launchVelocity.Value); } return spawnedItem; } private void DeferredSpawn3D(Node3D parent, Node3D instance, Vector3 position) { parent.AddChild(instance); instance.GlobalPosition = position; } }