commit c564d2e0590ce9cacaf5d9eacc280a498ab56a67 Author: iisaev Date: Sun Oct 18 12:41:37 2026 +0300 init mod diff --git a/locale/en.properties b/locale/en.properties new file mode 100644 index 0000000..d7cbd6b --- /dev/null +++ b/locale/en.properties @@ -0,0 +1,2 @@ +mod_starter_party_name = Starter Party +mod_starter_party_desc = Seeds the default starter party (Marao) and the slave_master skill after mod resources are ready, and restores it on NewGameStartedEvent. Split out of visual_novel_core so the base content mod stays pure content. diff --git a/locale/ru.properties b/locale/ru.properties new file mode 100644 index 0000000..3ed81ba --- /dev/null +++ b/locale/ru.properties @@ -0,0 +1,2 @@ +mod_starter_party_name = Стартовая партия +mod_starter_party_desc = Выдаёт стартовую партию (Марао) и умение slave_master после готовности ресурсов модов и восстанавливает её на событии новой игры. Вынесено из visual_novel_core, чтобы базовый контент-мод оставался чистым контентом. diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..60b17a9 --- /dev/null +++ b/manifest.json @@ -0,0 +1,16 @@ +{ + "id": "starter_party", + "name": "Starter Party", + "version": "1.0.0", + "author": "ct", + "description": "Seeds the default starter party (Marao) and the slave_master skill after mod resources are ready, and restores it on NewGameStartedEvent. Split out of visual_novel_core so the base content mod stays pure content (scenes/dialogs/quests/data) with no C# gameplay logic.", + "category": "engine, library", + "sources": [ + "src/**/*.cs" + ], + "depends": [ + "visual_novel_core>=1", + "skills_base>=1" + ], + "ui": [] +} diff --git a/src/StarterPartyInitializer.cs b/src/StarterPartyInitializer.cs new file mode 100644 index 0000000..44a0e35 --- /dev/null +++ b/src/StarterPartyInitializer.cs @@ -0,0 +1,69 @@ +using Cthangover.Core.Events; +using Cthangover.Core.Mods; +using Cthangover.Core.Settings; +using Cthangover.Mods.Skills; + +namespace Cthangover.Mods.StarterParty +{ + /// + /// Populates the initial player party with the default starter + /// character "Marao" when the starter_party mod finishes loading. + /// + /// The party can only be populated during OnModResourcesReady, + /// not earlier. OnModLoaded and the constructor fire inside + /// ModRegistry.Initialize → ModCompiler.LoadModCode, + /// where mod JSON resources are not yet guaranteed to be accessible. + /// AddCharacterToParty chains into CharacterFactory.Get, + /// which triggers the shared entity resolver's first scan — this requires + /// file providers to be fully set up, which only happens after the + /// entire ModRegistry.Initialize pipeline completes. + /// + /// OnModResourcesReady is invoked by ModInitializerRegistry + /// .NotifyResourcesReady at the end of SceneManager.Initialize, + /// after ModRegistry finishes discovery, SceneEventRegistry + /// is primed, and scene definitions are collected. At that point all + /// factories can safely read mod JSON data. + /// + /// Mods that introduce additional starter characters should implement + /// their own IModInitializer and call AddCharacterToParty + /// from OnModResourcesReady for their character IDs. + /// + public class StarterPartyInitializer : IModInitializer + { + private static bool newGameHookInstalled; + + /// + /// No-op: cross-mod lifecycle notifications are not needed for + /// starter party setup. Each mod's OnModResourcesReady + /// handles its own default characters independently. + /// + public void OnModLoaded(string modId) { } + + /// + /// Adds the starter_party mod's default starter character "Marao" + /// to both Characters and BattleSet via + /// CharacterData.AddCharacterToParty. Called once, after + /// all mod file providers and JSON resources are guaranteed to + /// be accessible. Also installs the one-time + /// hook so the starter party is + /// restored after ResetRuntime wipes it at the start of a + /// new game. Both operations are idempotent. + /// + public void OnModResourcesReady() + { + SeedStarterParty(); + + if (newGameHookInstalled) + return; + + newGameHookInstalled = true; + ModEventBus.Subscribe(_ => SeedStarterParty()); + } + + private static void SeedStarterParty() + { + GameData.Instance.Runtime.CharacterData.AddCharacterToParty("Marao"); + SkillService.GrantSkill("slave_master"); + } + } +}