diff --git a/.gitignore b/.gitignore index c301ca8..bb88804 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,37 @@ -# Godot 4.x -.godot/ -.idea/ -sdk/ -bin/ -obj/ - -#ai -.omo/ -.opencode/ - -gen/ -obj/ -bin/ - -*.tres~ -*.tscn~ - -# GDScript LSP -.godot/ - -# Export -*.exe -*.dmg -*.apk -*.aab -*.pck -*.zip -*.log - -# OS -.DS_Store -Thumbs.db - -# Editor -*.import -*.godot.uid +# Godot 4.x +.godot/ +.idea/ +sdk/ +bin/ +obj/ + +#ai +.omo/ +.opencode/ + +gen/ +obj/ +bin/ + +*.tres~ +*.tscn~ + +# GDScript LSP +.godot/ + +# Export +*.exe +*.dmg +*.apk +*.aab +*.pck +*.zip +*.log + +# OS +.DS_Store +Thumbs.db + +# Editor +*.import +*.godot.uid diff --git a/src/IRecruitBehaviour.cs b/src/IRecruitBehaviour.cs index 12e89b3..101cf97 100644 --- a/src/IRecruitBehaviour.cs +++ b/src/IRecruitBehaviour.cs @@ -1,48 +1,48 @@ -using Cthangover.Core.Settings; - -namespace Cthangover.Core.Relationship -{ - /// - /// Per-recruit behaviour plugin discovered via reflection from mod - /// assemblies. Each implementation is registered into - /// by - /// and then - /// invoked for every active recruit — not just those from the - /// owning mod — during tick, configure, and removal lifecycle events. - /// - /// This cross-recruit dispatch pattern is intentional: a behaviour - /// might want to introspect all recruits (e.g. a "rivalry" system - /// that checks for conflicting personalities), so the registry passes - /// the full recruit list to every behaviour rather than filtering by - /// ownership. - /// - public interface IRecruitBehaviour - { - /// Unique identifier for lookup via RecruitBehaviourRegistry.Get. - string Id { get; } - - /// - /// Called once when a recruit is added to the party - /// (via RecruitingData.Add). Use for initial stat - /// setup, buff application, or spawning companion nodes. - /// - void ConfigureRecruit(Recruit recruit, RuntimeData runtime); - - /// - /// Called every game tick for each active recruit. The - /// value is the global - /// RuntimeData.Time.Tick counter — use it for - /// cooldown-based or periodic logic rather than maintaining - /// a private timer. - /// - void OnTick(Recruit recruit, RuntimeData runtime, long currentTick); - - /// - /// Called when a recruit is removed from the party - /// (via RecruitingData.Remove). Clean up any - /// persisted state, buffs, or companion nodes. - /// - void OnRemove(Recruit recruit, RuntimeData runtime); - } - -} +using Cthangover.Core.Settings; + +namespace Cthangover.Core.Relationship +{ + /// + /// Per-recruit behaviour plugin discovered via reflection from mod + /// assemblies. Each implementation is registered into + /// by + /// and then + /// invoked for every active recruit — not just those from the + /// owning mod — during tick, configure, and removal lifecycle events. + /// + /// This cross-recruit dispatch pattern is intentional: a behaviour + /// might want to introspect all recruits (e.g. a "rivalry" system + /// that checks for conflicting personalities), so the registry passes + /// the full recruit list to every behaviour rather than filtering by + /// ownership. + /// + public interface IRecruitBehaviour + { + /// Unique identifier for lookup via RecruitBehaviourRegistry.Get. + string Id { get; } + + /// + /// Called once when a recruit is added to the party + /// (via RecruitingData.Add). Use for initial stat + /// setup, buff application, or spawning companion nodes. + /// + void ConfigureRecruit(Recruit recruit, RuntimeData runtime); + + /// + /// Called every game tick for each active recruit. The + /// value is the global + /// RuntimeData.Time.Tick counter — use it for + /// cooldown-based or periodic logic rather than maintaining + /// a private timer. + /// + void OnTick(Recruit recruit, RuntimeData runtime, long currentTick); + + /// + /// Called when a recruit is removed from the party + /// (via RecruitingData.Remove). Clean up any + /// persisted state, buffs, or companion nodes. + /// + void OnRemove(Recruit recruit, RuntimeData runtime); + } + +} diff --git a/src/IRecruitCondition.cs b/src/IRecruitCondition.cs index 6c8619b..ee6ff99 100644 --- a/src/IRecruitCondition.cs +++ b/src/IRecruitCondition.cs @@ -1,33 +1,33 @@ -using Cthangover.Core.Characters; -using Cthangover.Core.Settings; - -namespace Cthangover.Core.Relationship -{ - /// - /// Gating predicate for the recruit system. Implementations are - /// auto-discovered from mod assemblies by - /// and - /// evaluated conjunctively — all conditions must return - /// true for recruitment to succeed. - /// - /// Conditions receive the full and - /// so they can inspect character stats, - /// inventory, relationship flags, quest state, or any other - /// runtime-accessible data when deciding whether a given enemy is - /// recruitable. - /// - public interface IRecruitCondition - { - /// Unique identifier for debugging and override lookups. - string Id { get; } - - /// - /// Returns true if the given - /// can be recruited under current game state. Called from - /// RecruitBehaviourRegistry.CanRecruit as part of a - /// conjunctive gate — a single false blocks recruitment. - /// - bool CanRecruit(Character enemy, RuntimeData runtime); - } - -} +using Cthangover.Core.Characters; +using Cthangover.Core.Settings; + +namespace Cthangover.Core.Relationship +{ + /// + /// Gating predicate for the recruit system. Implementations are + /// auto-discovered from mod assemblies by + /// and + /// evaluated conjunctively — all conditions must return + /// true for recruitment to succeed. + /// + /// Conditions receive the full and + /// so they can inspect character stats, + /// inventory, relationship flags, quest state, or any other + /// runtime-accessible data when deciding whether a given enemy is + /// recruitable. + /// + public interface IRecruitCondition + { + /// Unique identifier for debugging and override lookups. + string Id { get; } + + /// + /// Returns true if the given + /// can be recruited under current game state. Called from + /// RecruitBehaviourRegistry.CanRecruit as part of a + /// conjunctive gate — a single false blocks recruitment. + /// + bool CanRecruit(Character enemy, RuntimeData runtime); + } + +} diff --git a/src/Recruit.cs b/src/Recruit.cs index ffea572..72a86b0 100644 --- a/src/Recruit.cs +++ b/src/Recruit.cs @@ -1,35 +1,35 @@ -using System; -using Cthangover.Core.Utils; - -namespace Cthangover.Core.Relationship -{ - /// - /// Runtime model for a recruited party member. Stores the recruit's - /// unique ID, the character template it was created from, and a - /// modifiable bag that behaviours - /// read and mutate during tick/configure events. - /// - /// Marked [Serializable] so the recruiting roster survives - /// save/load — PropertyData serialises its nested values - /// automatically. The PROP_HEALTH constant is the conventional - /// key for health tracking; behaviours that need custom state - /// (e.g. morale, loyalty timers) add their own keys to the - /// Properties bag at configure time. - /// - [Serializable] - public class Recruit - { - /// Conventional key for the recruit's health value in the Properties bag. - public const string PROP_HEALTH = "Health"; - - /// Unique instance ID (auto-generated via RecruitingData.GenID). - public string ID { get; set; } - - /// Character template ID this recruit was spawned from. - public string CharacterID { get; set; } - - /// Mutable property bag — behaviours read/write custom state here. - public PropertyData Properties { get; set; } = new(); - } - -} +using System; +using Cthangover.Core.Utils; + +namespace Cthangover.Core.Relationship +{ + /// + /// Runtime model for a recruited party member. Stores the recruit's + /// unique ID, the character template it was created from, and a + /// modifiable bag that behaviours + /// read and mutate during tick/configure events. + /// + /// Marked [Serializable] so the recruiting roster survives + /// save/load — PropertyData serialises its nested values + /// automatically. The PROP_HEALTH constant is the conventional + /// key for health tracking; behaviours that need custom state + /// (e.g. morale, loyalty timers) add their own keys to the + /// Properties bag at configure time. + /// + [Serializable] + public class Recruit + { + /// Conventional key for the recruit's health value in the Properties bag. + public const string PROP_HEALTH = "Health"; + + /// Unique instance ID (auto-generated via RecruitingData.GenID). + public string ID { get; set; } + + /// Character template ID this recruit was spawned from. + public string CharacterID { get; set; } + + /// Mutable property bag — behaviours read/write custom state here. + public PropertyData Properties { get; set; } = new(); + } + +} diff --git a/src/RecruitTickController.cs b/src/RecruitTickController.cs index 022e484..107c096 100644 --- a/src/RecruitTickController.cs +++ b/src/RecruitTickController.cs @@ -1,62 +1,62 @@ -using Cthangover.Core.Scenes; -using Cthangover.Core.UI.Event; - -namespace Cthangover.Core.Relationship -{ - /// - /// Lazy bridge between the scene timer system and the recruit - /// behaviour tick loop. Implements - /// so it can be registered with - /// via AddTimerTickEventListener. - /// - /// Registration is lazy ( is a no-op - /// after the first call) because the recruit system should not - /// force the timer subsystem to activate if no behaviours are - /// actually loaded. The first behaviour lifecycle method in - /// calls - /// EnsureRegistered, which finds the scene's - /// EventController node and subscribes. - /// - /// Priority = 0 so recruit ticks fire at a neutral point in - /// the timer event chain — before or after other listeners as - /// determined by their relative priorities. - /// - public class RecruitTickController : IOnTimeEvent - { - /// Neutral priority — doesn't preempt or follow any specific listener. - public int Priority => 0; - - private bool _registered; - - /// - /// Finds the scene's EventController node and subscribes - /// this controller as a timer-tick listener. Idempotent — - /// subsequent calls do nothing. - /// - public void EnsureRegistered() - { - if (_registered) - return; - var eventController = SceneContextNode.FindNode("EventController"); - if (eventController == null) - return; - eventController.AddTimerTickEventListener(this); - _registered = true; - } - - /// - /// Called by on every - /// timer tick. Delegates to - /// . - /// Ticks also fire during the launcher boot window, so the registry - /// side must not touch GameData.Instance.Runtime or mod data - /// until Boot.ModsReady (see the boot-window contract on - /// IOnTimeEvent; core-side reference: TimeTickController). - /// - public void OnTimerTick() - { - RecruitBehaviourRegistry.Instance.OnTick(); - } - } - -} +using Cthangover.Core.Scenes; +using Cthangover.Core.UI.Event; + +namespace Cthangover.Core.Relationship +{ + /// + /// Lazy bridge between the scene timer system and the recruit + /// behaviour tick loop. Implements + /// so it can be registered with + /// via AddTimerTickEventListener. + /// + /// Registration is lazy ( is a no-op + /// after the first call) because the recruit system should not + /// force the timer subsystem to activate if no behaviours are + /// actually loaded. The first behaviour lifecycle method in + /// calls + /// EnsureRegistered, which finds the scene's + /// EventController node and subscribes. + /// + /// Priority = 0 so recruit ticks fire at a neutral point in + /// the timer event chain — before or after other listeners as + /// determined by their relative priorities. + /// + public class RecruitTickController : IOnTimeEvent + { + /// Neutral priority — doesn't preempt or follow any specific listener. + public int Priority => 0; + + private bool _registered; + + /// + /// Finds the scene's EventController node and subscribes + /// this controller as a timer-tick listener. Idempotent — + /// subsequent calls do nothing. + /// + public void EnsureRegistered() + { + if (_registered) + return; + var eventController = SceneContextNode.FindNode("EventController"); + if (eventController == null) + return; + eventController.AddTimerTickEventListener(this); + _registered = true; + } + + /// + /// Called by on every + /// timer tick. Delegates to + /// . + /// Ticks also fire during the launcher boot window, so the registry + /// side must not touch GameData.Instance.Runtime or mod data + /// until Boot.ModsReady (see the boot-window contract on + /// IOnTimeEvent; core-side reference: TimeTickController). + /// + public void OnTimerTick() + { + RecruitBehaviourRegistry.Instance.OnTick(); + } + } + +}