Line endings: LF everywhere
.gitattributes forces LF (CRLF only for .bat/.cmd), core.autocrlf is off; files that differed only by CRLF are normalized.
This commit is contained in:
1 parent
f4dc0c0b04
commit
5f59b01a51
6 files changed
+245
-215
No files matched your search
+48
-48
@@ -1,48 +1,48 @@
|
||||
using Cthangover.Core.Settings;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Per-recruit behaviour plugin discovered via reflection from mod
|
||||
/// assemblies. Each implementation is registered into
|
||||
/// <see cref="RecruitBehaviourRegistry"/> by
|
||||
/// <see cref="Mods.ModAssemblyLoader.RegisterAssembly"/> and then
|
||||
/// invoked for <b>every</b> 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.
|
||||
/// </summary>
|
||||
public interface IRecruitBehaviour
|
||||
{
|
||||
/// <summary>Unique identifier for lookup via <c>RecruitBehaviourRegistry.Get</c>.</summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called once when a recruit is added to the party
|
||||
/// (via <c>RecruitingData.Add</c>). Use for initial stat
|
||||
/// setup, buff application, or spawning companion nodes.
|
||||
/// </summary>
|
||||
void ConfigureRecruit(Recruit recruit, RuntimeData runtime);
|
||||
|
||||
/// <summary>
|
||||
/// Called every game tick for each active recruit. The
|
||||
/// <paramref name="currentTick"/> value is the global
|
||||
/// <c>RuntimeData.Time.Tick</c> counter — use it for
|
||||
/// cooldown-based or periodic logic rather than maintaining
|
||||
/// a private timer.
|
||||
/// </summary>
|
||||
void OnTick(Recruit recruit, RuntimeData runtime, long currentTick);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a recruit is removed from the party
|
||||
/// (via <c>RecruitingData.Remove</c>). Clean up any
|
||||
/// persisted state, buffs, or companion nodes.
|
||||
/// </summary>
|
||||
void OnRemove(Recruit recruit, RuntimeData runtime);
|
||||
}
|
||||
|
||||
}
|
||||
using Cthangover.Core.Settings;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Per-recruit behaviour plugin discovered via reflection from mod
|
||||
/// assemblies. Each implementation is registered into
|
||||
/// <see cref="RecruitBehaviourRegistry"/> by
|
||||
/// <see cref="Mods.ModAssemblyLoader.RegisterAssembly"/> and then
|
||||
/// invoked for <b>every</b> 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.
|
||||
/// </summary>
|
||||
public interface IRecruitBehaviour
|
||||
{
|
||||
/// <summary>Unique identifier for lookup via <c>RecruitBehaviourRegistry.Get</c>.</summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called once when a recruit is added to the party
|
||||
/// (via <c>RecruitingData.Add</c>). Use for initial stat
|
||||
/// setup, buff application, or spawning companion nodes.
|
||||
/// </summary>
|
||||
void ConfigureRecruit(Recruit recruit, RuntimeData runtime);
|
||||
|
||||
/// <summary>
|
||||
/// Called every game tick for each active recruit. The
|
||||
/// <paramref name="currentTick"/> value is the global
|
||||
/// <c>RuntimeData.Time.Tick</c> counter — use it for
|
||||
/// cooldown-based or periodic logic rather than maintaining
|
||||
/// a private timer.
|
||||
/// </summary>
|
||||
void OnTick(Recruit recruit, RuntimeData runtime, long currentTick);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a recruit is removed from the party
|
||||
/// (via <c>RecruitingData.Remove</c>). Clean up any
|
||||
/// persisted state, buffs, or companion nodes.
|
||||
/// </summary>
|
||||
void OnRemove(Recruit recruit, RuntimeData runtime);
|
||||
}
|
||||
|
||||
}
|
||||
+33
-33
@@ -1,33 +1,33 @@
|
||||
using Cthangover.Core.Characters;
|
||||
using Cthangover.Core.Settings;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gating predicate for the recruit system. Implementations are
|
||||
/// auto-discovered from mod assemblies by
|
||||
/// <see cref="RecruitBehaviourRegistry.RegisterAssembly"/> and
|
||||
/// evaluated conjunctively — <b>all</b> conditions must return
|
||||
/// <c>true</c> for recruitment to succeed.
|
||||
///
|
||||
/// Conditions receive the full <see cref="Character"/> and
|
||||
/// <see cref="RuntimeData"/> 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.
|
||||
/// </summary>
|
||||
public interface IRecruitCondition
|
||||
{
|
||||
/// <summary>Unique identifier for debugging and override lookups.</summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if the given <paramref name="enemy"/>
|
||||
/// can be recruited under current game state. Called from
|
||||
/// <c>RecruitBehaviourRegistry.CanRecruit</c> as part of a
|
||||
/// conjunctive gate — a single <c>false</c> blocks recruitment.
|
||||
/// </summary>
|
||||
bool CanRecruit(Character enemy, RuntimeData runtime);
|
||||
}
|
||||
|
||||
}
|
||||
using Cthangover.Core.Characters;
|
||||
using Cthangover.Core.Settings;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Gating predicate for the recruit system. Implementations are
|
||||
/// auto-discovered from mod assemblies by
|
||||
/// <see cref="RecruitBehaviourRegistry.RegisterAssembly"/> and
|
||||
/// evaluated conjunctively — <b>all</b> conditions must return
|
||||
/// <c>true</c> for recruitment to succeed.
|
||||
///
|
||||
/// Conditions receive the full <see cref="Character"/> and
|
||||
/// <see cref="RuntimeData"/> 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.
|
||||
/// </summary>
|
||||
public interface IRecruitCondition
|
||||
{
|
||||
/// <summary>Unique identifier for debugging and override lookups.</summary>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if the given <paramref name="enemy"/>
|
||||
/// can be recruited under current game state. Called from
|
||||
/// <c>RecruitBehaviourRegistry.CanRecruit</c> as part of a
|
||||
/// conjunctive gate — a single <c>false</c> blocks recruitment.
|
||||
/// </summary>
|
||||
bool CanRecruit(Character enemy, RuntimeData runtime);
|
||||
}
|
||||
|
||||
}
|
||||
+35
-35
@@ -1,35 +1,35 @@
|
||||
using System;
|
||||
using Cthangover.Core.Utils;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Runtime model for a recruited party member. Stores the recruit's
|
||||
/// unique ID, the character template it was created from, and a
|
||||
/// modifiable <see cref="Utility.PropertyData"/> bag that behaviours
|
||||
/// read and mutate during tick/configure events.
|
||||
///
|
||||
/// Marked <c>[Serializable]</c> so the recruiting roster survives
|
||||
/// save/load — <c>PropertyData</c> serialises its nested values
|
||||
/// automatically. The <c>PROP_HEALTH</c> constant is the conventional
|
||||
/// key for health tracking; behaviours that need custom state
|
||||
/// (e.g. morale, loyalty timers) add their own keys to the
|
||||
/// <c>Properties</c> bag at configure time.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Recruit
|
||||
{
|
||||
/// <summary>Conventional key for the recruit's health value in the <c>Properties</c> bag.</summary>
|
||||
public const string PROP_HEALTH = "Health";
|
||||
|
||||
/// <summary>Unique instance ID (auto-generated via <c>RecruitingData.GenID</c>).</summary>
|
||||
public string ID { get; set; }
|
||||
|
||||
/// <summary>Character template ID this recruit was spawned from.</summary>
|
||||
public string CharacterID { get; set; }
|
||||
|
||||
/// <summary>Mutable property bag — behaviours read/write custom state here.</summary>
|
||||
public PropertyData Properties { get; set; } = new();
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using Cthangover.Core.Utils;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Runtime model for a recruited party member. Stores the recruit's
|
||||
/// unique ID, the character template it was created from, and a
|
||||
/// modifiable <see cref="Utility.PropertyData"/> bag that behaviours
|
||||
/// read and mutate during tick/configure events.
|
||||
///
|
||||
/// Marked <c>[Serializable]</c> so the recruiting roster survives
|
||||
/// save/load — <c>PropertyData</c> serialises its nested values
|
||||
/// automatically. The <c>PROP_HEALTH</c> constant is the conventional
|
||||
/// key for health tracking; behaviours that need custom state
|
||||
/// (e.g. morale, loyalty timers) add their own keys to the
|
||||
/// <c>Properties</c> bag at configure time.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Recruit
|
||||
{
|
||||
/// <summary>Conventional key for the recruit's health value in the <c>Properties</c> bag.</summary>
|
||||
public const string PROP_HEALTH = "Health";
|
||||
|
||||
/// <summary>Unique instance ID (auto-generated via <c>RecruitingData.GenID</c>).</summary>
|
||||
public string ID { get; set; }
|
||||
|
||||
/// <summary>Character template ID this recruit was spawned from.</summary>
|
||||
public string CharacterID { get; set; }
|
||||
|
||||
/// <summary>Mutable property bag — behaviours read/write custom state here.</summary>
|
||||
public PropertyData Properties { get; set; } = new();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +1,62 @@
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.UI.Event;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Lazy bridge between the scene timer system and the recruit
|
||||
/// behaviour tick loop. Implements <see cref="IOnTimeEvent"/>
|
||||
/// so it can be registered with <see cref="SceneEventController"/>
|
||||
/// via <c>AddTimerTickEventListener</c>.
|
||||
///
|
||||
/// Registration is lazy (<see cref="EnsureRegistered"/> 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
|
||||
/// <see cref="RecruitBehaviourRegistry"/> calls
|
||||
/// <c>EnsureRegistered</c>, which finds the scene's
|
||||
/// <c>EventController</c> node and subscribes.
|
||||
///
|
||||
/// <c>Priority = 0</c> so recruit ticks fire at a neutral point in
|
||||
/// the timer event chain — before or after other listeners as
|
||||
/// determined by their relative priorities.
|
||||
/// </summary>
|
||||
public class RecruitTickController : IOnTimeEvent
|
||||
{
|
||||
/// <summary>Neutral priority — doesn't preempt or follow any specific listener.</summary>
|
||||
public int Priority => 0;
|
||||
|
||||
private bool _registered;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the scene's <c>EventController</c> node and subscribes
|
||||
/// this controller as a timer-tick listener. Idempotent —
|
||||
/// subsequent calls do nothing.
|
||||
/// </summary>
|
||||
public void EnsureRegistered()
|
||||
{
|
||||
if (_registered)
|
||||
return;
|
||||
var eventController = SceneContextNode.FindNode<SceneEventController>("EventController");
|
||||
if (eventController == null)
|
||||
return;
|
||||
eventController.AddTimerTickEventListener(this);
|
||||
_registered = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="SceneEventController"/> on every
|
||||
/// timer tick. Delegates to
|
||||
/// <see cref="RecruitBehaviourRegistry.OnTick"/>.
|
||||
/// Ticks also fire during the launcher boot window, so the registry
|
||||
/// side must not touch <c>GameData.Instance.Runtime</c> or mod data
|
||||
/// until <c>Boot.ModsReady</c> (see the boot-window contract on
|
||||
/// <c>IOnTimeEvent</c>; core-side reference: TimeTickController).
|
||||
/// </summary>
|
||||
public void OnTimerTick()
|
||||
{
|
||||
RecruitBehaviourRegistry.Instance.OnTick();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.UI.Event;
|
||||
|
||||
namespace Cthangover.Core.Relationship
|
||||
{
|
||||
/// <summary>
|
||||
/// Lazy bridge between the scene timer system and the recruit
|
||||
/// behaviour tick loop. Implements <see cref="IOnTimeEvent"/>
|
||||
/// so it can be registered with <see cref="SceneEventController"/>
|
||||
/// via <c>AddTimerTickEventListener</c>.
|
||||
///
|
||||
/// Registration is lazy (<see cref="EnsureRegistered"/> 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
|
||||
/// <see cref="RecruitBehaviourRegistry"/> calls
|
||||
/// <c>EnsureRegistered</c>, which finds the scene's
|
||||
/// <c>EventController</c> node and subscribes.
|
||||
///
|
||||
/// <c>Priority = 0</c> so recruit ticks fire at a neutral point in
|
||||
/// the timer event chain — before or after other listeners as
|
||||
/// determined by their relative priorities.
|
||||
/// </summary>
|
||||
public class RecruitTickController : IOnTimeEvent
|
||||
{
|
||||
/// <summary>Neutral priority — doesn't preempt or follow any specific listener.</summary>
|
||||
public int Priority => 0;
|
||||
|
||||
private bool _registered;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the scene's <c>EventController</c> node and subscribes
|
||||
/// this controller as a timer-tick listener. Idempotent —
|
||||
/// subsequent calls do nothing.
|
||||
/// </summary>
|
||||
public void EnsureRegistered()
|
||||
{
|
||||
if (_registered)
|
||||
return;
|
||||
var eventController = SceneContextNode.FindNode<SceneEventController>("EventController");
|
||||
if (eventController == null)
|
||||
return;
|
||||
eventController.AddTimerTickEventListener(this);
|
||||
_registered = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="SceneEventController"/> on every
|
||||
/// timer tick. Delegates to
|
||||
/// <see cref="RecruitBehaviourRegistry.OnTick"/>.
|
||||
/// Ticks also fire during the launcher boot window, so the registry
|
||||
/// side must not touch <c>GameData.Instance.Runtime</c> or mod data
|
||||
/// until <c>Boot.ModsReady</c> (see the boot-window contract on
|
||||
/// <c>IOnTimeEvent</c>; core-side reference: TimeTickController).
|
||||
/// </summary>
|
||||
public void OnTimerTick()
|
||||
{
|
||||
RecruitBehaviourRegistry.Instance.OnTick();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user