diff --git a/S1API/Dialogues/DialogueChoiceListener.cs b/S1API/Dialogues/DialogueChoiceListener.cs
new file mode 100644
index 00000000..4e46c679
--- /dev/null
+++ b/S1API/Dialogues/DialogueChoiceListener.cs
@@ -0,0 +1,67 @@
+using System;
+using UnityEngine.Events;
+#if IL2CPPBEPINEX || IL2CPPMELON
+using Il2CppScheduleOne.Dialogue;
+#elif MONOBEPINEX || MONOMELON
+using ScheduleOne.Dialogue;
+#endif
+
+namespace S1API.Dialogues
+{
+ ///
+ /// A static utility class that listens for and responds to specific dialogue choices in the game's dialogue system.
+ ///
+ public static class DialogueChoiceListener
+ {
+ ///
+ /// Stores the label of the expected dialogue choice that, when selected,
+ /// triggers the associated callback action in the dialogue system.
+ ///
+ ///
+ /// This variable is utilized internally by the DialogueChoiceListener class
+ /// to match the label of the choice selected by the user. When the label matches
+ /// expectedChoiceLabel, the registered callback is executed.
+ ///
+ private static string expectedChoiceLabel;
+
+ ///
+ /// Represents a delegate invoked when a specific dialogue choice is selected during interaction.
+ ///
+ private static Action callback;
+
+ /// Registers a specific dialogue choice with a callback to be invoked when the choice is selected.
+ /// The reference to the DialogueHandler that manages dialogue choices.
+ /// The label identifying the specific dialogue choice to be registered.
+ /// The callback action to execute when the dialogue choice is selected.
+ public static void Register(DialogueHandler handlerRef, string label, Action action)
+ {
+ expectedChoiceLabel = label;
+ callback = action;
+
+ if (handlerRef != null)
+ {
+ void ForwardCall() => OnChoice();
+
+ // ✅ IL2CPP-safe: explicit method binding via wrapper
+ handlerRef.onDialogueChoiceChosen.AddListener((UnityAction)delegate (string choice)
+ {
+ if (choice == expectedChoiceLabel)
+ ((UnityAction)ForwardCall).Invoke();
+ });
+ }
+ }
+
+ ///
+ /// Executes the registered callback when the expected dialogue choice is selected.
+ ///
+ ///
+ /// This method is invoked internally and should not be called directly.
+ /// It ensures that the provided callback is executed only when the expected dialogue choice matches.
+ ///
+ private static void OnChoice()
+ {
+ callback?.Invoke();
+ callback = null; // optional: remove if one-time use
+ }
+ }
+}
\ No newline at end of file
diff --git a/S1API/Dialogues/DialogueInjection.cs b/S1API/Dialogues/DialogueInjection.cs
new file mode 100644
index 00000000..40208322
--- /dev/null
+++ b/S1API/Dialogues/DialogueInjection.cs
@@ -0,0 +1,75 @@
+using System;
+
+///
+/// Represents a dialogue injection configuration for adding custom dialogues into an NPC's conversation flow dynamically.
+///
+public class DialogueInjection
+{
+ ///
+ /// Represents the name of the NPC (Non-Player Character) to which the dialogue injection is associated.
+ /// This value is expected to match or partially match the name of an NPC in the game, allowing the system
+ /// to identify and target the specific NPC for dialogue modifications.
+ ///
+ public string NpcName;
+
+ ///
+ /// Represents the name of the dialogue container being referenced for injections or modifications
+ /// within the NPC's dialogue system.
+ ///
+ ///
+ /// This variable is used for identifying a specific dialogue container when attempting to
+ /// inject new dialogue nodes, choices, or links into an NPC's dialogue setup.
+ ///
+ public string ContainerName;
+
+ ///
+ /// Represents the unique identifier (GUID) of the starting dialogue node within a dialogue container.
+ ///
+ ///
+ /// This variable is used to identify the specific dialogue node from which a new choice or interaction is injected.
+ ///
+ public string FromNodeGuid;
+
+ ///
+ /// Represents the unique identifier (GUID) for the target dialogue node to which a choice or link is pointing in a dialogue system.
+ ///
+ public string ToNodeGuid;
+
+ ///
+ /// Represents a descriptive label for a dialogue choice used in the dialogue system.
+ ///
+ ///
+ /// This label is utilized for identifying a specific dialogue choice during execution
+ /// and for associating a callback or specific functionality when that choice is selected.
+ ///
+ public string ChoiceLabel;
+
+ ///
+ /// Represents the text displayed for a dialogue choice in the game's dialogue system.
+ ///
+ ///
+ /// The property is utilized to define the text that appears visually for a specific dialogue choice
+ /// in conjunction with the dialogue system. The text is injected dynamically during runtime for scenarios
+ /// requiring additional or modified dialogue options.
+ ///
+ public string ChoiceText;
+
+ ///
+ /// Represents a callback action that is invoked when a dialogue choice is confirmed.
+ ///
+ public Action OnConfirmed;
+
+ ///
+ /// Represents an injectable dialogue configuration that can be used to add or modify dialogue interactions in a game.
+ ///
+ public DialogueInjection(string npc, string container, string from, string to, string label, string text, Action onConfirmed)
+ {
+ NpcName = npc;
+ ContainerName = container;
+ FromNodeGuid = from;
+ ToNodeGuid = to;
+ ChoiceLabel = label;
+ ChoiceText = text;
+ OnConfirmed = onConfirmed;
+ }
+}
\ No newline at end of file
diff --git a/S1API/Dialogues/DialogueInjector.cs b/S1API/Dialogues/DialogueInjector.cs
new file mode 100644
index 00000000..85b8aee2
--- /dev/null
+++ b/S1API/Dialogues/DialogueInjector.cs
@@ -0,0 +1,163 @@
+using System.Collections.Generic;
+
+using UnityEngine;
+using MelonLoader;
+using S1API.Dialogues;
+#if IL2CPPMELON || IL2CPPBEPINEX
+using Il2CppScheduleOne.Dialogue;
+using Il2CppScheduleOne.NPCs;
+using Il2CppScheduleOne.NPCs.Schedules;
+#else
+using ScheduleOne.Dialogue;
+using ScheduleOne.NPCs;
+using ScheduleOne.NPCs.Schedules;
+#endif
+///
+/// The DialogueInjector class is a static utility that facilitates the injection of custom dialogue entries
+/// into a game's dialogue system at runtime. It provides methods for registering custom dialogue injections
+/// and ensures that these injections are processed correctly within the update loop.
+///
+public static class DialogueInjector
+{
+ ///
+ /// Represents a collection of dialogue injections waiting to be processed for corresponding NPCs in the game.
+ /// This variable stores pending dialogue link or choice modifications that need to be applied to NPC dialogue systems
+ /// and is used during a coroutine process to find the relevant NPC and complete the injection.
+ ///
+ private static List pendingInjections = new List();
+
+ ///
+ /// A boolean variable that indicates whether the update loop for injecting dialogue is currently hooked.
+ /// When true, the update loop has been hooked and is actively monitoring for pending dialogue injections; otherwise, it has not been hooked.
+ ///
+ private static bool isHooked = false;
+
+ ///
+ /// Registers a dialogue injection to be processed in the update loop.
+ ///
+ /// An instance of representing the dialogue to be injected into the game.
+ public static void Register(DialogueInjection injection)
+ {
+ pendingInjections.Add(injection);
+ HookUpdateLoop();
+ }
+
+ ///
+ /// Ensures that the dialogue injection system's loop is hooked into the game's update cycle.
+ /// This method starts a coroutine to monitor and inject pending dialogue changes into NPCs.
+ ///
+ ///
+ /// This method prevents multiple hookups by checking if the injection system is already active using an internal flag.
+ /// If not already hooked, the method initializes a coroutine that processes and injects queued dialogue data into the corresponding NPCs.
+ ///
+ private static void HookUpdateLoop()
+ {
+ if (isHooked) return;
+ isHooked = true;
+
+ MelonCoroutines.Start(WaitForNPCsAndInject());
+ }
+
+ ///
+ /// Monitors the current state of NPCs within the game world and manages the injection of dialogue
+ /// into the appropriate NPCs once they are found. This method waits for instances of NPC objects
+ /// that match the specified criteria in the pending dialogue injections and processes these injections
+ /// once a match is located. The method continues execution until all pending dialogue injections
+ /// have been completed.
+ ///
+ ///
+ /// An enumerator that handles the coroutine execution for periodic checks and dialogue injection processing.
+ ///
+ private static System.Collections.IEnumerator WaitForNPCsAndInject()
+ {
+ while (pendingInjections.Count > 0)
+ {
+ for (int i = pendingInjections.Count - 1; i >= 0; i--)
+ {
+ var injection = pendingInjections[i];
+ var npcs = GameObject.FindObjectsOfType();
+ NPC target = null;
+
+ for (int j = 0; j < npcs.Length; j++)
+ {
+ if (npcs[j] != null && npcs[j].name.Contains(injection.NpcName))
+ {
+ target = npcs[j];
+ break;
+ }
+ }
+
+ if (target != null)
+ {
+ TryInject(injection, target);
+ pendingInjections.RemoveAt(i);
+ }
+ }
+
+ yield return null; // Wait one frame
+ }
+ }
+
+ ///
+ /// Attempts to inject a dialogue choice and link into the specified NPC's dialogue system.
+ ///
+ /// The dialogue injection object containing the data for the choice to inject.
+ /// The NPC that will have the dialogue choice injected.
+ private static void TryInject(DialogueInjection injection, NPC npc)
+ {
+ var handler = npc.GetComponent();
+ var dialogueEvent = npc.GetComponentInChildren(true);
+ if (dialogueEvent == null || dialogueEvent.DialogueOverride == null) return;
+
+ if (dialogueEvent.DialogueOverride.name != injection.ContainerName) return;
+
+ var container = dialogueEvent.DialogueOverride;
+ if (container.DialogueNodeData == null) return;
+
+ DialogueNodeData node = null;
+ for (int i = 0; i < container.DialogueNodeData.Count; i++)
+ {
+ var n = container.DialogueNodeData[i];
+ if (n != null && n.Guid == injection.FromNodeGuid)
+ {
+ node = n;
+ break;
+ }
+ }
+
+ if (node == null) return;
+
+ var choice = new DialogueChoiceData
+ {
+ Guid = System.Guid.NewGuid().ToString(),
+ ChoiceLabel = injection.ChoiceLabel,
+ ChoiceText = injection.ChoiceText
+ };
+
+ var choiceList = new List();
+ if (node.choices != null)
+ choiceList.AddRange(node.choices);
+
+ choiceList.Add(choice);
+ node.choices = choiceList.ToArray();
+
+ var link = new NodeLinkData
+ {
+ BaseDialogueOrBranchNodeGuid = injection.FromNodeGuid,
+ BaseChoiceOrOptionGUID = choice.Guid,
+ TargetNodeGuid = injection.ToNodeGuid
+ };
+
+ if (container.NodeLinks == null)
+ #if IL2CPPMELON || IL2CPPBEPINEX
+ container.NodeLinks = new Il2CppSystem.Collections.Generic.List();
+#else
+ container.NodeLinks = new List();
+#endif
+ container.NodeLinks.Add(link);
+
+ DialogueChoiceListener.Register(handler, injection.ChoiceLabel, injection.OnConfirmed);
+
+ MelonLogger.Msg($"[DialogueInjector] Injected '{injection.ChoiceLabel}' into NPC '{npc.name}'");
+ }
+}
\ No newline at end of file
diff --git a/S1API/Property/BaseProperty.cs b/S1API/Property/BaseProperty.cs
new file mode 100644
index 00000000..8a1075f3
--- /dev/null
+++ b/S1API/Property/BaseProperty.cs
@@ -0,0 +1,69 @@
+namespace S1API.Property
+{
+ ///
+ /// Represents an abstract base class for properties in the system.
+ ///
+ public abstract class BaseProperty
+ {
+ ///
+ /// Gets the name of the property.
+ ///
+ ///
+ /// This property represents the name or title of the property entity.
+ /// It retrieves the value associated with the property from the underlying system or data structure.
+ ///
+ public abstract string PropertyName { get; }
+
+ ///
+ /// Gets the unique code that identifies the property.
+ ///
+ ///
+ /// This code is typically used to differentiate between various properties
+ /// within the system. It is unique to each property and can be leveraged
+ /// in operations like identification, filtering, or querying.
+ ///
+ public abstract string PropertyCode { get; }
+
+ ///
+ /// Represents the cost or monetary value associated with a property.
+ ///
+ ///
+ /// The Price property is a floating-point value that indicates the price for the property.
+ /// It provides a read-only mechanism to access this value.
+ /// This value is essential in determining the economic aspect of the property.
+ ///
+ ///
+ /// A float representing the monetary price of the property.
+ ///
+ public abstract float Price { get; }
+
+ /// Indicates whether the property is currently owned or not.
+ /// This property is read-only and reflects the ownership status
+ /// of the property.
+ public abstract bool IsOwned { get; }
+
+ ///
+ /// Gets or sets the maximum number of employees that can be assigned to the property.
+ ///
+ ///
+ /// This property represents the capacity for employees within a given property.
+ /// Modifying this value impacts the operations and resource management of the property.
+ /// Suitable for scenarios where resource allocation and workforce planning are essential.
+ ///
+ public abstract int EmployeeCapacity { get; set; }
+
+ ///
+ /// Marks the property as owned. This method updates the ownership status
+ /// of the property by interacting with the underlying property implementation.
+ /// Typically used to signify that the property has been acquired or purchased.
+ ///
+ public abstract void SetOwned();
+
+ ///
+ /// Determines whether a specified point lies within the boundary of the property.
+ ///
+ /// The point to check, specified as a Vector3 coordinate.
+ /// true if the point is within the property's boundary; otherwise, false.
+ public abstract bool IsPointInside(UnityEngine.Vector3 point);
+ }
+}
\ No newline at end of file
diff --git a/S1API/Property/PropertyManager.cs b/S1API/Property/PropertyManager.cs
new file mode 100644
index 00000000..48bcb166
--- /dev/null
+++ b/S1API/Property/PropertyManager.cs
@@ -0,0 +1,73 @@
+using System.Collections.Generic;
+#if IL2CPPMELON || IL2CPPBEPINEX
+using Il2CppScheduleOne.Property;
+#elif MONOMELON || MONOBEPINEX
+using ScheduleOne.Property;
+#endif
+namespace S1API.Property
+{
+ ///
+ /// Provides methods for managing and retrieving property data within the application.
+ ///
+ public static class PropertyManager
+ {
+ ///
+ /// Retrieves a list of all properties available.
+ ///
+ /// A list of objects representing all available properties.
+ public static List GetAllProperties()
+ {
+ var list = new List();
+ #if IL2CPPMELON || IL2CPPBEPINEX
+ foreach (var prop in Il2CppScheduleOne.Property.Property.Properties)
+#else
+ foreach (var prop in ScheduleOne.Property.Property.Properties)
+ #endif
+ {
+ list.Add(new PropertyWrapper(prop));
+ }
+ return list;
+ }
+
+ /// Retrieves a list of all properties that are currently owned.
+ ///
+ /// A list of PropertyWrapper objects representing the owned properties.
+ ///
+ public static List GetOwnedProperties()
+ {
+ var list = new List();
+#if IL2CPPMELON || IL2CPPBEPINEX
+ foreach (var prop in Il2CppScheduleOne.Property.Property.OwnedProperties)
+#elif MONOMELON || MONOBEPINEX
+ foreach (var prop in ScheduleOne.Property.Property.OwnedProperties)
+#endif
+ {
+ list.Add(new PropertyWrapper(prop));
+ }
+ return list;
+ }
+
+ ///
+ /// Finds a property with the given name from the list of available properties.
+ ///
+ /// The name of the property to search for.
+ ///
+ /// A representing the property with the specified name if found; otherwise, null.
+ ///
+ public static PropertyWrapper FindPropertyByName(string name)
+ {
+#if IL2CPPMELON || IL2CPPBEPINEX
+ foreach (var prop in Il2CppScheduleOne.Property.Property.Properties)
+#elif MONOMELON || MONOBEPINEX
+ foreach (var prop in ScheduleOne.Property.Property.Properties)
+#endif
+ {
+ if (prop.PropertyName == name)
+ {
+ return new PropertyWrapper(prop);
+ }
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/S1API/Property/PropertyWrapper.cs b/S1API/Property/PropertyWrapper.cs
new file mode 100644
index 00000000..fa4d180f
--- /dev/null
+++ b/S1API/Property/PropertyWrapper.cs
@@ -0,0 +1,104 @@
+using UnityEngine;
+
+namespace S1API.Property
+{
+ ///
+ /// Represents a wrapper class for handling properties derived from the
+ /// Il2CppScheduleOne.Property.Property class. Provides an abstraction for
+ /// interacting with property details and operations in Unity.
+ ///
+ public class PropertyWrapper : BaseProperty
+ {
+ ///
+ /// A readonly backing field encapsulating the core property instance
+ /// used within the PropertyWrapper class. This field provides access
+ /// to the underlying implementation of the property functionalities
+ /// and is leveraged across multiple overriden members to delegate
+ /// operations to the actual property instance.
+ ///
+ #if IL2CPPBEPINEX || IL2CPPMELON
+ internal readonly Il2CppScheduleOne.Property.Property InnerProperty;
+ #else
+ internal readonly ScheduleOne.Property.Property InnerProperty;
+ #endif
+ ///
+ /// A wrapper class that extends the functionality of
+ /// and acts as a bridge to interact with an inner property implementation
+ /// from the Il2CppScheduleOne.Property namespace.
+ ///
+#if IL2CPPBEPINEX || IL2CPPMELON
+ public PropertyWrapper(Il2CppScheduleOne.Property.Property property)
+
+ #else
+ public PropertyWrapper(ScheduleOne.Property.Property property)
+#endif
+ {
+ InnerProperty = property;
+ }
+
+ ///
+ /// Gets the name of the property.
+ /// Represents the underlying property name as defined by its implementation.
+ ///
+ public override string PropertyName => InnerProperty.PropertyName;
+
+ ///
+ /// Gets the unique code representing this property. This code serves as an identifier
+ /// for distinguishing the property in the system and is typically defined in the internal
+ /// implementation of the property.
+ ///
+ public override string PropertyCode => InnerProperty.PropertyCode;
+
+ ///
+ /// Gets the price of the property.
+ ///
+ ///
+ /// The price represents a floating-point value that denotes the monetary
+ /// value or cost associated with the property. This property is read-only
+ /// and retrieves the value from the underlying property implementation.
+ ///
+ public override float Price => InnerProperty.Price;
+
+ ///
+ /// Gets a value indicating whether the property is currently owned.
+ ///
+ ///
+ /// This property reflects the ownership status of the property. Returns true if the property
+ /// is owned and false otherwise. The ownership status is based on the internal state of the
+ /// wrapped property implementation.
+ ///
+ public override bool IsOwned => InnerProperty.IsOwned;
+
+ ///
+ /// Represents the maximum number of employees that can be allocated to the property.
+ /// This property is both readable and writable, allowing for dynamic configuration
+ /// of employee capacity based on the property's current requirements or constraints.
+ ///
+ public override int EmployeeCapacity
+ {
+ get => InnerProperty.EmployeeCapacity;
+ set => InnerProperty.EmployeeCapacity = value;
+ }
+
+ ///
+ /// Marks the property as owned within the PropertyWrapper implementation.
+ /// Updates the ownership status by delegating the operation to the underlying
+ /// Il2CppScheduleOne.Property.Property instance.
+ /// This is typically used to signify that the property has been acquired or purchased.
+ ///
+ public override void SetOwned()
+ {
+ InnerProperty.SetOwned();
+ }
+
+ ///
+ /// Determines whether a specified point lies within the boundary of the property.
+ ///
+ /// The point to check, specified as a Vector3 coordinate.
+ /// true if the point is within the property's boundary; otherwise, false.
+ public override bool IsPointInside(Vector3 point)
+ {
+ return InnerProperty.DoBoundsContainPoint(point);
+ }
+ }
+}
\ No newline at end of file