diff --git a/S1API/Console/ConsoleHelper.cs b/S1API/Console/ConsoleHelper.cs index ef60823b..a7bded34 100644 --- a/S1API/Console/ConsoleHelper.cs +++ b/S1API/Console/ConsoleHelper.cs @@ -1,15 +1,16 @@ -using System.Collections.Generic; - -#if IL2CPPMELON || IL2CPPBEPINEX +#if IL2CPP using Il2CppSystem.Collections.Generic; using static Il2CppScheduleOne.Console; - #else using static ScheduleOne.Console; +using System.Collections.Generic; #endif -namespace S1API.Utils +namespace S1API.Console { + /// + /// This class provides easy access to the in-game console system. + /// public static class ConsoleHelper { /// @@ -19,7 +20,7 @@ public static class ConsoleHelper /// The cash amount to add or remove. public static void RunCashCommand(int amount) { -#if IL2CPPMELON || IL2CPPBEPINEX +#if IL2CPP var command = new ChangeCashCommand(); var args = new Il2CppSystem.Collections.Generic.List(); #else @@ -30,4 +31,4 @@ public static void RunCashCommand(int amount) command.Execute(args); } } -} +} \ No newline at end of file diff --git a/S1API/Entities/Interfaces/IEntity.cs b/S1API/Entities/Interfaces/IEntity.cs new file mode 100644 index 00000000..cc551b10 --- /dev/null +++ b/S1API/Entities/Interfaces/IEntity.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace S1API.Entities.Interfaces +{ + /// + /// Represents an entity within the game world. + /// + public interface IEntity + { + /// + /// INTERNAL: Tracking of the GameObject associated with this entity. + /// + GameObject gameObject { get; } + + /// + /// The world position of the entity. + /// + public Vector3 Position { get; set; } + + /// + /// The scale of the entity. + /// + public float Scale { get; set; } + } +} \ No newline at end of file diff --git a/S1API/Entities/Interfaces/IHealth.cs b/S1API/Entities/Interfaces/IHealth.cs new file mode 100644 index 00000000..2be07bf1 --- /dev/null +++ b/S1API/Entities/Interfaces/IHealth.cs @@ -0,0 +1,57 @@ +using System; + +namespace S1API.Entities.Interfaces +{ + /// + /// Represents an entity that has health associated. + /// + public interface IHealth + { + /// + /// The current health of the entity. + /// + public float CurrentHealth { get; } + + /// + /// The max health of the entity. + /// + public float MaxHealth { get; set; } + + /// + /// Whether the entity is dead or not. + /// + public bool IsDead { get; } + + /// + /// Whether the entity is invincible. + /// + public bool IsInvincible { get; set; } + + /// + /// Revives the entity. + /// + public void Revive(); + + /// + /// Deals damage to the entity. + /// + /// Amount of damage to deal. + public void Damage(int amount); + + /// + /// Heals the entity. + /// + /// Amount of health to heal. + public void Heal(int amount); + + /// + /// Kills the entity. + /// + public void Kill(); + + /// + /// Called when entity's health is less than or equal to 0. + /// + public event Action OnDeath; + } +} \ No newline at end of file diff --git a/S1API/Entities/NPC.cs b/S1API/Entities/NPC.cs new file mode 100644 index 00000000..9d5b92e2 --- /dev/null +++ b/S1API/Entities/NPC.cs @@ -0,0 +1,632 @@ +#if (IL2CPP) +using S1DevUtilities = Il2CppScheduleOne.DevUtilities; +using S1Interaction = Il2CppScheduleOne.Interaction; +using S1Messaging = Il2CppScheduleOne.Messaging; +using S1Noise = Il2CppScheduleOne.Noise; +using S1Relation = Il2CppScheduleOne.NPCs.Relation; +using S1Responses = Il2CppScheduleOne.NPCs.Responses; +using S1PlayerScripts = Il2CppScheduleOne.PlayerScripts; +using S1ContactApps = Il2CppScheduleOne.UI.Phone.ContactsApp; +using S1WorkspacePopup = Il2CppScheduleOne.UI.WorldspacePopup; +using S1AvatarFramework = Il2CppScheduleOne.AvatarFramework; +using S1Behaviour = Il2CppScheduleOne.NPCs.Behaviour; +using S1Vehicles = Il2CppScheduleOne.Vehicles; +using S1Vision = Il2CppScheduleOne.Vision; +using S1NPCs = Il2CppScheduleOne.NPCs; +using Il2CppSystem.Collections.Generic; +#elif (MONO) +using S1DevUtilities = ScheduleOne.DevUtilities; +using S1Interaction = ScheduleOne.Interaction; +using S1Messaging = ScheduleOne.Messaging; +using S1Noise = ScheduleOne.Noise; +using S1Relation = ScheduleOne.NPCs.Relation; +using S1Responses = ScheduleOne.NPCs.Responses; +using S1PlayerScripts = ScheduleOne.PlayerScripts; +using S1ContactApps = ScheduleOne.UI.Phone.ContactsApp; +using S1WorkspacePopup = ScheduleOne.UI.WorldspacePopup; +using S1AvatarFramework = ScheduleOne.AvatarFramework; +using S1Behaviour = ScheduleOne.NPCs.Behaviour; +using S1Vehicles = ScheduleOne.Vehicles; +using S1Vision = ScheduleOne.Vision; +using S1NPCs = ScheduleOne.NPCs; +using System.Collections.Generic; +#endif + +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using HarmonyLib; +using S1API.Entities.Interfaces; +using S1API.Internal.Abstraction; +using S1API.Map; +using S1API.Messaging; +using UnityEngine; +using UnityEngine.Events; + +namespace S1API.Entities +{ + /// + /// An abstract class intended to be derived from for creating custom NPCs in the game. + /// + public abstract class NPC : Saveable, IEntity, IHealth + { + // Protected members intended to be used by modders. + // Intended to be used from within the class / derived classes ONLY. + #region Protected Members + + /// + /// A list of text responses you've added to your NPC. + /// + protected readonly System.Collections.Generic.List Responses = new System.Collections.Generic.List(); + + /// + /// Base constructor for a new NPC. + /// Not intended for instancing your NPC! + /// Instead, create your derived class and let S1API handle instancing. + /// + /// Unique identifier for your NPC. + /// The first name for your NPC. + /// The last name for your NPC. + /// The icon for your NPC for messages, realationships, etc. + protected NPC( + string id, + string? firstName, + string? lastName, + Sprite? icon = null + ) + { + IsCustomNPC = true; + gameObject = new GameObject(); + + // Deactivate game object til we're done + gameObject.SetActive(false); + + // Setup the base NPC class + S1NPC = gameObject.AddComponent(); + S1NPC.FirstName = firstName; + S1NPC.LastName = lastName; + S1NPC.ID = id; + S1NPC.MugshotSprite = icon ?? S1DevUtilities.PlayerSingleton.Instance.AppIcon; + S1NPC.BakedGUID = Guid.NewGuid().ToString(); + + // ReSharper disable once UseObjectOrCollectionInitializer (IL2CPP COMPAT) + S1NPC.ConversationCategories = new List(); + S1NPC.ConversationCategories.Add(S1Messaging.EConversationCategory.Customer); + + // Create our MessageConversation +#if (IL2CPP) + S1NPC.CreateMessageConversation(); +#elif (MONO) + MethodInfo createConvoMethod = AccessTools.Method(typeof(S1NPCs.NPC), "CreateMessageConversation"); + createConvoMethod.Invoke(S1NPC, null); +#endif + + // Add UnityEvents for NPCHealth + S1NPC.Health = gameObject.GetComponent(); + S1NPC.Health.onDie = new UnityEvent(); + S1NPC.Health.onKnockedOut = new UnityEvent(); + S1NPC.Health.Invincible = true; + S1NPC.Health.MaxHealth = 100f; + + // Awareness behaviour + GameObject awarenessObject = new GameObject("NPCAwareness"); + awarenessObject.transform.SetParent(gameObject.transform); + S1NPC.awareness = awarenessObject.AddComponent(); + S1NPC.awareness.onExplosionHeard = new UnityEvent(); + S1NPC.awareness.onGunshotHeard = new UnityEvent(); + S1NPC.awareness.onHitByCar = new UnityEvent(); + S1NPC.awareness.onNoticedDrugDealing = new UnityEvent(); + S1NPC.awareness.onNoticedGeneralCrime = new UnityEvent(); + S1NPC.awareness.onNoticedPettyCrime = new UnityEvent(); + S1NPC.awareness.onNoticedPlayerViolatingCurfew = new UnityEvent(); + S1NPC.awareness.onNoticedSuspiciousPlayer = new UnityEvent(); + S1NPC.awareness.Listener = gameObject.AddComponent(); + + /////// START BEHAVIOUR CODE //////// + // NPCBehaviours behaviour + GameObject behaviourObject = new GameObject("NPCBehaviour"); + behaviourObject.transform.SetParent(gameObject.transform); + S1Behaviour.NPCBehaviour behaviour = behaviourObject.AddComponent(); + + GameObject cowingBehaviourObject = new GameObject("CowingBehaviour"); + cowingBehaviourObject.transform.SetParent(behaviourObject.transform); + S1Behaviour.CoweringBehaviour coweringBehaviour = cowingBehaviourObject.AddComponent(); + + GameObject fleeBehaviourObject = new GameObject("FleeBehaviour"); + fleeBehaviourObject.transform.SetParent(behaviourObject.transform); + S1Behaviour.FleeBehaviour fleeBehaviour = fleeBehaviourObject.AddComponent(); + + behaviour.CoweringBehaviour = coweringBehaviour; + behaviour.FleeBehaviour = fleeBehaviour; + S1NPC.behaviour = behaviour; + /////// END BEHAVIOUR CODE //////// + + // Response to actions like gunshots, drug deals, etc. + GameObject responsesObject = new GameObject("NPCResponses"); + responsesObject.transform.SetParent(gameObject.transform); + S1NPC.awareness.Responses = responsesObject.AddComponent(); + + // Vision cone object and behaviour + GameObject visionObject = new GameObject("VisionCone"); + visionObject.transform.SetParent(gameObject.transform); + S1Vision.VisionCone visionCone = visionObject.AddComponent(); + visionCone.StatesOfInterest.Add(new S1Vision.VisionCone.StateContainer + { + state = S1PlayerScripts.PlayerVisualState.EVisualState.PettyCrime, RequiredNoticeTime = 0.1f + }); + S1NPC.awareness.VisionCone = visionCone; + + + // Suspicious ? icon in world space + S1NPC.awareness.VisionCone.QuestionMarkPopup = gameObject.AddComponent(); + + // Interaction behaviour +#if (IL2CPP) + S1NPC.intObj = gameObject.AddComponent(); +#elif (MONO) + FieldInfo intObjField = AccessTools.Field(typeof(S1NPCs.NPC), "intObj"); + intObjField.SetValue(S1NPC, gameObject.AddComponent()); +#endif + + // Relationship data + S1NPC.RelationData = new S1Relation.NPCRelationData(); + + // Inventory behaviour + S1NPCs.NPCInventory inventory = gameObject.AddComponent(); + + // Pickpocket behaviour + inventory.PickpocketIntObj = gameObject.AddComponent(); + + // Defaulting to the local player for Avatar TODO: Change + S1NPC.Avatar = S1AvatarFramework.MugshotGenerator.Instance.MugshotRig; + + // Enable our custom gameObjects so they can initialize + gameObject.SetActive(true); + + All.Add(this); + } + + /// + /// Called when a response is loaded from the save file. + /// Override this method for attaching your callbacks to your methods. + /// + /// The response that was loaded. + protected virtual void OnResponseLoaded(Response response) { } + + #endregion + + // Public members intended to be used by modders. + // Can be used inside your derived class, or outside via instance reference. + #region Public Members + + /// + /// INTERNAL: Tracking for the GameObject associated with this NPC. + /// Not intended for use by modders! + /// + public GameObject gameObject { get; } + + /// + /// The world position of the NPC. + /// + public Vector3 Position + { + get => gameObject.transform.position; + set => S1NPC.Movement.Warp(value); + } + + /// + /// The transform of the NPC. + /// Please do not set the properties of this transform. + /// + public Transform Transform => + gameObject.transform; + + /// + /// List of all NPCs within the base game and modded. + /// + public static readonly System.Collections.Generic.List All = new System.Collections.Generic.List(); + + /// + /// The first name of this NPC. + /// + public string FirstName + { + get => S1NPC.FirstName; + set => S1NPC.FirstName = value; + } + + /// + /// The last name of this NPC. + /// + public string LastName + { + get => S1NPC.LastName; + set => S1NPC.LastName = value; + } + + /// + /// The full name of this NPC. + /// If there is no last name, it will just return the first name. + /// + public string FullName => + S1NPC.fullName; + + /// + /// The unique identifier to assign to this NPC. + /// Used when saving and loading. Probably other things within the base game code. + /// + public string ID + { + get => S1NPC.ID; + protected set => S1NPC.ID = value; + } + + /// + /// The icon assigned to this NPC. + /// + public Sprite Icon + { + get => S1NPC.MugshotSprite; + set => S1NPC.MugshotSprite = value; + } + + /// + /// Whether the NPC is currently conscious or not. + /// + public bool IsConscious => + S1NPC.IsConscious; + + /// + /// Whether the NPC is currently inside a building or not. + /// + public bool IsInBuilding => + S1NPC.isInBuilding; + + /// + /// Whether the NPC is currently inside a vehicle or not. + /// + public bool IsInVehicle => + S1NPC.IsInVehicle; + + /// + /// Whether the NPC is currently panicking or not. + /// + public bool IsPanicking => + S1NPC.IsPanicked; + + /// + /// Whether the NPC is currently unsettled or not. + /// + public bool IsUnsettled => + S1NPC.isUnsettled; + + /// + /// UNCONFIRMED: Whether the NPC is currently visible to the player or not. + /// If you confirm this, please let us know so we can update the documentation! + /// + public bool IsVisible => + S1NPC.isVisible; + + /// + /// How aggressive this NPC is towards others. + /// + public float Aggressiveness + { + get => S1NPC.Aggression; + set => S1NPC.Aggression = value; + } + + /// + /// The region the NPC is associated with. + /// Note: Not the region they're in currently. Just the region they're designated to. + /// + public Region Region => + (Region)S1NPC.Region; + + /// + /// UNCONFIRMED: How long the NPC will panic for. + /// If you confirm this, please let us know so we can update the documentation! + /// + public float PanicDuration + { + get => (float)_panicField.GetValue(S1NPC)!; + set => _panicField.SetValue(S1NPC, value); + } + + /// + /// Sets the scale of the NPC. + /// + public float Scale + { + get => S1NPC.Scale; + set => S1NPC.SetScale(value); + } + + /// + /// Whether the NPC is knocked out or not. + /// + public bool IsKnockedOut => + S1NPC.Health.IsKnockedOut; + + /// + /// UNCONFIRMED: Whether the NPC requires the region unlocked in order to deal to. + /// If you confirm this, please let us know so we can update the documentation! + /// + public bool RequiresRegionUnlocked + { + get => (bool)_requiresRegionUnlockedField.GetValue(S1NPC)!; + set => _panicField.SetValue(S1NPC, value); + } + + // TODO: Add CurrentBuilding (currently missing NPCEnterableBuilding abstraction) + // public ??? CurrentBuilding { get; set; } + + // TODO: Add CurrentVehicle (currently missing LandVehicle abstraction) + // public ??? CurrentVehicle { get; set; } + + // TODO: Add Inventory (currently missing NPCInventory abstraction) + // public ??? Inventory { get; set; } + + /// + /// The current health the NPC has. + /// + public float CurrentHealth => + S1NPC.Health.Health; + + /// + /// The maximum health the NPC has. + /// + public float MaxHealth + { + get => S1NPC.Health.MaxHealth; + set => S1NPC.Health.MaxHealth = value; + } + + /// + /// Whether the NPC is dead or not. + /// + public bool IsDead => + S1NPC.Health.IsDead; + + /// + /// Whether the NPC is invincible or not. + /// + public bool IsInvincible + { + get => S1NPC.Health.Invincible; + set => S1NPC.Health.Invincible = value; + } + + /// + /// Revives the NPC. + /// + public void Revive() => + S1NPC.Health.Revive(); + + /// + /// Deals damage to the NPC. + /// + /// The amount of damage to deal. + public void Damage(int amount) + { + if (amount <= 0) + return; + + S1NPC.Health.TakeDamage(amount, true); + } + + /// + /// Heals the NPC. + /// + /// The amount of health to heal. + public void Heal(int amount) + { + if (amount <= 0) + return; + + float actualHealAmount = Mathf.Min(amount, S1NPC.Health.MaxHealth - S1NPC.Health.Health); + S1NPC.Health.TakeDamage(-actualHealAmount, false); + } + + /// + /// Kills the NPC. + /// + public void Kill() => + S1NPC.Health.TakeDamage(S1NPC.Health.MaxHealth); + + /// + /// Causes the NPC to become unsettled. + /// UNCONFIRMED: Will panic them for PanicDuration amount of time. + /// If you confirm this, please let us know so we can update the documentation! + /// + /// Length of time they should stay unsettled. + public void Unsettle(float duration) => + _unsettleMethod.Invoke(S1NPC, new object[] { duration }); + + /// + /// Smoothly scales the NPC over lerpTime. + /// + /// The scale you want set. + /// The time to scale over. + public void LerpScale(float scale, float lerpTime) => + S1NPC.SetScale(scale, lerpTime); + + /// + /// Causes the NPC to become panicked. + /// + public void Panic() => + S1NPC.SetPanicked(); + + /// + /// Causes the NPC to stop panicking, if they are currently. + /// + public void StopPanicking() => + _removePanicMethod.Invoke(S1NPC, new object[] { }); + + /// + /// Knocks the NPC out. + /// NOTE: Does not work for invincible NPCs. + /// + public void KnockOut() => + S1NPC.Health.KnockOut(); + + /// + /// Tells the NPC to travel to a specific position in world space. + /// + /// The position to travel to. + public void Goto(Vector3 position) => + S1NPC.Movement.SetDestination(position); + + // TODO: Add OnEnterVehicle listener (currently missing LandVehicle abstraction) + // public event Action OnEnterVehicle { } + + // TODO: Add OnExitVehicle listener (currently missing LandVehicle abstraction) + // public event Action OnExitVehicle { } + + // TODO: Add OnExplosionHeard listener (currently missing NoiseEvent abstraction) + // public event Action OnExplosionHeard { } + + // TODO: Add OnGunshotHeard listener (currently missing NoiseEvent abstraction) + // public event Action OnGunshotHeard { } + + // TODO: Add OnHitByCar listener (currently missing LandVehicle abstraction) + // public event Action OnHitByCar { } + + // TODO: Add OnNoticedDrugDealing listener (currently missing Player abstraction) + // public event Action OnNoticedDrugDealing { } + + // TODO: Add OnNoticedGeneralCrime listener (currently missing Player abstraction) + // public event Action OnNoticedGeneralCrime { } + + // TODO: Add OnNoticedPettyCrime listener (currently missing Player abstraction) + // public event Action OnNoticedPettyCrime { } + + // TODO: Add OnPlayerViolatingCurfew listener (currently missing Player abstraction) + // public event Action OnPlayerViolatingCurfew { } + + // TODO: Add OnNoticedSuspiciousPlayer listener (currently missing Player abstraction) + // public event Action OnNoticedSuspiciousPlayer { } + + /// + /// Called when the NPC died. + /// + public event Action OnDeath + { + add => EventHelper.AddListener(value, S1NPC.Health.onDie); + remove => EventHelper.RemoveListener(value, S1NPC.Health.onDie); + } + + /// + /// Called when the NPC's inventory contents change. + /// + public event Action OnInventoryChanged + { + add => EventHelper.AddListener(value, S1NPC.Inventory.onContentsChanged); + remove => EventHelper.RemoveListener(value, S1NPC.Inventory.onContentsChanged); + } + + /// + /// Sends a text message from this NPC to the players. + /// Supports responses with callbacks for additional logic. + /// + /// The message you want the player to see. Unity rich text is allowed. + /// Instances of to display. + /// The delay between when the message is sent and when the player can reply. + /// Whether this should propagate to all players or not. + public void SendTextMessage(string message, Response[]? responses = null, float responseDelay = 1f, bool network = true) + { + S1NPC.SendTextMessage(message); + S1NPC.MSGConversation.ClearResponses(); + + if (responses == null || responses.Length == 0) + return; + + Responses.Clear(); + + List responsesList = new List(); + + foreach (Response response in responses) + { + Responses.Add(response); + responsesList.Add(response.S1Response); + } + + S1NPC.MSGConversation.ShowResponses( + responsesList, + responseDelay, + network + ); + } + + /// + /// Gets the instance of an NPC. + /// Supports base NPCs as well as other mod NPCs. + /// For base NPCs, . + /// + /// The NPC class to get the instance of. + /// + public static NPC? Get() => + All.FirstOrDefault(npc => npc.GetType() == typeof(T)); + + #endregion + + // Internal members used by S1API. + // Please do not attempt to use these members! + #region Internal Members + + /// + /// INTERNAL: Reference to the NPC on the S1 side. + /// + internal readonly S1NPCs.NPC S1NPC; + + /// + /// INTERNAL: Constructor used for base game NPCs. + /// + /// Reference to a base game NPC. + internal NPC(S1NPCs.NPC npc) + { + S1NPC = npc; + gameObject = npc.gameObject; + IsCustomNPC = false; + All.Add(this); + } + + /// + /// INTERNAL: Initializes the responses that have been added / loaded + /// + internal override void CreateInternal() + { + // Assign responses to our tracked responses + foreach (S1Messaging.Response s1Response in S1NPC.MSGConversation.currentResponses) + { + Response response = new Response(s1Response) { Label = s1Response.label, Text = s1Response.text }; + Responses.Add(response); + OnResponseLoaded(response); + } + + base.CreateInternal(); + } + + internal override void SaveInternal(string folderPath, ref List extraSaveables) + { + string npcPath = Path.Combine(folderPath, S1NPC.SaveFolderName); + base.SaveInternal(npcPath, ref extraSaveables); + } + #endregion + + // Private members used by the NPC class. + // Please do not attempt to use these members! + #region Private Members + + internal readonly bool IsCustomNPC; + + private readonly FieldInfo _panicField = AccessTools.Field(typeof(S1NPCs.NPC), "PANIC_DURATION"); + private readonly FieldInfo _requiresRegionUnlockedField = AccessTools.Field(typeof(S1NPCs.NPC), "RequiresRegionUnlocked"); + + private readonly MethodInfo _unsettleMethod = AccessTools.Method(typeof(S1NPCs.NPC), "SetUnsettled"); + private readonly MethodInfo _removePanicMethod = AccessTools.Method(typeof(S1NPCs.NPC), "RemovePanicked"); + + #endregion + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/DanSamwell.cs b/S1API/Entities/NPCs/DanSamwell.cs new file mode 100644 index 00000000..e3f3b0aa --- /dev/null +++ b/S1API/Entities/NPCs/DanSamwell.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs +{ + /// + /// UNCONFIRMED: Dan Samwell is a customer. + /// He is the NPC that owns Dan's Hardware! + /// If you confirm this, please let us know so we can update the documentation! + /// + public class DanSamwell : NPC + { + internal DanSamwell() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "dan_samwell")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/AnnaChesterfield.cs b/S1API/Entities/NPCs/Docks/AnnaChesterfield.cs new file mode 100644 index 00000000..716271c2 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/AnnaChesterfield.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Anna Chesterfield is a customer. + /// She lives in the Docks region. + /// Anna also works at the Barbershop. + /// + public class AnnaChesterfield : NPC + { + internal AnnaChesterfield() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "anna_chesterfield")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/BillyKramer.cs b/S1API/Entities/NPCs/Docks/BillyKramer.cs new file mode 100644 index 00000000..1195c3ba --- /dev/null +++ b/S1API/Entities/NPCs/Docks/BillyKramer.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Billy Kramer is a customer. + /// He lives in the Docks region. + /// + public class BillyKramer : NPC + { + internal BillyKramer() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "billy_kramer")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/CrankyFrank.cs b/S1API/Entities/NPCs/Docks/CrankyFrank.cs new file mode 100644 index 00000000..b5b91835 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/CrankyFrank.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Cranky Frank is a customer. + /// He lives in the Docks region. + /// Frank is the NPC with a pot on his head! + /// + public class CrankyFrank : NPC + { + internal CrankyFrank() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "cranky_frank")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/GenghisBarn.cs b/S1API/Entities/NPCs/Docks/GenghisBarn.cs new file mode 100644 index 00000000..3f0053a9 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/GenghisBarn.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Genghis Barn is a customer. + /// He lives in the Docks region. + /// Genghis is the NPC with a mohawk! + /// + public class GenghisBarn : NPC + { + internal GenghisBarn() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "genghis_barn")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/JaneLucero.cs b/S1API/Entities/NPCs/Docks/JaneLucero.cs new file mode 100644 index 00000000..92dfb778 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/JaneLucero.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Jane Lucero is a dealer. + /// She lives in the Docks region. + /// Jane is the dealer with a tear tattoo! + /// + public class JaneLucero : NPC + { + internal JaneLucero() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jane_lucero")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/JavierPerez.cs b/S1API/Entities/NPCs/Docks/JavierPerez.cs new file mode 100644 index 00000000..d60491cd --- /dev/null +++ b/S1API/Entities/NPCs/Docks/JavierPerez.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Javier Perez is a customer. + /// He lives in the Docks region. + /// Javier works night shift at the Gas-Mart! + /// + public class JavierPerez : NPC + { + internal JavierPerez() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "javier_perez")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/LisaGardener.cs b/S1API/Entities/NPCs/Docks/LisaGardener.cs new file mode 100644 index 00000000..25ff3c57 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/LisaGardener.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Lisa Gardener is a customer. + /// She lives in the Docks region. + /// Lisa is the NPC wearing blue scrubs! + /// + public class LisaGardener : NPC + { + internal LisaGardener() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "lisa_gardener")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/MacCooper.cs b/S1API/Entities/NPCs/Docks/MacCooper.cs new file mode 100644 index 00000000..417812a9 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/MacCooper.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Mac Cooper is a customer. + /// He lives in the Docks region. + /// Mac is the NPC with a blonde mohawk and gold shades! + /// + public class MacCooper : NPC + { + internal MacCooper() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "mac_cooper")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/MarcoBaron.cs b/S1API/Entities/NPCs/Docks/MarcoBaron.cs new file mode 100644 index 00000000..acc1e4b9 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/MarcoBaron.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Marco Baron is a customer. + /// He lives in the Docks region. + /// Marco is the NPC that runs the Auto Shop! + /// + public class MarcoBaron : NPC + { + internal MarcoBaron() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "marco_baron")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/MelissaWood.cs b/S1API/Entities/NPCs/Docks/MelissaWood.cs new file mode 100644 index 00000000..f951d422 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/MelissaWood.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Melissa Wood is a customer. + /// She lives in the Docks region. + /// Melissa is the Blackjack dealer at the casino! + /// + public class MelissaWood : NPC + { + internal MelissaWood() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "melissa_wood")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Docks/SalvadorMoreno.cs b/S1API/Entities/NPCs/Docks/SalvadorMoreno.cs new file mode 100644 index 00000000..5874de36 --- /dev/null +++ b/S1API/Entities/NPCs/Docks/SalvadorMoreno.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Docks +{ + /// + /// Salvador Moreno is a supplier. + /// He lives in the Docks region. + /// Salvador is the NPC that supplies coca seeds to the player! + /// + public class SalvadorMoreno : NPC + { + internal SalvadorMoreno() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "salvador_moreno")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/BradCrosby.cs b/S1API/Entities/NPCs/Downtown/BradCrosby.cs new file mode 100644 index 00000000..193ff48c --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/BradCrosby.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Brad Crosby is a dealer. + /// He lives in the Downtown region. + /// Brad lives in a tent at the parking garage next to the casino! + /// + public class BradCrosby : NPC + { + internal BradCrosby() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "brad_crosby")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/ElizabethHomley.cs b/S1API/Entities/NPCs/Downtown/ElizabethHomley.cs new file mode 100644 index 00000000..cc5dc2e9 --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/ElizabethHomley.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Elizabeth Homley is a customer. + /// She lives in the Downtown region. + /// Elizabeth is the NPC is lightning blue hair! + /// + public class ElizabethHomley : NPC + { + internal ElizabethHomley() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "elizabeth_homley")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/EugeneBuckley.cs b/S1API/Entities/NPCs/Downtown/EugeneBuckley.cs new file mode 100644 index 00000000..e497a5cc --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/EugeneBuckley.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Eugene Buckley is a customer. + /// He lives in the Downtown region. + /// Eugene is the NPC with light brown hair, freckles, and black glasses! + /// + public class EugeneBuckley : NPC + { + internal EugeneBuckley() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "eugene_buckley")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/GregFliggle.cs b/S1API/Entities/NPCs/Downtown/GregFliggle.cs new file mode 100644 index 00000000..6645f34a --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/GregFliggle.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Greg Fliggle is a customer. + /// He lives in the Downtown region. + /// Greg is the NPC with a teardrop tattoo and wrinkles! + /// + public class GregFliggle : NPC + { + internal GregFliggle() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "greg_fliggle")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/JeffGilmore.cs b/S1API/Entities/NPCs/Downtown/JeffGilmore.cs new file mode 100644 index 00000000..8b7ca3d8 --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/JeffGilmore.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Jeff Gilmore is a customer. + /// He lives in the Downtown region. + /// Jeff is the NPC that runs the skateboard shop! + /// + public class JeffGilmore : NPC + { + internal JeffGilmore() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jeff_gilmore")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/JenniferRivera.cs b/S1API/Entities/NPCs/Downtown/JenniferRivera.cs new file mode 100644 index 00000000..7df65be4 --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/JenniferRivera.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Jennifer Rivera is a customer. + /// She lives in the Downtown region. + /// Jennifer is the NPC with blonde haired buns! + /// + public class JenniferRivera : NPC + { + internal JenniferRivera() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jennifer_rivera")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/KevinOakley.cs b/S1API/Entities/NPCs/Downtown/KevinOakley.cs new file mode 100644 index 00000000..6d841940 --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/KevinOakley.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Kevin Oakley is a customer. + /// He lives in the Downtown region. + /// Kevin is the NPC wearing a green apron! + /// + public class KevinOakley : NPC + { + internal KevinOakley() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "kevin_oakley")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/LouisFourier.cs b/S1API/Entities/NPCs/Downtown/LouisFourier.cs new file mode 100644 index 00000000..6012bb2c --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/LouisFourier.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Louis Fourier is a customer. + /// He lives in the Downtown region. + /// Louis is the NPC with a chef's hat! + /// + public class LouisFourier : NPC + { + internal LouisFourier() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "louis_fourier")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/LucyPennington.cs b/S1API/Entities/NPCs/Downtown/LucyPennington.cs new file mode 100644 index 00000000..97fde0e6 --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/LucyPennington.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Lucy Pennington is a customer. + /// She lives in the Downtown region. + /// Lucy is the NPC with blonde haired buns up high! + /// + public class LucyPennington : NPC + { + internal LucyPennington() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "lucy_pennington")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/PhilipWentworth.cs b/S1API/Entities/NPCs/Downtown/PhilipWentworth.cs new file mode 100644 index 00000000..42d715a3 --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/PhilipWentworth.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Philip Wentworth is a customer. + /// He lives in the Downtown region. + /// Philip is the bald NPC with a goatee! + /// + public class PhilipWentworth : NPC + { + internal PhilipWentworth() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "philip_wentworth")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Downtown/RandyCaulfield.cs b/S1API/Entities/NPCs/Downtown/RandyCaulfield.cs new file mode 100644 index 00000000..3a8fecca --- /dev/null +++ b/S1API/Entities/NPCs/Downtown/RandyCaulfield.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Downtown +{ + /// + /// Randy Caulfield is a customer. + /// He lives in the Downtown region. + /// Randy is the NPC wearing a green hat! + /// + public class RandyCaulfield : NPC + { + internal RandyCaulfield() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "randy_caulfield")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/IgorRomanovich.cs b/S1API/Entities/NPCs/IgorRomanovich.cs new file mode 100644 index 00000000..4723d905 --- /dev/null +++ b/S1API/Entities/NPCs/IgorRomanovich.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs +{ + /// + /// Igor Romanovich is a npc. + /// He is Manny's bodyguard. + /// Igor can be found inside the Warehouse! + /// + public class IgorRomanovich : NPC + { + internal IgorRomanovich() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "igor_romanovich")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/MannyOakfield.cs b/S1API/Entities/NPCs/MannyOakfield.cs new file mode 100644 index 00000000..403897a4 --- /dev/null +++ b/S1API/Entities/NPCs/MannyOakfield.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs +{ + /// + /// Manny is a NPC. + /// He provides workers to the player. + /// Manny can be found in the Warehouse! + /// + public class MannyOakfield : NPC + { + internal MannyOakfield() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "manny_oakfield")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/NPC_LIST.md b/S1API/Entities/NPCs/NPC_LIST.md new file mode 100644 index 00000000..334576fa --- /dev/null +++ b/S1API/Entities/NPCs/NPC_LIST.md @@ -0,0 +1,260 @@ +**manny_oakfield** +ScheduleOne.NPCs.CharacterClasses.Fixer +--- +**jessi_waters** +ScheduleOne.NPCs.CharacterClasses.Jessi +--- +**brad_crosby** +ScheduleOne.NPCs.CharacterClasses.Brad +--- +**donna_martin** +ScheduleOne.NPCs.NPC +--- +**keith_wagner** +ScheduleOne.NPCs.CharacterClasses.Keith +--- +**kevin_oakley** +ScheduleOne.NPCs.CharacterClasses.Kevin +--- +**billy_kramer** +ScheduleOne.NPCs.Billy +--- +**marco_baron** +ScheduleOne.NPCs.CharacterClasses.Marco +--- +**officergreen** +ScheduleOne.Police.PoliceOfficer +--- +**stan_carney** +ScheduleOne.NPCs.Stan +--- +**kathy_henderson** +ScheduleOne.NPCs.CharacterClasses.Kathy +--- +**jane_lucero** +ScheduleOne.NPCs.CharacterClasses.Jane +--- +**beth_penn** +ScheduleOne.NPCs.CharacterClasses.Beth +--- +**officerhoward** +ScheduleOne.Police.PoliceOfficer +--- +**officerlopez** +ScheduleOne.Police.PoliceOfficer +--- +**tobias_wentworth** +ScheduleOne.NPCs.CharacterClasses.Tobias +--- +**kim_delaney** +ScheduleOne.NPCs.CharacterClasses.Kim +--- +**officerdavis** +ScheduleOne.Police.PoliceOfficer +--- +**officermurphy** +ScheduleOne.Police.PoliceOfficer +--- +**lisa_gardener** +ScheduleOne.NPCs.CharacterClasses.Lisa +--- +**eugene_buckley** +ScheduleOne.NPCs.CharacterClasses.Eugene +--- +**karen_kennedy** +ScheduleOne.NPCs.CharacterClasses.Karen +--- +**jen_heard** +ScheduleOne.NPCs.CharacterClasses.Jen +--- +**michael_boog** +ScheduleOne.NPCs.CharacterClasses.Michael +--- +**dean_webster** +ScheduleOne.NPCs.CharacterClasses.Dean +--- +**elizabeth_homley** +ScheduleOne.NPCs.CharacterClasses.Elizabeth +--- +**herbert_bleuball** +ScheduleOne.NPCs.CharacterClasses.Herbert +--- +**mick_lubbin** +ScheduleOne.NPCs.CharacterClasses.Mick +--- +**mac_cooper** +ScheduleOne.NPCs.CharacterClasses.Mac +--- +**sam_thompson** +ScheduleOne.NPCs.CharacterClasses.Sam +--- +**molly_presley** +ScheduleOne.Economy.Dealer +--- +**greg_fliggle** +ScheduleOne.NPCs.CharacterClasses.Greg +--- +**jeff_gilmore** +ScheduleOne.NPCs.CharacterClasses.Jeff +--- +**benji_coleman** +ScheduleOne.NPCs.CharacterClasses.Benji +--- +**albert_hoover** +ScheduleOne.NPCs.CharacterClasses.Albert +--- +**chris_sullivan** +ScheduleOne.NPCs.CharacterClasses.Chris +--- +**oscar_holland** +ScheduleOne.NPCs.CharacterClasses.Oscar +--- +**peter_file** +ScheduleOne.NPCs.CharacterClasses.Peter +--- +**jennifer_rivera** +ScheduleOne.NPCs.CharacterClasses.Jennifer +--- +**hank_stevenson** +ScheduleOne.NPCs.CharacterClasses.Steve +--- +**officerjackson** +ScheduleOne.Police.PoliceOfficer +--- +**louis_fourier** +ScheduleOne.NPCs.CharacterClasses.Louis +--- +**officerlee** +ScheduleOne.Police.PoliceOfficer +--- +**melissa_wood** +ScheduleOne.NPCs.CharacterClasses.Melissa +--- +**jackie_stevenson** +ScheduleOne.NPCs.CharacterClasses.Jackie +--- +**lucy_pennington** +ScheduleOne.NPCs.NPC +--- +**peggy_myers** +ScheduleOne.NPCs.CharacterClasses.Peggy +--- +**joyce_ball** +ScheduleOne.NPCs.NPC +--- +**meg_cooley** +ScheduleOne.NPCs.Meg +--- +**trent_sherman** +ScheduleOne.NPCs.NPC +--- +**charles_rowland** +ScheduleOne.NPCs.CharacterClasses.Charles +--- +**george_greene** +ScheduleOne.NPCs.CharacterClasses.George +--- +**jerry_montero** +ScheduleOne.NPCs.Jerry +--- +**doris_lubbin** +ScheduleOne.NPCs.Doris +--- +**dan_samwell** +ScheduleOne.NPCs.CharacterClasses.Dan +--- +**uncle_nelson** +ScheduleOne.NPCs.CharacterClasses.UncleNelson +--- +**igor_romanovich** +ScheduleOne.NPCs.CharacterClasses.Igor +--- +**wei_long** +ScheduleOne.NPCs.CharacterClasses.Wei +--- +**leo_rivers** +ScheduleOne.NPCs.CharacterClasses.Leo +--- +**officerbailey** +ScheduleOne.Police.PoliceOfficer +--- +**officercooper** +ScheduleOne.Police.PoliceOfficer +--- +**officeroakley** +ScheduleOne.Police.PoliceOfficer +--- +**lily_turner** +ScheduleOne.NPCs.CharacterClasses.Lily +--- +**ray_hoffman** +ScheduleOne.NPCs.CharacterClasses.Ray +--- +**walter_cussler** +ScheduleOne.NPCs.CharacterClasses.Walter +--- +**pearl_moore** +ScheduleOne.NPCs.CharacterClasses.Pearl +--- +**fiona_hancock** +ScheduleOne.NPCs.CharacterClasses.Fiona +--- +**genghis_barn** +ScheduleOne.NPCs.CharacterClasses.Genghis +--- +**anna_chesterfield** +ScheduleOne.NPCs.CharacterClasses.Anna +--- +**javier_perez** +ScheduleOne.NPCs.CharacterClasses.Javier +--- +**cranky_frank** +ScheduleOne.NPCs.CharacterClasses.Frank +--- +**randy_caulfield** +ScheduleOne.NPCs.CharacterClasses.Randy +--- +**philip_wentworth** +ScheduleOne.NPCs.CharacterClasses.Philip +--- +**jeremy_wilkinson** +ScheduleOne.NPCs.CharacterClasses.Jeremy +--- +**alison_knight** +ScheduleOne.NPCs.CharacterClasses.Alison +--- +**carl_bundy** +ScheduleOne.NPCs.CharacterClasses.Carl +--- +**harold_colt** +ScheduleOne.NPCs.CharacterClasses.Harold +--- +**jack_knight** +ScheduleOne.NPCs.CharacterClasses.Jack +--- +**dennis_kennedy** +ScheduleOne.NPCs.CharacterClasses.Dennis +--- +**shirley_watts** +ScheduleOne.NPCs.CharacterClasses.Shirley +--- +**salvador_moreno** +ScheduleOne.NPCs.CharacterClasses.Salvador +--- +**kyle_cooley** +ScheduleOne.NPCs.CharacterClasses.Kyle +--- +**ludwig_meyer** +ScheduleOne.NPCs.NPC +--- +**austin_steiner** +ScheduleOne.NPCs.CharacterClasses.Austin +--- +**chloe_bowers** +ScheduleOne.NPCs.Chloe +--- +**ming** +ScheduleOne.NPCs.CharacterClasses.Ming +--- +**geraldine_poon** +ScheduleOne.NPCs.CharacterClasses.Geraldine \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/AlbertHoover.cs b/S1API/Entities/NPCs/Northtown/AlbertHoover.cs new file mode 100644 index 00000000..162bcfb8 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/AlbertHoover.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Albert Hoover is a supplier. + /// He lives in the Northtown region. + /// Albert is the supplier for weed seeds! + /// + public class AlbertHoover : NPC + { + internal AlbertHoover() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "albert_hoover")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/AustinSteiner.cs b/S1API/Entities/NPCs/Northtown/AustinSteiner.cs new file mode 100644 index 00000000..393ebf90 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/AustinSteiner.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Austin Steiner is a customer. + /// He lives in the Northtown region. + /// Austin is the NPC with a red/orange afro and black glasses! + /// + public class AustinSteiner : NPC + { + internal AustinSteiner() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "austin_steiner")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/BenjiColeman.cs b/S1API/Entities/NPCs/Northtown/BenjiColeman.cs new file mode 100644 index 00000000..b0c6528b --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/BenjiColeman.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Benji Coleman is a dealer. + /// He lives in the Northtown region. + /// Benji lives at the motel in room #2. + /// He is the first dealer the player unlocks! + /// + public class BenjiColeman : NPC + { + internal BenjiColeman() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "benji_coleman")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/BethPenn.cs b/S1API/Entities/NPCs/Northtown/BethPenn.cs new file mode 100644 index 00000000..e5538920 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/BethPenn.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Beth Penn is a customer. + /// She lives in the Northtown region. + /// Beth is the NPC with a blonde bowl cut and wears green glasses! + /// + public class BethPenn : NPC + { + internal BethPenn() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "beth_penn")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/ChloeBowers.cs b/S1API/Entities/NPCs/Northtown/ChloeBowers.cs new file mode 100644 index 00000000..03ab02b8 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/ChloeBowers.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Chloe Bowers is a customer. + /// She lives in the Northtown region. + /// Chloe is the NPC with long, straight, red hair! + /// + public class ChloeBowers : NPC + { + internal ChloeBowers() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "chloe_bowers")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/DonnaMartin.cs b/S1API/Entities/NPCs/Northtown/DonnaMartin.cs new file mode 100644 index 00000000..ef38ed01 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/DonnaMartin.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Donna Martin is a customer. + /// She lives in the Northtown region. + /// Donna is the attendant of the Motel! + /// + public class DonnaMartin : NPC + { + internal DonnaMartin() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "donna_martin")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/GeraldinePoon.cs b/S1API/Entities/NPCs/Northtown/GeraldinePoon.cs new file mode 100644 index 00000000..3b04d209 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/GeraldinePoon.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Geraldine Poon is a customer. + /// He lives in the Northtown region. + /// Geraldine is the balding NPC with small gold glasses! + /// + public class GeraldinePoon : NPC + { + internal GeraldinePoon() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "geraldine_poon")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/JessiWaters.cs b/S1API/Entities/NPCs/Northtown/JessiWaters.cs new file mode 100644 index 00000000..7ed78aaa --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/JessiWaters.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Jessi Waters is a customer. + /// She lives in the Northtown region. + /// Jessi is the purple haired NPC with face tattoos! + /// + public class JessiWaters : NPC + { + internal JessiWaters() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jessi_waters")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/KathyHenderson.cs b/S1API/Entities/NPCs/Northtown/KathyHenderson.cs new file mode 100644 index 00000000..58a9135b --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/KathyHenderson.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Kathy Henderson is a customer. + /// She lives in the Northtown region. + /// Kathy is the NPC with long blonde hair with bangs! + /// + public class KathyHenderson : NPC + { + internal KathyHenderson() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "kathy_henderson")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/KyleCooley.cs b/S1API/Entities/NPCs/Northtown/KyleCooley.cs new file mode 100644 index 00000000..b4104f2c --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/KyleCooley.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Kyle Cooley is a customer. + /// He lives in the Northtown region. + /// Kyle is the NPC that works at Taco Ticklers! + /// + public class KyleCooley : NPC + { + internal KyleCooley() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "kyle_cooley")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/LudwigMeyer.cs b/S1API/Entities/NPCs/Northtown/LudwigMeyer.cs new file mode 100644 index 00000000..e3b77d8c --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/LudwigMeyer.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Ludwig Meyer is a customer. + /// He lives in the Northtown region. + /// Ludwig is the NPC with spiky hair and gold glasses! + /// + public class LudwigMeyer : NPC + { + internal LudwigMeyer() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "ludwig_meyer")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/MickLubbin.cs b/S1API/Entities/NPCs/Northtown/MickLubbin.cs new file mode 100644 index 00000000..293e7a80 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/MickLubbin.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Mick Lubbin is a customer. + /// He lives in the Northtown region. + /// Mick is the owner of the pawn shop! + /// + public class MickLubbin : NPC + { + internal MickLubbin() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "mick_lubbin")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/Ming.cs b/S1API/Entities/NPCs/Northtown/Ming.cs new file mode 100644 index 00000000..5c5b3e11 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/Ming.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Mrs. Ming is a customer. + /// She lives in the Northtown region. + /// Ming is the NPC that owns the chinese restaurant! + /// + public class Ming : NPC + { + internal Ming() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "ming")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/PeggyMyers.cs b/S1API/Entities/NPCs/Northtown/PeggyMyers.cs new file mode 100644 index 00000000..875983ab --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/PeggyMyers.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Peggy Myers is a customer. + /// She lives in the Northtown region. + /// Peggy is the NPC with freckles and brown hair pulled back! + /// + public class PeggyMyers : NPC + { + internal PeggyMyers() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "peggy_myers")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/PeterFile.cs b/S1API/Entities/NPCs/Northtown/PeterFile.cs new file mode 100644 index 00000000..e2af8748 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/PeterFile.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Peter File is a customer. + /// He lives in the Northtown region. + /// Peter is the NPC with a black bowl cut and black glasses! + /// + public class PeterFile : NPC + { + internal PeterFile() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "peter_file")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Northtown/SamThompson.cs b/S1API/Entities/NPCs/Northtown/SamThompson.cs new file mode 100644 index 00000000..d9a49e98 --- /dev/null +++ b/S1API/Entities/NPCs/Northtown/SamThompson.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Northtown +{ + /// + /// Sam Thompson is a customer. + /// He lives in the Northtown region. + /// Sam is the NPC with a green hair and wrinkles! + /// + public class SamThompson : NPC + { + internal SamThompson() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "sam_thompson")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/OscarHolland.cs b/S1API/Entities/NPCs/OscarHolland.cs new file mode 100644 index 00000000..5a557110 --- /dev/null +++ b/S1API/Entities/NPCs/OscarHolland.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs +{ + /// + /// Oscar Holland is a NPC. + /// He is a supplier located in the Warehouse! + /// + public class OscarHolland : NPC + { + internal OscarHolland() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "oscar_holland")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerBailey.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerBailey.cs new file mode 100644 index 00000000..a5203922 --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerBailey.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Bailey is a police officer. + /// He is the bald officer with a swirling mustache! + /// + public class OfficerBailey : NPC + { + internal OfficerBailey() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officerbailey")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerCooper.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerCooper.cs new file mode 100644 index 00000000..c2c40ba9 --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerCooper.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Cooper is a police officer. + /// She is the officer with two high black buns and black glasses! + /// + public class OfficerCooper : NPC + { + internal OfficerCooper() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officercooper")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerGreen.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerGreen.cs new file mode 100644 index 00000000..a5950489 --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerGreen.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Green is a police officer. + /// She is the officer with light brown hair in a bun! + /// + public class OfficerGreen : NPC + { + internal OfficerGreen() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officergreen")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerHoward.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerHoward.cs new file mode 100644 index 00000000..b077a19b --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerHoward.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Howard is a police officer. + /// He is the officer with a light brown afro and goatee! + /// + public class OfficerHoward : NPC + { + internal OfficerHoward() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officerhoward")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerJackson.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerJackson.cs new file mode 100644 index 00000000..3c3c4a4e --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerJackson.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Jackson is a police officer. + /// He is the officer with a light brown goatee and police hat! + /// + public class OfficerJackson : NPC + { + internal OfficerJackson() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officerjackson")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerLee.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerLee.cs new file mode 100644 index 00000000..ce448bdf --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerLee.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Lee is a police officer. + /// He is the officer with a button-up shirt and black hair! + /// + public class OfficerLee : NPC + { + internal OfficerLee() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officerlee")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerLopez.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerLopez.cs new file mode 100644 index 00000000..6d2235b0 --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerLopez.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Lopez is a police officer. + /// She is the officer with a blue button-up and long black hair! + /// + public class OfficerLopez : NPC + { + internal OfficerLopez() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officerlopez")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerMurphy.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerMurphy.cs new file mode 100644 index 00000000..206b2eea --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerMurphy.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Murphy is a police officer. + /// He is the balding officer with grey hair and wrinkles! + /// + public class OfficerMurphy : NPC + { + internal OfficerMurphy() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officermurphy")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/PoliceOfficers/OfficerOakley.cs b/S1API/Entities/NPCs/PoliceOfficers/OfficerOakley.cs new file mode 100644 index 00000000..11724460 --- /dev/null +++ b/S1API/Entities/NPCs/PoliceOfficers/OfficerOakley.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.PoliceOfficers +{ + /// + /// Officer Oakley is a police officer. + /// He is the officer with light brown spiky hair and a goatee! + /// + public class OfficerOakley : NPC + { + internal OfficerOakley() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "officeroakley")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/StanCarney.cs b/S1API/Entities/NPCs/StanCarney.cs new file mode 100644 index 00000000..017983c5 --- /dev/null +++ b/S1API/Entities/NPCs/StanCarney.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs +{ + /// + /// Stan Carney is a NPC. + /// He is the NPC that sells weapons. + /// Stan can be found in the Warehouse! + /// + public class StanCarney : NPC + { + internal StanCarney() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "stan_carney")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/AlisonKnight.cs b/S1API/Entities/NPCs/Suburbia/AlisonKnight.cs new file mode 100644 index 00000000..a534cddc --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/AlisonKnight.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Alison Knight is a customer. + /// She lives in the Suburbia region. + /// Alison is the NPC with long light brown hair! + /// + public class AlisonKnight : NPC + { + internal AlisonKnight() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "alison_knight")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/CarlBundy.cs b/S1API/Entities/NPCs/Suburbia/CarlBundy.cs new file mode 100644 index 00000000..e9fcbbb6 --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/CarlBundy.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Carl Bundy is a customer. + /// He lives in the Suburbia region. + /// Carl is the NPC with a brown apron! + /// + public class CarlBundy : NPC + { + internal CarlBundy() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "carl_bundy")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/ChrisSullivan.cs b/S1API/Entities/NPCs/Suburbia/ChrisSullivan.cs new file mode 100644 index 00000000..5c24211c --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/ChrisSullivan.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Chris Sullivan is a customer. + /// He lives in the Suburbia region. + /// Chris is the NPC with black spiky hair and black glasses! + /// + public class ChrisSullivan : NPC + { + internal ChrisSullivan() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "chris_sullivan")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/DennisKennedy.cs b/S1API/Entities/NPCs/Suburbia/DennisKennedy.cs new file mode 100644 index 00000000..d733d06a --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/DennisKennedy.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Dennis Kennedy is a customer. + /// He lives in the Suburbia region. + /// Dennis is the NPC with light blonde spiky hair and a thick mustache! + /// + public class DennisKennedy : NPC + { + internal DennisKennedy() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "dennis_kennedy")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/HankStevenson.cs b/S1API/Entities/NPCs/Suburbia/HankStevenson.cs new file mode 100644 index 00000000..9440e3ec --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/HankStevenson.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Hank Stevenson is a customer. + /// He lives in the Suburbia region. + /// Hank is the balding NPC with greying brown hair and a goatee! + /// + public class HankStevenson : NPC + { + internal HankStevenson() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "hank_stevenson")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/HaroldColt.cs b/S1API/Entities/NPCs/Suburbia/HaroldColt.cs new file mode 100644 index 00000000..e313c440 --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/HaroldColt.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Harold Colt is a customer. + /// He lives in the Suburbia region. + /// Harold is the NPC with grey spiky hair and wrinkles! + /// + public class HaroldColt : NPC + { + internal HaroldColt() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "harold_colt")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/JackKnight.cs b/S1API/Entities/NPCs/Suburbia/JackKnight.cs new file mode 100644 index 00000000..921ef9d2 --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/JackKnight.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Jack Knight is a customer. + /// He lives in the Suburbia region. + /// Jack is the balding NPC with small gold glasses! + /// + public class JackKnight : NPC + { + internal JackKnight() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jack_knight")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/JackieStevenson.cs b/S1API/Entities/NPCs/Suburbia/JackieStevenson.cs new file mode 100644 index 00000000..ca504988 --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/JackieStevenson.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Jackie Stevenson is a customer. + /// He lives in the Suburbia region. + /// Jackie is the NPC with short brown hair and light freckles! + /// + public class JackieStevenson : NPC + { + internal JackieStevenson() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jackie_stevenson")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/JeremyWilkinson.cs b/S1API/Entities/NPCs/Suburbia/JeremyWilkinson.cs new file mode 100644 index 00000000..4a7ebe04 --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/JeremyWilkinson.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Jeremy Wilkinson is a customer. + /// He lives in the Suburbia region. + /// Jeremy is the NPC that works at Hyland Auto! + /// + public class JeremyWilkinson : NPC + { + internal JeremyWilkinson() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jeremy_wilkinson")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/KarenKennedy.cs b/S1API/Entities/NPCs/Suburbia/KarenKennedy.cs new file mode 100644 index 00000000..0df4bccd --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/KarenKennedy.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Karen Kennedy is a customer. + /// She lives in the Suburbia region. + /// Karen is the NPC with wavy blonde hair and purple eyelids! + /// She can be found at the casino upstairs when it's open. + /// + public class KarenKennedy : NPC + { + internal KarenKennedy() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "karen_kennedy")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Suburbia/WeiLong.cs b/S1API/Entities/NPCs/Suburbia/WeiLong.cs new file mode 100644 index 00000000..bec8f78f --- /dev/null +++ b/S1API/Entities/NPCs/Suburbia/WeiLong.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Suburbia +{ + /// + /// Wei Long is a dealer. + /// He lives in the Suburbia region. + /// Wei is the dealer with a black bowl cut and gold glasses! + /// + public class WeiLong : NPC + { + internal WeiLong() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "wei_long")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/UncleNelson.cs b/S1API/Entities/NPCs/UncleNelson.cs new file mode 100644 index 00000000..15e6b06b --- /dev/null +++ b/S1API/Entities/NPCs/UncleNelson.cs @@ -0,0 +1,18 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs +{ + /// + /// Uncle Nelson is a NPC. + /// He is the uncle of the main character! + /// + public class UncleNelson : NPC + { + internal UncleNelson() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "uncle_nelson")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/FionaHancock.cs b/S1API/Entities/NPCs/Uptown/FionaHancock.cs new file mode 100644 index 00000000..59a3b968 --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/FionaHancock.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Fiona Hancock is a customer. + /// She lives in the Uptown region. + /// Fiona is the NPC with light brown buns and green glasses! + /// + public class FionaHancock : NPC + { + internal FionaHancock() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "fiona_hancock")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/HerbertBleuball.cs b/S1API/Entities/NPCs/Uptown/HerbertBleuball.cs new file mode 100644 index 00000000..0361d983 --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/HerbertBleuball.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Herbert Bleuball is a customer. + /// He lives in the Uptown region. + /// Herbert is the NPC that owns Bleuball's Boutique! + /// + public class HerbertBleuball : NPC + { + internal HerbertBleuball() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "herbert_bleuball")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/JenHeard.cs b/S1API/Entities/NPCs/Uptown/JenHeard.cs new file mode 100644 index 00000000..d2ffe6b5 --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/JenHeard.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Jen Heard is a customer. + /// She lives in the Uptown region. + /// Jen is the NPC with low orange buns! + /// + public class JenHeard : NPC + { + internal JenHeard() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jen_heard")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/LeoRivers.cs b/S1API/Entities/NPCs/Uptown/LeoRivers.cs new file mode 100644 index 00000000..6f22c063 --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/LeoRivers.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Leo Rivers is a dealer. + /// He lives in the Uptown region. + /// Leo is the dealer wearing a black hat and gold shades! + /// + public class LeoRivers : NPC + { + internal LeoRivers() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "leo_rivers")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/LilyTurner.cs b/S1API/Entities/NPCs/Uptown/LilyTurner.cs new file mode 100644 index 00000000..a2d6b77f --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/LilyTurner.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Lily Turner is a customer. + /// She lives in the Uptown region. + /// Lily is the NPC with long brown hair with bangs! + /// + public class LilyTurner : NPC + { + internal LilyTurner() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "lily_turner")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/MichaelBoog.cs b/S1API/Entities/NPCs/Uptown/MichaelBoog.cs new file mode 100644 index 00000000..d8d160c2 --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/MichaelBoog.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Michael Boog is a customer. + /// He lives in the Uptown region. + /// Michael is the NPC with a bright blue flat cap and black glasses! + /// + public class MichaelBoog : NPC + { + internal MichaelBoog() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "michael_boog")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/PearlMoore.cs b/S1API/Entities/NPCs/Uptown/PearlMoore.cs new file mode 100644 index 00000000..902efae0 --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/PearlMoore.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Pearl Moore is a customer. + /// She lives in the Uptown region. + /// Pearl is the NPC with long white hair with bangs! + /// + public class PearlMoore : NPC + { + internal PearlMoore() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "pearl_moore")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/RayHoffman.cs b/S1API/Entities/NPCs/Uptown/RayHoffman.cs new file mode 100644 index 00000000..0716d33e --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/RayHoffman.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Ray Hoffman is a customer. + /// He lives in the Uptown region. + /// Ray is the NPC that owns Ray's Realty! + /// + public class RayHoffman : NPC + { + internal RayHoffman() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "ray_hoffman")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/TobiasWentworth.cs b/S1API/Entities/NPCs/Uptown/TobiasWentworth.cs new file mode 100644 index 00000000..b4950553 --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/TobiasWentworth.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Tobias Wentworth is a customer. + /// He lives in the Uptown region. + /// Tobias is the balding NPC with extremely light brown hair and small black glasses! + /// + public class TobiasWentworth : NPC + { + internal TobiasWentworth() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "tobias_wentworth")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Uptown/WalterCussler.cs b/S1API/Entities/NPCs/Uptown/WalterCussler.cs new file mode 100644 index 00000000..ee6b726e --- /dev/null +++ b/S1API/Entities/NPCs/Uptown/WalterCussler.cs @@ -0,0 +1,20 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; +using NPC = S1API.Entities.NPC; + +namespace S1API.Entities.NPCs.Uptown +{ + /// + /// Walter Cussler is a customer. + /// He lives in the Uptown region. + /// Walter is the NPC with white hair and dressed as a priest! + /// + public class WalterCussler : NPC + { + internal WalterCussler() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "walter_cussler")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/CharlesRowland.cs b/S1API/Entities/NPCs/Westville/CharlesRowland.cs new file mode 100644 index 00000000..a82f5374 --- /dev/null +++ b/S1API/Entities/NPCs/Westville/CharlesRowland.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Charles Rowland is a customer. + /// He lives in the Westville region. + /// Charles is the bald NPC with black glasses! + /// + public class CharlesRowland : NPC + { + internal CharlesRowland() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "charles_rowland")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/DeanWebster.cs b/S1API/Entities/NPCs/Westville/DeanWebster.cs new file mode 100644 index 00000000..00d9da03 --- /dev/null +++ b/S1API/Entities/NPCs/Westville/DeanWebster.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Dean Webster is a customer. + /// He lives in the Westville region. + /// Dean is the NPC that owns Top Tattoo! + /// + public class DeanWebster : NPC + { + internal DeanWebster() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "dean_webster")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/DorisLubbin.cs b/S1API/Entities/NPCs/Westville/DorisLubbin.cs new file mode 100644 index 00000000..a30fd86a --- /dev/null +++ b/S1API/Entities/NPCs/Westville/DorisLubbin.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Doris Lubbin is a customer. + /// She lives in the Westville region. + /// Doris is the NPC with light brown, wavy hair and black glasses! + /// + public class DorisLubbin : NPC + { + internal DorisLubbin() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "doris_lubbin")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/GeorgeGreene.cs b/S1API/Entities/NPCs/Westville/GeorgeGreene.cs new file mode 100644 index 00000000..0aa2e27a --- /dev/null +++ b/S1API/Entities/NPCs/Westville/GeorgeGreene.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// George Greene is a customer. + /// He lives in the Westville region. + /// George is the NPC with light brown, spiky hair and gold glasses! + /// + public class GeorgeGreene : NPC + { + internal GeorgeGreene() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "george_greene")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/JerryMontero.cs b/S1API/Entities/NPCs/Westville/JerryMontero.cs new file mode 100644 index 00000000..8100e54c --- /dev/null +++ b/S1API/Entities/NPCs/Westville/JerryMontero.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Jerry Montero is a customer. + /// He lives in the Westville region. + /// Jerry is the NPC with a green hat and black glasses! + /// + public class JerryMontero : NPC + { + internal JerryMontero() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "jerry_montero")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/JoyceBall.cs b/S1API/Entities/NPCs/Westville/JoyceBall.cs new file mode 100644 index 00000000..83452668 --- /dev/null +++ b/S1API/Entities/NPCs/Westville/JoyceBall.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Joyce Ball is a customer. + /// She lives in the Westville region. + /// Joyce is the NPC with light brown hair and wrinkles! + /// + public class JoyceBall : NPC + { + internal JoyceBall() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "joyce_ball")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/KeithWagner.cs b/S1API/Entities/NPCs/Westville/KeithWagner.cs new file mode 100644 index 00000000..98b0b302 --- /dev/null +++ b/S1API/Entities/NPCs/Westville/KeithWagner.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Keith Wagner is a customer. + /// He lives in the Westville region. + /// Keith is the NPC with blonde spiky hair and always angry! + /// + public class KeithWagner : NPC + { + internal KeithWagner() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "keith_wagner")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/KimDelaney.cs b/S1API/Entities/NPCs/Westville/KimDelaney.cs new file mode 100644 index 00000000..abbc07a4 --- /dev/null +++ b/S1API/Entities/NPCs/Westville/KimDelaney.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Kim Delaney is a customer. + /// She lives in the Westville region. + /// Kim is the NPC with long, black hair with bangs! + /// + public class KimDelaney : NPC + { + internal KimDelaney() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "kim_delaney")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/MegCooley.cs b/S1API/Entities/NPCs/Westville/MegCooley.cs new file mode 100644 index 00000000..b60df006 --- /dev/null +++ b/S1API/Entities/NPCs/Westville/MegCooley.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Meg Cooley is a customer. + /// She lives in the Westville region. + /// Meg is the npc with a mustard yellow bowl cut hairstyle! + /// + public class MegCooley : NPC + { + internal MegCooley() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "meg_cooley")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/MollyPresley.cs b/S1API/Entities/NPCs/Westville/MollyPresley.cs new file mode 100644 index 00000000..7f55b99f --- /dev/null +++ b/S1API/Entities/NPCs/Westville/MollyPresley.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Molly Presley is a dealer. + /// She lives in the Westville region. + /// Molly is the dealer with gold shades and a red backward cap! + /// + public class MollyPresley : NPC + { + internal MollyPresley() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "molly_presley")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/ShirleyWatts.cs b/S1API/Entities/NPCs/Westville/ShirleyWatts.cs new file mode 100644 index 00000000..705bb0a2 --- /dev/null +++ b/S1API/Entities/NPCs/Westville/ShirleyWatts.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Shirley Watts is a supplier. + /// She lives in the Westville region. + /// Shirley is the supplier for pseudo! + /// + public class ShirleyWatts : NPC + { + internal ShirleyWatts() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "shirley_watts")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/NPCs/Westville/TrentSherman.cs b/S1API/Entities/NPCs/Westville/TrentSherman.cs new file mode 100644 index 00000000..e46f1c2b --- /dev/null +++ b/S1API/Entities/NPCs/Westville/TrentSherman.cs @@ -0,0 +1,19 @@ +#if IL2CPP +using Il2CppScheduleOne.NPCs; +#else +using ScheduleOne.NPCs; +#endif +using System.Linq; + +namespace S1API.Entities.NPCs.Westville +{ + /// + /// Trent Sherman is a customer. + /// He lives in the Westville region. + /// Trent is the NPC with short black hair and dark-colored skin! + /// + public class TrentSherman : NPC + { + internal TrentSherman() : base(NPCManager.NPCRegistry.ToArray().First(n => n.ID == "trent_sherman")) { } + } +} \ No newline at end of file diff --git a/S1API/Entities/Player.cs b/S1API/Entities/Player.cs new file mode 100644 index 00000000..a8abc0e6 --- /dev/null +++ b/S1API/Entities/Player.cs @@ -0,0 +1,192 @@ +#if IL2CPP +using S1PlayerScripts = Il2CppScheduleOne.PlayerScripts; +using S1Health = Il2CppScheduleOne.PlayerScripts.Health; +#else +using S1PlayerScripts = ScheduleOne.PlayerScripts; +using S1Health = ScheduleOne.PlayerScripts.Health; +#endif + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using HarmonyLib; +using MelonLoader; +using S1API.Entities.Interfaces; +using S1API.Internal.Abstraction; +using UnityEngine; + +namespace S1API.Entities +{ + /// + /// Represents a player within the game. + /// + public class Player : IEntity, IHealth + { + /// + /// Health when the player is invincible. + /// Invincibility isn't baked in the base game. + /// Hence, why we're doing it this way :). + /// + private const float InvincibleHealth = 1000000000f; + + /// + /// The standard MAX_HEALTH of a player. + /// + private const float MortalHealth = 100f; + + /// + /// All players currently in the game. + /// + public static readonly List All = new List(); + + /// + /// INTERNAL: Tracking of the S1 instance of the player. + /// + internal S1PlayerScripts.Player S1Player; + + /// + /// INTERNAL: Constructor to create a new player from an S1 instance. + /// + /// + internal Player(S1PlayerScripts.Player player) + { + S1Player = player; + All.Add(this); + } + + /// + /// The current client player (player executing your code). + /// + public static Player Local => + All.FirstOrDefault(player => player.IsLocal)!; + + /// + /// Whether this player is the client player or a networked player. + /// + public bool IsLocal => + S1Player.IsLocalPlayer; + + /// + /// The name of the player. + /// For single player, this appears to always return `Player`. + /// + public string Name => + S1Player.PlayerName; + + /// + /// INTERNAL: The game object associated with this player. + /// + GameObject IEntity.gameObject => + S1Player.gameObject; + + /// + /// The world position of the player. + /// + public Vector3 Position + { + get => ((IEntity)this).gameObject.transform.position; + set => ((IEntity)this).gameObject.transform.position = value; + } + + /// + /// The transform of the player. + /// Please do not set the properties of the Transform. + /// + public Transform Transform => + ((IEntity)this).gameObject.transform; + + /// + /// The scale of the player. + /// + public float Scale + { + get => S1Player.Scale; + set => S1Player.SetScale(value); + } + + /// + /// The current health of the player. + /// + public float CurrentHealth => + S1Player.Health.CurrentHealth; + + /// + /// The maximum health of the player. + /// + public float MaxHealth + { + get => (float)_maxHealthField.GetValue(S1Player.Health)!; + set => _maxHealthField.SetValue(S1Player.Health, value); + } + + /// + /// Whether the player is dead or not. + /// + public bool IsDead => + !S1Player.Health.IsAlive; + + /// + /// Whether the player is invincible or not. + /// + public bool IsInvincible + { + get => MaxHealth == InvincibleHealth; + set + { + MaxHealth = value ? InvincibleHealth : MortalHealth; + S1Player.Health.SetHealth(MaxHealth); + } + } + + /// + /// Revives the player. + /// + public void Revive() => + S1Player.Health.Revive(Position, Quaternion.identity); + + /// + /// Deals damage to the player. + /// + /// The amount of damage to deal. + public void Damage(int amount) + { + if (amount <= 0) + return; + + S1Player.Health.TakeDamage(amount); + } + + /// + /// Heals the player. + /// + /// The amount of healing to apply to the player. + public void Heal(int amount) + { + if (amount <= 0) + return; + + S1Player.Health.SetHealth(CurrentHealth + amount); + } + + /// + /// Kills the player. + /// + public void Kill() => + S1Player.Health.SetHealth(0f); + + /// + /// Called when the player dies. + /// + public event Action OnDeath + { + add => EventHelper.AddListener(value, S1Player.Health.onDie); + remove => EventHelper.RemoveListener(value, S1Player.Health.onDie); + } + + /// + /// INTERNAL: Field access for the MAX_HEALTH const. + /// + private readonly FieldInfo _maxHealthField = AccessTools.Field(typeof(S1Health.PlayerHealth), "MAX_HEALTH"); + } +} diff --git a/S1API/GameTime/Day.cs b/S1API/GameTime/Day.cs index 61311920..38b2fa45 100644 --- a/S1API/GameTime/Day.cs +++ b/S1API/GameTime/Day.cs @@ -5,12 +5,39 @@ /// public enum Day { + /// + /// Represents the first day of the week. + /// Monday, + + /// + /// Represents the second day of the week. + /// Tuesday, + + /// + /// Represents the third day of the week. + /// Wednesday, + + /// + /// Represents the fourth day of the week. + /// Thursday, + + /// + /// Represents the fifth day of the week. + /// Friday, + + /// + /// Represents the sixth day of the week. + /// Saturday, + + /// + /// Represents the seventh day of the week. + /// Sunday } } \ No newline at end of file diff --git a/S1API/Internal/Abstraction/EventHelper.cs b/S1API/Internal/Abstraction/EventHelper.cs index 1dd94e81..900eeaee 100644 --- a/S1API/Internal/Abstraction/EventHelper.cs +++ b/S1API/Internal/Abstraction/EventHelper.cs @@ -36,7 +36,7 @@ internal static void AddListener(Action listener, UnityEvent unityEvent) /// The event you want to unsubscribe from. internal static void RemoveListener(Action listener, UnityEvent unityEvent) { - SubscribedActions.TryGetValue(listener, out UnityAction wrappedAction); + SubscribedActions.TryGetValue(listener, out UnityAction? wrappedAction); SubscribedActions.Remove(listener); unityEvent.RemoveListener(wrappedAction); } diff --git a/S1API/Internal/Abstraction/Saveable.cs b/S1API/Internal/Abstraction/Saveable.cs index 4dd23602..7afa79aa 100644 --- a/S1API/Internal/Abstraction/Saveable.cs +++ b/S1API/Internal/Abstraction/Saveable.cs @@ -33,7 +33,7 @@ internal virtual void LoadInternal(string folderPath) FieldInfo[] saveableFields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo saveableField in saveableFields) { - SaveableField saveableFieldAttribute = saveableField.GetCustomAttribute(); + SaveableField? saveableFieldAttribute = saveableField.GetCustomAttribute(); if (saveableFieldAttribute == null) continue; @@ -68,7 +68,7 @@ internal virtual void SaveInternal(string folderPath, ref List extraSave FieldInfo[] saveableFields = ReflectionUtils.GetAllFields(GetType(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo saveableField in saveableFields) { - SaveableField saveableFieldAttribute = saveableField.GetCustomAttribute(); + SaveableField? saveableFieldAttribute = saveableField.GetCustomAttribute(); if (saveableFieldAttribute == null) continue; @@ -78,7 +78,7 @@ internal virtual void SaveInternal(string folderPath, ref List extraSave string saveDataPath = Path.Combine(folderPath, saveFileName); - object value = saveableField.GetValue(this); + object? value = saveableField.GetValue(this); if (value == null) // Remove the save if the field is null File.Delete(saveDataPath); diff --git a/S1API/Internal/Patches/NPCPatches.cs b/S1API/Internal/Patches/NPCPatches.cs index b00bba50..0c06a5bf 100644 --- a/S1API/Internal/Patches/NPCPatches.cs +++ b/S1API/Internal/Patches/NPCPatches.cs @@ -11,9 +11,10 @@ using System; using System.IO; using System.Linq; +using System.Reflection; using HarmonyLib; +using S1API.Entities; using S1API.Internal.Utils; -using S1API.NPCs; namespace S1API.Internal.Patches { @@ -23,13 +24,6 @@ namespace S1API.Internal.Patches [HarmonyPatch] internal class NPCPatches { - - // ReSharper disable once RedundantNameQualifier - /// - /// List of all custom NPCs currently created. - /// - private static readonly System.Collections.Generic.List NPCs = new System.Collections.Generic.List(); - /// /// Patching performed for when game NPCs are loaded. /// @@ -41,13 +35,19 @@ private static void NPCsLoadersLoad(S1Loaders.NPCsLoader __instance, string main { foreach (Type type in ReflectionUtils.GetDerivedClasses()) { - NPC customNPC = (NPC)Activator.CreateInstance(type); - NPCs.Add(customNPC); + NPC? customNPC = (NPC)Activator.CreateInstance(type, true)!; + if (customNPC == null) + throw new Exception($"Unable to create instance of {type.FullName}!"); + + // We skip any S1API NPCs, as they are base NPC wrappers. + if (type.Assembly == Assembly.GetExecutingAssembly()) + continue; + string npcPath = Path.Combine(mainPath, customNPC.S1NPC.SaveFolderName); customNPC.LoadInternal(npcPath); } } - + /// /// Patching performed for when a single NPC starts (including modded in NPCs). /// @@ -55,7 +55,8 @@ private static void NPCsLoadersLoad(S1Loaders.NPCsLoader __instance, string main [HarmonyPatch(typeof(S1NPCs.NPC), "Start")] [HarmonyPostfix] private static void NPCStart(S1NPCs.NPC __instance) => - NPCs.FirstOrDefault(npc => npc.S1NPC == __instance)?.CreateInternal(); + NPC.All.FirstOrDefault(npc => npc.IsCustomNPC && npc.S1NPC == __instance)?.CreateInternal(); + /// /// Patching performed for when an NPC calls to save data. @@ -66,7 +67,7 @@ private static void NPCStart(S1NPCs.NPC __instance) => [HarmonyPatch(typeof(S1NPCs.NPC), "WriteData")] [HarmonyPostfix] private static void NPCWriteData(S1NPCs.NPC __instance, string parentFolderPath, ref List __result) => - NPCs.FirstOrDefault(npc => npc.S1NPC == __instance)?.SaveInternal(parentFolderPath, ref __result); + NPC.All.FirstOrDefault(npc => npc.IsCustomNPC && npc.S1NPC == __instance)?.SaveInternal(parentFolderPath, ref __result); /// /// Patching performed for when an NPC is destroyed. @@ -74,14 +75,7 @@ private static void NPCWriteData(S1NPCs.NPC __instance, string parentFolderPath, /// Instance of the NPC [HarmonyPatch(typeof(S1NPCs.NPC), "OnDestroy")] [HarmonyPostfix] - private static void NPCOnDestroy(S1NPCs.NPC __instance) - { - NPCs.RemoveAll(npc => npc.S1NPC == __instance); - NPC? npc = NPCs.FirstOrDefault(npc => npc.S1NPC == __instance); - if (npc == null) - return; - - NPCs.Remove(npc); - } + private static void NPCOnDestroy(S1NPCs.NPC __instance) => + NPC.All.Remove(NPC.All.First(npc => npc.S1NPC == __instance)); } } diff --git a/S1API/Internal/Patches/PhoneAppPatches.cs b/S1API/Internal/Patches/PhoneAppPatches.cs index 7d48da32..9c9bf913 100644 --- a/S1API/Internal/Patches/PhoneAppPatches.cs +++ b/S1API/Internal/Patches/PhoneAppPatches.cs @@ -3,12 +3,11 @@ using UnityEngine.SceneManagement; using S1API.Internal.Utils; using S1API.Internal.Abstraction; -using S1API.Logging; using S1API.PhoneApp; namespace S1API.Internal.Patches -{ -#if IL2CPPMELON || IL2CPPBEPINEX +{ +#if IL2CPP [HarmonyPatch(typeof(SceneManager), nameof(SceneManager.Internal_SceneLoaded))] #else [HarmonyPatch(typeof(SceneManager), "Internal_SceneLoaded", new Type[] { typeof(Scene), typeof(LoadSceneMode) })] @@ -16,8 +15,7 @@ namespace S1API.Internal.Patches #endif internal static class PhoneAppPatches { - private static readonly Log _loggerInstance = new Log("PhoneAppPatches"); - + // TODO (@omar-akermi): Can you look into if this is still needed pls? private static bool _loaded = false; /// @@ -44,9 +42,9 @@ static void Postfix(Scene scene, LoadSceneMode mode) } catch (System.Exception e) { - _loggerInstance.Warning($"[PhoneApp] Failed to register {type.FullName}: {e.Message}"); + MelonLoader.MelonLogger.Warning($"[PhoneApp] Failed to register {type.FullName}: {e.Message}"); } } } } -} +} \ No newline at end of file diff --git a/S1API/Internal/Patches/PlayerPatches.cs b/S1API/Internal/Patches/PlayerPatches.cs new file mode 100644 index 00000000..d3f24c65 --- /dev/null +++ b/S1API/Internal/Patches/PlayerPatches.cs @@ -0,0 +1,39 @@ +#if IL2CPP +using S1PlayerScripts = Il2CppScheduleOne.PlayerScripts; +#else +using S1PlayerScripts = ScheduleOne.PlayerScripts; +#endif + + +using System.Linq; +using HarmonyLib; +using S1API.Entities; + +namespace S1API.Internal.Patches +{ + /// + /// INTERNAL: Patches to apply to the Players for tracking. + /// + [HarmonyPatch] + internal class PlayerPatches + { + /// + /// INTERNAL: Adds players to the player list upon wake. + /// + /// The player to add. + [HarmonyPatch(typeof(S1PlayerScripts.Player), "Awake")] + [HarmonyPostfix] + private static void PlayerAwake(S1PlayerScripts.Player __instance) => + new Player(__instance); + + + /// + /// INTERNAL: Removes players from the player list upon destruction. + /// + /// The player to remove. + [HarmonyPatch(typeof(S1PlayerScripts.Player), "OnDestroy")] + [HarmonyPostfix] + private static void PlayerOnDestroy(S1PlayerScripts.Player __instance) => + Player.All.Remove(Player.All.First(player => player.S1Player == __instance)); + } +} \ No newline at end of file diff --git a/S1API/Internal/Patches/QuestPatches.cs b/S1API/Internal/Patches/QuestPatches.cs index 6b825e21..035bbe64 100644 --- a/S1API/Internal/Patches/QuestPatches.cs +++ b/S1API/Internal/Patches/QuestPatches.cs @@ -59,8 +59,8 @@ private static void QuestsLoaderLoad(S1Loaders.QuestsLoader __instance, string m string[] questDirectories = Directory.GetDirectories(mainPath) .Select(Path.GetFileName) - .Where(directory => directory.StartsWith("Quest_")) - .ToArray(); + .Where(directory => directory != null && directory.StartsWith("Quest_")) + .ToArray()!; foreach (string questDirectory in questDirectories) { diff --git a/S1API/Internal/Utils/ButtonListener.cs b/S1API/Internal/Utils/ButtonListener.cs index 75f6a75a..8f8d6ab3 100644 --- a/S1API/Internal/Utils/ButtonListener.cs +++ b/S1API/Internal/Utils/ButtonListener.cs @@ -1,69 +1,76 @@ -using UnityEngine.UI; using System; using S1API.Internal.Abstraction; using UnityEngine; +using UnityEngine.UI; -public static class ButtonUtils +namespace S1API.Internal.Utils { /// - /// Adds a click listener to the specified button, ensuring compatibility with IL2CPP and Mono. + /// Utility class for managing UI Buttons. + /// TODO (@omar-akermi): Is this intended to be internal instead of public?? /// - public static void AddListener(Button button, Action action) + public static class ButtonUtils { - if (button == null || action == null) return; - EventHelper.AddListener(action, button.onClick); - } + /// + /// Adds a click listener to the specified button, ensuring compatibility with IL2CPP and Mono. + /// + public static void AddListener(Button button, Action action) + { + if (button == null || action == null) return; + EventHelper.AddListener(action, button.onClick); + } - /// - /// Removes a previously added click listener from the specified button. - /// - public static void RemoveListener(Button button, Action action) - { - if (button == null || action == null) return; - EventHelper.RemoveListener(action, button.onClick); - } + /// + /// Removes a previously added click listener from the specified button. + /// + public static void RemoveListener(Button button, Action action) + { + if (button == null || action == null) return; + EventHelper.RemoveListener(action, button.onClick); + } - /// - /// Removes all listeners from the specified button safely. - /// - public static void ClearListeners(Button button) - { - if (button == null) return; - button.onClick.RemoveAllListeners(); - } + /// + /// Removes all listeners from the specified button safely. + /// + public static void ClearListeners(Button button) + { + if (button == null) return; + button.onClick.RemoveAllListeners(); + } - /// - /// Enables the button and optionally updates the label. - /// - public static void Enable(Button button, Text label = null, string text = null) - { - if (button != null) button.interactable = true; - if (label != null && !string.IsNullOrEmpty(text)) label.text = text; - } + /// + /// Enables the button and optionally updates the label. + /// + public static void Enable(Button button, Text? label = null, string? text = null) + { + if (button != null) button.interactable = true; + if (label != null && !string.IsNullOrEmpty(text)) label.text = text; + } - /// - /// Disables the button and optionally updates the label. - /// - public static void Disable(Button button, Text label = null, string text = null) - { - if (button != null) button.interactable = false; - if (label != null && !string.IsNullOrEmpty(text)) label.text = text; - } + /// + /// Disables the button and optionally updates the label. + /// + public static void Disable(Button button, Text? label = null, string? text = null) + { + if (button != null) button.interactable = false; + if (label != null && !string.IsNullOrEmpty(text)) label.text = text; + } - /// - /// Sets the label text of a button with a known Text child. - /// - public static void SetLabel(Text label, string text) - { - if (label != null) label.text = text; - } - /// - /// Sets the button label and background color. - /// - public static void SetStyle(Button button, Text label, string text, Color bg) - { - if (button == null || label == null) return; - label.text = text; - button.image.color = bg; + /// + /// Sets the label text of a button with a known Text child. + /// + public static void SetLabel(Text label, string text) + { + if (label != null) label.text = text; + } + /// + /// Sets the button label and background color. + /// + public static void SetStyle(Button button, Text label, string text, Color bg) + { + if (button == null || label == null) return; + label.text = text; + button.image.color = bg; + } } } \ No newline at end of file diff --git a/S1API/Internal/Utils/ImageUtils.cs b/S1API/Internal/Utils/ImageUtils.cs index 8ca166e1..62365758 100644 --- a/S1API/Internal/Utils/ImageUtils.cs +++ b/S1API/Internal/Utils/ImageUtils.cs @@ -4,6 +4,10 @@ namespace S1API.Internal.Utils { + /// + /// A utility class to assist with loading images into the game. + /// Useful for icons such as on phone apps, custom NPCs, quests, etc. + /// public static class ImageUtils { private static readonly Log _loggerInstance = new Log("ImageUtils"); @@ -15,7 +19,7 @@ public static class ImageUtils /// /// A Sprite object representing the loaded image, or null if the image could not be loaded or the file does not exist. /// - public static Sprite LoadImage(string fileName) + public static Sprite? LoadImage(string fileName) { string fullPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? string.Empty, fileName); if (!File.Exists(fullPath)) diff --git a/S1API/Internal/Utils/RandomUtils.cs b/S1API/Internal/Utils/RandomUtils.cs index a1d984ac..f57dc030 100644 --- a/S1API/Internal/Utils/RandomUtils.cs +++ b/S1API/Internal/Utils/RandomUtils.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; -using UnityEngine; -namespace S1API.Utils +namespace S1API.Internal.Utils { /// /// A utility class providing random selection functionality for lists and numeric ranges. @@ -17,7 +16,7 @@ public static class RandomUtils public static T PickOne(this IList list) { if (list == null || list.Count == 0) - return default; + return default!; return list[UnityEngine.Random.Range(0, list.Count)]; } @@ -32,8 +31,8 @@ public static T PickOne(this IList list) /// A randomly selected item that satisfies the condition, or the default value of the type if no valid item is found. public static T PickUnique(this IList list, Func isDuplicate, int maxTries = 10) { - if (list == null || list.Count == 0) - return default; + if (list.Count == 0) + return default!; for (int i = 0; i < maxTries; i++) { @@ -42,7 +41,7 @@ public static T PickUnique(this IList list, Func isDuplicate, int return item; } - return default; + return default!; } /// @@ -54,7 +53,9 @@ public static T PickUnique(this IList list, Func isDuplicate, int /// A list containing the selected random items, or an empty list if the input list is null or empty. public static List PickMany(this IList list, int count) { - if (list == null || list.Count == 0) return new List(); + if (list.Count == 0) + return new List(); + var copy = new List(list); var result = new List(); diff --git a/S1API/Internal/Utils/ReflectionUtils.cs b/S1API/Internal/Utils/ReflectionUtils.cs index ff22e152..664c6e7d 100644 --- a/S1API/Internal/Utils/ReflectionUtils.cs +++ b/S1API/Internal/Utils/ReflectionUtils.cs @@ -19,12 +19,12 @@ internal static List GetDerivedClasses() { List derivedClasses = new List(); Assembly[] applicableAssemblies = AppDomain.CurrentDomain.GetAssemblies() - .Where(assembly => !assembly.FullName.StartsWith("System") && - !assembly.FullName.StartsWith("Unity") && - !assembly.FullName.StartsWith("Il2Cpp") && - !assembly.FullName.StartsWith("mscorlib") && - !assembly.FullName.StartsWith("Mono.") && - !assembly.FullName.StartsWith("netstandard")) + .Where(assembly => !assembly.FullName!.StartsWith("System") && + !assembly.FullName!.StartsWith("Unity") && + !assembly.FullName!.StartsWith("Il2Cpp") && + !assembly.FullName!.StartsWith("mscorlib") && + !assembly.FullName!.StartsWith("Mono.") && + !assembly.FullName!.StartsWith("netstandard")) .ToArray(); foreach (Assembly assembly in applicableAssemblies) derivedClasses.AddRange(assembly.GetTypes() diff --git a/S1API/Items/ItemCategory.cs b/S1API/Items/ItemCategory.cs index 483a6ed2..a4e88df8 100644 --- a/S1API/Items/ItemCategory.cs +++ b/S1API/Items/ItemCategory.cs @@ -5,17 +5,66 @@ /// 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/S1API/Leveling/Rank.cs b/S1API/Leveling/Rank.cs index 1582ee51..9144b28f 100644 --- a/S1API/Leveling/Rank.cs +++ b/S1API/Leveling/Rank.cs @@ -5,16 +5,59 @@ /// public enum Rank { + /// + /// Represents the first rank for the player. + /// StreetRat, + + /// + /// Represents the second rank for the player. + /// Hoodlum, + + /// + /// Represents the third rank for the player. + /// Peddler, + + /// + /// Represents the fourth rank for the player. + /// Hustler, + + /// + /// Represents the fifth rank for the player. + /// Bagman, + + /// + /// Represents the sixth rank for the player. + /// Enforcer, + + /// + /// Represents the seventh rank for the player. + /// ShotCaller, + + /// + /// Represents the eighth rank for the player. + /// BlockBoss, + + /// + /// Represents the ninth rank for the player. + /// Underlord, + + /// + /// Represents the tenth rank for the player. + /// Baron, + + /// + /// Represents the eleventh rank for the player. + /// Kingpin } } \ No newline at end of file diff --git a/S1API/Map/Region.cs b/S1API/Map/Region.cs new file mode 100644 index 00000000..1ed6785b --- /dev/null +++ b/S1API/Map/Region.cs @@ -0,0 +1,38 @@ +namespace S1API.Map +{ + /// + /// The regions available in the game. + /// + public enum Region + { + /// + /// The first region in the game. + /// + Northtown, + + /// + /// The second region in the game. + /// + Westville, + + /// + /// The third region in the game. + /// + Downtown, + + /// + /// The fourth region in the game. + /// + Docks, + + /// + /// The fifth region in the game. + /// + Suburbia, + + /// + /// The sixth region in the game. + /// + Uptown + } +} \ No newline at end of file diff --git a/S1API/NPCs/Response.cs b/S1API/Messaging/Response.cs similarity index 94% rename from S1API/NPCs/Response.cs rename to S1API/Messaging/Response.cs index 9ab12e45..1e9028c6 100644 --- a/S1API/NPCs/Response.cs +++ b/S1API/Messaging/Response.cs @@ -1,11 +1,11 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) +#if (IL2CPP) using S1Messaging = Il2CppScheduleOne.Messaging; -#elif (MONOMELON || MONOBEPINEX) +#elif (MONO) using S1Messaging = ScheduleOne.Messaging; #endif using System; -namespace S1API.NPCs +namespace S1API.Messaging { /// /// Represents a message response displayed for the player. @@ -55,4 +55,4 @@ public string Text set => S1Response.text = value; } } -} +} \ No newline at end of file diff --git a/S1API/NPCs/NPC.cs b/S1API/NPCs/NPC.cs deleted file mode 100644 index f39611db..00000000 --- a/S1API/NPCs/NPC.cs +++ /dev/null @@ -1,270 +0,0 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) -using S1DevUtilities = Il2CppScheduleOne.DevUtilities; -using S1Interaction = Il2CppScheduleOne.Interaction; -using S1Messaging = Il2CppScheduleOne.Messaging; -using S1Noise = Il2CppScheduleOne.Noise; -using S1Relation = Il2CppScheduleOne.NPCs.Relation; -using S1Responses = Il2CppScheduleOne.NPCs.Responses; -using S1PlayerScripts = Il2CppScheduleOne.PlayerScripts; -using S1ContactApps = Il2CppScheduleOne.UI.Phone.ContactsApp; -using S1WorkspacePopup = Il2CppScheduleOne.UI.WorldspacePopup; -using S1AvatarFramework = Il2CppScheduleOne.AvatarFramework; -using S1Behaviour = Il2CppScheduleOne.NPCs.Behaviour; -using S1Vehicles = Il2CppScheduleOne.Vehicles; -using S1Vision = Il2CppScheduleOne.Vision; -using S1NPCs = Il2CppScheduleOne.NPCs; -using Il2CppSystem.Collections.Generic; -#elif (MONOMELON || MONOBEPINEX) -using S1DevUtilities = ScheduleOne.DevUtilities; -using S1Interaction = ScheduleOne.Interaction; -using S1Messaging = ScheduleOne.Messaging; -using S1Noise = ScheduleOne.Noise; -using S1Relation = ScheduleOne.NPCs.Relation; -using S1Responses = ScheduleOne.NPCs.Responses; -using S1PlayerScripts = ScheduleOne.PlayerScripts; -using S1ContactApps = ScheduleOne.UI.Phone.ContactsApp; -using S1WorkspacePopup = ScheduleOne.UI.WorldspacePopup; -using S1AvatarFramework = ScheduleOne.AvatarFramework; -using S1Behaviour = ScheduleOne.NPCs.Behaviour; -using S1Vehicles = ScheduleOne.Vehicles; -using S1Vision = ScheduleOne.Vision; -using S1NPCs = ScheduleOne.NPCs; -using System.Collections.Generic; -using System.Reflection; -using HarmonyLib; -#endif - -using System; -using System.IO; -using S1API.Internal.Abstraction; -using UnityEngine; -using UnityEngine.Events; - -namespace S1API.NPCs -{ - /// - /// An abstract class intended to be derived from for creating custom NPCs in the game. - /// - public abstract class NPC : Saveable - { - /// - /// A list of text responses you've added to your NPC. - /// - protected readonly System.Collections.Generic.List Responses = - new System.Collections.Generic.List(); - - internal readonly S1NPCs.NPC S1NPC; - - private readonly GameObject _gameObject; - /// - /// Optional custom mugshot icon sprite. If null, defaults to ContactsApp icon. - /// protected override Sprite? NPCIcon => ImageUtils.LoadImage("icon.png"); - /// - protected virtual Sprite? NPCIcon => null; - - /// - /// Base constructor for a new NPC. - /// Intended to be wrapped in your derived class constructor such as: - /// public class MyNPC : NPC ... - /// public MyNPC() : base(id, fname, lname) { ... } - /// - /// The unique identifier for this NPC - /// - /// - public NPC(string guid, string firstName, string lastName) - { - _gameObject = new GameObject("NPC"); - - // Deactivate game object til we're done - _gameObject.SetActive(false); - - // Setup the base NPC class - S1NPC = _gameObject.AddComponent(); - S1NPC.FirstName = firstName; - S1NPC.LastName = lastName; - S1NPC.ID = guid; - S1NPC.BakedGUID = Guid.NewGuid().ToString(); - S1NPC.MugshotSprite = NPCIcon ?? S1DevUtilities.PlayerSingleton.Instance.AppIcon; - - // ReSharper disable once UseObjectOrCollectionInitializer - S1NPC.ConversationCategories = new List(); - S1NPC.ConversationCategories.Add(S1Messaging.EConversationCategory.Customer); - - // Create our MessageConversation -#if (IL2CPPMELON || IL2CPPBEPINEX) - S1NPC.CreateMessageConversation(); -#elif (MONOMELON || MONOBEPINEX) - MethodInfo createConvoMethod = AccessTools.Method(typeof(S1NPCs.NPC), "CreateMessageConversation"); - createConvoMethod.Invoke(S1NPC, null); -#endif - - // Add UnityEvents for NPCHealth - S1NPC.Health = _gameObject.GetComponent(); - S1NPC.Health.onDie = new UnityEvent(); - S1NPC.Health.onKnockedOut = new UnityEvent(); - S1NPC.Health.Invincible = true; - S1NPC.Health.MaxHealth = 100f; - - // Awareness behaviour - GameObject awarenessObject = new GameObject("NPCAwareness"); - awarenessObject.SetActive(false); - awarenessObject.transform.SetParent(_gameObject.transform); - S1NPC.awareness = awarenessObject.AddComponent(); - S1NPC.awareness.onExplosionHeard = new UnityEvent(); - S1NPC.awareness.onGunshotHeard = new UnityEvent(); - S1NPC.awareness.onHitByCar = new UnityEvent(); - S1NPC.awareness.onNoticedDrugDealing = new UnityEvent(); - S1NPC.awareness.onNoticedGeneralCrime = new UnityEvent(); - S1NPC.awareness.onNoticedPettyCrime = new UnityEvent(); - S1NPC.awareness.onNoticedPlayerViolatingCurfew = new UnityEvent(); - S1NPC.awareness.onNoticedSuspiciousPlayer = new UnityEvent(); - S1NPC.awareness.Listener = _gameObject.AddComponent(); - - /////// START BEHAVIOUR CODE //////// - // NPCBehaviours behaviour - GameObject behaviourObject = new GameObject("NPCBehaviour"); - behaviourObject.SetActive(false); - behaviourObject.transform.SetParent(_gameObject.transform); - S1Behaviour.NPCBehaviour behaviour = behaviourObject.AddComponent(); - - GameObject cowingBehaviourObject = new GameObject("CowingBehaviour"); - cowingBehaviourObject.transform.SetParent(behaviourObject.transform); - S1Behaviour.CoweringBehaviour coweringBehaviour = cowingBehaviourObject.AddComponent(); - - GameObject fleeBehaviourObject = new GameObject("FleeBehaviour"); - fleeBehaviourObject.transform.SetParent(behaviourObject.transform); - S1Behaviour.FleeBehaviour fleeBehaviour = fleeBehaviourObject.AddComponent(); - - behaviour.CoweringBehaviour = coweringBehaviour; - behaviour.FleeBehaviour = fleeBehaviour; - S1NPC.behaviour = behaviour; - /////// END BEHAVIOUR CODE //////// - - // Response to actions like gunshots, drug deals, etc. - GameObject responsesObject = new GameObject("NPCResponses"); - responsesObject.SetActive(false); - responsesObject.transform.SetParent(_gameObject.transform); - S1NPC.awareness.Responses = responsesObject.AddComponent(); - - // Vision cone object and behaviour - GameObject visionObject = new GameObject("VisionCone"); - visionObject.SetActive(false); - visionObject.transform.SetParent(_gameObject.transform); - S1Vision.VisionCone visionCone = visionObject.AddComponent(); - visionCone.StatesOfInterest.Add(new S1Vision.VisionCone.StateContainer - { - state = S1PlayerScripts.PlayerVisualState.EVisualState.PettyCrime, RequiredNoticeTime = 0.1f - }); - S1NPC.awareness.VisionCone = visionCone; - - - // Suspicious ? icon in world space - S1NPC.awareness.VisionCone.QuestionMarkPopup = _gameObject.AddComponent(); - - // Interaction behaviour -#if (IL2CPPMELON || IL2CPPBEPINEX) - S1NPC.intObj = _gameObject.AddComponent(); -#elif (MONOMELON || MONOBEPINEX) - FieldInfo intObjField = AccessTools.Field(typeof(S1NPCs.NPC), "intObj"); - intObjField.SetValue(S1NPC, _gameObject.AddComponent()); -#endif - - // Relationship data - S1NPC.RelationData = new S1Relation.NPCRelationData(); - - // void OnUnlockAction(S1Relation.NPCRelationData.EUnlockType unlockType, bool notify) - // { - // if (!string.IsNullOrEmpty(S1NPC.NPCUnlockedVariable)) - // { - // S1DevUtilities.NetworkSingleton.Instance.SetVariableValue(S1NPC.NPCUnlockedVariable, true.ToString()); - // } - // } - - // S1NPC.RelationData.onUnlocked += (Action)OnUnlockAction; - - // Inventory behaviour - S1NPCs.NPCInventory inventory = _gameObject.AddComponent(); - - // Pickpocket behaviour - inventory.PickpocketIntObj = _gameObject.AddComponent(); - - // Defaulting to the local player for Avatar TODO: Change - S1NPC.Avatar = S1AvatarFramework.MugshotGenerator.Instance.MugshotRig; - - - // NetworkObject networkObject = gameObject.AddComponent(); - // // networkObject.NetworkBehaviours = InstanceFinder.NetworkManager; - // PropertyInfo networkBehavioursProperty = AccessTools.Property(typeof(NetworkObject), "NetworkBehaviours"); - // networkBehavioursProperty.SetValue(networkObject, new [] { this }); - - // Enable our custom gameObjects so they can initialize - _gameObject.SetActive(true); - visionObject.SetActive(true); - responsesObject.SetActive(true); - awarenessObject.SetActive(true); - behaviourObject.SetActive(true); - } - - /// - /// INTERNAL: Initializes the responses that have been added / loaded - /// - internal override void CreateInternal() - { - // Assign responses to our tracked responses - foreach (S1Messaging.Response s1Response in S1NPC.MSGConversation.currentResponses) - { - Response response = new Response(s1Response) { Label = s1Response.label, Text = s1Response.text }; - Responses.Add(response); - OnResponseLoaded(response); - } - - base.CreateInternal(); - } - - internal override void SaveInternal(string folderPath, ref List extraSaveables) - { - string npcPath = Path.Combine(folderPath, S1NPC.SaveFolderName); - base.SaveInternal(npcPath, ref extraSaveables); - } - - /// - /// Sends a text message from this NPC to the players. - /// Supports responses with callbacks for additional logic. - /// - /// The message you want the player to see. Unity rich text is allowed. - /// Instances of to display. - /// The delay between when the message is sent and when the player can reply. - /// Whether this should propagate to all players or not. - public void SendTextMessage(string message, Response[]? responses = null, float responseDelay = 1f, bool network = true) - { - S1NPC.SendTextMessage(message); - S1NPC.MSGConversation.ClearResponses(); - - if (responses == null || responses.Length == 0) - return; - - Responses.Clear(); - - List responsesList = new List(); - - foreach (Response response in responses) - { - Responses.Add(response); - responsesList.Add(response.S1Response); - } - - S1NPC.MSGConversation.ShowResponses( - responsesList, - responseDelay, - network - ); - } - - /// - /// Called when a response is loaded from the save file. - /// Override this method for attaching your callbacks to your methods. - /// - /// The response that was loaded. - protected virtual void OnResponseLoaded(Response response) { } - } -} diff --git a/S1API/NPCs/NPCInstance.cs b/S1API/NPCs/NPCInstance.cs deleted file mode 100644 index 27354028..00000000 --- a/S1API/NPCs/NPCInstance.cs +++ /dev/null @@ -1,13 +0,0 @@ -#if (IL2CPPMELON || IL2CPPBEPINEX) -using S1NPCs = Il2CppScheduleOne.NPCs; -#elif (MONOMELON || MONOBEPINEX) -using S1NPCs = ScheduleOne.NPCs; -#endif - -namespace S1API.NPCs -{ - public class NPCInstance - { - - } -} diff --git a/S1API/NPCs/NPCManager.cs b/S1API/NPCs/NPCManager.cs deleted file mode 100644 index b8fa86dc..00000000 --- a/S1API/NPCs/NPCManager.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace S1API.NPCs -{ - public class NPCManager - { - - } -} \ No newline at end of file diff --git a/S1API/PhoneApp/MyAwesomeApp.cs b/S1API/PhoneApp/MyAwesomeApp.cs index 54ef4495..31d3c30f 100644 --- a/S1API/PhoneApp/MyAwesomeApp.cs +++ b/S1API/PhoneApp/MyAwesomeApp.cs @@ -5,13 +5,15 @@ namespace S1API.PhoneApp { - /// - /// Defines the MyAwesomeApp, a specialized application integrated into an in-game phone system. - /// - /// - /// This class leverages the PhoneApp framework to specify application-specific properties like name, title, - /// icon label, and icon file name. It also overrides the method for defining the user interface layout upon creation. - /// + // TODO(@omar-akermi): Can we move this into markdown pls <3 + + // /// + // /// Defines the MyAwesomeApp, a specialized application integrated into an in-game phone system. + // /// + // /// + // /// This class leverages the PhoneApp framework to specify application-specific properties like name, title, + // /// icon label, and icon file name. It also overrides the method for defining the user interface layout upon creation. + // /// /* public class MyAwesomeApp : PhoneApp { diff --git a/S1API/PhoneApp/PhoneApp.cs b/S1API/PhoneApp/PhoneApp.cs index 4b9dbb33..7f59e4e7 100644 --- a/S1API/PhoneApp/PhoneApp.cs +++ b/S1API/PhoneApp/PhoneApp.cs @@ -1,25 +1,11 @@ -#if IL2CPPMELON || IL2CPPBEPINEX -using UnityEngine; -using UnityEngine.UI; -using UnityEngine.Events; -#elif MONOMELON || MONOBEPINEX -using UnityEngine; -using UnityEngine.UI; -using UnityEngine.Events; -#endif - -using FishNet; -using System.Collections; +using System.Collections; using System.IO; -#if MONOMELON || IL2CPPMELON using MelonLoader; -using MelonLoader.Utils; -#elif MONOBEPINEX || IL2CPPBEPINEX -using BepInEx.Logging; -#endif +using UnityEngine; +using UnityEngine.UI; using Object = UnityEngine.Object; +using MelonLoader.Utils; using S1API.Internal.Abstraction; -using S1API.Logging; namespace S1API.PhoneApp { @@ -33,27 +19,31 @@ namespace S1API.PhoneApp /// public abstract class PhoneApp : Registerable { - protected static readonly Log LoggerInstance = new Log("PhoneApp"); + /// + /// INTERNAL: A dedicated logger for all custom phone apps. + /// + protected static readonly MelonLogger.Instance LoggerInstance = new MelonLogger.Instance("PhoneApp"); /// /// The player object in the scene. /// - protected GameObject Player; + private GameObject? _player; /// /// The in-game UI panel representing the app. /// - protected GameObject AppPanel; + private GameObject? _appPanel; + // TODO (@omar-akermi): Can you look into if this is still needed pls? /// /// Whether the app was successfully created. /// - protected bool AppCreated; + private bool _appCreated; /// /// Whether the app icon was already modified. /// - protected bool IconModified; + private bool _iconModified; /// /// Unique GameObject name of the app (e.g. "SilkroadApp"). @@ -64,7 +54,7 @@ public abstract class PhoneApp : Registerable /// The title shown at the top of the app UI. /// protected abstract string AppTitle { get; } - + /// /// The label shown under the app icon on the home screen. /// @@ -86,10 +76,7 @@ public abstract class PhoneApp : Registerable /// protected override void OnCreated() { - // @TODO: Find out if this actually is the proper way of starting a coroutine - // for both BepInEx and MelonLoader - // Old code: MelonCoroutines.Start(InitApp()); - InstanceFinder.TimeManager.StartCoroutine(InitApp()); + MelonCoroutines.Start(InitApp()); } /// @@ -97,14 +84,14 @@ protected override void OnCreated() /// protected override void OnDestroyed() { - if (AppPanel != null) + if (_appPanel != null) { - Object.Destroy(AppPanel); - AppPanel = null; + Object.Destroy(_appPanel); + _appPanel = null; } - AppCreated = false; - IconModified = false; + _appCreated = false; + _iconModified = false; } /// @@ -114,8 +101,8 @@ private IEnumerator InitApp() { yield return new WaitForSeconds(5f); - Player = GameObject.Find("Player_Local"); - if (Player == null) + _player = GameObject.Find("Player_Local"); + if (_player == null) { LoggerInstance.Error("Player_Local not found."); yield break; @@ -131,8 +118,8 @@ private IEnumerator InitApp() Transform existingApp = appsCanvas.transform.Find(AppName); if (existingApp != null) { - AppPanel = existingApp.gameObject; - SetupExistingAppPanel(AppPanel); + _appPanel = existingApp.gameObject; + SetupExistingAppPanel(_appPanel); } else { @@ -143,10 +130,10 @@ private IEnumerator InitApp() yield break; } - AppPanel = Object.Instantiate(templateApp.gameObject, appsCanvas.transform); - AppPanel.name = AppName; + _appPanel = Object.Instantiate(templateApp.gameObject, appsCanvas.transform); + _appPanel.name = AppName; - Transform containerTransform = AppPanel.transform.Find("Container"); + Transform containerTransform = _appPanel.transform.Find("Container"); if (containerTransform != null) { GameObject container = containerTransform.gameObject; @@ -154,14 +141,14 @@ private IEnumerator InitApp() OnCreatedUI(container); } - AppCreated = true; + _appCreated = true; } - AppPanel.SetActive(true); + _appPanel.SetActive(true); - if (!IconModified) + if (!_iconModified) { - IconModified = ModifyAppIcon(IconLabel, IconFileName); + _iconModified = ModifyAppIcon(IconLabel, IconFileName); } } @@ -182,7 +169,7 @@ private void SetupExistingAppPanel(GameObject panel) } } - AppCreated = true; + _appCreated = true; } private void ClearContainer(GameObject container) @@ -206,14 +193,14 @@ private bool ModifyAppIcon(string labelText, string fileName) GameObject parent = GameObject.Find("Player_Local/CameraContainer/Camera/OverlayCamera/GameplayMenu/Phone/phone/HomeScreen/AppIcons/"); if (parent == null) { - LoggerInstance.Error("AppIcons not found."); + LoggerInstance?.Error("AppIcons not found."); return false; } - Transform lastIcon = parent.transform.childCount > 0 ? parent.transform.GetChild(parent.transform.childCount - 1) : null; + Transform? lastIcon = parent.transform.childCount > 0 ? parent.transform.GetChild(parent.transform.childCount - 1) : null; if (lastIcon == null) { - LoggerInstance.Error("No icon found to clone."); + LoggerInstance?.Error("No icon found to clone."); return false; } @@ -221,8 +208,9 @@ private bool ModifyAppIcon(string labelText, string fileName) iconObj.name = AppName; Transform labelTransform = iconObj.transform.Find("Label"); - Text label = labelTransform?.GetComponent(); - if (label != null) label.text = labelText; + Text? label = labelTransform?.GetComponent(); + if (label != null) + label.text = labelText; return ChangeAppIconImage(iconObj, fileName); } @@ -237,18 +225,14 @@ private bool ModifyAppIcon(string labelText, string fileName) private bool ChangeAppIconImage(GameObject iconObj, string filename) { Transform imageTransform = iconObj.transform.Find("Mask/Image"); - Image image = imageTransform?.GetComponent(); + Image? image = imageTransform?.GetComponent(); if (image == null) { LoggerInstance?.Error("Image component not found in icon."); return false; } -#if MONOMELON || IL2CPPMELON string path = Path.Combine(MelonEnvironment.ModsDirectory, filename); -#elif MONOBEPINEX || IL2CPPBEPINEX - string path = Path.Combine(BepInEx.Paths.PluginPath, filename); -#endif if (!File.Exists(path)) { LoggerInstance?.Error("Icon file not found: " + path); diff --git a/S1API/Player/Player.cs b/S1API/Player/Player.cs new file mode 100644 index 00000000..34f0a683 --- /dev/null +++ b/S1API/Player/Player.cs @@ -0,0 +1,10 @@ +// using UnityEngine; +// +// namespace S1API.Player +// { +// public class Player +// { +// public static Player Local => new Player(); +// public Vector3 Position = Vector3.zero; +// } +// } \ No newline at end of file diff --git a/S1API/Products/ProductDefinitionWrapper.cs b/S1API/Products/ProductDefinitionWrapper.cs index a8374c83..a6fb9eb5 100644 --- a/S1API/Products/ProductDefinitionWrapper.cs +++ b/S1API/Products/ProductDefinitionWrapper.cs @@ -7,9 +7,12 @@ namespace S1API.Products { - public static class ProductDefinitionWrapper + /// + /// INTERNAL: A wrapper class for converting a product definition to its proper dedicated class. + /// + internal static class ProductDefinitionWrapper { - public static ProductDefinition Wrap(ProductDefinition def) + internal static ProductDefinition Wrap(ProductDefinition def) { var item = def.S1ItemDefinition; if (CrossType.Is(item, out var weed)) diff --git a/S1API/Quests/QuestManager.cs b/S1API/Quests/QuestManager.cs index bf15845d..36e694f9 100644 --- a/S1API/Quests/QuestManager.cs +++ b/S1API/Quests/QuestManager.cs @@ -29,7 +29,10 @@ public static Quest CreateQuest(string? guid = null) where T : Quest => /// public static Quest CreateQuest(Type questType, string? guid = null) { - Quest quest = (Quest)Activator.CreateInstance(questType); + Quest? quest = (Quest)Activator.CreateInstance(questType)!; + if (quest == null) + throw new Exception($"Unable to create quest instance of {questType.FullName}!"); + Quests.Add(quest); return quest; } diff --git a/S1API/Quests/QuestState.cs b/S1API/Quests/QuestState.cs index 8f02c675..d907b328 100644 --- a/S1API/Quests/QuestState.cs +++ b/S1API/Quests/QuestState.cs @@ -5,11 +5,34 @@ /// public enum QuestState { + /// + /// Represents a quest / quest entry that has not been started yet. + /// Inactive, + + /// + /// Represents a quest / quest entry that has been started but not ended. + /// Active, + + /// + /// Represents a quest / quest entry that has been completed successfully by the player. + /// Completed, + + /// + /// Represents a quest / quest entry that has been failed by the played. + /// Failed, + + /// + /// Represents a quest / quest entry that has been expired. + /// Expired, + + /// + /// Represents a quest / quest entry that has been cancelled. + /// Cancelled } } \ No newline at end of file diff --git a/S1API/S1API.cs b/S1API/S1API.cs index b3c3936b..847adb45 100644 --- a/S1API/S1API.cs +++ b/S1API/S1API.cs @@ -5,6 +5,9 @@ namespace S1API { + /// + /// Not currently utilized by S1API. + /// public class S1API : MelonMod { } diff --git a/S1API/S1API.csproj b/S1API/S1API.csproj index 51a19069..223cc89b 100644 --- a/S1API/S1API.csproj +++ b/S1API/S1API.csproj @@ -7,7 +7,6 @@ - netstandard2.1 KaBooMa S1API A Schedule One Mono / Il2Cpp Cross Compatibility Layer @@ -17,6 +16,15 @@ MonoMelon;MonoBepInEx;Il2CppMelon;Il2CppBepInEx AnyCPU S1API + true + + + + netstandard2.1 + + + + net6.0 @@ -86,15 +94,15 @@ - - - - + + + + - - - - + + + + diff --git a/S1API/Saveables/SaveableField.cs b/S1API/Saveables/SaveableField.cs index ec5be204..1df462af 100644 --- a/S1API/Saveables/SaveableField.cs +++ b/S1API/Saveables/SaveableField.cs @@ -4,6 +4,8 @@ namespace S1API.Saveables { /// /// Marks a field to be saved alongside the class instance. + /// This attribute is intended to work across all custom game elements. + /// (For example, custom NPCs, quests, etc.) /// [AttributeUsage(AttributeTargets.Field)] public class SaveableField : Attribute @@ -13,6 +15,10 @@ public class SaveableField : Attribute /// internal string SaveName { get; } + /// + /// Base constructor for initializing a SaveableField. + /// + /// public SaveableField(string saveName) { SaveName = saveName; diff --git a/S1API/UI/UIFactory.cs b/S1API/UI/UIFactory.cs index f97eab43..4ae6d900 100644 --- a/S1API/UI/UIFactory.cs +++ b/S1API/UI/UIFactory.cs @@ -1,15 +1,12 @@ -#if IL2CPPMELON || IL2CPPBEPINEX -using UnityEngine; -using UnityEngine.UI; +#if IL2CPP using Il2CppInterop.Runtime.InteropTypes.Arrays; -#else -using UnityEngine; -using UnityEngine.UI; #endif using System; +using S1API.Internal.Utils; +using UnityEngine; using UnityEngine.Events; -using Object = UnityEngine.Object; +using UnityEngine.UI; namespace S1API.UI { @@ -239,33 +236,15 @@ public static void CreateRowButton(GameObject go, UnityAction clickHandler, bool /// The transform whose child objects will be destroyed. public static void ClearChildren(Transform parent) { - if (parent == null) - { - return; - } - - try - { - int count = parent.childCount; - for (int i = count - 1; i >= 0; i--) - { - var child = parent.GetChild(i); - if (child != null) - Object.Destroy(child.gameObject); - } - - } - catch (System.Exception e) - { - return; - } + foreach (Transform child in parent) + GameObject.Destroy(child.gameObject); } /// Configures a GameObject to use a VerticalLayoutGroup with specified spacing and padding. /// The GameObject to which a VerticalLayoutGroup will be added or configured. /// The spacing between child objects within the VerticalLayoutGroup. Default is 10. /// The padding around the edges of the VerticalLayoutGroup. If null, a default RectOffset of (10, 10, 10, 10) will be used. - public static void VerticalLayoutOnGO(GameObject go, int spacing = 10, RectOffset padding = null) + public static void VerticalLayoutOnGO(GameObject go, int spacing = 10, RectOffset? padding = null) { var layout = go.AddComponent(); layout.spacing = spacing; @@ -288,8 +267,8 @@ public static GameObject CreateQuestRow(string name, Transform parent, out GameO rowRT.sizeDelta = new Vector2(0f, 90f); // Let layout handle width row.AddComponent().minHeight = 50f; row.AddComponent().effectColor = new Color(0, 0, 0, 0.2f); // or Image line separator below - - + + var line = UIFactory.Panel("Separator", row.transform, new Color(1,1,1,0.05f)); line.GetComponent().sizeDelta = new Vector2(300f, 1f); @@ -338,41 +317,57 @@ public static GameObject CreateQuestRow(string name, Transform parent, out GameO /// The height of the button, if displayed. /// An optional action to be invoked when the button is clicked. If null, the button will not be created. /// The text to display on the optional button. Defaults to "Action" if not specified. + /// The size of the top bar. + /// The left position of the bar. + /// The right position of the bar. + /// The top position of the bar. + /// The bottom position of the bar. /// The created GameObject representing the top bar. - public static GameObject TopBar(string name, Transform parent, string title,float buttonWidth,float buttonHeight,float topbarSize,int rectleft,int rectright,int recttop,int rectbottom, - Action onRightButtonClick = null, - string rightButtonText = "Action") -{ - var topBar = Panel(name, parent, new Color(0.15f, 0.15f, 0.15f), - new Vector2(0f, topbarSize), new Vector2(1f, 1f)); - - var layout = topBar.AddComponent(); - layout.padding = new RectOffset(rectleft,rectright,recttop,rectbottom);; - layout.spacing = 20; - layout.childAlignment = TextAnchor.MiddleCenter; - layout.childForceExpandWidth = false; - layout.childForceExpandHeight = true; - - // Title - var titleText = Text("TopBarTitle", title, topBar.transform, 26, TextAnchor.MiddleLeft, FontStyle.Bold); - var titleLayout = titleText.gameObject.AddComponent(); - titleLayout.minWidth = 300; - titleLayout.flexibleWidth = 1; - - // Button (if any) - if (onRightButtonClick != null) - { - var (btnGO, btn, label) = ButtonWithLabel("TopBarButton", rightButtonText, topBar.transform, new Color(0.25f, 0.5f, 1f), buttonWidth, buttonHeight); - ButtonUtils.AddListener(btn, onRightButtonClick); - - var btnLayout = btnGO.AddComponent(); - btnLayout.minWidth = buttonWidth; - btnLayout.preferredHeight = buttonHeight; - btnLayout.flexibleWidth = 0; - } + public static GameObject TopBar( + string name, + Transform parent, + string title, + float buttonWidth, + float buttonHeight, + float topBarSize, + int rectLeft, + int rectRight, + int rectTop, + int rectBottom, + Action? onRightButtonClick = null, + string rightButtonText = "Action" + ) + { + var topBar = Panel(name, parent, new Color(0.15f, 0.15f, 0.15f), + new Vector2(0f, topBarSize), new Vector2(1f, 1f)); - return topBar; -} + var layout = topBar.AddComponent(); + layout.padding = new RectOffset(rectLeft,rectRight,rectTop,rectBottom);; + layout.spacing = 20; + layout.childAlignment = TextAnchor.MiddleCenter; + layout.childForceExpandWidth = false; + layout.childForceExpandHeight = true; + + // Title + var titleText = Text("TopBarTitle", title, topBar.transform, 26, TextAnchor.MiddleLeft, FontStyle.Bold); + var titleLayout = titleText.gameObject.AddComponent(); + titleLayout.minWidth = 300; + titleLayout.flexibleWidth = 1; + + if (onRightButtonClick == null) + return topBar; + + // Create the button element if we have an Action to invoke + var (btnGO, btn, label) = ButtonWithLabel("TopBarButton", rightButtonText, topBar.transform, new Color(0.25f, 0.5f, 1f), buttonWidth, buttonHeight); + ButtonUtils.AddListener(btn, onRightButtonClick); + + var btnLayout = btnGO.AddComponent(); + btnLayout.minWidth = buttonWidth; + btnLayout.preferredHeight = buttonHeight; + btnLayout.flexibleWidth = 0; + + return topBar; + } /// Binds an action to a button and updates its label text. @@ -387,35 +382,35 @@ public static void BindAcceptButton(Button btn, Text label, string text, UnityAc btn.onClick.AddListener(callback); } } -} - -/// -/// Represents a handler that encapsulates a callback action to be invoked when a click event occurs. -/// -/// -/// This class provides a mechanism to handle and execute logic when a click event is triggered. -/// It associates an action defined by a UnityAction delegate with the click event. -/// -public class ClickHandler -{ - /// - /// A private field that stores the UnityAction delegate to be invoked during a specific click event. - /// - private readonly UnityAction _callback; + /// /// Represents a handler that encapsulates a callback action to be invoked when a click event occurs. - public ClickHandler(UnityAction callback) - { - _callback = callback; - } - - /// Invokes the callback action associated with a click event. + /// /// - /// Executes the UnityAction delegate provided during the creation of the ClickHandler instance. - /// This method is used to process and handle click events associated with the handler. + /// This class provides a mechanism to handle and execute logic when a click event is triggered. + /// It associates an action defined by a UnityAction delegate with the click event. /// - public void OnClick() + public class ClickHandler { - _callback.Invoke(); + /// + /// A private field that stores the UnityAction delegate to be invoked during a specific click event. + /// + private readonly UnityAction _callback; + + /// Represents a handler that encapsulates a callback action to be invoked when a click event occurs. + public ClickHandler(UnityAction callback) + { + _callback = callback; + } + + /// Invokes the callback action associated with a click event. + /// + /// Executes the UnityAction delegate provided during the creation of the ClickHandler instance. + /// This method is used to process and handle click events associated with the handler. + /// + public void OnClick() + { + _callback.Invoke(); + } } -} +} \ No newline at end of file