diff --git a/Growing/PlantInstance.cs b/Growing/PlantInstance.cs new file mode 100644 index 00000000..8bcfe5b6 --- /dev/null +++ b/Growing/PlantInstance.cs @@ -0,0 +1,77 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1Growing = Il2CppScheduleOne.Growing; +#elif (MONOMELON || MONOBEPINEX) +using S1Growing = ScheduleOne.Growing; +#endif + +using S1API.Internal.Utils; +using S1API.Items; +using UnityEngine; + +namespace S1API.Growing +{ + /// + /// Represents an instance of a growing plant in the world. + /// + public class PlantInstance + { + /// + /// INTERNAL: The in-game Plant object. + /// + internal readonly S1Growing.Plant S1Plant; + + /// + /// INTERNAL: Create a wrapper around an existing Plant. + /// + /// The in-game Plant to wrap. + internal PlantInstance(S1Growing.Plant plant) + { + S1Plant = plant; + } + + /// + /// The current growth stage as a float from 0.0 to 1.0. + /// + public float NormalizedGrowth => + S1Plant.NormalizedGrowthProgress; + + /// + /// Whether the plant is fully grown. + /// + public bool IsFullyGrown => + S1Plant.IsFullyGrown; + + /// + /// The SeedDefinition that this plant originated from. + /// + public SeedDefinition SeedDefinition => + new SeedDefinition(S1Plant.SeedDefinition); + + /// + /// The quality level of this plant. + /// + public float Quality => + S1Plant.QualityLevel; + + /// + /// The yield level (amount) of this plant. + /// + public float Yield => + S1Plant.YieldLevel; + + /// + /// The GameObject of the plant. + /// + public GameObject GameObject => + S1Plant.gameObject; + + /// + /// Destroys this plant in-game. + /// + /// Whether to drop trash scraps. + public void Destroy(bool dropScraps = false) + { + S1Plant.Destroy(dropScraps); + } + } +} diff --git a/Growing/SeedCreator.cs b/Growing/SeedCreator.cs new file mode 100644 index 00000000..8729a58f --- /dev/null +++ b/Growing/SeedCreator.cs @@ -0,0 +1,57 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1Growing = Il2CppScheduleOne.Growing; +using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1Registry = Il2CppScheduleOne.Registry; +#elif (MONOMELON || MONOBEPINEX) +using S1Growing = ScheduleOne.Growing; +using S1ItemFramework = ScheduleOne.ItemFramework; +using S1Registry = ScheduleOne.Registry; +#endif + +using UnityEngine; +using System.Linq; + + +namespace S1API.Growing +{ + /// + /// The seed Creator for custom seeds to be added. + /// + public static class SeedCreator + { + public static SeedDefinition CreateSeed( + string id, + string name, + string description, + int stackLimit = 10, + GameObject functionSeedPrefab = null, + GameObject plantPrefab = null, + Sprite icon = null) + { + S1Growing.SeedDefinition seed = ScriptableObject.CreateInstance(); + + seed.ID = id; + seed.Name = name; + seed.Description = description; + seed.StackLimit = stackLimit; + seed.Category = S1ItemFramework.EItemCategory.Growing; + + // if (icon != null) + // { + // seed.Icon = icon; + // } + // commented out for more test later. + + if (functionSeedPrefab != null) + seed.FunctionSeedPrefab = functionSeedPrefab.GetComponent(); + + if (plantPrefab != null) + seed.PlantPrefab = plantPrefab.GetComponent(); + + S1Registry.Instance.AddToRegistry(seed); + + return new SeedDefinition(seed); + } + + } +} \ No newline at end of file diff --git a/Growing/SeedDefinition.cs b/Growing/SeedDefinition.cs new file mode 100644 index 00000000..745a8e17 --- /dev/null +++ b/Growing/SeedDefinition.cs @@ -0,0 +1,54 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1Growing = Il2CppScheduleOne.Growing; +#elif (MONOMELON || MONOBEPINEX) +using S1Growing = ScheduleOne.Growing; +#endif + +using S1API.Internal.Utils; +using S1API.Items; + +namespace S1API.Growing +{ + /// + /// Represents the definition of a Seed item (what you buy in shops). + /// + public class SeedDefinition : ItemDefinition + { + /// + /// INTERNAL: Stored reference to the SeedDefinition. + /// + internal S1Growing.SeedDefinition S1SeedDefinition => + CrossType.As(S1ItemDefinition); + + /// + /// INTERNAL: Create a new wrapper around an existing SeedDefinition. + /// + /// The in-game SeedDefinition to wrap. + internal SeedDefinition(S1Growing.SeedDefinition definition) : base(definition) { } + + /// + /// The prefab that is spawned when planting this seed. + /// + public UnityEngine.GameObject FunctionalSeedPrefab => + S1SeedDefinition.FunctionSeedPrefab?.gameObject; + + /// + /// The plant prefab this seed grows into. + /// + public UnityEngine.GameObject PlantPrefab => + S1SeedDefinition.PlantPrefab?.gameObject; + + /// + /// Creates an instance of this seed in the world (FunctionalSeed prefab). + /// + public UnityEngine.GameObject CreateSeedInstance() + { + if (S1SeedDefinition.FunctionSeedPrefab != null) + return UnityEngine.Object.Instantiate(S1SeedDefinition.FunctionSeedPrefab).gameObject; + + throw new System.NullReferenceException("No FunctionalSeedPrefab assigned to this SeedDefinition!"); + } + + + } +} \ No newline at end of file diff --git a/Growing/SeedInstance.cs b/Growing/SeedInstance.cs new file mode 100644 index 00000000..97bafe45 --- /dev/null +++ b/Growing/SeedInstance.cs @@ -0,0 +1,55 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1Growing = Il2CppScheduleOne.Growing; +#elif (MONOMELON || MONOBEPINEX) +using S1Growing = ScheduleOne.Growing; +#endif + +using UnityEngine; +using S1API.Internal.Utils; + +namespace S1API.Growing +{ + /// + /// Represents an instance of a functional seed in the world. + /// (Not just the definition — this is the physical object you interact with.) + /// + public class SeedInstance + { + /// + /// INTERNAL: Reference to the in-game FunctionalSeed object. + /// + internal readonly S1Growing.FunctionalSeed S1FunctionalSeed; + + /// + /// INTERNAL: Creates a wrapper around the existing FunctionalSeed. + /// + /// The FunctionalSeed object to wrap. + internal SeedInstance(S1Growing.FunctionalSeed functionalSeed) + { + S1FunctionalSeed = functionalSeed; + } + + /// + /// The underlying GameObject of this seed. + /// + private GameObject GameObject => + S1FunctionalSeed.gameObject; + + /// + /// Whether the seed currently has exited its vial. + /// + public bool HasExitedVial { get; private set; } = false; + + /// + /// Force the seed to exit the vial manually. + /// + public void ForceExitVial() + { + if (S1FunctionalSeed.Vial != null) + { + S1FunctionalSeed.TriggerExit(S1FunctionalSeed.Vial.GetComponent()); + HasExitedVial = true; + } + } + } +} \ No newline at end of file diff --git a/Items/ItemCategory.cs b/Items/ItemCategory.cs new file mode 100644 index 00000000..a4e88df8 --- /dev/null +++ b/Items/ItemCategory.cs @@ -0,0 +1,70 @@ +namespace S1API.Items +{ + /// + /// A list of item categories available in-game. + /// + public enum ItemCategory + { + /// + /// Represents items such as Cocaine, Weed, etc. + /// Oddly, SpeedGrow is in this category as of (v0.3.4f8). + /// + Product, + + /// + /// Represents items such as Baggies, Bricks, Jars, etc. + /// + Packaging, + + /// + /// Represents items such as Soil, Fertilizer, Pots, etc. + /// + Growing, + + /// + /// Represents equipment tools such as the clippers. + /// Oddly, trash bags is in this category as of (v0.3.4f8). + /// + Tools, + + /// + /// Represents items such as TV, Trash Can, Bed, etc. + /// + Furniture, + + /// + /// Represents items such as Floor Lamps, Halogen Lights, etc. + /// + Lighting, + + /// + /// Represents cash-based items. + /// + Cash, + + /// + /// Represents items such as Cuke, Energy Drink, etc. + /// + Consumable, + + /// + /// Represents items such as Drying Rack, Brick Press, Mixing Station, etc. + /// + Equipment, + + /// + /// Represents items such as Acid, Banana, Chili, etc. + /// + Ingredient, + + /// + /// Represents items such as GoldBar, WallClock, WoodSign, etc. + /// + Decoration, + + /// + /// Represents clothing items. + /// + Clothing + } +} \ No newline at end of file diff --git a/Items/ItemDefinition.cs b/Items/ItemDefinition.cs new file mode 100644 index 00000000..c2f3b4db --- /dev/null +++ b/Items/ItemDefinition.cs @@ -0,0 +1,156 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +#elif (MONOMELON || MONOBEPINEX) +using S1ItemFramework = ScheduleOne.ItemFramework; +#endif + +using UnityEngine; +using S1API.Internal.Abstraction; + +namespace S1API.Items +{ + /// + /// Represents an item definition in-game. + /// Use this class to read and create new item definitions dynamically. + /// + public class ItemDefinition : IGUIDReference + { + /// + /// INTERNAL: A reference to the native game item definition. + /// + internal S1ItemFramework.ItemDefinition S1ItemDefinition { get; } + + /// + /// INTERNAL: Wraps an existing native item definition. + /// + internal ItemDefinition(S1ItemFramework.ItemDefinition definition) + { + S1ItemDefinition = definition; + } + + /// + /// The unique ID of this item. + /// + public string ID + { + get => S1ItemDefinition.ID; + set => S1ItemDefinition.ID = value; + } + + /// + /// The display name for this item. + /// + public string Name + { + get => S1ItemDefinition.Name; + set => S1ItemDefinition.Name = value; + } + + /// + /// A short description for this item. + /// + public string Description + { + get => S1ItemDefinition.Description; + set => S1ItemDefinition.Description = value; + } + + /// + /// Stack limit for this item (max quantity per slot). + /// + public int StackLimit + { + get => S1ItemDefinition.StackLimit; + set => S1ItemDefinition.StackLimit = value; + } + + /// + /// The category for inventory sorting. + /// + public ItemCategory Category + { + get => (ItemCategory)S1ItemDefinition.Category; + set => S1ItemDefinition.Category = (S1ItemFramework.EItemCategory)value; + } + + /// + /// The icon for this item. + /// + public Sprite Icon + { + get => S1ItemDefinition.Icon; + set => S1ItemDefinition.Icon = value; + } + + /// + /// Whether this item is available in the demo version of the game. + /// + public bool AvailableInDemo + { + get => S1ItemDefinition.AvailableInDemo; + set => S1ItemDefinition.AvailableInDemo = value; + } + + /// + /// Legal status of the item (e.g., illegal drugs). + /// + public LegalStatus LegalStatus + { + get => (LegalStatus)S1ItemDefinition.legalStatus; + set => S1ItemDefinition.legalStatus = (S1ItemFramework.ELegalStatus)value; + } + + + /// + /// The color of the label shown in UI. + /// + public Color LabelDisplayColor + { + get => S1ItemDefinition.LabelDisplayColor; + set => S1ItemDefinition.LabelDisplayColor = value; + } + + /// + /// Any keywords used to filter/search this item. + /// + public string[] Keywords + { + get => S1ItemDefinition.Keywords; + set => S1ItemDefinition.Keywords = value; + } + + /// + /// Creates a new item instance with the specified quantity. + /// + public virtual ItemInstance CreateInstance(int quantity = 1) + { + var inst = S1ItemDefinition.GetDefaultInstance(quantity); + return new ItemInstance(inst); + } + + + public string GUID => ID; + + public override bool Equals(object? obj) => + obj is ItemDefinition other && S1ItemDefinition == other.S1ItemDefinition; + + public override int GetHashCode() => + S1ItemDefinition?.GetHashCode() ?? 0; + + public static bool operator ==(ItemDefinition? a, ItemDefinition? b) => + ReferenceEquals(a, b) || (a is not null && b is not null && a.S1ItemDefinition == b.S1ItemDefinition); + + public static bool operator !=(ItemDefinition? a, ItemDefinition? b) => + !(a == b); + } + + /// + /// Represents the legal status of an item (e.g., legal or illegal). + /// + public enum LegalStatus + { + Legal, + Illegal, + // More if needed + } +} diff --git a/Items/ItemInstance.cs b/Items/ItemInstance.cs new file mode 100644 index 00000000..df388f4e --- /dev/null +++ b/Items/ItemInstance.cs @@ -0,0 +1,52 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +#elif (MONOMELON || MONOBEPINEX) +using S1ItemFramework = ScheduleOne.ItemFramework; +#endif + +using S1API.Items; +using S1API.Internal.Utils; + +namespace S1API.Items +{ + /// + /// Represents an item instance in the game world (physical item you own). + /// + public class ItemInstance + { + /// + /// INTERNAL: Reference to the in-game item instance. + /// + internal readonly S1ItemFramework.ItemInstance S1ItemInstance; + + /// + /// INTERNAL: Creates an ItemInstance wrapper. + /// + /// In-game item instance + internal ItemInstance(S1ItemFramework.ItemInstance itemInstance) => + S1ItemInstance = itemInstance; + + // ====== Properties ====== + + /// + /// The definition (template) this instance was created from. + /// + public ItemDefinition Definition => + new ItemDefinition(S1ItemInstance.Definition); + + /// + /// Current quantity of this item (stacks). + /// + public int Quantity + { + get => S1ItemInstance.Quantity; + set => S1ItemInstance.SetQuantity(value); + } + + /// + /// Whether this instance is stackable (based on StackLimit). + /// + public bool IsStackable => + Definition.StackLimit > 1; + } +} diff --git a/Items/ItemManager.cs b/Items/ItemManager.cs new file mode 100644 index 00000000..e886c6df --- /dev/null +++ b/Items/ItemManager.cs @@ -0,0 +1,42 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1 = Il2CppScheduleOne; +using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1Product = Il2CppScheduleOne.Product; +#elif (MONOMELON || MONOBEPINEX) +using S1 = ScheduleOne; +using S1ItemFramework = ScheduleOne.ItemFramework; +using S1Product = ScheduleOne.Product; +#endif + +using S1API.Internal.Utils; +using S1API.Money; +using S1API.Products; + +namespace S1API.Items +{ + /// + /// Provides access to managing items across the game. + /// + public static class ItemManager + { + /// + /// Gets the definition of an item by its ID. + /// + /// The ID of the item. + /// An instance of the item definition. + public static ItemDefinition GetItemDefinition(string itemID) + { + S1ItemFramework.ItemDefinition itemDefinition = S1.Registry.GetItem(itemID); + + if (CrossType.Is(itemDefinition, + out S1Product.ProductDefinition productDefinition)) + return new ProductDefinition(productDefinition); + + if (CrossType.Is(itemDefinition, + out S1ItemFramework.CashDefinition cashDefinition)) + return new CashDefinition(cashDefinition); + + return new ItemDefinition(itemDefinition); + } + } +} diff --git a/Items/ItemSlotInstance.cs b/Items/ItemSlotInstance.cs new file mode 100644 index 00000000..ad51429d --- /dev/null +++ b/Items/ItemSlotInstance.cs @@ -0,0 +1,70 @@ +#if (IL2CPPMELON || IL2CPPBEPINEX) +using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1Product = Il2CppScheduleOne.Product; +#elif (MONOMELON || MONOBEPINEX) +using S1ItemFramework = ScheduleOne.ItemFramework; +using S1Product = ScheduleOne.Product; +#endif + +using S1API.Internal.Utils; +using S1API.Money; +using S1API.Products; + +namespace S1API.Items +{ + /// + /// Represents an item slot within the game. + /// These are present within storage, the hot bar, etc. + /// + public class ItemSlotInstance + { + /// + /// INTERNAL: The reference to the item slot in the game. + /// + internal readonly S1ItemFramework.ItemSlot S1ItemSlot; + + /// + /// Creates an item slot instance from the in game slot. + /// + /// + internal ItemSlotInstance(S1ItemFramework.ItemSlot itemSlot) => + S1ItemSlot = itemSlot; + + /// + /// The quantity of item in this slot. + /// + public int Quantity => + S1ItemSlot.Quantity; + + /// + /// The item instance the slot contains. + /// + public ItemInstance? ItemInstance + { + get + { + if (CrossType.Is(S1ItemSlot.ItemInstance, + out S1Product.ProductItemInstance productItemInstance)) + return new ProductInstance(productItemInstance); + + if (CrossType.Is(S1ItemSlot.ItemInstance, + out S1ItemFramework.CashInstance cashInstance)) + return new CashInstance(cashInstance); + + if (CrossType.Is(S1ItemSlot.ItemInstance, + out S1ItemFramework.ItemInstance itemInstance)) + return new ItemInstance(itemInstance); + + return null; + } + } + + /// + /// Adds a quantity to the item in this slot. + /// NOTE: Negative numbers are supported and allowed. + /// + /// + public void AddQuantity(int amount) => + S1ItemSlot.ChangeQuantity(amount); + } +} diff --git a/S1API/Growing/PlantInstance.cs b/S1API/Growing/PlantInstance.cs new file mode 100644 index 00000000..b706b05d --- /dev/null +++ b/S1API/Growing/PlantInstance.cs @@ -0,0 +1,77 @@ +#if (IL2CPPMELON) +using S1Growing = Il2CppScheduleOne.Growing; +#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) +using S1Growing = ScheduleOne.Growing; +#endif + +using S1API.Internal.Utils; +using S1API.Items; +using UnityEngine; + +namespace S1API.Growing +{ + /// + /// Represents an instance of a growing plant in the world. + /// + public class PlantInstance + { + /// + /// INTERNAL: The in-game Plant object. + /// + internal readonly S1Growing.Plant S1Plant; + + /// + /// INTERNAL: Create a wrapper around an existing Plant. + /// + /// The in-game Plant to wrap. + internal PlantInstance(S1Growing.Plant plant) + { + S1Plant = plant; + } + + /// + /// The current growth stage as a float from 0.0 to 1.0. + /// + public float NormalizedGrowth => + S1Plant.NormalizedGrowthProgress; + + /// + /// Whether the plant is fully grown. + /// + public bool IsFullyGrown => + S1Plant.IsFullyGrown; + + /// + /// The SeedDefinition that this plant originated from. + /// + public SeedDefinition SeedDefinition => + new SeedDefinition(S1Plant.SeedDefinition); + + /// + /// The quality level of this plant. + /// + public float Quality => + S1Plant.QualityLevel; + + /// + /// The yield level (amount) of this plant. + /// + public float Yield => + S1Plant.YieldLevel; + + /// + /// The GameObject of the plant. + /// + private GameObject GameObject => + S1Plant.gameObject; + + /// + /// Destroys this plant in-game. + /// + /// Whether to drop trash scraps. + public void Destroy(bool dropScraps = false) + { + S1Plant.Destroy(dropScraps); + } + } +} diff --git a/S1API/Growing/SeedCreator.cs b/S1API/Growing/SeedCreator.cs new file mode 100644 index 00000000..18b7a556 --- /dev/null +++ b/S1API/Growing/SeedCreator.cs @@ -0,0 +1,55 @@ +#if (IL2CPPMELON) +using S1Growing = Il2CppScheduleOne.Growing; +using S1ItemFramework = Il2CppScheduleOne.ItemFramework; +using S1Registry = Il2CppScheduleOne.Registry; +#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) +using S1Growing = ScheduleOne.Growing; +using S1ItemFramework = ScheduleOne.ItemFramework; +using S1Registry = ScheduleOne.Registry; +#endif + +using UnityEngine; + +namespace S1API.Growing +{ + /// + /// The seed Creator for custom seeds to be added. + /// + public static class SeedCreator + { + public static SeedDefinition CreateSeed( + string id, + string name, + string description, + int stackLimit = 10, + GameObject? functionSeedPrefab = null, + GameObject? plantPrefab = null, + Sprite? icon = null) + { + S1Growing.SeedDefinition seed = ScriptableObject.CreateInstance(); + + seed.ID = id; + seed.Name = name; + seed.Description = description; + seed.StackLimit = stackLimit; + seed.Category = S1ItemFramework.EItemCategory.Growing; + + // if (icon != null) + // { + // seed.Icon = icon; + // } + // commented out for more test later. + + if (functionSeedPrefab != null) + seed.FunctionSeedPrefab = functionSeedPrefab.GetComponent(); + + if (plantPrefab != null) + seed.PlantPrefab = plantPrefab.GetComponent(); + + S1Registry.Instance.AddToRegistry(seed); + + return new SeedDefinition(seed); + } + + } +} diff --git a/S1API/Growing/SeedDefinition.cs b/S1API/Growing/SeedDefinition.cs new file mode 100644 index 00000000..d3e0886c --- /dev/null +++ b/S1API/Growing/SeedDefinition.cs @@ -0,0 +1,55 @@ +#if (IL2CPPMELON) +using S1Growing = Il2CppScheduleOne.Growing; +#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) +using S1Growing = ScheduleOne.Growing; +#endif + +using System; +using UnityEngine; + +using S1API.Internal.Utils; +using S1API.Items; + +namespace S1API.Growing +{ + /// + /// Represents the definition of a Seed item (what you buy in shops). + /// + public class SeedDefinition : ItemDefinition + { + /// + /// INTERNAL: Stored reference to the SeedDefinition. + /// + internal S1Growing.SeedDefinition S1SeedDefinition => + CrossType.As(S1ItemDefinition); + + /// + /// INTERNAL: Create a new wrapper around an existing SeedDefinition. + /// + /// The in-game SeedDefinition to wrap. + internal SeedDefinition(S1Growing.SeedDefinition definition) : base(definition) { } + + /// + /// The prefab that is spawned when planting this seed. + /// + public GameObject? FunctionalSeedPrefab => S1SeedDefinition.FunctionSeedPrefab?.gameObject; + + /// + /// The plant prefab this seed grows into. + /// + public GameObject? PlantPrefab => S1SeedDefinition.PlantPrefab?.gameObject; + + /// + /// Creates an instance of this seed in the world (FunctionalSeed prefab). + /// + public GameObject CreateSeedInstance() + { + if (S1SeedDefinition.FunctionSeedPrefab != null) + return UnityEngine.Object.Instantiate(S1SeedDefinition.FunctionSeedPrefab).gameObject; + + throw new NullReferenceException("No FunctionalSeedPrefab assigned to this SeedDefinition!"); + } + + + } +} diff --git a/S1API/Growing/SeedInstance.cs b/S1API/Growing/SeedInstance.cs new file mode 100644 index 00000000..f9767b78 --- /dev/null +++ b/S1API/Growing/SeedInstance.cs @@ -0,0 +1,55 @@ +#if (IL2CPPMELON) +using S1Growing = Il2CppScheduleOne.Growing; +#elif (MONOMELON || MONOBEPINEX || IL2CPPBEPINEX) +using S1Growing = ScheduleOne.Growing; +#endif + +using UnityEngine; +using S1API.Internal.Utils; + +namespace S1API.Growing +{ + /// + /// Represents an instance of a functional seed in the world. + /// (Not just the definition — this is the physical object you interact with.) + /// + public class SeedInstance + { + /// + /// INTERNAL: Reference to the in-game FunctionalSeed object. + /// + internal readonly S1Growing.FunctionalSeed S1FunctionalSeed; + + /// + /// INTERNAL: Creates a wrapper around the existing FunctionalSeed. + /// + /// The FunctionalSeed object to wrap. + internal SeedInstance(S1Growing.FunctionalSeed functionalSeed) + { + S1FunctionalSeed = functionalSeed; + } + + /// + /// The underlying GameObject of this seed. + /// + private GameObject GameObject => + S1FunctionalSeed.gameObject; + + /// + /// Whether the seed currently has exited its vial. + /// + public bool HasExitedVial { get; private set; } = false; + + /// + /// Force the seed to exit the vial manually. + /// + public void ForceExitVial() + { + if (S1FunctionalSeed.Vial != null) + { + S1FunctionalSeed.TriggerExit(S1FunctionalSeed.Vial.GetComponent()); + HasExitedVial = true; + } + } + } +} diff --git a/S1API/Items/ItemDefinition.cs b/S1API/Items/ItemDefinition.cs index b4ba934e..24b6e213 100644 --- a/S1API/Items/ItemDefinition.cs +++ b/S1API/Items/ItemDefinition.cs @@ -4,115 +4,174 @@ using S1ItemFramework = ScheduleOne.ItemFramework; #endif +using UnityEngine; using S1API.Internal.Abstraction; namespace S1API.Items { /// /// Represents an item definition in-game. - /// NOTE: A definition is "what" the item is. For example, "This is a `Soda`". - /// Any instanced items in the game will be a instead. + /// Use this class to read and create new item definitions dynamically. /// public class ItemDefinition : IGUIDReference { /// - /// INTERNAL: A reference to the item definition in the game. + /// INTERNAL: A reference to the native game item definition. /// - internal readonly S1ItemFramework.ItemDefinition S1ItemDefinition; + internal S1ItemFramework.ItemDefinition S1ItemDefinition { get; } /// - /// Creates a new item definition from the game item definition instance. + /// INTERNAL: Wraps an existing native item definition. /// - /// - internal ItemDefinition(S1ItemFramework.ItemDefinition s1ItemDefinition) => - S1ItemDefinition = s1ItemDefinition; + internal ItemDefinition(S1ItemFramework.ItemDefinition definition) + { + S1ItemDefinition = definition; + } /// - /// INTERNAL: Gets an item definition from a GUID. + /// The unique ID of this item. /// - /// The GUID to look for - /// The applicable item definition, if found. - internal static ItemDefinition GetFromGUID(string guid) => - ItemManager.GetItemDefinition(guid); + public string ID + { + get => S1ItemDefinition.ID; + set => S1ItemDefinition.ID = value; + } /// - /// Performs an equals check on the game item definition instance. + /// The display name for this item. /// - /// The item definition you want to compare against. - /// Whether the item definitions are the same or not. - public override bool Equals(object? obj) => - obj is ItemDefinition other && S1ItemDefinition == other.S1ItemDefinition; + public string Name + { + get => S1ItemDefinition.Name; + set => S1ItemDefinition.Name = value; + } /// - /// Snags the hash code from the game instance versus this instance. + /// A short description for this item. /// - /// The game intance hash code - public override int GetHashCode() => - S1ItemDefinition?.GetHashCode() ?? 0; + public string Description + { + get => S1ItemDefinition.Description; + set => S1ItemDefinition.Description = value; + } /// - /// Performs an == check on the game item definition instance. + /// Stack limit for this item (max quantity per slot). /// - /// The first item definition to compare. - /// The second item definition to compare. - /// Whether the item definitions are the same or not. - public static bool operator ==(ItemDefinition? left, ItemDefinition? right) + public int StackLimit { - if (ReferenceEquals(left, right)) return true; - return left?.S1ItemDefinition == right?.S1ItemDefinition; + get => S1ItemDefinition.StackLimit; + set => S1ItemDefinition.StackLimit = value; } /// - /// Performs an != check on the game item definition instance. + /// The category for inventory sorting. /// - /// The first item definition to compare. - /// The second item definition to compare. - /// Whether the item definitions are different or not. - public static bool operator !=(ItemDefinition left, ItemDefinition right) => - !(left == right); + public ItemCategory Category + { + get => (ItemCategory)S1ItemDefinition.Category; + set => S1ItemDefinition.Category = (S1ItemFramework.EItemCategory)value; + } /// - /// The unique identifier assigned to this item definition. + /// The icon for this item. /// - public virtual string GUID => - S1ItemDefinition.ID; + public Sprite Icon + { + get => S1ItemDefinition.Icon; + set => S1ItemDefinition.Icon = value; + } /// - /// The unique identifier assigned to this item definition. + /// Whether this item is available in the demo version of the game. /// - public string ID => - S1ItemDefinition.ID; + public bool AvailableInDemo + { + get => S1ItemDefinition.AvailableInDemo; + set => S1ItemDefinition.AvailableInDemo = value; + } /// - /// The display name for this item. + /// Legal status of the item (e.g., illegal drugs). + /// + public LegalStatus LegalStatus + { + get => (LegalStatus)S1ItemDefinition.legalStatus; + set => S1ItemDefinition.legalStatus = (S1ItemFramework.ELegalStatus)value; + } + + + /// + /// The color of the label shown in UI. + /// + public Color LabelDisplayColor + { + get => S1ItemDefinition.LabelDisplayColor; + set => S1ItemDefinition.LabelDisplayColor = value; + } + + /// + /// Any keywords used to filter/search this item. /// - public string Name => - S1ItemDefinition.Name; + public string[] Keywords + { + get => S1ItemDefinition.Keywords; + set => S1ItemDefinition.Keywords = value; + } /// - /// The description used for this item. + /// Creates a new item instance with the specified quantity. /// - public string Description => - S1ItemDefinition.Description; + public virtual ItemInstance CreateInstance(int quantity = 1) + { + var inst = S1ItemDefinition.GetDefaultInstance(quantity); + return new ItemInstance(inst); + } /// - /// The category this item is assigned to. + /// Gets the globally unique identifier (GUID) of the item, which is equivalent to the ID. /// - public ItemCategory Category => - (ItemCategory)S1ItemDefinition.Category; + public string GUID => ID; /// - /// The stack limit for this item. + /// Determines whether the specified object is equal to the current object. /// - public int StackLimit => - S1ItemDefinition.StackLimit; + /// The object to compare with the current object. + /// true if the specified object is an and has the same S1ItemDefinition; otherwise, false. + public override bool Equals(object? obj) => + obj is ItemDefinition other && S1ItemDefinition == other.S1ItemDefinition; /// - /// Creates an instance of this item from the definition. + /// Serves as the default hash function. /// - /// How many of the item the instance will have. - /// A new item instance within the game. - public virtual ItemInstance CreateInstance(int quantity = 1) => - new ItemInstance(S1ItemDefinition.GetDefaultInstance(quantity)); + /// A hash code for the current object based on S1ItemDefinition. + public override int GetHashCode() => S1ItemDefinition.GetHashCode(); + + /// + /// Determines whether two instances are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if both instances are equal or have the same S1ItemDefinition; otherwise, false. + public static bool operator ==(ItemDefinition? a, ItemDefinition? b) => + ReferenceEquals(a, b) || a != null && b != null && a.S1ItemDefinition == b.S1ItemDefinition; + + /// + /// Determines whether two instances are not equal. + /// + /// The first to compare. + /// The second to compare. + /// true if the instances are not equal; otherwise, false. + public static bool operator !=(ItemDefinition? a, ItemDefinition? b) => !(a == b); + } + + /// + /// Represents the legal status of an item (e.g., legal or illegal). + /// + public enum LegalStatus + { + Legal, + Illegal, + // More if needed } } diff --git a/S1API/Items/ItemInstance.cs b/S1API/Items/ItemInstance.cs index 3f9bb0c2..d3776c63 100644 --- a/S1API/Items/ItemInstance.cs +++ b/S1API/Items/ItemInstance.cs @@ -4,32 +4,49 @@ using S1ItemFramework = ScheduleOne.ItemFramework; #endif +using S1API.Items; +using S1API.Internal.Utils; namespace S1API.Items { /// - /// Represents an item instance in the game. - /// NOTE: A instance is the item existing in the game world. For example, "I have five sodas in my hand.". - /// The definition for items in the game will be a instead. + /// Represents an item instance in the game world (physical item you own). /// public class ItemInstance { /// - /// INTERNAL: The reference to the instance of this item. + /// INTERNAL: Reference to the in-game item instance. /// internal readonly S1ItemFramework.ItemInstance S1ItemInstance; /// - /// INTERNAL: Creates an item instance + /// INTERNAL: Creates an ItemInstance wrapper. /// - /// The instance of the item instance in-game. + /// In-game item instance internal ItemInstance(S1ItemFramework.ItemInstance itemInstance) => S1ItemInstance = itemInstance; + // ====== Properties ====== + /// - /// The item definition of this item. + /// The definition (template) this instance was created from. /// public ItemDefinition Definition => new ItemDefinition(S1ItemInstance.Definition); + + /// + /// Current quantity of this item (stacks). + /// + public int Quantity + { + get => S1ItemInstance.Quantity; + set => S1ItemInstance.SetQuantity(value); + } + + /// + /// Whether this instance is stackable (based on StackLimit). + /// + public bool IsStackable => + Definition.StackLimit > 1; } } diff --git a/S1API/S1API.csproj b/S1API/S1API.csproj index 51ca67e3..cc105058 100644 --- a/S1API/S1API.csproj +++ b/S1API/S1API.csproj @@ -56,6 +56,7 @@ + @@ -73,6 +74,7 @@ + @@ -90,7 +92,7 @@ - +