From df8c75485cdd6b9fa2a60e0c5fe42a5bf9cc6687 Mon Sep 17 00:00:00 2001 From: randychihuahua Date: Sat, 29 Aug 2026 20:06:30 +0200 Subject: [PATCH 1/6] Added migration plan --- CSharpSourceCode/AbilitySystem/CLAUDE.md | 52 ++++ .../AbilitySystem/CrossHairs/CLAUDE.md | 23 ++ .../AbilitySystem/Scripts/CLAUDE.md | 46 ++++ .../AbilitySystem/SpellCasting/CLAUDE.md | 10 + .../AbilitySystem/Spells/CLAUDE.md | 24 ++ .../AbilitySystem/Spells/Prayers/CLAUDE.md | 11 + .../AbilitySystem/Spells/SpellBook/CLAUDE.md | 14 + CSharpSourceCode/Audio/CLAUDE.md | 20 ++ .../BattleMechanics/AI/ArtilleryAI/CLAUDE.md | 5 + CSharpSourceCode/BattleMechanics/AI/CLAUDE.md | 84 ++++++ .../CastingAI/AgentCastingBehavior/CLAUDE.md | 21 ++ .../CastingAI/AgentTacticalBehavior/CLAUDE.md | 10 + .../BattleMechanics/AI/CastingAI/CLAUDE.md | 12 + .../AI/CastingAI/Components/CLAUDE.md | 8 + .../CastingAI/SupportMissionLogic/CLAUDE.md | 6 + .../AI/CivilianMissionAI/CLAUDE.md | 10 + .../AI/CommonAIFunctions/CLAUDE.md | 16 ++ .../BattleMechanics/AI/TeamAI/CLAUDE.md | 11 + .../AI/TeamAI/FormationBehavior/CLAUDE.md | 13 + .../AI/TeamAI/TeamBehavior/CLAUDE.md | 7 + .../AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md | 6 + .../BattleMechanics/Artillery/CLAUDE.md | 19 ++ .../BattleMechanics/Banners/CLAUDE.md | 13 + CSharpSourceCode/BattleMechanics/CLAUDE.md | 59 ++++ .../CustomArenaModes/CLAUDE.md | 17 ++ .../BattleMechanics/DamageSystem/CLAUDE.md | 24 ++ .../BattleMechanics/Dismemberment/CLAUDE.md | 6 + .../BattleMechanics/Firearms/CLAUDE.md | 9 + .../BattleMechanics/Morale/CLAUDE.md | 6 + .../BattleMechanics/SFX/CLAUDE.md | 12 + .../BattleMechanics/SniperScope/CLAUDE.md | 6 + .../BattleMechanics/StatusEffect/CLAUDE.md | 35 +++ .../BattleMechanics/TriggeredEffect/CLAUDE.md | 33 +++ .../TriggeredEffect/Scripts/CLAUDE.md | 26 ++ .../BattleMechanics/Voice/CLAUDE.md | 15 ++ .../CampaignMechanics/Assimilation/CLAUDE.md | 10 + .../CampaignMechanics/BountyMaster/CLAUDE.md | 5 + CSharpSourceCode/CampaignMechanics/CLAUDE.md | 62 +++++ .../CampaignMechanics/Careers/CLAUDE.md | 14 + .../CampaignMechanics/Chaos/CLAUDE.md | 6 + .../CharacterCreation/CLAUDE.md | 35 +++ .../CampaignMechanics/Companions/CLAUDE.md | 7 + .../CampaignMechanics/Crafting/CLAUDE.md | 28 ++ .../CampaignMechanics/CustomDialogs/CLAUDE.md | 23 ++ .../CustomDialogs/ConversationTags/CLAUDE.md | 18 ++ .../CampaignMechanics/CustomEvents/CLAUDE.md | 14 + .../CustomResourceBehavior/CLAUDE.md | 10 + .../CustomResources/CLAUDE.md | 31 +++ .../CustomResources/WaaaghMeter/CLAUDE.md | 11 + .../CampaignMechanics/Diplomacy/CLAUDE.md | 19 ++ .../MapNotifications/CLAUDE.md | 5 + .../MasterEngineer/CLAUDE.md | 5 + .../PostBattleLoot/CLAUDE.md | 5 + .../RaidingParties/CLAUDE.md | 9 + .../CampaignMechanics/RaiseDead/CLAUDE.md | 12 + .../RegimentsOfRenown/CLAUDE.md | 11 + .../CampaignMechanics/Religion/CLAUDE.md | 22 ++ .../ServeAsAHireling/CLAUDE.md | 9 + .../CampaignMechanics/SpellTrainers/CLAUDE.md | 7 + .../TORCustomSettlement/CLAUDE.md | 37 +++ .../TORCustomSettlement/Component/CLAUDE.md | 18 ++ .../CustomSettlementMenus/CLAUDE.md | 17 ++ .../CampaignMechanics/UniqueSpawns/CLAUDE.md | 11 + .../CampaignMechanics/Villages/CLAUDE.md | 6 + .../CharacterDevelopment/CLAUDE.md | 36 +++ .../CareerSystem/CLAUDE.md | 40 +++ .../CareerSystem/CareerButton/CLAUDE.md | 27 ++ .../CareerSystem/Choices/CLAUDE.md | 19 ++ CSharpSourceCode/Extensions/CLAUDE.md | 30 +++ .../Extensions/ExtendedInfoSystem/CLAUDE.md | 24 ++ CSharpSourceCode/Extensions/UI/CLAUDE.md | 36 +++ .../Extensions/UI/MainMenu/CLAUDE.md | 13 + CSharpSourceCode/GameManagers/CLAUDE.md | 20 ++ CSharpSourceCode/HarmonyPatches/CLAUDE.md | 46 ++++ CSharpSourceCode/INDEX.md | 134 ++++++++++ CSharpSourceCode/Ink/CLAUDE.md | 23 ++ CSharpSourceCode/Items/CLAUDE.md | 33 +++ .../Items/InventoryUseScripts/CLAUDE.md | 20 ++ .../Items/WeaponHitScripts/CLAUDE.md | 22 ++ CSharpSourceCode/Missions/CLAUDE.md | 38 +++ CSharpSourceCode/Models/CLAUDE.md | 53 ++++ .../Models/CustomBattleModels/CLAUDE.md | 12 + CSharpSourceCode/Properties/CLAUDE.md | 4 + CSharpSourceCode/Quests/CLAUDE.md | 23 ++ CSharpSourceCode/Quests/Careers/CLAUDE.md | 10 + CSharpSourceCode/SaveGameSystem/CLAUDE.md | 17 ++ CSharpSourceCode/Utilities/CLAUDE.md | 59 ++++ docs/architecture-overview.md | 103 +++++++ docs/vertical-slicing-proposal.md | 251 ++++++++++++++++++ 89 files changed, 2249 insertions(+) create mode 100644 CSharpSourceCode/AbilitySystem/CLAUDE.md create mode 100644 CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md create mode 100644 CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md create mode 100644 CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md create mode 100644 CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md create mode 100644 CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md create mode 100644 CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md create mode 100644 CSharpSourceCode/Audio/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md create mode 100644 CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md create mode 100644 CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md create mode 100644 CSharpSourceCode/CharacterDevelopment/CLAUDE.md create mode 100644 CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md create mode 100644 CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md create mode 100644 CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md create mode 100644 CSharpSourceCode/Extensions/CLAUDE.md create mode 100644 CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md create mode 100644 CSharpSourceCode/Extensions/UI/CLAUDE.md create mode 100644 CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md create mode 100644 CSharpSourceCode/GameManagers/CLAUDE.md create mode 100644 CSharpSourceCode/HarmonyPatches/CLAUDE.md create mode 100644 CSharpSourceCode/INDEX.md create mode 100644 CSharpSourceCode/Ink/CLAUDE.md create mode 100644 CSharpSourceCode/Items/CLAUDE.md create mode 100644 CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md create mode 100644 CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md create mode 100644 CSharpSourceCode/Missions/CLAUDE.md create mode 100644 CSharpSourceCode/Models/CLAUDE.md create mode 100644 CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md create mode 100644 CSharpSourceCode/Properties/CLAUDE.md create mode 100644 CSharpSourceCode/Quests/CLAUDE.md create mode 100644 CSharpSourceCode/Quests/Careers/CLAUDE.md create mode 100644 CSharpSourceCode/SaveGameSystem/CLAUDE.md create mode 100644 CSharpSourceCode/Utilities/CLAUDE.md create mode 100644 docs/architecture-overview.md create mode 100644 docs/vertical-slicing-proposal.md diff --git a/CSharpSourceCode/AbilitySystem/CLAUDE.md b/CSharpSourceCode/AbilitySystem/CLAUDE.md new file mode 100644 index 00000000..65a66834 --- /dev/null +++ b/CSharpSourceCode/AbilitySystem/CLAUDE.md @@ -0,0 +1,52 @@ +# AbilitySystem + +The "magic" layer of TOR: Warhammer's Winds of Magic spells, priestly Prayers, and +per-Career signature abilities, all built on one shared runtime. + +## Core model + +- **`Ability`** (abstract, `Ability.cs`) — runtime instance wrapping an `AbilityTemplate`. + Handles cooldowns, cast validation (`CanCast`/`IsDisabled`), cast-frame calculation for + player/AI/quick-cast, spawning the effect `GameEntity`, and wiring up the right + `AbilityScript` subclass based on `AbilityEffectType` (Missile, Wind, Heal, Augment, + Summoning, Hex, Vortex, Blast, Bombardment, ArtilleryPlacement, TimeWarpEffect, etc.). + Three concrete subclasses: + - **`Spells/Spell.cs`** — Winds-of-Magic spells (costs Winds, has miscast chance, `SpellTier`, `BelongsToLoreID`). + - **`Prayer.cs`** — priest prayers (separate cooldown pool, `PrayerLevel` tier). + - **`CareerAbility.cs`** — each Career's unique active ability (see `CharacterDevelopment/CareerSystem`). + - **`ItemBoundAbility.cs`** — abilities granted by wielding a specific item. +- **`AbilityTemplate`** (`ITemplate`) — XML-serializable data definition (damage via + `TriggeredEffects`, visuals, cast type/time, crosshair type, target type, distances...). + Loaded/cloned via `AbilityFactory` from `AbilityTemplates.xml`-style data. +- **`AbilityFactory`** — loads and indexes all `AbilityTemplate`s at startup (`SubModule.OnSubModuleLoad`). +- **`AbilityComponent`** (`AgentComponent`) — attached to agents that can cast; tracks + known abilities (`KnownAbilitySystem`), Anvil-of-Doom state for Rune magic, prayer cooldown, quick-cast state. +- **`AbilityManagerMissionLogic`** — mission-level `MissionLogic` driving input → cast + requests, ticking cooldowns/wind-up casts, and mediating with the HUD. +- **`AbilityHUD_VM`** / **`CareerAbilityHUD_VM`** / **`AbilityRadialSelection_VM`** + + `AbilityRadialSelectionItemWidget` — in-mission UI (hotbar + radial ability picker). +- **`AbilityType`** / **`AbilityEffectType`** / **`AbilityTargetType`** / `CastType` / + `TriggerType` enums (in `AbilityType.cs`) drive most of the switch logic above. +- **`SeekerController`/`SeekerParameters`** — homing-missile behavior for seeker spells. +- **`SummonedAgentOrigin`/`SummonedCombatant`** — lets summoned troops (from Summoning abilities) + count as a proper battle combatant/origin for kill credit, banners, etc. + +## Subfolders + +- **`CrossHairs/`** — player aiming reticles per ability shape (see its CLAUDE.md). +- **`Scripts/`** — `AbilityScript` (`ScriptComponentBehavior`) implementations: the actual + mission-side visual/physics/timing logic for each `AbilityEffectType`, plus one + `CareerAbilityScript` subclass per Career signature ability (see its CLAUDE.md). +- **`SpellCasting/`** — `SpellCastSession`, tracks an in-progress multi-step cast (used for + Winds-of-Magic miscast rolls / windup UX outside the basic Ability flow). +- **`Spells/`** — `Spell`, `LoreObject` (a school/"Lore" of magic, e.g. Lore of Fire), + `SpellCastingLevel`; plus `SpellBook/` (in-mission spellbook screen: `SpellBookScreen`, + `SpellBookVM`, item/lore view-models) and `Prayers/` (battle prayer book equivalent: + `BattlePrayerScreen`, `BattlePrayersVM`, `PrayerItemVM`). + +## Notes + +- Loaded once at `SubModule.OnSubModuleLoad` via `AbilityFactory.LoadTemplates()`. +- AI casting decisions live outside this folder in + `BattleMechanics/AI/CastingAI` (`WizardAIComponent`, `AgentCastingBehavior`, + `AgentTacticalBehavior`) — this folder is the mechanism, that folder is the brain. diff --git a/CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md b/CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md new file mode 100644 index 00000000..94458008 --- /dev/null +++ b/CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md @@ -0,0 +1,23 @@ +# AbilitySystem/CrossHairs + +Player-facing aiming reticles shown while an ability is armed, one shape per +`CrosshairType` (set on `AbilityTemplate.CrosshairType`). + +- **`ICrosshair`** — `Show()/Hide()/Tick()/IsVisible`. +- **`Crosshair`** — plain default implementation of `ICrosshair`. +- **`AbilityCrosshair`** (abstract, `IDisposable, ICrosshair`) — base for ability-aware + crosshairs; exposes `Frame`/`Position` used by `Ability.CalculatePlayerCastMatrixFrame` + to place the spawned effect entity. + - `SelfCrosshair` — no aiming, centers on caster. + - `Pointer` — simple ground/world pointer (ability placement, e.g. Augment/Heal-on-ground). + - `MissileCrosshair` — aiming reticle for projectile/missile-type abilities. + - `SingleTargetCrosshair(AbilityTemplate)` — locks onto a single valid agent under the + reticle (`CachedTarget`), used for SingleAlly/SingleEnemy target types. + - `TargetedAOECrosshair` — ground-targeted area indicator. + - `WindCrosshair` — directional cone/line indicator for Wind-type abilities. +- **`ProjectileCrosshair_VM`** — view-model backing the crosshair widget's Gauntlet UI. +- **`CrosshairType`** enum — the switch key `AbilityTemplate`/`Ability` use to pick which + of the above to instantiate. + +Consumed by `Ability.GetSpawnFrame` (via `Ability.Crosshair`) and set up by whatever mission +UI arms the ability (`AbilityManagerMissionLogic` / `AbilityHUD_VM`). diff --git a/CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md new file mode 100644 index 00000000..21f1d6b9 --- /dev/null +++ b/CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md @@ -0,0 +1,46 @@ +# AbilitySystem/Scripts + +`AbilityScript` (`ScriptComponentBehavior`) and its subclasses — the mission-side entity +that actually flies/sits/pulses in the world while an `Ability` is active, and decides +when to trigger the ability's `TriggeredEffect`s (damage/heal/status/etc., from +`BattleMechanics/TriggeredEffect`). + +## Base class: `AbilityScript.cs` + +Owns the entity lifetime: ticking, movement (`ShouldMove`/`GetNextGlobalFrame`), lifetime +expiry vs `Template.Duration`, collision detection (`OnPhysicsCollision`/`CollidedWithAgent`), +sound looping, and `TriggerType`-driven firing (`OnCollision`, `EveryTick`, `TickOnce`, +`OnStop`). `TriggerEffects` opens/uses an `AbilityManagerMissionLogic` spell session +(`_castId`) so damage from this cast can be attributed for XP/kill-credit. Subclasses +override `GetNextGlobalFrame`, `ShouldMove`, `OnBeforeTick`/`OnAfterTick`, +`GetEffectsToTrigger`, `HandleCollision`. + +## Effect-type scripts (one per `AbilityEffectType`, picked by `Ability.AddBehaviour`) + +`ProjectileScript`, `MissileScript` (also serves SeekerMissile via `SeekerController`), +`WindScript`, `HealScript`, `AugmentScript` (also TacticalReposition), `SummoningScript`, +`HexScript`, `VortexScript`, `BlastScript`, `BombardmentScript`, `ArtilleryPlacementScript` +(also ItemPlacement), `TimeWarpScript`. + +## Career signature abilities + +**`CareerAbilityScript`** — base for `CareerAbility`'s effect: re-clones its +`TriggeredEffectTemplate` per cast and lets the caster's `CareerObject.MutateTriggeredEffect` +tweak numbers (perk-driven scaling), then follows the caster instead of flying free. +One subclass per Career ability (`CharacterDevelopment/CareerSystem/CareerObject` +wires these up by StringID): + +- `KnightlyChargeScript` / `KnightlyStrikeScript` (Grail Knight/Knight of the Old World) +- `AccusationScript`, `MindControlScript`, `ShadowStepScript` (Witch Hunter / Necrarch-adjacent) +- `TeleportScript` (+ `DamselTeleportScript`, `TeleportTriggeredScript`) (Grail Damsel) +- `ArcaneConduit`, `WisdomOfThungniScript` (Runelord/Runesmith — Dwarf rune magic) +- `ArmedToDaTeef`, `CallOfDaGreen`, `RedFuryScript`, `WrathOfTheWoodScript` (Greenskin careers) +- `AxeOfUlricScript`, `HawkEyeScript`, `LethalShotScript`, `DoomSeekingScript`, + `SummonChampionScript`, `ImpenetrableScript` (various human/elf careers) +- **`CareerAbilityMissleScript`** — missile variant base, subclassed by + `ArrowOfKurnousScript` (Waywatcher) and `BlastOfAgonyScript`. + +## Other + +- **`ITriggeredScript`** — separate lightweight interface (see + `BattleMechanics/TriggeredEffect/Scripts`) implemented by `TeleportTriggeredScript` here. diff --git a/CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md b/CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md new file mode 100644 index 00000000..868f7b81 --- /dev/null +++ b/CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md @@ -0,0 +1,10 @@ +# AbilitySystem/SpellCasting + +Single file: **`SpellCastSession`** — an accounting object for one ability cast, created by +`AbilityManagerMissionLogic.CreateSpellSession` when an `AbilityScript` first triggers and +collected once its effects (including any lingering `StatusEffect` durations) have played +out. Books damage/healing/kills/status-effects dealt by that cast, split into +friendly-fire vs. enemy buckets, and exposes totals (`TotalDamageDealt`, +`AgentsKilledCount`, `HasData`, etc.) used for post-cast feedback (kill credit, XP, +combat log/HUD numbers). Not persisted — purely an in-mission bookkeeping struct keyed by +`CastID`. diff --git a/CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md new file mode 100644 index 00000000..1ccfb7f8 --- /dev/null +++ b/CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md @@ -0,0 +1,24 @@ +# AbilitySystem/Spells + +Winds-of-Magic spell layer on top of the generic `Ability`/`AbilityTemplate` system. + +- **`Spell`** (`: Ability`) — a castable Winds-of-Magic spell instance. +- **`SpellCastingLevel`** enum — spell tier labels used in UI (mirrors `AbilityTemplate.SpellTier`). +- **`LoreObject`** — one "Lore" of magic (school), e.g. `LoreOfFire`, `LoreOfLife`, + `HighMagic`, `DarkMagic`, `Necromancy`, `RuneMagic`, `BigWaaagh`, `MinorMagic`. + Hardcoded static list (`GetAll`/`GetLore`) encodes lore-vs-culture eligibility + (`DisabledForCultures`) and `IsRestrictedToVampires` — this is where "which races can + learn which magic" is defined (see `Utilities/TORConstants.Cultures` for the culture IDs: + Empire, Bretonnia, Mousillon, Sylvania, Asrai, Eonir, Dawi/Dwarfs, Greenskin...). + Note the in-code caveat: Spellsingers (Asrai) get a special-cased bypass of the + High/Dark Magic culture lock via `CampaignMechanics/SpellTrainers/SpellTrainerInTownBehavior`. + +## Subfolders + +- **`SpellBook/`** — the campaign-map spellbook screen for learning/viewing spells: + `SpellBookScreen`/`SpellBookState` (game state + screen), `SpellBookVM` (root VM), + `AbilityItemVM` (abstract row VM) → `SpellItemVM`, `LoreObjectVM`, + `SpellBookMapIconVM`, `StatItemVM` (stat-line rows shown via `AbilityTemplate.GetStats`). +- **`Prayers/`** — the equivalent in-mission book for battle Prayers: + `BattlePrayerScreen`/`BattlePrayerBookState`, `BattlePrayersVM`, + `PrayerItemVM` (`: AbilityItemVM`), `PrayerLoreObjectVM`. diff --git a/CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md new file mode 100644 index 00000000..a3790dcf --- /dev/null +++ b/CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md @@ -0,0 +1,11 @@ +# AbilitySystem/Spells/Prayers + +In-mission "Prayer book" UI — the Prayer equivalent of `../SpellBook`, but opened during a +battle rather than on the campaign map: + +- **`BattlePrayerScreen`** (`ScreenBase, IGameStateListener`) + **`BattlePrayerBookState`** + (`GameState`) — screen/state pair. +- **`BattlePrayersVM`** — root view-model listing the caster's known `Prayer`s. +- **`PrayerItemVM`** (`: AbilityItemVM`, base defined in `../SpellBook`) — one prayer row. +- **`PrayerLoreObjectVM`** — grouping VM analogous to `LoreObjectVM`, but for prayer + "lores"/deities rather than Winds-of-Magic lores. diff --git a/CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md new file mode 100644 index 00000000..8eac9136 --- /dev/null +++ b/CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md @@ -0,0 +1,14 @@ +# AbilitySystem/Spells/SpellBook + +Campaign-map "Spellbook" screen UI (a `ScreenBase` + `GameState`, Gauntlet-based, not a +mission behavior): + +- **`SpellBookScreen`** (`ScreenBase, IGameStateListener`) + **`SpellBookState`** (`GameState`) + — screen/state pair pushed onto the game state stack to open the spellbook. +- **`SpellBookVM`** — root view-model: lists known/learnable spells grouped by `LoreObject`. +- **`AbilityItemVM`** (abstract `ViewModel`) — shared row VM for a single ability entry; + base for `SpellItemVM` here and `PrayerItemVM` in `../Prayers`. +- **`LoreObjectVM`** — VM wrapper around a `LoreObject` (lore icon/name/unlock state). +- **`SpellBookMapIconVM`** — the map-bar icon/button that opens the spellbook. +- **`StatItemVM`** — one label/value stat row (cooldown, Winds cost, tier, type), built from + `AbilityTemplate.GetStats`. diff --git a/CSharpSourceCode/Audio/CLAUDE.md b/CSharpSourceCode/Audio/CLAUDE.md new file mode 100644 index 00000000..292232f5 --- /dev/null +++ b/CSharpSourceCode/Audio/CLAUDE.md @@ -0,0 +1,20 @@ +# Audio + +Small standalone audio subsystem for playing sound files that live outside the game's +FMOD sound-bank pipeline (loaded directly from disk as .ogg/.wav under the TOR_Armory +module's `ModuleSounds/` folder). + +- **`TORAudioManager`** (static) — loads a file into a `TORModuleSound` via + `CreateSoundInstance` (tries `.ogg` then falls back to `.wav`), plays it through a native + `SoundEvent.CreateEventFromExternalFile` using a dummy FMOD event + (`event:/Extra/voiceover`) as the carrier, and ticks all `_activeSounds` every frame + (`SubModule.OnApplicationTick`) to handle looping (`RestartsWhenFinished`) and cleanup. + `StopAll()` is called on `SubModule.OnGameEnd`. +- **`TORModuleSound`** — handle for one loaded sound: play/remove, 3D position + falloff + range (`SetPosition`), restart-on-finish behavior. +- **`TORAudioAmbientSoundEmitter`** (`ScriptComponentBehavior`) — a scene-prop/entity script + (also usable in the level editor via `OnEditorInit`/`OnEditorVariableChanged`) that plays + a looping 3D ambient sound from `AudioName` when the camera is within `Range`, using the + manager above. Drop this on a prop in a scene to give it ambient audio. + +Distinct from voice lines / battle shouts, which live in `BattleMechanics/Voice`. diff --git a/CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md new file mode 100644 index 00000000..1a602c3c --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md @@ -0,0 +1,5 @@ +# BattleMechanics/AI/ArtilleryAI + +**`FieldSiegeWeaponAI`** (`: UsableMachineAIBase`) — AI crew behavior for the field siege +weapons defined in `BattleMechanics/Artillery` (trebuchets etc.): aim, reload, and fire +decision loop for an AI-controlled operator. diff --git a/CSharpSourceCode/BattleMechanics/AI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CLAUDE.md new file mode 100644 index 00000000..ae410f6e --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CLAUDE.md @@ -0,0 +1,84 @@ +# BattleMechanics/AI + +Custom battlefield AI, layered on top of TaleWorlds' `HumanAIComponent`/`BehaviorComponent`/ +`TeamAIGeneral` framework. Three broad concerns: + +1. **Spellcaster ("wizard") AI** — `CastingAI/` — utility-scored decisions about when/what + to cast and how to stay safe while doing it. +2. **Formation/team AI overrides** — `TeamAI/` — TOR replacements for vanilla formation + behaviors (charge/retreat/skirmish/defend/aggressive-melee) and the team general. +3. **Misc battlefield AI** — artillery crew AI (`ArtilleryAI/`), non-combatant/civilian + mission AI (`CivilianMissionAI/`), and shared scoring/utility helpers (`CommonAIFunctions/`). + +Root file: **`TORCultureBattleSettings`** (static) — per-culture tuning knobs for battle AI +(aggression, formation spacing, etc. — used to give e.g. Greenskins vs. Empire different +"feel"). **`AIKickAgentComponent`** — lets AI-controlled agents throw kick attacks. + +## `CommonAIFunctions/` — shared utility-AI building blocks + +Used by both `CastingAI` and (indirectly) `TeamAI`: + +- **`IAgentBehavior`** — interface every scoreable per-agent behavior implements + (`Execute`, `Terminate`, `CalculateUtility`). +- **`BehaviorOption`** — a `(Behavior, Target, UtilityValue)` tuple candidate. +- **`Target` : `Threat`** — a scoring target: an enemy `Formation`, a `TacticalPosition`, etc. +- **`Axis`/`AxisExtensions`** — named utility curves ("axes") that get combined via + `GeometricMean` into one utility score per candidate (classic utility-AI pattern). +- **`ScoringFunctions`** — the actual curve functions (distance falloff, density, etc.) + that `Axis`es wrap. +- **`DecisionManager`** — `EvaluateCastingBehaviors`: flattens all behaviors' scored + options and picks the single best (`MaxBy` utility). +- **`CommonAIFunctions`** (`CommonAIDecisionFunctions`/`CommonAIStateFunctions`/ + `CommonAIFunctions`) — grab-bag of static helpers reused across behaviors (formation + queries, positioning math). + +## `CastingAI/` — spellcasters + +- **`Components/WizardAIComponent`** (`: HumanAIComponent`) — replaces the agent's stock + `HumanAIComponent` entirely. Every ~3s (`EvalInterval`, jittered) it re-evaluates + `AvailableCastingBehaviors` via `DecisionManager` and picks the best-scoring + `AbstractAgentCastingBehavior`; every tick it runs that behavior's `TacticalBehavior` + (positioning/safety) then the casting behavior itself, unless the formation is on + Hold Fire. +- **`AgentCastingBehaviorConfiguration`** (static) — registers, per ability-effect-type, + which `Axis`es feed its utility score (`UtilityByType`) and builds the list of available + behaviors for an agent from its known abilities (`PrepareCastingBehaviors`). +- **`AgentCastingBehavior/`** — one class per casting "shape", all `: AbstractAgentCastingBehavior` + (`IAgentBehavior`): `MissileCastingBehavior` (base for aimed-projectile spells), + `AoETargetedCastingBehavior` → `SelectSingleTargetCastingBehavior`/`SelectMultiTargetCastingBehavior`, + `AoEAdjacentCastingBehavior`, `AoEDirectionalCastingBehavior`, `SummoningCastingBehavior`, + `ArtilleryPlacementCastingBehavior`, `PreserveWindsCastingBehavior` (chooses not to cast, + conserving Winds of Magic), `TacticalTeleportCastingBehavior`. `AbstractAgentCastingBehavior` + itself owns cooldown/range/line-of-sight checks, target updating, and the + utility-score calc (`CalculateUtility` = geometric mean of its `Axis` list + target + hysteresis to avoid target-flip-flopping). +- **`AgentTacticalBehavior/`** — `AbstractAgentTacticalBehavior` (`IAgentBehavior`) and + concrete positioning behaviors run alongside casting: `KeepSafeTacticalBehavior` + (kite away from danger), `AoEAdjacentTacticalBehavior`/`AoEDirectionalTacticalBehavior` + (reposition to land AoE shapes). +- **`SupportMissionLogic/`** — `QuerySystemExtensions`/`QuerySystemExtensionsMissionLogic`, + extends TaleWorlds' formation `QuerySystem` (tactical position queries) for the above. + +## `TeamAI/` + +- **`FormationBehavior/`** — TOR subclasses of vanilla `BehaviorComponent`s: + `TORBehaviorBase` (abstract shared base), `TORBehaviorCharge`, `TORBehaviorDefend`, + `TORBehaviorRetreat`, `TORBehaviorSkirmish`, `TORBehaviorAggressiveMelee`, + `TORBehaviorProtectArtillery` (new), `TORFormationClass`. +- **`TeamBehavior/TORTeamAIGeneral`** (`: TeamAIGeneral`) — top-level team AI override. + - **`TeamBehavior/Tactics/TORTacticPositionalArtillery`** (`: TacticDefensiveLine`) — + a tactic that keeps a defensive line while positioning artillery. +- **`TORMissionCombatantsLogic`** (`: MissionCombatantsLogic`) — replaces the vanilla + combatants logic (see `SubModule.OnBeforeMissionBehaviorInitialize`, + `CreateFromInstance`). + +## `ArtilleryAI/` + +- **`FieldSiegeWeaponAI`** (`: UsableMachineAIBase`) — AI crew behavior for the field + siege weapons in `BattleMechanics/Artillery` (aim/reload/fire loop). + +## `CivilianMissionAI/` + +Non-combat town/village mission AI (townsfolk going about their day, reacting to trouble): +`TORDailyBehaviorGroup`/`TORAlarmedBehaviorGroup` (`AgentBehaviorGroup`), +`TORWalkingBehavior`/`TORFightBehavior` (`AgentBehavior`). diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md new file mode 100644 index 00000000..f800b0c0 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md @@ -0,0 +1,21 @@ +# BattleMechanics/AI/CastingAI/AgentCastingBehavior + +One `AbstractAgentCastingBehavior` (`: IAgentBehavior`) subclass per spell-casting "shape". +Each wraps cooldown/range/line-of-sight checks and a utility score +(`CalculateUtility` = geometric mean of registered `Axis`es, see +`../../CommonAIFunctions`), and on `Execute()` selects the ability and calls +`Agent.TryCastCurrentAbility`. + +- **`AbstractAgentCastingBehavior`** — shared base (see class doc in parent CLAUDE.md). +- **`MissileCastingBehavior`** — base for aimed single-projectile spells. + - **`AoETargetedCastingBehavior`** — aims at a scored ground/formation target. + - **`SelectSingleTargetCastingBehavior`**, **`SelectMultiTargetCastingBehavior`** — + single- vs. multi-target variants. +- **`AoEAdjacentCastingBehavior`** / **`AoEDirectionalCastingBehavior`** — self-centered or + directional area spells (cones/lines), paired with the matching `AgentTacticalBehavior`. +- **`SummoningCastingBehavior`** — casts summon-type abilities. +- **`ArtilleryPlacementCastingBehavior`** — places artillery/item-placement abilities; + cooperates with `WizardAIComponent.UpdateArtilleryTargetPosition`. +- **`PreserveWindsCastingBehavior`** — a "do nothing, conserve Winds of Magic" option so the + utility system can prefer not casting when nothing scores well. +- **`TacticalTeleportCastingBehavior`** — casts reposition/teleport-type abilities. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md new file mode 100644 index 00000000..1197d214 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md @@ -0,0 +1,10 @@ +# BattleMechanics/AI/CastingAI/AgentTacticalBehavior + +Positioning/safety behaviors run every tick alongside a caster's chosen +`AgentCastingBehavior` (see `WizardAIComponent.OnTick`), all `: AbstractAgentTacticalBehavior` +(`IAgentBehavior`). + +- **`AbstractAgentTacticalBehavior`** — shared base. +- **`KeepSafeTacticalBehavior`** — kite away from nearby danger/melee threats. +- **`AoEAdjacentTacticalBehavior`** / **`AoEDirectionalTacticalBehavior`** — reposition to + land the caster's adjacent/directional AoE shape on its target. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md new file mode 100644 index 00000000..9a733ef0 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md @@ -0,0 +1,12 @@ +# BattleMechanics/AI/CastingAI + +Utility-AI for agents that can cast spells/prayers/career abilities in battle. See +`../CLAUDE.md` ("CastingAI") for the full picture. Quick map: + +- **`AgentCastingBehaviorConfiguration`** (this folder, root) — registers which `Axis`es + score each casting-behavior type and builds an agent's `PrepareCastingBehaviors` list + from its known abilities. +- **`Components/WizardAIComponent`** — the `HumanAIComponent` replacement driving it all. +- **`AgentCastingBehavior/`** — the actual cast decisions (one class per spell "shape"). +- **`AgentTacticalBehavior/`** — positioning/safety run alongside casting. +- **`SupportMissionLogic/`** — `QuerySystem` extensions the above rely on for formation queries. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md new file mode 100644 index 00000000..f50dfbf5 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md @@ -0,0 +1,8 @@ +# BattleMechanics/AI/CastingAI/Components + +**`WizardAIComponent`** (`: HumanAIComponent`) — replaces a spellcasting agent's stock +`HumanAIComponent` (removes it via `agent.RemoveComponent` in its ctor). Every ~3 seconds +(jittered per-agent) it re-evaluates `AvailableCastingBehaviors` through +`DecisionManager.EvaluateCastingBehaviors` and adopts the best-scoring +`AbstractAgentCastingBehavior`; every tick (unless the formation is on Hold Fire) it runs +that behavior's `TacticalBehavior` then the behavior itself. See parent `../CLAUDE.md`. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md new file mode 100644 index 00000000..3ab80e3a --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md @@ -0,0 +1,6 @@ +# BattleMechanics/AI/CastingAI/SupportMissionLogic + +**`FormationQuerySystemExtensions`** (`QuerySystemExtensions.cs`) + +**`QuerySystemExtensionsMissionLogic`** — extend TaleWorlds' formation `QuerySystem` with +extra tactical-position queries that the casting/tactical behaviors in the sibling folders +rely on for finding safe spots and AoE landing positions. diff --git a/CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md new file mode 100644 index 00000000..ff0e2637 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md @@ -0,0 +1,10 @@ +# BattleMechanics/AI/CivilianMissionAI + +Non-combat AI for town/village scenes — NPCs going about their day and reacting to trouble. + +- **`TORDailyBehaviorGroup`** (`: AgentBehaviorGroup`) — normal daytime routine group. +- **`TORAlarmedBehaviorGroup`** (`: AgentBehaviorGroup`) — takes over when something alarms + the civilian population (a fight breaks out, a crime is witnessed). +- **`TORWalkingBehavior`** (`: AgentBehavior`) — idle wandering/walking-to-destination. +- **`TORFightBehavior`** (`: SandBox.Missions.AgentBehaviors.AgentBehavior`) — a civilian + joining/reacting to a brawl. diff --git a/CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md new file mode 100644 index 00000000..93d514a4 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md @@ -0,0 +1,16 @@ +# BattleMechanics/AI/CommonAIFunctions + +Shared utility-AI primitives used by `CastingAI` (and available to `TeamAI`): + +- **`IAgentBehavior`** — interface every scoreable behavior implements (`Execute`, + `Terminate`, `CalculateUtility`). +- **`BehaviorOption`** — `(Behavior, Target, UtilityValue)` candidate tuple. +- **`Target : Threat`** — a scoring target (enemy `Formation`, `TacticalPosition`, etc.). +- **`Axis` / `AxisExtensions`** — named utility curves combined via `GeometricMean` into one + score per candidate — the core "utility AI" mechanism. +- **`ScoringFunctions`** — the actual curve functions (distance falloff, density, etc.). +- **`DecisionManager`** — `EvaluateCastingBehaviors`: flattens every behavior's scored + options and picks the single best via `MaxBy`. +- **`CommonAIDecisionFunctions` / `CommonAIStateFunctions` / `CommonAIFunctions`** + (`CommonAIFunctions.cs`) — grab-bag of static formation/positioning helpers reused across + behaviors. diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md new file mode 100644 index 00000000..a752621c --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md @@ -0,0 +1,11 @@ +# BattleMechanics/AI/TeamAI + +TOR's replacements for vanilla team/formation-level battle AI. + +- **`TORMissionCombatantsLogic`** (`: MissionCombatantsLogic`) — swaps in for the vanilla + combatants logic; installed via `SubModule.OnBeforeMissionBehaviorInitialize` + (`TORMissionCombatantsLogic.CreateFromInstance`). +- **`FormationBehavior/`** — per-formation behavior overrides (charge/defend/retreat/ + skirmish/aggressive-melee + a new protect-artillery behavior). +- **`TeamBehavior/`** — `TORTeamAIGeneral` (`: TeamAIGeneral`) and, under `Tactics/`, + `TORTacticPositionalArtillery` (`: TacticDefensiveLine`). diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md new file mode 100644 index 00000000..abe1f153 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md @@ -0,0 +1,13 @@ +# BattleMechanics/AI/TeamAI/FormationBehavior + +TOR subclasses of vanilla `BehaviorComponent`s, registered wherever formations pick their +AI behavior set (culture settings in `../../TORCultureBattleSettings` feed into this): + +- **`TORBehaviorBase`** (abstract) — shared base for the overrides below. +- **`TORBehaviorCharge`** (`: BehaviorCharge`), **`TORBehaviorDefend`** (`: BehaviorDefend`), + **`TORBehaviorRetreat`** (`: BehaviorRetreat`), **`TORBehaviorSkirmish`** + (`: BehaviorSkirmish`), **`TORBehaviorAggressiveMelee`** (`: BehaviorComponent`) — tuned/ + patched versions of the matching vanilla formation behavior. +- **`TORBehaviorProtectArtillery`** (`: BehaviorComponent`) — new behavior: keeps a + formation screening friendly artillery pieces. +- **`TORFormationClass`** — formation classification helper used to pick behaviors. diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md new file mode 100644 index 00000000..852b9662 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md @@ -0,0 +1,7 @@ +# BattleMechanics/AI/TeamAI/TeamBehavior + +**`TORTeamAIGeneral`** (`: TeamAIGeneral`) — top-level per-team AI override deciding +overall tactics/formation assignment for a side in battle. + +- **`Tactics/TORTacticPositionalArtillery`** (`: TacticDefensiveLine`) — a battle-wide tactic + that holds a defensive line while positioning artillery pieces for effective fire. diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md new file mode 100644 index 00000000..70435eaf --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md @@ -0,0 +1,6 @@ +# BattleMechanics/AI/TeamAI/TeamBehavior/Tactics + +**`TORTacticPositionalArtillery`** (`: TacticDefensiveLine`) — battle-wide tactic variant +that holds a defensive line formation while positioning/protecting friendly artillery +pieces so they can keep firing. Selected by `TORTeamAIGeneral` for sides that have +artillery on the field. diff --git a/CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md new file mode 100644 index 00000000..d2fbf4b8 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md @@ -0,0 +1,19 @@ +# BattleMechanics/Artillery + +Field (non-siege-only) artillery pieces usable in open battles, extending TaleWorlds' +`RangedSiegeWeapon`/`StandingPoint` machinery. AI crew logic lives separately in +`BattleMechanics/AI/ArtilleryAI`; team-level protection behavior in +`BattleMechanics/AI/TeamAI` (`TORBehaviorProtectArtillery`, `TORTacticPositionalArtillery`). + +- **`BaseFieldSiegeWeapon`** (abstract `: RangedSiegeWeapon`) — shared base for field + artillery: ammo, aiming, firing. + - **`FieldTrebuchet`** — concrete field trebuchet usable outside sieges. + - **`ArtilleryRangedSiegeWeapon`** — general field artillery piece (cannon-type). +- **`ArtilleryStandingPoint`** / **`TrebuchetStandingPoint`** (`: StandingPoint`) and + **`AmmoPickUpStandingPoint`** (`: StandingPointWithWeaponRequirement`) — the usable + positions troops interact with to crew/reload the weapon. +- **`CannonBallPile`** (`: SiegeMachineStonePile`) — ammo pile prop for cannon-type weapons. +- **`Ballistics`** (static) — trajectory/aiming math shared by the weapons above. + +Placement in battle is driven by `AbilitySystem`'s `ArtilleryPlacementScript`/ +`ArtilleryPlacementCastingBehavior` for player/AI-called artillery abilities. diff --git a/CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md new file mode 100644 index 00000000..822e7e93 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md @@ -0,0 +1,13 @@ +# BattleMechanics/Banners + +Custom faction/unit banners usable in missions (beyond the game's per-clan banner system). + +- **`CustomBannerManager`** (static) — loads banner definitions from XML + (`LoadXML`, called in `SubModule.OnSubModuleLoad`); **`FactionBannerOverride`** — + per-faction override entry (lets a Warhammer faction/culture use a specific custom + banner texture instead of the generated vanilla one). +- **`CustomBannerMissionLogic`** (`: MissionLogic`) — applies the overrides to banner-bearer + agents/props during a mission; added in `SubModule.OnMissionBehaviorInitialize`. + +Also see `Models/TORBattleBannerBearersModel` (which agents get banners) and +`HarmonyPatches/FactionBannerPatches.cs`. diff --git a/CSharpSourceCode/BattleMechanics/CLAUDE.md b/CSharpSourceCode/BattleMechanics/CLAUDE.md new file mode 100644 index 00000000..419cbf94 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/CLAUDE.md @@ -0,0 +1,59 @@ +# BattleMechanics + +Everything that runs inside a `Mission` (battles, sieges, tournaments, arena fights): +custom AI, status effects, damage/triggered-effect resolution, siege artillery, banners, +dismemberment, firearms, monster-siege support, and misc SFX/voice mission logics. This is +the largest and most mission-behavior-heavy folder in the mod; most classes are either a +`MissionLogic`/`MissionView` registered in `SubModule.OnMissionBehaviorInitialize`, or an +`AgentComponent`/`ScriptComponentBehavior` attached per-agent or per-prop. + +## Root-level mission logics + +- **`TORBattleAgentLogic`** (`: BattleAgentLogic`) — replaces the vanilla per-agent battle + logic (kill credit, morale-on-death, etc.) to route through TOR's own systems. +- **`AddAgentComponentsMissionLogic`** — attaches TOR's custom `AgentComponent`s + (`AbilityComponent`, `StatusEffectComponent`, `AgentVoiceComponent`, AI components) to + every spawned agent. +- **`CareerPerkMissionBehavior`** — applies/reacts to Career perks during missions. +- **`CinematicCameraMissionView`** — scripted camera moves (cutscene-style shots). +- **`CustomCrosshairMissionBehavior`** — swaps in TOR ability/weapon crosshairs, replacing + `MissionGauntletCrosshair` (removed in `SubModule`). +- **`SiegeEarlyVictoryMissionLogic`** — lets a siege end early under custom conditions. +- **`TORMonsterSiegeLogic`** — large file; lets giant-monster troops (trolls, etc.) act as + their own siege "detachment" (ladders/gates), with several internal Harmony patch classes + (`TORMonsterSiegeLadderQueueConditionsPatch`, `...GateDamagePatch`, etc.) colocated here + rather than in `HarmonyPatches/`. + +## Subfolders + +- **`AI/`** — custom battlefield AI: formation behaviors, team AI, spellcaster AI, + civilian mission AI, artillery AI, and shared decision-making helpers (own CLAUDE.md tree). +- **`Artillery/`** — field siege weapons (trebuchets etc.) beyond the vanilla siege-only ones. +- **`Banners/`** — custom faction banner assets/overrides usable in missions. +- **`CustomArenaModes/`** — archery contest and joust tournament game modes for the arena. +- **`DamageSystem/`** — `DamageType` enum + `TORDamageHelper`, shared damage-type/resistance + math used by both spell damage (`Models/TORAbilityModel`) and physical damage + (`Models/TORAgentApplyDamageModel`). +- **`Dismemberment/`** — `DismembermentMissionLogic` (gore/limb-loss on kill). +- **`Firearms/`** — black-powder weapon mechanics (Empire handguns/cannons — reload, + misfire, continuous-fire tracking). +- **`Morale/`** — `UndeadMoraleAgentComponent` (undead troops ignore/are immune to morale). +- **`SFX/`** — small standalone `ScriptComponentBehavior`s for scene dressing + (light dampening, object spinning/animating, face-toward-target, flyable objects). +- **`SniperScope/`** — a zoom/scope `ICrosshair` implementation for long-range weapons. +- **`StatusEffect/`** — the buff/debuff (DOT/HOT/stat-mod) system applied by spells, items, + and prayers. +- **`TriggeredEffect/`** — the data-driven "what happens on hit/cast" system: damage, + healing, status application, summoning, script triggers — the payload `Ability`/item + scripts fire off. +- **`Voice/`** — custom battle shouts and per-agent voice-over component. + +## Key shared types + +- **`TORDamageHelper`** — routes spell/melee/ranged damage through the same + per-`DamageType` proportion/amplification/resistance math, and folds in Career-passive + bonuses (`CareerHelper.AddCareerPassivesForDamageValues`) when the main party is involved. +- **`TriggeredEffect`/`TriggeredEffectTemplate`/`TriggeredEffectManager`** — XML-defined + "effect packages" (damage, heal, status effects, summon, spawn prefab, run a named + `ITriggeredScript`) resolved by AoE/target-type against nearby agents; used by both + Ability scripts and item weapon-hit scripts. diff --git a/CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md b/CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md new file mode 100644 index 00000000..871217bb --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md @@ -0,0 +1,17 @@ +# BattleMechanics/CustomArenaModes + +New arena/tournament game modes beyond vanilla melee tournaments. + +- **`ArcheryContestTournamentGame`** (`: FightTournamentGame`) + + **`ArcheryContestTournamentBehavior`** (`: TournamentBehavior`, in + `CustomTournamentBehaviors.cs`) + **`ArcheryContestAgentController`** (`: AgentController`) + — a ranged-only archery contest mode. Driven in the campaign layer by + `Missions/ArcheryContestMissionController`. +- **`JoustTournamentGame`** (`: FightTournamentGame`) + + **`JoustTournamentBehavior`** (`: TournamentBehavior`, in `CustomTournamentBehaviors.cs`) + + **`JoustLaneEndVolumeBox`** (`: MissionObject`) — a mounted joust mode with dedicated + lanes; the volume box marks/triggers lane-end turnaround. Driven by + `Missions/JoustFightMissionController`. + +See `Missions/` for the campaign-facing controllers that set these modes up, and +`CharacterCreation`/settlement menus for how a player enters them. diff --git a/CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md b/CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md new file mode 100644 index 00000000..92cdf725 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md @@ -0,0 +1,24 @@ +# BattleMechanics/DamageSystem + +The shared damage-type/resistance math used by every damage source in the mod (melee, +ranged, spells). + +- **`DamageType`** enum — TOR's extended damage typing (beyond vanilla Cut/Pierce/Blunt), + e.g. Fire/Physical/etc. (see `TriggeredEffectTemplate.DamageType`, + `StatusEffectTemplate.DamageType`), plus an `All` sentinel used for array sizing. +- **`TORDamageHelper`** (static) — the actual formulas: + - `CalculateDamageWithProportions` — splits one base damage value across multiple + `DamageType`s by proportion, applies per-type amplification minus resistance + (used for melee/ranged where `TORAgentApplyDamageModel` blends types). + - `CalculateSingleTypeDamage` — single-`DamageType` version (used for spells, + `TORAbilityModel`). + - `ApplyCareerPassives` — folds `CharacterDevelopment/CareerSystem` `CareerHelper` + passive bonuses into the attack/defense percentage arrays when the main party is + involved in the hit. + - `DetermineMask(Blow/KillingBlow)` — classifies a hit as Spell/Ranged/Melee + (`AttackTypeMask`), checking `Utilities/TORSpellBlowHelper` first so spell damage isn't + misclassified as a normal ranged/melee hit. + +Consumed by `Models/TORAgentApplyDamageModel`, `Models/TORAbilityModel`, +`BattleMechanics/StatusEffect` (amplification/resistance aggregation), and +`BattleMechanics/TriggeredEffect`. diff --git a/CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md new file mode 100644 index 00000000..cc11cdc3 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md @@ -0,0 +1,6 @@ +# BattleMechanics/Dismemberment + +**`DismembermentMissionLogic`** (`: MissionLogic`) — gore mechanic: on a sufficiently heavy +killing blow, detaches/replaces limb meshes on the corpse instead of (or alongside) the +normal ragdoll, matching Warhammer's more brutal combat tone. Added in +`SubModule.OnMissionBehaviorInitialize`. diff --git a/CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md new file mode 100644 index 00000000..3a8ce64b --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md @@ -0,0 +1,9 @@ +# BattleMechanics/Firearms + +**`FirearmsMissionLogic`** (`: MissionLogic`) — black-powder weapon mechanics (Empire +handguns/pistols, grenades, the Dwarf "Trollhammer torpedo", cannon-type explosions): +custom explosion damage/radius per weapon type (`_explosionDamage`/`_explosionRadius`, +torpedo variant sized 30% smaller), continuous-fire tracking per agent +(`ContinousFiringData`, `_continousFiringAgents`) for sustained-fire weapons, and managed +gunshot/grenade sound events (validated once, played/cleaned up per shot). Added in +`SubModule.OnMissionBehaviorInitialize`. diff --git a/CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md new file mode 100644 index 00000000..702a40b6 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md @@ -0,0 +1,6 @@ +# BattleMechanics/Morale + +**`UndeadMoraleAgentComponent`** (`: AgentComponent`) — attached to undead troops +(Vampire Counts/Mousillon/Sylvania factions) to make them ignore or heavily resist morale +loss/routing, matching tabletop Warhammer's undead "unbreakable/immune to psychology" +theme. Complements `Models/TORBattleMoraleModel` and `Models/TORPartyMoraleModel`. diff --git a/CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md b/CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md new file mode 100644 index 00000000..0133c998 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md @@ -0,0 +1,12 @@ +# BattleMechanics/SFX + +Small, reusable `ScriptComponentBehavior`s for scene-prop dressing, usable from the scene +editor as well as spawned at runtime (e.g. by `AbilitySystem`/`StatusEffect` visuals): + +- **`TORSpinner`** — continuously rotates its entity (`RotationSpeed`); used by + `StatusEffectComponent` for effects flagged `Template.Rotation`. +- **`TORFaceArmy`** (in `TORFaceEnemy.cs`) — orients an entity to face a target/enemy. +- **`TORLightDampener`** — attenuates a light source's intensity over time/conditions. +- **`TORSimpleObjectAnimator`** — plays a simple keyframe/transform animation on an entity. +- **`PlayerFlyableObjectScript`** — lets the player fly/ride an otherwise-static object + (used for spectacle set-pieces, e.g. mounts summoned by abilities). diff --git a/CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md b/CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md new file mode 100644 index 00000000..d29f64b3 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md @@ -0,0 +1,6 @@ +# BattleMechanics/SniperScope + +**`SniperScope`** (`: ICrosshair`) — a zoom/scope-style aiming reticle for long-range +weapons (e.g. Empire long rifles from `BattleMechanics/Firearms`), separate from the +`AbilitySystem/CrossHairs` family since it's a weapon-aiming aid rather than an +ability-targeting reticle. diff --git a/CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md b/CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md new file mode 100644 index 00000000..d6a5b56c --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md @@ -0,0 +1,35 @@ +# BattleMechanics/StatusEffect + +The buff/debuff system: DOTs/HOTs, damage amplification/resistance, movement/attack/reload +speed mods, lance steadiness, temporary character attributes — applied by spells, prayers, +items, and terrain. + +- **`StatusEffectTemplate`** (`ITemplate, IEquatable`) — XML-defined effect data: + `EffectType` (`DamageOverTime`, `HealthOverTime`, `WindsOverTime`, `DamageAmplification`, + `Resistance`, `MovementManipulation`, `AttackSpeedManipulation`, `ReloadSpeedManipulation`, + `LanceSteadiness`, `TemporaryAttributeOnly`), `BaseEffectValue`, target `DamageType`/ + `AttackTypeMask` (for amplification/resistance types), particle/visual config + (`ParticleId`, `ParticleIntensity`, `ApplyToRootBoneOnly`, `Rotation`). +- **`StatusEffectManager`** (static) — loads/indexes all templates + (`LoadStatusEffects`, called from `SubModule.OnSubModuleLoad`) and creates runtime + `StatusEffect` instances (`CreateNewStatusEffect`, handles cloning for career-mutated effects). +- **`StatusEffect`** (`IDisposable, IEquatable`) — one active instance on an agent: + template + applier + remaining duration + `CastId` (links back to the + `AbilitySystem/SpellCasting/SpellCastSession` that applied it, for kill/XP credit). +- **`StatusEffectComponent`** (`: AgentComponent, IDisposable`) — attached per-agent + (via `AddAgentComponentsMissionLogic`); the real engine of the system: + - Ticks every ~1s (`OnElapsed`), decrementing durations and removing expired effects. + - Aggregates all active effects into one `EffectAggregate` per tick (sum of DoT/HoT/Winds- + over-time/speed mods/resistances/amplifications across `AttackTypeMask`×`DamageType`), + exposed via `GetAmplifiers`/`GetResistances`/`GetMovementSpeedModifier`/etc. for other + systems (damage models, agent driven properties) to query. + - Owns a pooled particle-visual system (`StatusParticleVisualPoolEntry`) so repeated + stacking/refreshing of the same effect on the same agent reuses particle systems + instead of recreating them, with a dormant-pool cleanup timer. + - Restores/resynchronizes `AgentDrivenProperties` (speed, swing/reload speed, mount stats) + when effects apply or expire (`SynchronizeBaseValues`/`RefreshStatusStateAfterRemoval`). +- **`StatusEffectMissionLogic`** (`: MissionLogic`) — mission-level driver that ticks every + agent's `StatusEffectComponent` (added in `SubModule.OnMissionBehaviorInitialize`). + +Consumed by `AbilitySystem` (spell/prayer effects), `BattleMechanics/TriggeredEffect` +(`AssociatedStatusEffects`), and item enchantments (`Items/ItemTrait`). diff --git a/CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md b/CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md new file mode 100644 index 00000000..9cf53373 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md @@ -0,0 +1,33 @@ +# BattleMechanics/TriggeredEffect + +The data-driven "payload" system for what happens when a spell/weapon/trap fires: damage, +healing, status-effect application, unit summoning, prefab spawning, or running a named +custom script. Both `AbilitySystem` (via `Ability.Template.TriggeredEffects`) and item +weapon-hit scripts (`Items/WeaponHitScripts`) resolve their actual effects through this. + +- **`TriggeredEffectTemplate`** (`ITemplate`) — XML data: `DamageType`/`DamageAmount`/ + `DamageVariance`, `Radius`/`HasShockWave`, `TargetType` (Self/Enemy/Friendly/All), + `ImbuedStatusEffects` (→ resolved to `StatusEffectTemplate`s), particle/sound feedback, + and optional `ScriptNameToTrigger` (reflection-instantiated `ITriggeredScript`), + `SpawnPrefabName`, or `TroopIdToSummon`/`NumberToSummon` for summon effects. +- **`TriggeredEffectManager`** (static) — loads/indexes templates + (`LoadTemplates`, from `SubModule.OnSubModuleLoad`), `GetTemplateWithId`/ + `GetTemplatesWithIds` used everywhere a `TriggeredEffects` string list needs resolving. +- **`TriggeredEffect`** (`IDisposable`) — runtime `Trigger(...)` call: resolves targets by + `TargetType` + radius, applies the `TORAbilityModel`'s skill/perk scaling + (`GetSkillEffectivenessForAbilityDamage`, radius/duration scaling) when in campaign, + routes damage/heal through `TORMissionHelper.DamageAgents`/`HealAgents`, queues status + effects (batches through `AbilityManagerMissionLogic` when present, for correct + visual/sound sequencing and spell-session bookkeeping), spawns burst + particles/sound, and finally reflection-invokes the configured `ITriggeredScript`. + Uses a small time-delayed disposal queue (`ProcessPendingDisposals`) to avoid + disposing sound handles mid-tick. +- **`AnimationTrigger`/`AnimationTriggerManager`/`AnimationTriggerMissionLogic`** — + separate, simpler system: named triggers fired from animation events (e.g. a weapon + swing keyframe) rather than ability/weapon-hit code; `AnimationTriggerTuple` pairs a + trigger name with its handler. + +## Subfolder + +- **`Scripts/`** — `ITriggeredScript` implementations invoked via `ScriptNameToTrigger` + (see its CLAUDE.md). diff --git a/CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md b/CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md new file mode 100644 index 00000000..c9656422 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md @@ -0,0 +1,26 @@ +# BattleMechanics/TriggeredEffect/Scripts + +`ITriggeredScript` (`OnTrigger(position, triggerer, targets, duration)`) implementations, +reflection-instantiated by `TriggeredEffect.TriggerScript` via +`TriggeredEffectTemplate.ScriptNameToTrigger`. One-off bespoke behaviors too specific to +generalize into template fields. + +- **`DynamicItemTraitScripts.cs`** — largest file; one class per weapon/item enchantment + proc effect (Lore-of-Magic flavored): `ApplySwiftShiverTrait`, `ApplyHagbaneTrait`, + `ApplyStarFireTrait`, `ApplyFlamingItemTraitScript`/`ApplyLesserFlamingItemTraitScript`, + `ApplyLightItemTraitScript`/`ApplyLesserLightItemTraitScript`, + `ApplyHeavensItemTraitScript`/`ApplyLesserHeavensItemTraitScript`/`ApplyGreaterHeavensItemTraitScript`/`ApplyMightyHeavensItemTraitScript`, + `ApplyDeathDamageItemTraitScript`, `ApplyMetalItemTraitScript`, + `ApplyQuickSilverWeaponItemTraitScript`, `ApplyHolyItemTraitScript`, + `ApplyAzyrForesightScript`, `EnchantWeaponScript`, `ApplyTranquillityCadaiTrait`, + `SpiritLeech` — each applies a specific `Items/ItemTrait` / status effect on hit. +- **`RuneMagicScripts.cs`** — Dwarf Rune Magic procs: `OathAndSteelScript`, + `HearthAndHome`, `SpellbreakerRuneScript`, `WrathAndRuinScript`. +- **`AnvilOfDoomSpawnerScript`** — spawns the Anvil of Doom prop (Runelord/Runesmith + ability prerequisite, see `AbilitySystem/Ability.IsDisabled`). +- **`PrefabSpawnerScript`** — generic "spawn this prefab" trigger. +- **`SummonScript`** — spawns `TroopIdToSummon` × `NumberToSummon` (Summoning abilities). +- **`KnockDownScript`** — knocks affected agents down. +- **`TraitHelper`** (static) — shared helpers for the trait scripts above. +- **`ITriggeredScript`** — the interface itself (also implemented by + `AbilitySystem/Scripts/TeleportScript.TeleportTriggeredScript`). diff --git a/CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md new file mode 100644 index 00000000..581fc8e2 --- /dev/null +++ b/CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md @@ -0,0 +1,15 @@ +# BattleMechanics/Voice + +Custom voice-over playback that bypasses the native `Agent.MakeVoice` (which the comments +note can crash for TOR's custom races/monsters). + +- **`TORVoiceManager`** (singleton) — loads `tor_voice_definitions.xml` (from the + TOR_Armory module's data folder) mapping a race/monster name to a `VoiceDefinition` + (internal class) of sound file names; `GetVoiceToPlay(agent, voiceType)` picks the right + line for that agent's race (human/vampire/skeleton/spirit_host/wraith/etc.) and + `SkinVoiceType`. Played back through `Audio/TORAudioManager`, not native FMOD voice events. + Initialized in `SubModule.OnSubModuleLoad`. +- **`AgentVoiceComponent(agent)`** (`: AgentComponent`) — per-agent component that requests + voice lines (hurt/death/battle cries) from the manager at the right moments. +- **`BattleShoutsMissionLogic`** (`: MissionLogic`) — mission-level trigger for battle-cry + style shouts (charge, morale events), added in `SubModule.OnMissionBehaviorInitialize`. diff --git a/CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md new file mode 100644 index 00000000..ffb950ba --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md @@ -0,0 +1,10 @@ +# CampaignMechanics/Assimilation + +Handles what happens to a settlement's population/culture when it changes hands between +very different factions (e.g. Greenskins sacking an Empire town) — Warhammer factions don't +peacefully "convert" the way vanilla Calradia cultures do. + +- **`AssimilationCampaignBehavior`** (`: CampaignBehaviorBase`) — the assimilation + mechanic itself (loyalty/culture drift, or replacement, after conquest). +- **`RaceFixCampaignBehavior`** — corrects/normalizes character race data that can drift + or mismatch after culture/faction changes (also see `HarmonyPatches/RaceFixPatches.cs`). diff --git a/CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md new file mode 100644 index 00000000..66055576 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md @@ -0,0 +1,5 @@ +# CampaignMechanics/BountyMaster + +**`BountyMasterCampaignBehavior`** (`: CampaignBehaviorBase`) — a settlement service that +issues bounty-hunting contracts against enemies/criminals, rewarding the player for +tracking down and defeating the target. diff --git a/CSharpSourceCode/CampaignMechanics/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CLAUDE.md new file mode 100644 index 00000000..9a128333 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CLAUDE.md @@ -0,0 +1,62 @@ +# CampaignMechanics + +The largest folder: every `CampaignBehaviorBase` (registered in +`SubModule.InitializeGameStarter`) plus its supporting helpers/VMs/screens. This is where +Warhammer's setting gets expressed on the campaign map — factions, careers, religion, +custom resources (Waaagh, Teef, Oath Gold, Chivalry, Forest Harmony, Favor), diplomacy, +crafting/enchanting, and unique named characters/settlements. + +Most files follow one of these shapes: +- **`XyzCampaignBehavior` / `XyzTownBehavior`** (`: CampaignBehaviorBase`) — registers game + events (`AddBehaviors`) and reacts to them; one per mechanic, added individually in + `SubModule.cs`. +- **`XyzHelper`** (static) — pure logic/queries a behavior or UI delegates to. +- **`XyzVM` / `XyzScreen`** — Gauntlet view-model/screen pairs for a dedicated UI (crafting, + spellbook-adjacent, religion encyclopedia, etc.). + +## Root-level files + +- **`CampaignEventHelpers`** (static) — shared helpers for wiring up `CampaignEvents`. +- **`TorRecruitmentHelpers`/`TORAIRecruitmentCampaignBehavior`** — custom troop recruitment + rules (including AI lord recruitment). +- **`TORPartyUpgraderCampaignBehavior`** — custom troop-upgrade-path logic per party. +- **`TORCaptivityCampaignBehavior`** — custom prisoner/captivity handling. +- **`TORSpecialSettlementBehavior`** — hooks for TOR's special settlement types. +- **`TORFactionDiscontinuationCampaignBehavior`** — handles a faction ceasing to exist + (Warhammer factions can be wiped out/disabled, unlike vanilla's always-present kingdoms). +- **`TORStartupBehavior`** — first-run/new-campaign setup. +- **`GreenskinAICampaignBehavior`** — Waaagh-flavored AI behavior for Greenskin lords. +- **`SkillTrainerBehavior`** (+ `HeroTrainingData`) — companion/hero skill training over time. +- **`TorMapBarSpriteWidget`** (`: IconBrushWidget`) — custom map-bar icon widget. +- **`TORCampaignMusicHandler`** (`: IMusicHandler`) — custom campaign music selection. + +## Subfolders (one mechanic each — see each folder's own CLAUDE.md) + +- **`Assimilation/`** — race/culture "fixing" and assimilation of captured settlements. +- **`BountyMaster/`** — bounty-hunting contracts. +- **`Careers/`** — campaign-side glue for the Career system (dialogs, perks) — the core + Career data model itself lives in `CharacterDevelopment/CareerSystem`. +- **`Chaos/`** — the Chaos faction/invasion mechanic. +- **`CharacterCreation/`** — TOR's custom character-creation flow (race/culture specializations). +- **`Companions/`** — companion recruitment/AI companion behavior. +- **`Crafting/`** — weapon/armor enchanting system (screen, VMs, ingredients, loot). +- **`CustomDialogs/`** — extra conversation lines/behaviors + culture-specific + `ConversationTags/`. +- **`CustomEvents/`** — generic scripted campaign events framework. +- **`CustomResourceBehavior/`** — town/campaign behaviors that grant/spend custom resources. +- **`CustomResources/`** — the custom resource system itself (Waaagh, Teef, Oath Gold, + Chivalry, Forest Harmony, Favor) + `WaaaghMeter/` UI. +- **`Diplomacy/`** — alliances, trade agreements, kingdom decisions. +- **`MapNotifications/`** — custom map notification popups. +- **`MasterEngineer/`** — Dwarf Master Engineer town service. +- **`PostBattleLoot/`** — post-battle looted-troop bookkeeping. +- **`RaidingParties/`** — raider war-party AI/component. +- **`RaiseDead/`** — Vampire Counts/Necromancy raise-dead mechanics, graveyards, tree spirits. +- **`RegimentsOfRenown/`** — named elite unit regiments recruitable at settlements. +- **`Religion/`** — the religion/deity system and its encyclopedia page. +- **`ServeAsAHireling/`** — player-as-hireling activity. +- **`SpellTrainers/`** — trainers who teach spells/lores in town. +- **`TORCustomSettlement/`** — TOR's bespoke settlement types (Troll Cave, Chaos Portal, + Shrine, Herdstone, Cursed Site, Oak of Ages, World Roots, Slaver Camp) + their menus/components. +- **`UniqueSpawns/`** — named unique heroes/monsters spawned into the world (e.g. Orion). +- **`Villages/`** — custom village types. diff --git a/CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md new file mode 100644 index 00000000..7a7e5a86 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md @@ -0,0 +1,14 @@ +# CampaignMechanics/Careers + +Campaign-map glue for the Career system (the core data model — `CareerObject`, +`CareerChoiceObject`, perks — lives in `CharacterDevelopment/CareerSystem`; this folder is +the campaign-behavior/dialog layer on top of it). + +- **`TORCareerPerkCampaignBehavior`** (`: CampaignBehaviorBase`) — applies/reacts to + career perk effects at the campaign level (companion in + `BattleMechanics/CareerPerkMissionBehavior` for missions). +- **`CareerDialogOptionsCampaignBehavior`** — registers career-specific dialog lines/options. +- **`CareerButtonDialogs`** (static) — dialog text/logic backing the in-mission "career + button" special actions (see `CharacterDevelopment/CareerSystem/CareerButton`). +- **`GrailDamselEnvoyOfTheLadyPerkDialog`** — a specific perk-triggered dialog for the + Grail Damsel career's "Envoy of the Lady" perk. diff --git a/CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md new file mode 100644 index 00000000..8be93030 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md @@ -0,0 +1,6 @@ +# CampaignMechanics/Chaos + +**`ChaosCampaignBehavior`** (`: CampaignBehaviorBase`) — the Chaos faction/invasion +mechanic: escalating incursions from Chaos-aligned forces (spawned via +`CampaignMechanics/TORCustomSettlement/Component/ChaosPortalComponent` portals), +independent of the normal kingdom-war system. Added in `SubModule.InitializeGameStarter`. diff --git a/CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md new file mode 100644 index 00000000..e2921e9e --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md @@ -0,0 +1,35 @@ +# CampaignMechanics/CharacterCreation + +TOR's replacement character-creation flow: race/culture-specific narrative stages plus a +custom final "Specialization" stage (pick a starting profession/background per race). + +- **`TORCharacterCreationContentHandler`** (`: ICharacterCreationContentHandler`, singleton + `Instance`) — the central driver: builds `CharacterCreationOption`/`SpecializationOption` + lists, tracks stage navigation (`LastStageIndex`, per-stage selections e.g. Wood Elf gods + / Dwarf grudges / profession), applies the final race/equipment/religion/specialization + choice on finish. Has an in-code TODO noting it needs rework for the 1.3.1 native + `ICharacterCreationContentHandler` pattern (replaced the older `CharacterCreationContentBase`). +- **`CharacterCreationOption`** / **`SpecializationOption`** — XML-loadable option data for + the generic stages and the custom specialization stage respectively. +- **`TORSpecializationStage`** (`: CharacterCreationStageBase`) — the custom final stage. + - **`TORSpecializationStageView`** (`: CharacterCreationStageViewBase`) — its Gauntlet view. + - **`TORSpecializationStageVM`** (+ `SpecializationOptionVM`, + `TORSpecializationGainedPropertiesVM`, `SpecializationAttributeGroupVM`, + `SpecializationAttributeVM`, `SpecializationSkillItemVM`, `FocusIconVM`, all in the same + file) — the stage's view-model tree, showing attribute/skill/focus gains per option. +- **`FaceGenHelper`** (static) — face-generation helpers per race (pairs with + `HarmonyPatches/FaceGenPatches.cs`). +- **`TORCharacterCreationException`** (+ `TORCCXmlLoadException`, + `TORCCSpecializationStageLoadException`, `TORCCReflectionException`, + `TORCCEquipmentUpdateException`, `TORCCInvalidOptionTypeException`) — a small exception + hierarchy for reporting specific character-creation data/loading failures. + +## TODO + +- **`TORSpecializationStageView`** used to track an instance `_wasVisited` flag (set true + on affirmative action, reset false when backing out to jump to the Profession stage), + deliberately instance-scoped rather than static "to prevent cross-session contamination + when creating multiple characters" per its own comment — but nothing ever read it, so it + was removed as dead code (see the TODO comment left at its old declaration site). Restore + it if visited-state still needs tracking; likely related to the class's other in-code TODO + about needing a full rework for the 1.3.1 `ICharacterCreationContentHandler` pattern. diff --git a/CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md new file mode 100644 index 00000000..4a304df5 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md @@ -0,0 +1,7 @@ +# CampaignMechanics/Companions + +- **`TORCompanionsCampaignBehavior`** (`: CampaignBehaviorBase`) — custom companion + recruitment/management rules (companion pools likely skewed by culture/race, matching + Warhammer factions). +- **`TORAICompanionCampaignBehavior`** — AI-side companion behavior (how AI lords use/hire + companions). diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md new file mode 100644 index 00000000..906069b1 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md @@ -0,0 +1,28 @@ +# CampaignMechanics/Crafting + +TOR's item-enchanting system: a full Gauntlet screen (separate from vanilla smithing) that +applies magical `Items/ItemTrait`s to weapons/armor using ingredients and priest/artisan +services. + +- **`EnchantmentHelper`** (static) — `CreateEnchantedItem`: clones an `ItemObject` with a + fresh generated id and applies the chosen traits/`ItemModifier`, optionally flagged + player-crafted. +- **`EnchantingScreen`** (`: ScreenBase, IGameStateListener`) + **`EnchantingState`** + (`: GameState`) — the screen/state pair that opens the enchanting UI. +- **`EnchantingVM`** (root view-model) with supporting VMs: **`EnchantableItemVM`** + (an item eligible for enchanting), **`EnchantableTraitVM`** (a selectable trait/effect), + **`EnchantingIngredientVM`** (+ **`EnchantingIngredientWidget`** `: RichTextWidget`, + internal), **`EnchantingItemTableauVM`** (3D item preview tableau). +- **`EnchanterTownBehavior`** (`: CampaignBehaviorBase`) — the town service entry point + that opens `EnchantingScreen`. +- **`PriestBehavior`** (`: CampaignBehaviorBase`) — a related town service (priest-blessed + enchantments/holy traits, ties into `CampaignMechanics/Religion`). +- **`TORArtisanDistrictCampaignBehavior`** (+ `TorItemDuplicationData`, + `TorItemBeingCraftedData`) — an artisan-district crafting service (queued item + crafting/duplication over time). +- **`LootCampaignBehavior`** / **`EnchantmentIngredientLootCampaignBehavior`** — adds + enchanting ingredients and enchanted items to post-battle/dungeon loot tables. + +See `Items/TorEnchantingIngredients`, `Items/ItemTrait`, and +`Models/TOREnchantmentCraftingModel`/`TOREnchantmentIngredientsModel` for the underlying +data/cost models this UI drives. diff --git a/CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md new file mode 100644 index 00000000..bd57fa6e --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md @@ -0,0 +1,23 @@ +# CampaignMechanics/CustomDialogs + +Extra conversation content: new dialog flows/behaviors plus (in `ConversationTags/`) the +`ConversationTag`s that gate culture/race-specific lines in both vanilla and TOR dialogs. + +- **`CustomDialogCampaignBehavior`** (`: CampaignBehaviorBase`) — registers TOR's general + additional dialog lines/flows. +- **`TORCompanionDialogBehavior`** — companion-specific conversation content. +- **`CareerSwitchCampaignBehavior`** — the dialog/flow for changing a hero's Career. +- **`DuelBehavior`** — dialog-triggered honor duels (see also + `Missions/DuelFightMissionController`). +- **`BloodKissSceneNotificationItem`** (`: SceneNotificationData`) — a scripted scene + notification for the Vampire "Blood Kiss" (turning a companion into a vampire) narrative + moment. + +## Subfolder + +- **`ConversationTags/`** — `ConversationTag` (`IsApplicableTo(CharacterObject)`) + implementations used as dialog conditions, one file per race/culture family: + `CommonTags` (`PlayerIsRenownedTag`), `HumanTags` (Bretonnian/Empire/Warrior + Priest/Grail Knight checks), `DwarfTags`, `AsraiTag` (+ elf/player-is-elf variants), + `EonirTag`, `GreenskinTags` (orc/goblin), `VampireTags` (male/female), `BloodDragonTag`, + `MousillonTag`. diff --git a/CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md new file mode 100644 index 00000000..225cff56 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md @@ -0,0 +1,18 @@ +# CampaignMechanics/CustomDialogs/ConversationTags + +`ConversationTag` implementations (`IsApplicableTo(CharacterObject character)`) used as +dialog line conditions/filters, so a conversation line can be written once and +automatically apply only to characters of the right race/culture/background. + +- **`CommonTags.cs`** — `PlayerIsRenownedTag` (player clan tier > 2). +- **`HumanTags.cs`** — `IsBretonnianTag`/`IsEmpireTag` and their `PlayerIs...` variants, + `IsWarriorPriestTag`/`PlayerIsWarriorPriestTag`, `PlayerIsGrailKnightTag`. +- **`DwarfTags.cs`** — `IsDwarfTag`, `PlayerIsDwarfTag`. +- **`AsraiTag.cs`** — `AsraiTag`, `ElfMaleTag`, `PlayerIsElfTag`, `PlayerIsAsraiTag`. +- **`EonirTag.cs`** — `EonirTag`, `PlayerIsEonirTag`. +- **`GreenskinTags.cs`** — `IsOrcTag`, `IsGoblinTag`, `PlayerIsOrcTag`. +- **`VampireTags.cs`** — `VampireMaleTag`, `VampireFemaleTag`. +- **`BloodDragonTag.cs`** / **`MousillonTag.cs`** — specific vampire bloodline/culture tags. + +Referenced from dialog registration code in `../CustomDialogCampaignBehavior` and other +`CampaignBehaviorBase`s that add conversation lines via `CampaignGameStarter.AddDialogLine`. diff --git a/CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md new file mode 100644 index 00000000..f3f9b198 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md @@ -0,0 +1,14 @@ +# CampaignMechanics/CustomEvents + +A generic scripted-event framework: named events with a frequency tier, cooldown, a +condition predicate, and a consequence action — a lightweight alternative to writing a +full `CampaignBehaviorBase` for every one-off flavor event. + +- **`CustomEvent`** — `(StringId, CustomEventFrequency, Cooldown, Func condition, + Action consequence)`; `DoesConditionHold()`/`Trigger()`. `CustomEventFrequency`: + Rare/Uncommon/Common/Abundant/Special. +- **`CustomEventsCampaignBehavior`** (`: CampaignBehaviorBase`) — periodically rolls + registered `CustomEvent`s against their frequency/cooldown and fires the ones whose + condition holds. +- **`SimpleCareerQuestBehavior`** (`: CampaignBehaviorBase`) — lightweight one-off + Career-flavor quests built on this same event pattern rather than a full `Quests/` quest class. diff --git a/CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md new file mode 100644 index 00000000..c0074a42 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md @@ -0,0 +1,10 @@ +# CampaignMechanics/CustomResourceBehavior + +Campaign/town behaviors that actually grant or spend the resources defined in +`../CustomResources`, keyed to specific settlement services: + +- **`OathGoldBehavior`** (+ `ExpeditionReward`) — Dwarf Oath Gold: expeditions and their + rewards (large file — the most developed of these systems). +- **`TeefBehavior`** — Greenskin Teef gain/spend hooks. +- **`PrestigeNobleTownBehavior`** — Empire Prestige gained via noble/town interactions. +- **`EonirFavorEnvoyTownBehavior`** — Eonir Council Favor via an envoy town service. diff --git a/CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md new file mode 100644 index 00000000..e5507f83 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md @@ -0,0 +1,31 @@ +# CampaignMechanics/CustomResources + +TOR's per-culture "second currency" system — each major culture has its own thematic +resource tracked alongside gold/influence. + +- **`CustomResource`** — definition: `StringId`, localized name/description + (`tor_custom_resource_name/description` game texts), icon, which culture(s) it belongs to, + and an optional custom tooltip function. `GetCustomResourceIconAsText` renders it as an + inline `` tag for use in UI text. +- **`CustomResourceManager`** (singleton) — registers all resources on `Initialize()` + (called from `SubModule.InitializeGameStarter`): + - Empire → **Prestige** + - Bretonnia → **Chivalry** (`ChivalryHelper`) + - Sylvania/Mousillon (Vampire factions) → **DarkEnergy** + - Asrai (Wood Elves) → **ForestHarmony** (`ForestHarmonyHelper`) + - Eonir (Wood Elves) → **CouncilFavor** (`FavorHelper`) + - Dawi (Dwarfs) → **OathGold** (`OathGoldHelper`) + - Greenskin → **Teef**/**Waaagh** (see `TeefHelper`, `WaaaghMeter/`) + + Also tracks a `_massBudget`/`_resourceChanges` and hooks the party screen + (`ScreenManager.OnPushScreen/OnPopScreen`) to show resource changes in the party UI. +- **`ChivalryHelper` / `ForestHarmonyHelper` / `FavorHelper` / `OathGoldHelper` / `TeefHelper`** + (static) — per-resource gain/spend rules and tooltip info providers. + +Actual gain/spend triggers live in the sibling `CustomResourceBehavior/` folder; +`Models/TORCustomResourceModel` governs generalized cost scaling +(`CustomResource.GetCustomResourceGeneralizedFactor`). + +## Subfolder + +- **`WaaaghMeter/`** — Greenskin-specific Waaagh resource UI (map view + VM) and behavior. diff --git a/CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md new file mode 100644 index 00000000..7a4f7e16 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md @@ -0,0 +1,11 @@ +# CampaignMechanics/CustomResources/WaaaghMeter + +Greenskin "Waaagh" meter — a mass-momentum resource that grows as Greenskin factions +win battles/raid, unlocking benefits at thresholds ("Big Waaagh"). + +- **`WaaaghBehavior`** (`: CampaignBehaviorBase`) — accrues/decays the meter based on + campaign events; ties into `WaaaghHelper` for the actual math and + `AbilitySystem/Spells/LoreObject` ("BigWaaagh" lore unlock). +- **`WaaaghHelper`** (static) — gain/threshold calculations. +- **`WaaaghMeterMapView`** (`: MapView`) — the on-map meter widget. +- **`WaaaghMeterVM`** — its view-model. diff --git a/CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md new file mode 100644 index 00000000..4855879b --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md @@ -0,0 +1,19 @@ +# CampaignMechanics/Diplomacy + +Alliance/war/trade-agreement mechanics beyond vanilla kingdom diplomacy. + +- **`HonorAllianceDecision`** (`: KingdomDecision`, + nested `HonorAllianceOutcome`, + + `HonorAllianceDecisionTypeDefiner : SaveableTypeDefiner`) — a Total-War-style forced + choice: when an ally is attacked, the kingdom must vote within 24h to either join the war + or break the alliance — no "do nothing and stay allied" option. +- **`TORAllianceWarBehavior`** (`: CampaignBehaviorBase`, + + `TORAllianceWarBehaviorTypeDefiner : SaveableTypeDefiner`) — tracks alliances and raises + `HonorAllianceDecision`s when one is tested; persists alliance state via the type definer. +- **`TORKingdomDecisionsCampaignBehavior`** — registers/manages TOR's custom kingdom + decisions generally. +- **`TORTradeAgreementAIBehavior`** — AI logic for proposing/accepting trade agreements + (see `Models/TORTradeAgreementModel`, `Models/DiplomacyHelpers`). + +See `Models/TORAllianceModel`, `Models/TORDiplomacyModel`, +`Models/TORKingdomDecisionPermissionModel` for the scoring/permission rules these behaviors +call into. diff --git a/CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md new file mode 100644 index 00000000..954ebbf7 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md @@ -0,0 +1,5 @@ +# CampaignMechanics/MapNotifications + +- **`TORMapNotification`** (`: InformationData`) — a custom map notification payload + (icon/text for TOR-specific events not covered by vanilla notification types). +- **`TORMapNotificationView`** (`: MapNotificationView`) — its Gauntlet view. diff --git a/CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md new file mode 100644 index 00000000..9fb8e2c0 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md @@ -0,0 +1,5 @@ +# CampaignMechanics/MasterEngineer + +**`MasterEngineerTownBehaviour`** (`: CampaignBehaviorBase`) — a Dwarf-flavored town +service where a Master Engineer NPC offers engineering-related interactions (likely +artillery/equipment crafting or upgrades — pairs with `Quests/EngineerQuest`). diff --git a/CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md new file mode 100644 index 00000000..66b8a9d1 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md @@ -0,0 +1,5 @@ +# CampaignMechanics/PostBattleLoot + +**`PendingLootedTroopManager`** (static) — tracks troops/items looted from a battle that +are pending resolution (e.g. captured troops or gear to be claimed after the post-battle +screen), decoupling the moment of victory from when loot is actually granted. diff --git a/CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md new file mode 100644 index 00000000..e81c5412 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md @@ -0,0 +1,9 @@ +# CampaignMechanics/RaidingParties + +Raider-type war parties (Greenskin/Chaos/Beastmen war-bands that raid rather than hold territory). + +- **`IRaidingParty`** — marker/contract interface for a raiding party component. +- **`RaidingPartyComponent`** (`: WarPartyComponent, IRaidingParty`) — the party component + itself: identifies a `MobileParty` as a raider band with raiding-specific AI/lifecycle. +- **`RaidingPartyCampaignBehavior`** (`: CampaignBehaviorBase`) — spawns/manages raiding + parties campaign-wide (from `../TORCustomSettlement` raider-spawner settlements, etc.). diff --git a/CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md new file mode 100644 index 00000000..a2599c6e --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md @@ -0,0 +1,12 @@ +# CampaignMechanics/RaiseDead + +Vampire Counts / Mousillon (undead) and Asrai (tree spirit) resurrection-flavored mechanics. + +- **`RaiseDeadInTownBehavior`** (`: CampaignBehaviorBase`) — a town service letting an + undead-aligned player raise fallen troops as undead reinforcements. +- **`PostBattleCampaignBehavior`** — post-battle hook that ties into raising the dead after + a fight (corpses available to raise scale with the battle just fought). +- **`GraveyardNightWatchPartyComponent`** (`: PartyComponent`) — a party that guards a + graveyard at night (tied to `BattleMechanics` graveyard fight content in `Missions/`). +- **`TreeSpiritHelpers`** (static) — Wood Elf tree-spirit summoning/raising helpers + (parallel mechanic for Asrai, thematically similar to undead raising). diff --git a/CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md new file mode 100644 index 00000000..55dd229e --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md @@ -0,0 +1,11 @@ +# CampaignMechanics/RegimentsOfRenown + +Named elite "Regiment of Renown" units (a tabletop Warhammer concept: unique, upgraded +unit templates) recruitable from specific settlements. + +- **`RORManager`** (static) — loads/indexes ROR templates (`LoadTemplates`, called from + `SubModule.OnSubModuleLoad`). +- **`RORSettlementTemplate`** — links a settlement to the regiment(s) it can recruit. +- **`RORCampaignBehavior`** (`: CampaignBehaviorBase`) — availability/recruitment logic. +- **`ToRSettlementNameplateVM`** (`: SettlementNameplateVM`) — extends the map settlement + nameplate VM, presumably to flag settlements offering a Regiment of Renown. diff --git a/CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md new file mode 100644 index 00000000..499b3950 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md @@ -0,0 +1,22 @@ +# CampaignMechanics/Religion + +Warhammer deity/pantheon system layered onto heroes and settlements. + +- **`ReligionObject`** (`: MBObjectBase`, XML-defined via `MBObjectManager`) — a deity/faith: + name, deity name, lore/blessing text, associated `CultureObject`, `Pantheon` enum, + `HostileReligions` (feeds `GetHostilityFactor`, used by diplomacy/relations math), + religious troops/elite units/artifacts, `InitialClans`. `FillAll()` loads the full list + from `Religions.xml` (`SubModule.BeginGameStart`). Has an encyclopedia link. +- **`ReligionObjectHelper`** (static) — queries/helpers (e.g. a hero's dominant religion, + compatibility scoring between religions/pantheons). +- **`ReligionCampaignBehavior`** (`: CampaignBehaviorBase, IDisposable`) — the runtime + mechanic: heroes gain/lose faith, blessings apply, hostility affects relations. +- **`ReligionEncyclopediaPage`** (`: EncyclopediaPage, IPublicEncyclopediaPage`) + + **`TorEncyclopediaModel`** (`: OverrideEncyclopediaModel`) + + **`TorEncyclopediaListItemNameComparer`** — adds a Religion category/page to the game's + encyclopedia. +- **`EncyclopediaReligionObjectVM`** (`: EncyclopediaContentPageVM`) — the page's view-model. + +Settlements can be tied to a religion via `ReligionObject` on +`CampaignMechanics/TORCustomSettlement/Component/TORBaseSettlementComponent` (shrines, etc.). +Also see `Models/TORFaithModel`. diff --git a/CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md new file mode 100644 index 00000000..a4b078ae --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md @@ -0,0 +1,9 @@ +# CampaignMechanics/ServeAsAHireling + +Lets the player take service as a hireling under an AI lord/faction instead of leading +their own party. + +- **`ServeAsAHirelingCampaignBehavior`** (`: CampaignBehaviorBase`) — entry/exit points and + state management for the activity. +- **`ServeAsAHirelingActivities`** — the day-to-day activities/tasks performed while serving. +- **`ServeAsAHirelingHelpers`** (static) — shared query/eligibility helpers. diff --git a/CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md new file mode 100644 index 00000000..2d15b6e6 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md @@ -0,0 +1,7 @@ +# CampaignMechanics/SpellTrainers + +**`SpellTrainerInTownBehavior`** (`: CampaignBehaviorBase`) — a town service where an NPC +trainer teaches the player/companions spells from a `LoreObject` (see +`AbilitySystem/Spells/LoreObject`), gated by culture eligibility — including the special +Spellweaver dialog bypass that lets Asrai Spellsingers learn High/Dark Magic despite the +normal culture lock (see the note in `AbilitySystem/Spells/CLAUDE.md`). diff --git a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md new file mode 100644 index 00000000..6bd0d019 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md @@ -0,0 +1,37 @@ +# CampaignMechanics/TORCustomSettlement + +TOR's bespoke settlement/world-object types — special map locations beyond +towns/castles/villages, each with its own component, menu, and (usually) a +`CampaignBehaviorBase`. Registered as engine object types in `SubModule.BeginGameStart` +(`game.ObjectManager.RegisterType<...Component>(...)`). + +- **`TORCustomSettlementCampaignBehavior`** — umbrella behavior wiring the custom + settlement types into the campaign (spawning, menus, persistence). +- **`TrollCaveCampaignBehavior`** — Troll Cave lair: spawns defending trolls + (`TrollCaveDefenderPartyComponent`), raidable by the player. +- **`GreenskinBrawlBehavior`** (+ `BrawlMissionResult`) — Greenskin settlement brawl + mini-game (scored mission result feeding back into the campaign). +- **`GoblinRecruitmentBehavior`** — goblin troop recruitment from custom settlements. +- **`TORSettlementMenuHelpers`** (static) — shared menu-building helpers for the + `CustomSettlementMenus/` logic classes. + +## Subfolders + +- **`Component/`** — `SettlementComponent` subclasses, one per settlement type (see its + CLAUDE.md): `TORBaseSettlementComponent` (abstract base: owner clan, `ReligionObject`, + active flag) → `BaseRaiderSpawnerComponent` (abstract, spawns raiders periodically) → + `ChaosPortalComponent`, `HerdStoneComponent`, `SlaverCampComponent`, `TrollCaveComponent`; + plus `CursedSiteComponent`, `OakOfAgesComponent`, `ShrineComponent`, `WorldRootsComponent`. +- **`CustomSettlementMenus/`** — `TORBaseSettlementMenuLogic` (abstract) and its concrete + per-settlement-type menu builders (Troll Cave, Cursed Site, Oak of Ages, Shrine, + Raiding Site). + +## TODO + +- **`TORCustomSettlementCampaignBehavior`**'s victory-loot item selection has a stray + `continue;` right after the first line of its enchanting loop (near the + `unmodifiedItems`/`enchantedItems` split), which skips the ~90 lines of "lesser_loot" + item-trait selection entirely. Victory loot from Chaos Portal/Troll Cave/etc. currently + never receives enchantments — every item passes through unmodified. The dead code is + still there (warning-suppressed, not deleted), pending a decision on whether to + re-enable it or remove it for good — found while enabling `TreatWarningsAsErrors`. diff --git a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md new file mode 100644 index 00000000..b454339a --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md @@ -0,0 +1,18 @@ +# CampaignMechanics/TORCustomSettlement/Component + +`SettlementComponent` subclasses, one per bespoke settlement/world-object type registered +in `SubModule.BeginGameStart`. + +- **`TORBaseSettlementComponent`** (abstract `: SettlementComponent`) — shared base: parses + common XML attrs (`background_mesh`, `wait_mesh`, `background_crop_position`, `religion`), + resolves `Religion` (`CampaignMechanics/Religion`), tracks `OwnerClan`/`IsActive`. + - **`BaseRaiderSpawnerComponent`** (abstract) — adds periodic raider-troop spawning; base + for the "hostile lair" settlement types: + - **`ChaosPortalComponent`** — Chaos incursion portal. + - **`HerdStoneComponent`** — Beastmen herdstone. + - **`SlaverCampComponent`** — Dark Elf/Norscan-style slaver camp. + - **`TrollCaveComponent`** — troll lair (pairs with `../TrollCaveCampaignBehavior`). + - **`CursedSiteComponent`** (`IDisposable`) — a cursed/haunted site (Vampire-flavored). + - **`OakOfAgesComponent`** — Wood Elf sacred site. + - **`ShrineComponent`** — a religious shrine tied to a `ReligionObject`. + - **`WorldRootsComponent`** — Wood Elf world-roots network site. diff --git a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md new file mode 100644 index 00000000..cac00cf8 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md @@ -0,0 +1,17 @@ +# CampaignMechanics/TORCustomSettlement/CustomSettlementMenus + +Settlement-menu ("wait menu") builders for the custom settlement types in `../Component`. + +- **`TORBaseSettlementMenuLogic`** (abstract) — shared menu-registration scaffolding + (takes a `CampaignGameStarter`). +- **`TrollCaveMenuLogic`**, **`CursedSiteMenuLogic`**, **`OakOfAgesMenuLogic`**, + **`ShrineMenuLogic`**, **`RaidingSiteMenuLogic`** — one concrete menu per settlement type, + built with `../TORSettlementMenuHelpers`. + +## TODO + +- **`TrollCaveMenuLogic`** used to track an `_isClearingCave` flag (true when clearing the + cave, false when a luring attempt goes wrong) but nothing downstream ever read it, so it + was removed as dead code (see the TODO comment left at its old declaration site). If + `StartClearCave`/`StartTrollBattle` are meant to diverge on outcome (different + loot/message/etc.), that distinction still needs implementing. diff --git a/CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md new file mode 100644 index 00000000..5a2362da --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md @@ -0,0 +1,11 @@ +# CampaignMechanics/UniqueSpawns + +Named unique heroes/monsters spawned into the campaign world (lore characters/creatures +rather than generic troops). + +- **`UniqueSpawnCampaignBehavior`** (`: CampaignBehaviorBase`) — generic framework for + spawning and tracking unique named entities. +- **`UniqueSpawnPartyComponent`** (`: WarPartyComponent`) — party component marking a + unique spawn's war party. +- **`OrionCampaignBehavior`** — a specific named unique spawn (Orion, the Wood Elf King in + the Wood — a Warhammer lore character), its own dedicated behavior. diff --git a/CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md new file mode 100644 index 00000000..12ed1a57 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md @@ -0,0 +1,6 @@ +# CampaignMechanics/Villages + +- **`TORVillageTypes`** (`: DefaultVillageTypes`) — TOR's replacement/extension of the + vanilla village-type list (per-culture village flavors matching Warhammer factions). +- **`TORTownManagementVillageItemVM`** — view-model for a village row in the town + management screen, extended for TOR's village data. diff --git a/CSharpSourceCode/CharacterDevelopment/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CLAUDE.md new file mode 100644 index 00000000..38162005 --- /dev/null +++ b/CSharpSourceCode/CharacterDevelopment/CLAUDE.md @@ -0,0 +1,36 @@ +# CharacterDevelopment + +Character progression data: skills, attributes, perks, traits, and the Career system +(Warhammer-flavored "prestige classes" like Grail Knight, Witch Hunter, Runelord, Slayer, +Orc Boss). Most root-level files are static-ish registries initialized once at startup +(`SubModule.BeginGameStart`/game object registration) mirroring vanilla's +`DefaultSkills`/`DefaultTraits` pattern. + +## Root-level registries + +- **`TORSkills`** — TOR's additional skill definitions. +- **`TORSkillEffects`** — skill-driven passive effects. +- **`TORAttributes`** — additional character attributes. +- **`TORCharacterTraits`** — additional personality/character traits. +- **`TORPerks`** (+ nested static `Spellcraft`, `GunPowder`, `Faith` groups) — TOR's extra + perks, grouped by theme (e.g. `TORPerks.Spellcraft.ArcaneLink`, referenced by + `BattleMechanics/TriggeredEffect/TriggeredEffect`). +- **`TORPerkHandlerCampaignBehavior`** (`: CampaignBehaviorBase`) — applies perk effects + campaign-side. +- **`TORCareers`** — registry of every `CareerObject` (Blood Knight, Grail Damsel, Grail + Knight, Mercenary, Minor Vampire, Necromancer, Warrior Priest [+ Ulric variant], Witch + Hunter, Black Grail Knight, Necrarch, Imperial Magister, Waywatcher, Spellsinger, Warden, + Grey Lord, Knight of the Old World, Ironbreaker, Slayer, Runelord, Orc Boss, Orc Shaman). +- **`TORCareerChoices`** (+ `CareerHasNoChoicesException`) — registry of all + `CareerChoiceObject`s (the perk-tree nodes within a career). +- **`TORCareerChoiceGroups`** — registry of `CareerChoiceGroupObject`s (tiers/branches + grouping choices within a career tree). +- **`CareerAbilityChargeSupplier`** (static) — supplies charge-gain hooks for careers whose + signature ability builds "charge" from combat actions rather than a plain cooldown + (`ChargeType.Custom` on `CareerObject`). + +## Subfolder + +- **`CareerSystem/`** — the Career data model itself (`CareerObject`, `CareerChoiceObject`, + `CareerChoiceGroupObject`), its screen/VMs, and the perk-tree "special button" + + per-career choice-effect implementations (see its CLAUDE.md). diff --git a/CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md new file mode 100644 index 00000000..82e06db7 --- /dev/null +++ b/CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md @@ -0,0 +1,40 @@ +# CharacterDevelopment/CareerSystem + +The Career data model — Warhammer "prestige class" progression (Grail Knight, Witch +Hunter, Runelord, Slayer, Orc Boss, etc.), each with a signature `CareerAbility` +(see `AbilitySystem/CareerAbility` + `AbilitySystem/Scripts/CareerAbilityScript`), a perk +tree, and often a special right-click "career button" action. + +## Core model + +- **`CareerObject`** (`: PropertyObject`, XML-defined via `MBObjectManager`) — one career: + `AbilityTemplateID`/`AbilityScriptType` (its signature ability), `ChargeType` + (`CooldownOnly` vs `Custom`, the latter driven by a `ChargeFunction` computing charge from + combat hits — see `CareerAbilityChargeSupplier`), `RootNode`/`ChoiceGroups` (the perk tree), + an eligibility `Predicate`. `MutateAbility`/`MutateTriggeredEffect`/ + `MutateStatusEffect` let unlocked choices numerically tweak the career's ability/effects + at cast time (called from `AbilitySystem/Scripts/CareerAbilityScript`, + `BattleMechanics/StatusEffect/StatusEffectComponent`). +- **`CareerChoiceObject`** (`: PropertyObject`, + nested `MutationObject`, `PassiveEffect`) + — one perk-tree node: a `PassiveEffect` (flat/percentage stat bonus, + `PassiveEffectType`-keyed, consumed by `CareerHelper.ApplyBasicCareerPassives`/ + `AddCareerPassivesForDamageValues`) and/or a `MutationObject` (numeric tweak applied to + the career's ability/triggered-effect/status-effect). +- **`CareerChoiceGroupObject`** (`: PropertyObject`) — groups/tiers of `CareerChoiceObject`s + forming the tree structure. +- **`CareerHelper`** (static) — the query/application layer used everywhere else in the + codebase: `ApplyBasicCareerPassives`, `AddCareerPassivesForDamageValues` (feeds + `BattleMechanics/DamageSystem/TORDamageHelper`), `IsValidCareerMissionInteractionBetweenAgents`, + `PrayerCooldownIsNotShared`. +- **`CareerObjectVM`/`CareerChoiceObjectVM`/`CareerChoiceGroupObjectVM`** — view-models for + the tree UI; **`CareerAbilityEffectVM`** — shows the ability's current numeric effect. +- **`CareerScreen`** (`: ScreenBase, IGameStateListener`) + **`CareerScreenGameState`** + (`: GameState`) + **`CareerScreenVM`** — the dedicated Career screen (pick/respec choices). + +## Subfolders + +- **`Choices/`** — one `TORCareerChoicesBase` subclass per career, registering that + career's actual `CareerChoiceObject`/`PassiveEffect`/`MutationObject` data + (see its CLAUDE.md). +- **`CareerButton/`** — right-click "special action" buttons some careers add to the + party/prisoner screen (see its CLAUDE.md). diff --git a/CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md new file mode 100644 index 00000000..71eb61f2 --- /dev/null +++ b/CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md @@ -0,0 +1,27 @@ +# CharacterDevelopment/CareerSystem/CareerButton + +Right-click "special action" buttons that some careers add to the party-roster/prisoner +screen (e.g. sacrificing a prisoner, converting a troop, using a career resource on a unit) +— distinct from the in-mission `CareerAbility`. + +- **`CareerButtonBehaviorBase`** (abstract, ctor takes the owning `CareerObject`) — contract: + `ButtonClickedEvent`, `ShouldButtonBeVisible`, `ShouldButtonBeActive` (+ disable reason + text), `CareerButtonIcon`; registers itself with + `SpecialbuttonEventManagerHandler.Instance` via `Register()`. +- **`SpecialbuttonHandler.cs`** — **`SpecialbuttonEventManagerHandler`** (singleton) — the + registry/dispatcher all button behaviors register into; routed to from wherever the + roster screen fires its click event (see `HarmonyPatches`/`Extensions/UI`). +- **`CareerButtons`** — static list/lookup of all registered button behaviors. +- **`GreenskinCareerButton`** (abstract `: CareerButtonBehaviorBase`) — shared base for + Greenskin careers' buttons: + - **`OrcBossCareerButton`**, **`OrcShamanCareerButton`**. +- Per-career concrete behaviors: **`BlackGrailKnightCareerButtonBehavior`**, + **`GrailKnightCareerButtonBehavior`** (+ `KnightPuritySeal` in + `KnightOldWorldCareerButtonBehavior.cs`... see below), **`ImperialMagisterCareerButtonBehavior`** + (+ `PowerstoneHelper`/`PowerStone` — a resource-stone mechanic), **`IronbreakerCareerButton`** + (→ `IronbreakerCareerButtonBehavior`), **`KnightOldWorldCareerButtonBehavior`** + (+ `KnightPuritySeal`), **`MercenaryCareerButtonBehavior`**, **`NecrarchCareerButtonBehavior`**, + **`RunelordCareerButtonBehavior`** (+ `UnitRune`), **`SlayerCareerButtonBehavior`**, + **`WaywatcherCareerButtonBehavior`** (+ `ArrowType`), **`WitchHunterCareerButtonBehavior`**. +- **`CareerButtonHelper`** (static) — shared query/action helpers used across the concrete + behaviors above. diff --git a/CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md new file mode 100644 index 00000000..d5cf41fb --- /dev/null +++ b/CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md @@ -0,0 +1,19 @@ +# CharacterDevelopment/CareerSystem/Choices + +One `TORCareerChoicesBase` (abstract, ctor takes the owning `CareerObject`) subclass per +Career, registering that career's `CareerChoiceGroupObject`/`CareerChoiceObject` tree +(passives + ability mutations). `CareerChoicesHelper` (static) holds shared construction +helpers used by all of them. + +Subclasses (one per `CharacterDevelopment.TORCareers` entry): +`BlackGrailKnightCareerChoices`, `BloodKnightCareerChoices`, `GrailDamselCareerChoices`, +`GrailKnightCareerChoices`, `GreyLordCareerChoices`, `ImperialMagisterCareerChoices`, +`IronbreakerCareerChoices`, `KnightOldWorldCareerChoices`, `MercenaryCareerChoices`, +`NecrarchCareerChoices`, `NecromancerCareerChoices`, `OrcBossCareerChoices`, +`OrcShamanCareerChoices`, `RunelordCareerChoices`, `SlayerCareerChoices`, +`SpellsingerCareerChoices`, `VampireCountCareerChoices`, `WardenCareerChoices`, +`WarriorPriestCareerChoices`, `WarriorPriestUlricCareerChoices`, +`WaywatcherCareerChoices`, `WitchHunterCareerChoices`. + +Consumed by `CharacterDevelopment/TORCareerChoices`/`TORCareerChoiceGroups` at startup and +rendered by `../CareerScreenVM`/`CareerChoiceObjectVM`. diff --git a/CSharpSourceCode/Extensions/CLAUDE.md b/CSharpSourceCode/Extensions/CLAUDE.md new file mode 100644 index 00000000..a690938d --- /dev/null +++ b/CSharpSourceCode/Extensions/CLAUDE.md @@ -0,0 +1,30 @@ +# Extensions + +Grab-bag of C# extension methods on vanilla TaleWorlds types, plus two more structured +sub-frameworks: the "extended info" side-data system and the "view-model extension" UI +injection system. + +## Root-level extension method classes + +One static class per extended type, all in `TOR_Core.Extensions`: +`AgentExtensions`, `AgentDrivenPropertiesExtensions`, `BannerExtensions`, +`CharacterObjectExtensions`, `ClanExtensions`, `CollectionExtensions`, +`ConversationManagerExtensions`, `FormationExtensions`, `GameMenuExtensions`, +`GameModelsExtensions` (shortcuts to `Campaign.Current.Models.GetXyzModel()`), +`HeroExtensions`, `ItemObjectExtensions`, `KingdomExtension`, `MissionExtensions`, +`MobilePartyExtensions`, `SettlementExtensions`, `SkillExtensions`, `TeamExtensions`, +`ViewModelExtensions`. Also **`DebugMethods`** (static) — misc debug/diagnostic helpers. +These are the mod's "everywhere" utility layer — e.g. `AgentExtensions.GetHero()`, +`GetCareer()`, `GetAbility()`, `IsSpellCaster()`, `HasCareer()` used throughout +`AbilitySystem`/`BattleMechanics`/`CharacterDevelopment`. + +## `ExtendedInfoSystem/` + +TOR needs to attach extra runtime/persisted data to vanilla objects +(`CharacterObject`, `Hero`, `MobileParty`) without subclassing them — see its CLAUDE.md. + +## `UI/` + +The "view-model extension" pattern: attaches extra bindable properties/commands onto +vanilla Gauntlet `ViewModel`s (party screen, character developer, encyclopedia, crafting, +conversation, etc.) without needing a full custom screen — see its CLAUDE.md. diff --git a/CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md b/CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md new file mode 100644 index 00000000..01fd99c4 --- /dev/null +++ b/CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md @@ -0,0 +1,24 @@ +# Extensions/ExtendedInfoSystem + +Side-table data attached to vanilla `CharacterObject`/`Hero`/`MobileParty` instances (keyed +by string id) since those types can't be subclassed with extra fields. + +- **`ExtendedInfoManager`** (`: CampaignBehaviorBase`, singleton `Instance`) — owns the + dictionaries (`_characterInfos`, `_heroInfos`, `_partyInfos`, plus banner-resource and + settlement-info tables), loads static per-troop data from + `tor_extendedunitproperties.xml` (TOR_Core's ExtendedData folder), and hooks nearly every + relevant `CampaignEvents` (session launch, new game, hourly/daily/quarter-daily ticks, + hero created/killed, party created/destroyed, troop upgrades, battle end) to keep the + side-tables in sync. For `CustomGame` (non-campaign), `CreateDefaultInstanceAndLoad()` is + used instead (see `SubModule.InitializeGameStarter`). +- **`CharacterExtendedInfo`** (+ `ResourceCostTuple`, `ResistanceTuple`, `AmplifierTuple`, + `DamageProportionTuple`, all `IEquatable`) — per-`CharacterObject` extra data: resource + costs, damage-type resistances/amplifications/proportions (feeds + `BattleMechanics/DamageSystem/TORDamageHelper`), race/culture-driven combat traits. +- **`HeroExtendedInfo(character)`** — per-`Hero` data (e.g. `CareerID` — see + `AbilitySystem/Scripts/CareerAbilityScript.GetEffectsToTrigger`, — Winds of Magic pool, + religion/faith state). +- **`MobilePartyExtendedInfo`** — per-party data. + +Accessed via extension methods in `../HeroExtensions`/`../CharacterObjectExtensions`/ +`../MobilePartyExtensions` (e.g. `hero.GetExtendedInfo()`) rather than directly. diff --git a/CSharpSourceCode/Extensions/UI/CLAUDE.md b/CSharpSourceCode/Extensions/UI/CLAUDE.md new file mode 100644 index 00000000..a9b970e4 --- /dev/null +++ b/CSharpSourceCode/Extensions/UI/CLAUDE.md @@ -0,0 +1,36 @@ +# Extensions/UI + +A reflection-based "view-model extension" framework that bolts extra bindable +properties/commands onto vanilla Gauntlet `ViewModel`s, so TOR can add UI hooks to native +screens (party, character developer, encyclopedia, crafting/refinement, conversation, map +info, SP item tooltip) without subclassing or fully replacing them. + +- **`IViewModelExtension`** / **`BaseViewModelExtension`** (abstract, `IDisposable`) — base + for every extension: wraps a target `ViewModel` (`_vm`), and via reflection forwards + property/method access (`GetPropertyValue`/`SetPropertyValue`/`ExecuteCommand`/ + `GetViewModelAtPath`) to either the extension's own members (if declared on an + `IViewModelExtension`-derived type) or the wrapped VM's — letting Gauntlet's XML/Prefab + data-binding address extension properties as if they were on the original VM. Registers + itself with the manager on construction. +- **`ViewModelExtensionManager`** (singleton) — `CollectViewModelExtensions()` scans for + `[ViewModelExtension]`-attributed types at startup + (`SubModule.OnSubModuleLoad` calls `Initialize()` before Harmony patches, since patches + reroute vanilla VM construction to also construct/register the matching extension); holds + a `ConditionalWeakTable` so extensions are GC'd with their VM. +- **`ViewModelExtensionAttribute`** — marks a `BaseViewModelExtension` subclass and the + vanilla `ViewModel` type it targets. + +## Concrete extensions (one per extended vanilla VM) + +`PartyVMExtension` (+ `PendingResourceCostVM`), `PartyCharacterVMExtension`, +`CharacterDeveloperVMExtension`, `CraftingVMExtension`, `RefinementVMExtension`, +`ConversationItemVMExtension`, `MissionConversationVMExtension`, +`HeroEncyclopediaVMExtension`, `UnitEncyclopediaVMExtension`, `SPItemVMExtension`, +`TORMapInfoVMExtension`. + +## Other + +- **`TORInitialScreen`** (`: ScreenBase, IGameStateListener`) — TOR's replacement initial + loading/splash screen. +- **`MainMenu/`** — main-menu-specific VMs/services (welcome popup, recommended-settings + warning, shader-cache warning, extra main-menu links) — see its CLAUDE.md. diff --git a/CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md b/CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md new file mode 100644 index 00000000..2f5b0664 --- /dev/null +++ b/CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md @@ -0,0 +1,13 @@ +# Extensions/UI/MainMenu + +Main-menu screen additions/warnings, shown before a campaign is loaded. + +- **`TORWelcomePopupVM`** — a first-run/update welcome popup. +- **`TORRecommendedSettingsWarningVM`** (+ **`TORRecommendedSettingsService`**, internal + static) — warns the player if their graphics/game settings don't match TOR's recommended + configuration (this mod adds heavy shader/particle content). +- **`TORShaderCacheWarning`** (internal static) — warns about/handles shader-cache-related + first-launch stutter (pairs with `Utilities/ShaderSourceManager` and + `SubModule`'s shader-compilation tracking in `OnApplicationTick`). +- **`TORMainMenuLinksVM`** (+ **`TORMainMenuLinkLauncher`**, internal static) — extra + main-menu links (e.g. Discord/wiki/mod page) opened via the launcher helper. diff --git a/CSharpSourceCode/GameManagers/CLAUDE.md b/CSharpSourceCode/GameManagers/CLAUDE.md new file mode 100644 index 00000000..7b5691c8 --- /dev/null +++ b/CSharpSourceCode/GameManagers/CLAUDE.md @@ -0,0 +1,20 @@ +# GameManagers + +Low-level game/campaign bootstrapping that has to run very early, outside the normal +`CampaignBehaviorBase` lifecycle. + +- **`TorCampaignGameManager`** (`: SandBoxGameManager`) — TOR's replacement campaign game + manager. On load finish it pushes `CharacterCreationState` and registers + `TORCharacterCreationContentHandler` (see `CampaignMechanics/CharacterCreation`) via the + 1.3.1-era `OnCharacterCreationInitializedEvent`, replacing the older direct-constructor + handler registration pattern. +- **`TORKeyInputManager`** (static) — registers TOR's custom hotkey category + (`TORGameKeyContext`, "The Old Realms") and its key bindings (e.g. Quick Cast, Quick Cast + Selection Menu) with `HotKeyManager`. Must use hardcoded text, not + `Utilities/TORTextHelper`, since it runs before the game text manager exists. Initialized + in `SubModule.OnSubModuleLoad`. +- **`TORGameKeyContext`** (`: GameKeyContext`) — the custom key-binding category itself, + including the `TorKeyMap` key indices (`QuickCast`, `QuickCastSelectionMenu`, etc.). +- **`TORShaderGameManager`** — game-manager variant used to drive/track shader compilation + state (pairs with `Utilities/ShaderSourceManager` and the shader-cache warning in + `Extensions/UI/MainMenu`). diff --git a/CSharpSourceCode/HarmonyPatches/CLAUDE.md b/CSharpSourceCode/HarmonyPatches/CLAUDE.md new file mode 100644 index 00000000..5622a52f --- /dev/null +++ b/CSharpSourceCode/HarmonyPatches/CLAUDE.md @@ -0,0 +1,46 @@ +# HarmonyPatches + +Every Harmony patch in the mod (one static class per patched vanilla system, using +`[HarmonyPatch]` attributes — prefix/postfix/transpiler methods named `...Patch`). +Applied via `SubModule.HarmonyInstance.PatchAllUncategorized()` at `OnSubModuleLoad`, except +classes tagged `[HarmonyPatchCategory("LatePatches")]` (e.g. `AgentPatches`), which are +applied later in `SubModule.OnGameInitializationFinished` — after the campaign's text +manager exists, needed for patches that touch localized strings (see the `SubModule` +remarks on `InitializeGameStarter`). Some monster/siege-specific patches live outside this +folder, colocated in `BattleMechanics/TORMonsterSiegeLogic.cs` instead. + +Grouped by what they patch (not exhaustive — see individual files for exact target methods): + +- **Agents/combat**: `AgentPatches` (custom voice routing via + `BattleMechanics/Voice/AgentVoiceComponent`), `MissionCombatMechanicsHelpers`, + `MissionPatches`, `RetreatPatches` (`TORAutoResolveRetreatPatches`), + `AnimationSystemDataPatches`, `MountCreationPatches`. +- **Custom battle / arena / tournaments**: `CustomBattlePatches`, `ArenaPracticePatch`, + `TournamentPatches`, `ArtilleryPatches`. +- **Items/inventory/crafting**: `ItemPatches`, `InventoryPatches`, `InventoryResetPatch`, + `FastTradeInventoryPatch`, `CraftingPatches`, `VeterinarianPatch`. +- **Characters/creation/race**: `CharacterObjectPatches` (+ townsfolk/villager spawn-rate + sub-patches), `CharacterCreationPatches` (positive-effect text, narrative stage start, + gained-attribute population), `RaceFixPatches`, `FaceGenPatches`. +- **Campaign map/world**: `SettlementPatches`, `HideoutPatches`, `MobilePartyPatches`, + `MapEventJoinRestrictionsPatch` (+ `StartBattleActionJoinRestrictionsPatch`), + `EncounterPatches` (+ `EncounterGameMenuBehaviorPatches`), `CustomWorldMapPatch` + (+ `QuestPartyMapTrackerProviderPatches`), `NotablesCampaignBehaviorPatches`, + `ObjectManagerPatches`, `CaravanVisualPatch`. +- **Diplomacy/factions**: `FactionBannerPatches`. +- **Custom resources**: `CustomResourcePatches`. +- **Models**: `ModelPatches` (+ `ClampTroopsLeftToGarrisonCapacityPatch`). +- **UI/VM**: `ViewModelPatches` (+ `ScoreboardBaseVMPatches`, + `RefinementVMOnSelectActionPatch`), `ViewModelRefreshPatch`, `PartyScreenPerformancePatches` + (`PartyVM_TransferAllTroops_PerformancePatch`), `EncyclopediaPatches` (+ unit + property/tooltip sub-patches), `TableauRenderPatches`, `GameTextPatches`, + `LogEntryNotificationPatches`, `MainMenuOptionsPatches`, `MainMenuCrashPatch` + (`MainMenuDeferredClearAllCleanup`, `ToMainMenuClearAllFix`), `LoadingScreenPatches`, + `GameKeyOptionsCategoryPatch`. +- **Dialogue**: `ConversationPatches`. +- **Perks/skills**: `PerkResetRelatedPatch`. +- **Music**: `MBMusicManagerPatches`. +- **Debug**: `BaseGameDebugPatches`. + +Consult `Utilities/TORConfig`/`TORConstants` and the target class's file for the exact +method signatures being patched before modifying one of these. diff --git a/CSharpSourceCode/INDEX.md b/CSharpSourceCode/INDEX.md new file mode 100644 index 00000000..8ad305cf --- /dev/null +++ b/CSharpSourceCode/INDEX.md @@ -0,0 +1,134 @@ +# TOR_Core — Index + +**The Old Realms** is a Mount & Blade II: Bannerlord total-conversion mod bringing Games +Workshop's *Warhammer Fantasy Battles* setting to Bannerlord. This is `TOR_Core`, the main +C# gameplay-logic module (there are sibling modules — `TOR_Armory` for art/data assets, +`TOR_Environment`, and Bannerlord's own `Native`/`SandBox`/`StoryMode`/`CustomBattle` — +referenced by the launch args in `TOR_Core.csproj`, but not present in this source tree). + +Every folder in this tree (down to leaf subfolders) has its own `CLAUDE.md` with details; +this file is the map of how they fit together. Start here, then drill into the folder that +owns the system you're touching. + +## Orientation + +- **Entry point**: `SubModule.cs` (`TOR_Core.SubModule : MBSubModuleBase`). Read this file + first when you need to know "where does X get registered/initialized" — it is the single + place that lists every `CampaignBehaviorBase`, `GameModel`, and mission behavior the mod + adds, plus Harmony setup and startup ordering. If a system isn't wired up, it starts here. +- **Project file**: `TOR_Core.csproj` — old-style (non-SDK) .NET Framework 4.8 project; + every source file must be listed in a `` element or it won't build. + References are DLLs from the installed game (`../../../bin/Win64_Shipping_Client/`) and + sibling modules (`Native`, `SandBox`, `StoryMode`, `CustomBattle`) — this is a Bannerlord + mod, not a standalone app; you cannot build/run it without a Bannerlord installation. +- **`lib/`** — two vendored DLLs (`ink-engine-runtime.dll`, `ink_compiler.dll`) for the + `Ink/` narrative-scripting integration. **`obj/`**/**`bin/`** — build output, ignore. +- **`Properties/`** — just `AssemblyInfo.cs`. + +## Architectural patterns you'll see everywhere + +- **`CampaignBehaviorBase` per mechanic** — almost every gameplay system in + `CampaignMechanics/` is one behavior class registered in `SubModule.InitializeGameStarter`. + To find how a mechanic starts, grep its behavior class name in `SubModule.cs`. +- **`GameModel` overrides** — `Models/` replaces vanilla formulas one at a time + (`TORXyzModel : DefaultXyzModel`), registered in `SubModule.OnGameStart`. To change a + formula, find the matching model here before writing a Harmony patch. +- **Harmony patches** (`HarmonyPatches/`) are the fallback for anything vanilla doesn't + expose a model/behavior/virtual method for. Most patch at `OnSubModuleLoad`; a few need + `[HarmonyPatchCategory("LatePatches")]` to run after `Game.Current`'s text manager exists. +- **XML-defined template data + a static loader/factory**: `AbilityTemplate` + (`AbilitySystem/AbilityFactory`), `TriggeredEffectTemplate` + (`BattleMechanics/TriggeredEffect/TriggeredEffectManager`), `StatusEffectTemplate` + (`BattleMechanics/StatusEffect/StatusEffectManager`), `ItemTrait` + (`Items/ItemTraitManager`), `ReligionObject`/`CareerObject`/`CareerChoiceObject` + (native `MBObjectManager` + XML). All loaded once in `SubModule.OnSubModuleLoad`/ + `BeginGameStart`. If you need to add a new spell/effect/trait/career-choice, you're + almost always adding a data entry + maybe one script class, not new infrastructure. +- **Utility-AI** (`BattleMechanics/AI`) — behaviors implement `IAgentBehavior` and score + themselves via `Axis`/`ScoringFunctions`; `DecisionManager` picks the best score. This + pattern is specific to spellcaster AI (`CastingAI/`) but the primitives + (`CommonAIFunctions/`) are reusable. +- **Extension methods over subclassing** — `Extensions/` adds behavior to vanilla types + (`Agent`, `Hero`, `CharacterObject`, ...) as static extension methods rather than wrapper + classes, since most vanilla types aren't designed to be subclassed. +- **Two ways to attach "extra data" to a vanilla object**: + - Runtime/campaign side data → `Extensions/ExtendedInfoSystem` (side dictionaries keyed + by string id, e.g. `hero.GetExtendedInfo()`). + - Extra bindable UI properties on a vanilla `ViewModel` → `Extensions/UI`'s + `BaseViewModelExtension`/`ViewModelExtensionManager` (reflection-based property/command + forwarding, registered via `[ViewModelExtension]`). +- **Save compatibility**: every persisted custom type must be registered in a + `SaveableTypeDefiner` (mainly `SaveGameSystem/TORSaveableTypeDefiner`, but a few + behaviors define their own inline) with a **stable, never-reused** numeric id — see that + file's own warning before adding or renumbering one. + +## The Warhammer domain model (so the folder docs make sense) + +- **Cultures** (`Utilities/TORConstants.Cultures`) map onto (and often reuse the game-object + slot of) vanilla Bannerlord cultures: Empire (`empire`), Bretonnia (`vlandia`), Sylvania + (`khuzait`), Mousillon (`mousillon`), Asrai/Wood Elves (`battania`), Eonir/Wood Elves + (`eonir`), Dawi/Dwarfs (`sturgia`), Greenskin (`aserai`) — plus Druchii, Beastmen, Chaos, + and several bandit-culture reskins. `Cultures.All` lists the 8 main playable ones. +- **Magic**: Winds-of-Magic **Spells** (Lores: Fire/Light/Heavens/Life/Metal/Beasts/Death, + High Magic, Dark Magic, Necromancy, Big Waaagh) and Dwarf **Rune Magic** are one system + (`AbilitySystem`); priestly **Prayers** are a parallel system tied to + `CampaignMechanics/Religion`; each **Career** has its own unique signature + `CareerAbility`. All three share the same `Ability`/`AbilityTemplate` runtime. +- **Careers** (`CharacterDevelopment/CareerSystem`) are Warhammer-flavored "prestige + classes" — Grail Knight, Black Grail Knight, Grail Damsel, Knight of the Old World, + Witch Hunter, Warrior Priest (+ of Ulric), Blood Knight, Vampire Count, Necromancer, + Necrarch, Imperial Magister, Waywatcher, Spellsinger, Warden, Grey Lord, Mercenary, + Ironbreaker, Runelord, Slayer, Orc Boss, Orc Shaman — each with a perk tree + (`CareerSystem/Choices`), a signature ability, and sometimes a special roster-screen + button (`CareerSystem/CareerButton`). +- **Per-culture "second currency"** (`CampaignMechanics/CustomResources`): Prestige + (Empire), Chivalry (Bretonnia), DarkEnergy (Sylvania/Mousillon), ForestHarmony (Asrai), + CouncilFavor (Eonir), OathGold (Dawi), Teef/Waaagh (Greenskin). +- **Bespoke settlement types** (`CampaignMechanics/TORCustomSettlement`): Chaos Portal, + Herdstone, Slaver Camp, Troll Cave (all raider-spawning lairs), Cursed Site, Oak of Ages, + Shrine, World Roots. +- **Damage/effects pipeline**: an `Ability`/weapon-hit fires a + `BattleMechanics/TriggeredEffect` → resolves target set → applies damage via + `BattleMechanics/DamageSystem/TORDamageHelper` and/or a + `BattleMechanics/StatusEffect` → both get scaled by `Models/TORAbilityModel` + (skill/perk effectiveness) and `CharacterDevelopment/CareerSystem/CareerHelper` + (career passives) along the way. + +## Top-level folder map + +| Folder | What it owns | +|---|---| +| `AbilitySystem/` | Spells, prayers, career abilities: the shared casting/effect runtime. | +| `Audio/` | Standalone file-based sound playback (ambient sounds). | +| `BattleMechanics/` | In-mission mechanics: AI, status effects, triggered effects, artillery, banners, firearms, dismemberment, voice, arena modes. | +| `CampaignMechanics/` | Every campaign-map mechanic (largest folder): factions, careers, religion, custom resources, diplomacy, crafting, custom settlements, quests-adjacent behaviors. | +| `CharacterDevelopment/` | Skills, perks, traits, attributes, and the Career data model. | +| `Extensions/` | Extension methods on vanilla types; the ExtendedInfo side-data system; the ViewModel-extension UI injection system. | +| `GameManagers/` | Early campaign bootstrapping, hotkeys, shader-related game managers. | +| `HarmonyPatches/` | Every Harmony patch, grouped by what vanilla system they touch. | +| `Ink/` | Branching-narrative integration (Inkle's Ink language). | +| `Items/` | Item traits/enchantments, weapon on-hit scripts, inventory-use scripts. | +| `Missions/` | Mission-open factory methods + scripted one-off fight controllers. | +| `Models/` | `GameModel` overrides (vanilla formula replacements) + Custom Battle variants. | +| `Quests/` | `QuestBase` quest classes, including Career storyline quests. | +| `SaveGameSystem/` | Save-type registration (`SaveableTypeDefiner`). | +| `Utilities/` | Cross-cutting static helpers (config, paths, constants, math, logging). | + +## Where to look for a given task + +- **"Add/tune a spell or prayer"** → `AbilitySystem/` (template + maybe a new + `AbilityScript`), `AbilitySystem/Spells/LoreObject` if it's a new Lore. +- **"Add a new status effect / DOT / buff"** → `BattleMechanics/StatusEffect`. +- **"A weapon should do something special on hit"** → `Items/WeaponHitScripts` + + `Items/ItemTrait`. +- **"Add/tune a Career perk or its passive"** → `CharacterDevelopment/CareerSystem/Choices`. +- **"Change how damage/resistance math works"** → `BattleMechanics/DamageSystem` + + `Models/TORAgentApplyDamageModel`/`TORAbilityModel`. +- **"Add a new campaign mechanic/town service"** → a new `CampaignBehaviorBase` under + `CampaignMechanics/`, registered in `SubModule.InitializeGameStarter`. +- **"Vanilla formula needs to behave differently"** → check `Models/` first; only reach for + `HarmonyPatches/` if there's no model hook for it. +- **"AI isn't casting/behaving right"** → `BattleMechanics/AI/CastingAI` (spellcasters) or + `BattleMechanics/AI/TeamAI` (formation/team AI). +- **"Add UI to an existing vanilla screen"** → `Extensions/UI` (`BaseViewModelExtension`) + rather than a Harmony patch on the screen class, if at all possible. diff --git a/CSharpSourceCode/Ink/CLAUDE.md b/CSharpSourceCode/Ink/CLAUDE.md new file mode 100644 index 00000000..f0d365cc --- /dev/null +++ b/CSharpSourceCode/Ink/CLAUDE.md @@ -0,0 +1,23 @@ +# Ink + +Integration of Inkle's [Ink](https://www.inklestudios.com/ink/) narrative scripting +language (via `lib/ink-engine-runtime.dll` + `lib/ink_compiler.dll`, referenced in +`TOR_Core.csproj`) for branching story content — used for narrative events/quests too +complex for simple dialog trees. + +- **`InkStoryManager`** (singleton) — loads every `*.ink` file from the module's + `InkStories/` folder into an `InkStory` (`Initialize()`, called from + `SubModule.OnSubModuleLoad`); `AllStories`/`LastStoryId` track loaded/most-recent story. +- **`InkStory`** — wraps a compiled Ink `Story` runtime instance and bridges it to game + state: exposes choices/continue-text, and lets Ink script "external functions" reach into + the campaign (spawning items via `Items`, custom settlements via + `CampaignMechanics/TORCustomSettlement`, custom events, quests, missions, audio) so a + story file can trigger real game effects, not just show text. +- **`InkFileHandler`** — file I/O helper for locating/reading `.ink`/compiled story assets. +- **`InkFakeMarketData`** — mock market data used when an Ink story needs to reference + prices/trade without a real market context. +- **`InkStoryCampaignBehavior`** (`: CampaignBehaviorBase`) — campaign-level hook that + starts/advances stories (also see `Items/InventoryUseScripts/StartInkStoryScript`, an + item that launches a story when used). +- **`InkStoryVM`** / **`InkStoryChoiceVM`** — Gauntlet view-models for presenting the + current story text and its choices to the player. diff --git a/CSharpSourceCode/Items/CLAUDE.md b/CSharpSourceCode/Items/CLAUDE.md new file mode 100644 index 00000000..54fb37b0 --- /dev/null +++ b/CSharpSourceCode/Items/CLAUDE.md @@ -0,0 +1,33 @@ +# Items + +Item-level extensions: magical weapon/armor traits (enchantments), custom item metadata, +and inventory-item "use" scripts (right-click a campaign item to trigger an effect). + +- **`ItemTrait`** (`IEquatable`, XML-defined) — a magical trait/enchantment + definition: `ResistanceTuple`/`AmplifierTuple`/`AdditionalDamageTuple` + (from `Extensions/ExtendedInfoSystem/CharacterExtendedInfo`'s tuple types, reused here for + items), an `OnWeaponHitScript`/`OnInventoryUseScript` reference (by name, resolved to a + script class), `ImbuedStatusEffectId`/`ImbuedEffectChance`, crafting cost + (`IsCraftable`, `IngredientItem`/`IngredientAmount`), valid item type, and a `StatsTuple` + for flat stat bonuses. This is the data half of `CampaignMechanics/Crafting`'s enchanting + system and of pre-enchanted unique items. +- **`ItemTraitManager`** (static) — loads/indexes all `ItemTrait`s (`LoadItemTraits`, + called from `SubModule.OnSubModuleLoad`). +- **`ItemTraitAgentComponent`** (`: AgentComponent`) — tracks which traits are active on an + agent's equipped gear during a mission. +- **`ExtendedItemObjectManager`** / **`ExtendedItemObjectProperties`** — extra per-`ItemObject` + metadata beyond what `ItemTrait` covers (loaded via `ExtendedItemObjectManager.LoadXML` + in `SubModule.OnSubModuleLoad`). +- **`TorEnchantingIngredients`** — ingredient item definitions used by the crafting UI. +- **`TorItemMenuVM`** / **`TorItemTraitVM`** / **`TorInventoryItemTupleWidget`** / + **`TorImageIdentifierWidget`** — inventory/tooltip UI showing an item's traits. +- **`InventoryUseScriptsCampaignBehavior`** (`: CampaignBehaviorBase`) — dispatches + "use this item" actions from the inventory screen to the matching + `InventoryUseScripts/` script. + +## Subfolders + +- **`WeaponHitScripts/`** — `IWeaponHitScript` implementations: on-hit weapon procs + (see its CLAUDE.md). +- **`InventoryUseScripts/`** — `IInventoryUseScript` implementations: right-click item-use + effects on the campaign map (see its CLAUDE.md). diff --git a/CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md b/CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md new file mode 100644 index 00000000..9ca25616 --- /dev/null +++ b/CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md @@ -0,0 +1,20 @@ +# Items/InventoryUseScripts + +Right-click "use this item" effects on the campaign map, referenced by name from +`Items/ItemTrait.OnInventoryUseScript` and dispatched by +`Items/InventoryUseScriptsCampaignBehavior`. + +- **`IInventoryUseScript`** — `OnUse(userParty, item)`, `OnHourlyTick`/`OnDailyTick` + (for items with a recurring effect while carried, not just a one-shot use). +- **`BaseInventoryUseScript(string[] arguments)`** (`IEquatable`, `[SaveableField]` + arguments — persisted with the save) — default base; `UseScript` wraps `OnUse` and fires + `Utilities/TORCampaignEvents.Instance.OnUseInventoryUseScriptObject` for other systems to + react to. Equality is by type + arguments, so save/load can match instances back up. + Also defines **`TORUseScriptArgumentException`** and **`ScriptUseData`** (a small + saveable record of who used what item, when, and how many times). +- **`StartInkStoryScript`** — using the item launches an `Ink/` narrative story. +- **`SkillBookScript`** — grants skill XP/unlocks when read. +- **`CustomResourceContainerScript`** — using the item grants/converts a + `CampaignMechanics/CustomResources` resource. +- **`EnchantmentBlueprintScript`** — teaches/unlocks an enchantment recipe for + `CampaignMechanics/Crafting`. diff --git a/CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md b/CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md new file mode 100644 index 00000000..c2c91326 --- /dev/null +++ b/CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md @@ -0,0 +1,22 @@ +# Items/WeaponHitScripts + +On-hit weapon proc effects, referenced by name from `Items/ItemTrait.OnWeaponHitScript` +and instantiated per hit. + +- **`IWeaponHitScript`** — `OnHit(attackingAgent, attackedAgent, blow, missionWeapon, + collisionData)`. +- **`BaseWeaponHitScript(string[] arguments)`** — default base implementing the interface; + `ApplyWeaponTraitDamage` routes secondary/bonus damage through + `AbilitySystem/AbilityManagerMissionLogic.QueueOnHitSecondaryDamage` when available + (deferred outside the original hit callback to avoid mutating agent state mid-resolution), + else falls back to `Extensions/AgentExtensions.ApplyDamage` directly. +- **`WeaponScripts.cs`** — the bulk of concrete on-hit procs (elemental/magical weapon + effects triggered on a successful hit). +- **`DefenseScripts.cs`** — on-hit scripts that trigger from the defender's side (e.g. + reactive/retaliation effects, damage reduction procs). +- **`KnightlyStrikeHitScript`** — the on-hit effect tied to the Grail Knight/Knight career + "Knightly Strike" ability (see `AbilitySystem/Scripts/KnightlyStrikeScript`). + +Dispatched via **`WeaponHitScriptsMissionLogic`** (root `Items/` folder, +`: MissionLogic`), added in `SubModule.OnMissionBehaviorInitialize`, which listens for hit +events and looks up the attacker's weapon's `ItemTrait.OnWeaponHitScript` to invoke. diff --git a/CSharpSourceCode/Missions/CLAUDE.md b/CSharpSourceCode/Missions/CLAUDE.md new file mode 100644 index 00000000..92e1f3d1 --- /dev/null +++ b/CSharpSourceCode/Missions/CLAUDE.md @@ -0,0 +1,38 @@ +# Missions + +Campaign-facing "how do we open a mission scene and what runs it" layer — factory methods +for launching a mission scene plus small `MissionLogic` controllers for scripted one-off +fights (as opposed to `BattleMechanics/`, which is the in-mission mechanics that run once +inside any mission). + +- **`TorMissionManager`** (static, `[MissionManager]`) — `[MissionMethod]`-attributed + factory methods (the same pattern as vanilla's `MissionManager`/`CampaignMissionManager`) + that build and open a `Mission` for a given scene: e.g. + `OpenArcheryContestMission(scene, ArcheryContestTournamentGame, settlement, culture, + isPlayerParticipating)`. This is the entry point `CampaignMechanics`/`Quests` code calls + to actually start one of TOR's custom mission types. +- **`TORMissionAgentHandler`** — shared agent-spawning logic reused by several of the + scripted-fight controllers below. +- **`MissionExperienceBehavior`** — custom XP granting rules for missions. + +## Scripted fight controllers (one per special encounter type, all `: MissionLogic`) + +- **`QuestFightMissionController(enemyPartyTemplate, enemyCount, onMissionEnd, ...)`** — + generic "fight this templated enemy party, then run a callback" controller used by quests. +- **`DuelFightMissionController`** — 1v1 honor duel (see + `CampaignMechanics/CustomDialogs/DuelBehavior`). +- **`BrawlMissionController`** — settlement brawl mini-game (see + `CampaignMechanics/TORCustomSettlement/GreenskinBrawlBehavior`). +- **`GraveyardFightMissionController`** — graveyard night-watch fight (see + `CampaignMechanics/RaiseDead`). +- **`TrollCaveMissionController`** — Troll Cave raid mission. +- **`ArcheryContestMissionController`** / **`JoustFightMissionController`** — wrap the + `BattleMechanics/CustomArenaModes` archery/joust tournament games for campaign use. + +## TODO + +- **`TrollCaveMissionController`** used to set a `_playerCanLeave` flag on victory but + nothing ever read it (the real "let the mission end" signal is + `_battleEndLogic.ChangeCanCheckForEndCondition(true)`, called right alongside it), so it + was removed as dead code. Restore it (see the TODO comment left at its old declaration + site) if a leave-mission check still needs it. diff --git a/CSharpSourceCode/Models/CLAUDE.md b/CSharpSourceCode/Models/CLAUDE.md new file mode 100644 index 00000000..90b3055f --- /dev/null +++ b/CSharpSourceCode/Models/CLAUDE.md @@ -0,0 +1,53 @@ +# Models + +TaleWorlds `GameModel` overrides — the game's standard "swap out the formula" extension +point. Almost every file here is `TORXyzModel : DefaultXyzModel` (or `SandboxXyzModel`), +overriding one or more virtual calculation methods while calling `base.Xyz(...)` for the +rest. All are registered in `SubModule.OnGameStart` via `gameStarterObject.AddModel(new +TORXyzModel())` — that method is the authoritative list of which vanilla model each +replaces. A few (`TORAbilityModel`, `TORFaithModel`, `TORCustomResourceModel`, +`TOREnchantmentCraftingModel`, `TOREnchantmentIngredientsModel`, +`TORHiringCompatibilityModel`, `TORCompanionTrainingModel`, `TORReinforcementRestrictionModel`) +extend `GameModel` directly — new mechanics vanilla has no equivalent formula for. + +## By theme + +- **Combat/agent stats**: `TORAgentStatCalculateModel` (`: SandboxAgentStatCalculateModel`), + `TORAgentApplyDamageModel` (`: SandboxAgentApplyDamageModel` — routes through + `BattleMechanics/DamageSystem/TORDamageHelper`), `TORStrikeMagnitudeModel` + (`: SandboxStrikeMagnitudeModel`), `TORCombatSimulationModel`, `TORCombatXpModel`, + `TORBattleMoraleModel` (`: SandboxBattleMoraleModel`), `TORBattleBannerBearersModel` + (`: SandboxBattleBannerBearersModel`), `TORBattleRewardModel`, `TORDamageParticleModel`. +- **Abilities/magic**: `TORAbilityModel` (`: GameModel` — spell damage/radius/duration + scaling by skill/perk, called from `BattleMechanics/TriggeredEffect`), `TORFaithModel` + (`: GameModel` — prayer/religion mechanics). +- **Party**: `TORPartySizeModel`, `TORPartySpeedCalculatingModel`, `TORPartyWageModel`, + `TORPartyHealingModel`, `TORPartyMoraleModel`, `TORPartyDesertionModel`, + `TORPartyTrainingModel`, `TORPartyTroopUpgradeModel`, `TORMobilePartyAIModel`, + `TORMobilePartyFoodConsumptionModel`, `TORReinforcementRestrictionModel` (`: GameModel`). +- **Character/skills**: `TORCharacterDevelopmentModel`, `TORCharacterStatsModel`, + `TORCompanionTrainingModel` (`: GameModel`), `TORCompanionHiringPriceCalculationModel`, + `TORPrisonerRecruitmentCalculationModel`, `TORHiringCompatibilityModel` (`: GameModel`). +- **Clan/kingdom/diplomacy**: `TORClanFinanceModel`, `TORClanTierModel`, + `TORClanPoliticsModel`, `TORDiplomacyModel`, `TORAllianceModel`, `TORTradeAgreementModel`, + `TORKingdomDecisionPermissionModel` (`: KingdomDecisionPermissionModel`), + `TORMinorFactionsModel`, `TORMarriageModel`, `TORPersuasionModel`. +- **Settlement/economy**: `TORSettlementFoodModel`, `TORSettlementLoyaltyModel`, + `TORSettlementMilitiaModel`, `TORSettlementProsperityModel` (sealed), + `TORVillageProductionCalculatorModel`, `TORTradeItemPriceFactorModel` (sealed), + `TORTroopSupplierModel`, `TORBuildingEffectModel`, `TORAlleyModel`, + `TORBanditDensityModel`, `TORInventoryCapacityModel`. +- **Crafting/smithing**: `TORSmithingModel`, `TOREnchantmentCraftingModel` (`: GameModel`), + `TOREnchantmentIngredientsModel` (`: GameModel`), `TOREquipmentSelectionModel`. +- **Custom resources**: `TORCustomResourceModel` (`: GameModel` — generalized cost scaling, + see `CampaignMechanics/CustomResources/CustomResource.GetCustomResourceGeneralizedFactor`). +- **Encounters/map/raids**: `TOREncounterModel`, `TOREncounterGameMenuModel`, + `TORMapVisibilityModel`, `TORRaidModel`, `TORVoiceOverModel`. +- **Siege/tournament**: `TORSiegeEngineCalculationModel`, `TORTournamentModel`. +- **Misc**: `TORVolunteerModel`, `DiplomacyHelpers` (static — shared math for + `TORDiplomacyModel`/`TORAllianceModel`/`TORTradeAgreementModel`). + +## Subfolder + +- **`CustomBattleModels/`** — the parallel model set used for the game's Custom Battle mode + (`Game.Current.GameType is CustomGame`) instead of a real campaign — see its CLAUDE.md. diff --git a/CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md b/CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md new file mode 100644 index 00000000..aef263c2 --- /dev/null +++ b/CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md @@ -0,0 +1,12 @@ +# Models/CustomBattleModels + +Model overrides used specifically in TaleWorlds' Custom Battle mode +(`Game.Current.GameType is CustomGame`), registered in `SubModule.OnGameStart`'s +`else if (Game.Current.GameType is CustomGame ...)` branch instead of the campaign branch. + +- **`TORCustomBattleMoraleModel`** (`: CustomBattleMoraleModel`). +- **`TORCustomBattleAgentStatCalculateModel`** (`: CustomBattleAgentStatCalculateModel`). + +Both mirror their campaign counterparts (`../TORBattleMoraleModel`, +`../TORAgentStatCalculateModel`) but against the Custom Battle base classes, since Custom +Battle mode has no `Campaign`/`Hero`/career context to draw on. diff --git a/CSharpSourceCode/Properties/CLAUDE.md b/CSharpSourceCode/Properties/CLAUDE.md new file mode 100644 index 00000000..c8983391 --- /dev/null +++ b/CSharpSourceCode/Properties/CLAUDE.md @@ -0,0 +1,4 @@ +# Properties + +Standard .NET project metadata folder — contains only `AssemblyInfo.cs` +(assembly title/version/GUID attributes generated by Visual Studio). No TOR-specific logic. diff --git a/CSharpSourceCode/Quests/CLAUDE.md b/CSharpSourceCode/Quests/CLAUDE.md new file mode 100644 index 00000000..1932ff19 --- /dev/null +++ b/CSharpSourceCode/Quests/CLAUDE.md @@ -0,0 +1,23 @@ +# Quests + +`QuestBase`-derived campaign quests, plus generic quest infrastructure. (Career-flavor +one-off scripted events use the lighter `CampaignMechanics/CustomEvents` framework instead +of a full quest class.) + +- **`TORQuestHelper`** (static) — `StartCareerQuest(questPath)`: generic quest-launcher + used by Career content — resolves a `TOR_Core.` type name via reflection and + starts it if not already ongoing (guards against duplicate quest instances by `StringId`). +- **`QuestPartyComponent`** — party component marking a `MobileParty` as belonging to an + active quest (e.g. an escort or hunted target). +- **`EngineerQuest`** — a Dwarf-engineering-flavored quest (pairs with + `CampaignMechanics/MasterEngineer`). +- **`SpecializeLoreQuest`** — quest for specializing into a Winds-of-Magic Lore + (`AbilitySystem/Spells/LoreObject`) beyond the basic trainer interaction. +- **`HuntCultistsQuestCampaignBehavior`** / **`PlaguedVillageQuestCampaignBehavior`** + (`: CampaignBehaviorBase`) — self-contained quest-line behaviors (issue, track, and + resolve their quest without needing a separate `QuestBase` subclass registered elsewhere). + +## Subfolder + +- **`Careers/`** — one `QuestBase` subclass per Career-specific storyline quest, launched + via `TORQuestHelper.StartCareerQuest` (see its CLAUDE.md). diff --git a/CSharpSourceCode/Quests/Careers/CLAUDE.md b/CSharpSourceCode/Quests/Careers/CLAUDE.md new file mode 100644 index 00000000..28ddaa49 --- /dev/null +++ b/CSharpSourceCode/Quests/Careers/CLAUDE.md @@ -0,0 +1,10 @@ +# Quests/Careers + +One `QuestBase` subclass per Career-specific storyline quest (multi-stage, `JournalLog` +tasks saved via `[SaveableField]`), launched through `../TORQuestHelper.StartCareerQuest` +with a `questPath` like `"Quests.Careers.RunesmithQuest"`. + +- **`RunesmithQuest`** / **`RunelordQuest`** — Dwarf Runelord career questline (crafting + runes, tied to `CampaignMechanics/Menagery`/`Crafting`). +- **`OrcBossQuest1`** / **`OrcBossQuest2`** — Orc Boss career questline (sequential parts). +- **`OrcShamanQuest1`** / **`OrcShamanQuest2`** — Orc Shaman career questline. diff --git a/CSharpSourceCode/SaveGameSystem/CLAUDE.md b/CSharpSourceCode/SaveGameSystem/CLAUDE.md new file mode 100644 index 00000000..95459e48 --- /dev/null +++ b/CSharpSourceCode/SaveGameSystem/CLAUDE.md @@ -0,0 +1,17 @@ +# SaveGameSystem + +Single file: **`TORSaveableTypeDefiner`** (`: SaveableTypeDefiner`, base id `771000`) — +registers every custom class/interface that needs to be persisted in save games (party +components, settlement components, quest data, inventory-use-script data, custom-battle +tournament games, notification types, etc.) with a stable numeric id via +`AddClassDefinition`/`AddInterfaceDefinition`. + +**Critical constraint (called out in the file's own remarks):** never change an existing +type's id once players have saves using it — old saves will crash on load when the game +scans the save folder. Only ever append new ids; only renumber if you're deliberately +breaking save compatibility and know players will need to clear their saves. + +Other `SaveableTypeDefiner`s exist too, colocated with what they define (e.g. +`CampaignMechanics/Diplomacy/TORAllianceWarBehavior.TORAllianceWarBehaviorTypeDefiner`, +`HonorAllianceDecision.HonorAllianceDecisionTypeDefiner`) — check for those before assuming +this file is the only place a type gets registered. diff --git a/CSharpSourceCode/Utilities/CLAUDE.md b/CSharpSourceCode/Utilities/CLAUDE.md new file mode 100644 index 00000000..a0b47aeb --- /dev/null +++ b/CSharpSourceCode/Utilities/CLAUDE.md @@ -0,0 +1,59 @@ +# Utilities + +Cross-cutting static helpers used from every other folder. No campaign-behavior/mission +logic of its own — pure infrastructure. + +- **`TORConstants`** — every magic number/id string in one place, including the important + **`Cultures`** struct mapping Warhammer culture names to the underlying vanilla + `CultureObject.StringId` they're built on/reuse: `EMPIRE="empire"`, + `BRETONNIA="vlandia"`, `SYLVANIA="khuzait"`, `MOUSILLON="mousillon"`, + `ASRAI="battania"`, `DRUCHII="druchii"`, `BEASTMEN="steppe_bandits"`, + `CHAOS="chaos_culture"`, `EONIR="eonir"`, `DAWI="sturgia"` (Dwarfs), `GREENSKIN="aserai"`, + plus bandit/deserter variant cultures. `Cultures.All` is the 8 "main" playable cultures. + Also has a **`Factions`** struct (Empire provinces: Reikland, Middenland, Ostland, + Ostermark, Stirland, Hochland, Averland, Wissenland, Talabecland, Nordland, Moot, + Wasteland, ...) and religion/devotion/voice-index constants. +- **`TORCommon`** (static) — grab-bag: `Say`/`Log` (message + NLog wrappers), + `GetRandomDirection`/`GetRandomOrientation`, `FindNearestSettlement`/ + `FindSettlementsAroundPosition`/`FindPartiesAroundPosition` (spatial queries via + `Locatable` search), `CopyEquipmentToClipBoard` (debug helper). +- **`TORConfig`** — loads `TORConfiguration` from an XML config file (`ReadConfig`, called + from `SubModule.OnSubModuleLoad`) exposing tunable campaign constants (kingdom war + cadence, bandit party caps, career perk point cap, declare-war score weights, + `UseAlternativeVoiceManager`, `DisableMinstrelEvent`) plus a password-gated + `EnableFreeRaceSelection` debug toggle. +- **`TORPaths`** — module root/data/log path resolution (`TORCoreModuleRootPath`, + `TORArmoryModuleRootPath`, `TORLogPath`, etc.) — everything else that reads XML/assets + goes through this rather than hardcoding relative paths. +- **`TORCampaignEvents`** — TOR's own custom `CampaignEvent` definitions (beyond vanilla + `CampaignEvents`), e.g. `OnUseInventoryUseScriptObject` (see `Items/InventoryUseScripts`). +- **`TORConsoleCommands`** — debug console commands. +- **`TORTests`** — in-game smoke tests, likely surfaced via console commands. +- **`CTBlog`** — a debug/telemetry logging helper (separate from NLog, per its name — check + before assuming it's dead code). +- **`TORNotificationHelper`** — builds/shows `CampaignMechanics/MapNotifications`. +- **`TORTextHelper`** / **`TextObjectExtension`** / **`StringExtensions`** / + **`DictionaryExtensions`** — localization text lookup wrappers and small generic + extensions. +- **`TORDamageDisplay`** — floating combat-text style damage number display. +- **`TORSpellBlowHelper`** — classifies whether a `Blow`/`KillingBlow` originated from a + spell (used by `BattleMechanics/DamageSystem/TORDamageHelper.DetermineMask`). +- **`TORSummonHelper`** — mission agent-limit checks for summon-type abilities + (`AbilitySystem/Ability.IsDisabled` calls `CanSummon()`). +- **`TORMissionHelper`** — mission-side damage/heal/status-effect + application entry points used by `BattleMechanics/TriggeredEffect` + (`DamageAgents`/`HealAgents`/`ApplyStatusEffectToAgent`). +- **`TORHireHelper`** — hiring-cost/eligibility helpers. +- **`TOREquipmentHelper`** — equipment set resolution helpers (character creation, troops). +- **`TORExtendedInfoHelper`** — query helpers over `Extensions/ExtendedInfoSystem` data. +- **`TORGameStarterHelper`** — startup wiring helpers (`CleanCampaignStarter`, + `AddVerifiedIssueBehaviors`, called from `SubModule.InitializeGameStarter`). +- **`TORGameMenuBackgroundSwitcher`** — swaps settlement menu background art by context. +- **`TORMassMaterialSwitcher`** — bulk material/shader swapping on entities (visual variants). +- **`TOREntityRotator`** — simple entity rotation helper (scene/prop tool). +- **`TORParticleSystem`** (+ `ParticleIntensity` enum) — attaches/pools particle effects + on agents/entities; used heavily by `BattleMechanics/StatusEffect/StatusEffectComponent`. +- **`TORAnimationLogger`** — debug mission behavior logging animation events (added only + when a debugger is attached, see `SubModule.OnMissionBehaviorInitialize`). +- **`ShaderSourceManager`** — copies TOR_Armory shader sources into the game folder before + shader compilation (`SubModule.OnSubModuleLoad`, gated by `ENABLECOPYSHADERS`). diff --git a/docs/architecture-overview.md b/docs/architecture-overview.md new file mode 100644 index 00000000..0c43ec04 --- /dev/null +++ b/docs/architecture-overview.md @@ -0,0 +1,103 @@ +# TOR_Core — Current Architecture Overview + +This document describes the codebase as it stands today (`CSharpSourceCode/`), as input to a +proposed vertical-slicing refactor (see [`vertical-slicing-proposal.md`](./vertical-slicing-proposal.md)). + +## The shape of the mod + +TOR_Core is a single Bannerlord sub-module assembly. Content is organized into ~15 top-level +folders, most named after a technical layer or a broad theme (`CampaignMechanics`, +`BattleMechanics`, `AbilitySystem`, `Models`, ...). Within `CampaignMechanics` and +`BattleMechanics`, there's a second level of folders that map much more closely to actual +features (`Religion/`, `Chaos/`, `Firearms/`, `Crafting/`, ...) — so the raw material for a +feature-oriented ("vertical slice") structure already mostly exists. What's missing is +*isolation*: nothing about a feature's folder makes it self-contained or independently +registrable. + +## The registration bottleneck: `SubModule.cs` + +Every feature wires itself up by being manually `new`'d in one enormous class, +[`SubModule.cs`](../CSharpSourceCode/SubModule.cs): + +| Method | What it does | Approx. count | +|---|---|---| +| `OnSubModuleLoad` | Harmony patching, config/template loading (abilities, status effects, triggered effects, items, banners, careers, voices, ink stories) | ~15 manager `Load`/`Initialize` calls | +| `InitializeGameStarter` | `starter.AddBehavior(new XyzCampaignBehavior())` | ~60 campaign behaviors | +| `OnGameStart` | `gameStarterObject.AddModel(new TORXyzModel())` | ~90 game models | +| `OnMissionBehaviorInitialize` | `mission.AddMissionBehavior(new XyzMissionLogic())` | ~15 mission behaviors | +| `BeginGameStart` | `game.ObjectManager.RegisterType(...)` for custom settlement/career/religion object types | ~13 types | + +Every one of these lines is a hard dependency from the "hub" onto a "spoke" feature's concrete +type — `using TOR_Core.CampaignMechanics.Religion;` etc., 65 `using` statements deep. Adding, +removing, or reasoning about one feature in isolation means reading (and safely editing) this +2,600+ line god-object regardless of which feature you actually touch. + +## Current wiring + +```mermaid +flowchart TB + SM["SubModule.cs
(god object — ~60 AddBehavior, ~90 AddModel,
~15 AddMissionBehavior calls, all hand-written)"] + + subgraph INFRA["Infrastructure-shaped folders"] + direction LR + UTIL[Utilities] + EXT[Extensions] + SAVE[SaveGameSystem] + GM[GameManagers] + HP[HarmonyPatches] + AUDIO[Audio] + INK[Ink] + MISS[Missions] + end + + subgraph COMBAT["Battle-simulation core"] + direction LR + ABIL[AbilitySystem] + SE["StatusEffect /
TriggeredEffect /
DamageSystem"] + AI["BattleMechanics/AI"] + end + + subgraph FEATURES["~26 CampaignMechanics feature folders"] + direction LR + CAREERS[Careers] + RELIGION[Religion] + CHAOS[Chaos] + CRES[CustomResources] + CRAFT[Crafting] + DIPLO[Diplomacy] + SETTLE[TORCustomSettlement] + MORE1["... 19 more"] + end + + subgraph MISSIONFX["~9 BattleMechanics content add-ons"] + direction LR + FIRE[Firearms] + DISM[Dismemberment] + ARTY[Artillery] + BANN[Banners] + ARENA[CustomArenaModes] + MORE2["... 4 more"] + end + + INFRA -.depended on by everything.-> COMBAT + INFRA -.depended on by everything.-> FEATURES + INFRA -.depended on by everything.-> MISSIONFX + COMBAT -.depended on by.-> FEATURES + COMBAT -.depended on by.-> MISSIONFX + + FEATURES -- "new'd individually, one line each" --> SM + MISSIONFX -- "new'd individually, one line each" --> SM + COMBAT -- "new'd individually" --> SM + INFRA -- "Initialize()/LoadXML() called individually" --> SM +``` + +## Observations + +- **Folders already suggest features; registration does not respect that.** `CampaignMechanics/Religion/` is a coherent, mostly-self-contained unit of code — but you can't tell that from `SubModule.cs`, where its one `AddBehavior` call sits between unrelated features. +- **Cross-cutting infrastructure is not marked as such.** `Utilities/`, `Extensions/`, `SaveGameSystem/`, `GameManagers/`, `Audio/`, `Ink/`, and most of `HarmonyPatches/` have no feature identity at all — they're pure plumbing every feature depends on, but they sit at the same folder depth as `Chaos/` or `Firearms/`, obscuring the dependency direction. +- **A few systems are structurally "framework" but organizationally trapped inside `BattleMechanics/`**: `AbilitySystem`'s parent concepts (`StatusEffect`, `TriggeredEffect`, `DamageSystem`, `AI`) are the shared combat runtime every spell/prayer/item/career-ability is built on, not a feature themselves. +- **`Models/` is a 90-entry flat registry with no feature grouping at all** — `TORFaithModel` (Religion), `TORCustomResourceModel` (CustomResources), and `TORPartySizeModel` (nothing in particular) all live in the same folder and get added in the same block in `SubModule.OnGameStart`. +- **A handful of files are already colocated correctly** despite the lack of formal structure — e.g. `TORAllianceWarBehavior` carries its own `SaveableTypeDefiner` nested class rather than adding to the central `TORSaveableTypeDefiner`. This is the pattern a vertical-slice structure should generalize. + +See [`vertical-slicing-proposal.md`](./vertical-slicing-proposal.md) for the proposed target +shape, a folder-by-folder Framework/Module classification, and a phased migration plan. diff --git a/docs/vertical-slicing-proposal.md b/docs/vertical-slicing-proposal.md new file mode 100644 index 00000000..328dd566 --- /dev/null +++ b/docs/vertical-slicing-proposal.md @@ -0,0 +1,251 @@ +# Vertical Slicing Proposal + +Companion to [`architecture-overview.md`](./architecture-overview.md). Proposes splitting +`CSharpSourceCode/` into a **`Framework/`** layer (engine-shaped, no feature toggles, everything +depends on it) and a **`Modules/`** layer (self-contained vertical slices — own behaviors, own +models, own quests, own save data, own UI — each responsible for registering itself). + +This is a proposal for discussion, not a plan already agreed — see [Open questions](#open-questions-before-executing) +at the end. + +## Goal + +Two tests for "is this a Module": + +1. **Could a maintainer delete this folder and, modulo a couple of registration lines, have the + rest of the mod still compile and play?** If yes → Module. If half the codebase reaches into + it → Framework. +2. **Does it represent one coherent piece of Warhammer content/mechanic** (Religion, Firearms, + Crafting, the Chaos faction) **or a reusable mechanism** (an effect-resolution pipeline, a + save-id registry, a view-model injection trick)? Content → Module. Mechanism → Framework. + +## Target shape + +```mermaid +flowchart TB + subgraph REG["Registration"] + SM2["SubModule.cs
(thin: Harmony init, then discovers & drives ITORModules)"] + REGISTRY["TORModuleRegistry
(reflection scan for [TORModule]-attributed types,
same pattern already used by ViewModelExtensionManager)"] + end + + subgraph FW["Framework/ — engine-shaped, no feature toggles"] + direction LR + FUTIL[Utilities] + FEXT[Extensions] + FSAVE[SaveGameSystem] + FGM[GameManagers] + FHP[Patches] + FAUDIO[Audio] + FINK[Narrative /Ink] + FMISS[Missions] + FABIL[AbilitySystem] + FBATTLE["Battle/
StatusEffect, TriggeredEffect,
DamageSystem, AI"] + FITEMS["Items
(trait/metadata engine)"] + FCHARDEV["CharacterDevelopment
(skills/attributes/traits scaffold)"] + FMODELS["Models
(generic formula overrides)"] + FQUESTS[Quests infra] + FEVENTS[CustomEvents] + FDIALOGUE[Dialogue] + FUI["UI
(notifications, VM-extension, main menu)"] + end + + subgraph MODS["Modules/ — self-contained vertical slices"] + direction LR + M1["Careers/"] + M2["Religion/"] + M3["CustomResources/"] + M4["Crafting/"] + M5["Diplomacy/"] + M6["TORCustomSettlement/"] + M7["Firearms/"] + M8["Chaos/, RaiseDead/,
RegimentsOfRenown/, ...
(~20 more, one per mechanic)"] + end + + SM2 --> REGISTRY + REGISTRY -- "calls each module's
RegisterCampaignBehaviors/RegisterModels/
RegisterMissionBehaviors" --> MODS + MODS -- "depends on (read-only)" --> FW + FW -.no dependency on Modules.-> MODS +``` + +Key invariant: **arrows only point from `Modules/` into `Framework/`, never back.** If a +`Framework/` class needs to call into a specific module, that's a signal the class isn't +actually framework — either promote the mechanism up (generalize it) or push the call down (let +the module opt in via an event/hook rather than the framework knowing the module by name). + +## Proposed registration contract + +Replace the hand-written `AddBehavior`/`AddModel`/`AddMissionBehavior` blocks in `SubModule.cs` +with a small interface each module implements once, discovered the same way +`Extensions/UI`'s `ViewModelExtensionManager` already discovers `[ViewModelExtension]` types — +so this isn't a new idiom for the codebase, just the existing one applied to module registration: + +```csharp +public interface ITORModule +{ + void RegisterCampaignBehaviors(CampaignGameStarter starter) { } + void RegisterMissionBehaviors(Mission mission) { } + void RegisterModels(IGameStarter starter) { } + void RegisterGameObjectTypes(Game game) { } // ObjectManager.RegisterType + void OnSubModuleLoad() { } // template/XML loading, if any +} + +[AttributeUsage(AttributeTargets.Class)] +public class TORModuleAttribute : Attribute { } +``` + +```mermaid +classDiagram + class ITORModule { + <> + +RegisterCampaignBehaviors(CampaignGameStarter) + +RegisterMissionBehaviors(Mission) + +RegisterModels(IGameStarter) + +RegisterGameObjectTypes(Game) + +OnSubModuleLoad() + } + class TORModuleAttribute { + <> + } + class CareersModule + class ReligionModule + class CraftingModule + ITORModule <|.. CareersModule + ITORModule <|.. ReligionModule + ITORModule <|.. CraftingModule + TORModuleAttribute ..> CareersModule + TORModuleAttribute ..> ReligionModule + TORModuleAttribute ..> CraftingModule +``` + +`SubModule.cs` shrinks to: Harmony setup, `Framework/` initialization calls (still explicit — +framework pieces have real load-order constraints worth keeping visible), then one +`TORModuleRegistry.DiscoverAndRegister(...)` call per lifecycle hook. Adding a new feature +becomes "add a folder under `Modules/` with a class implementing `ITORModule`" instead of "edit +`SubModule.cs` in five places and hope you didn't collide with someone else's line." + +Save-id registration stays centrally *tracked* (id collisions are catastrophic and must be +reviewable in one place) but each module keeps contributing its own `SaveableTypeDefiner` +colocated with its types — generalizing the pattern `Diplomacy/TORAllianceWarBehavior` and +`Diplomacy/HonorAllianceDecision` already use, rather than growing the central +`TORSaveableTypeDefiner` forever. + +## Classification + +Legend: **FW** = moves to `Framework/`, **MOD** = moves to `Modules//`, **SPLIT** = the +folder's contents are genuinely mixed and need to be divided. + +### Already-framework-shaped top-level folders + +| Folder | Verdict | Notes | +|---|---|---| +| `Utilities/` | FW | Uncontroversial — pure cross-cutting helpers already. | +| `SaveGameSystem/` | FW | Keep as the id-ledger; push individual type definitions out to modules over time (see above). | +| `GameManagers/` | FW | Bootstrap, key bindings, shader compilation tracking. | +| `Audio/` | FW | Standalone subsystem, no feature identity. | +| `Ink/` | FW | The Ink *engine* bridge is generic (spawn item/settlement/event/quest/mission/audio); authored `.ink` files are already data, not code. | +| `Missions/` (root) | FW | `TorMissionManager`, `TORMissionAgentHandler`, `MissionExperienceBehavior` are generic mission-launch plumbing used by many modules. | +| `Extensions/` (root ext. methods, `DebugMethods`) | FW | Generic extension methods on vanilla types. | +| `Extensions/ExtendedInfoSystem/` | FW | The side-table *mechanism*; consumed by nearly every module. | +| `Extensions/UI/` (VM-extension framework, `TORInitialScreen`, `MainMenu/`) | FW mechanism, **SPLIT** concrete extensions | `IViewModelExtension`/`ViewModelExtensionManager` stay FW; concrete `CraftingVMExtension`/`RefinementVMExtension` move to `Modules/Crafting/`, etc. — anything named after a specific screen that only one module cares about. | +| `HarmonyPatches/` | mostly FW, **SPLIT** the rest | Engine-wide patches (`AgentPatches`, `MissionPatches`, `ObjectManagerPatches`, `ViewModelPatches`, `GameTextPatches`, `LoadingScreenPatches`, `MainMenuCrashPatch`, ...) stay FW. Patches that only touch one module's own types (`CraftingPatches`, `CustomResourcePatches`, `TournamentPatches`, `ArtilleryPatches`, `ArenaPracticePatch`, `CustomBattlePatches`) move to live beside that module. | + +### `AbilitySystem/` and combat runtime — Framework + +| Folder | Verdict | Notes | +|---|---|---| +| `AbilitySystem/` (core: `Ability`, `AbilityTemplate`, `AbilityFactory`, `AbilityComponent`, `AbilityManagerMissionLogic`, HUD) | FW | The magic/prayer/career-ability *engine* — every module that grants an ability is a client of this, not a peer. | +| `AbilitySystem/CrossHairs/`, `SpellCasting/`, `Spells/` (+`SpellBook/`), `Spells/Prayers/` | FW | Same engine; Lore/Spell/Prayer data model and its UI are generic magic-system plumbing, not one module's content. | +| `AbilitySystem/Scripts/` | **SPLIT** | Base `AbilityScript` machinery → FW. Per-Career `CareerAbilityScript` subclasses → `Modules/Careers/Abilities/`. | +| `BattleMechanics/StatusEffect/`, `TriggeredEffect/`, `DamageSystem/` | FW | The shared effect-resolution pipeline every spell/item/prayer fires through. | +| `BattleMechanics/AI/` (all of it: `CastingAI/`, `TeamAI/`, `ArtilleryAI/`, `CivilianMissionAI/`, `CommonAIFunctions/`) | FW | Battle-simulation infrastructure, not a toggleable feature — every battle uses it regardless of which content modules are involved. | +| `BattleMechanics/` root (`TORBattleAgentLogic`, `AddAgentComponentsMissionLogic`, `CustomCrosshairMissionBehavior`, `CinematicCameraMissionView`) | FW | Generic mission plumbing. | +| `BattleMechanics/` root — `CareerPerkMissionBehavior` | MOD → `Careers/` | Career-specific despite living at `BattleMechanics/` root today. | +| `BattleMechanics/` root — `TORMonsterSiegeLogic`, `SiegeEarlyVictoryMissionLogic` | MOD → `TORCustomSettlement/` | Monster-siege support exists for Troll Cave content. | + +### `BattleMechanics/*` content add-ons — Modules + +| Folder | Verdict | Notes | +|---|---|---| +| `Firearms/` | MOD | Self-contained black-powder mechanics. | +| `Dismemberment/` | MOD | Self-contained gore-on-kill logic. | +| `Artillery/` | MOD | Field siege weapons; depends on FW `AI/ArtilleryAI`. | +| `Banners/` | MOD | Custom faction banner content. | +| `CustomArenaModes/` | MOD → `Tournaments/` | Pair with `Missions/ArcheryContestMissionController` + `JoustFightMissionController`. | +| `SniperScope/` | MOD → `Firearms/` | Long-range-weapon scope, used by Firearms content. | +| `Voice/` | FW | Generic battle-shout/voice-over system every agent uses, not one feature. | +| `Morale/` (`UndeadMoraleAgentComponent`) | FW | A core race rule (undead ignore morale), not a toggle. | +| `SFX/` | FW | Generic scene-prop scripting toolkit (spin, face-target, light dampening), reused by whichever module drops a prop in a scene. | + +### `CampaignMechanics/` — the bulk of the feature surface + +| Folder | Verdict | Notes | +|---|---|---| +| `Assimilation/`, `BountyMaster/`, `Chaos/`, `CharacterCreation/`, `Companions/`, `Crafting/`, `Diplomacy/`, `MasterEngineer/`, `PostBattleLoot/`, `RaidingParties/`, `RaiseDead/`, `RegimentsOfRenown/`, `Religion/`, `ServeAsAHireling/`, `SpellTrainers/`, `TORCustomSettlement/` (+`Component/`, `CustomSettlementMenus/`), `UniqueSpawns/`, `Villages/` | MOD | Already well-isolated folders — the most direct wins. Each becomes `Modules//` basically as-is, plus an `ITORModule` implementation. | +| `Careers/` | MOD → merge into `Modules/Careers/` | Along with `CharacterDevelopment/CareerSystem/` (+`Choices/`, `CareerButton/`), `CharacterDevelopment` root's `TORCareers`/`TORCareerChoices`/`TORCareerChoiceGroups`/`CareerAbilityChargeSupplier`, `Quests/Careers/`, and the `AbilitySystem/Scripts` career scripts noted above. This is the largest single module — spans five current top-level folders. | +| `CustomResourceBehavior/` + `CustomResources/` (+`WaaaghMeter/`) | MOD → `Modules/CustomResources/` | The whole per-culture resource system (Prestige/Chivalry/DarkEnergy/ForestHarmony/CouncilFavor/OathGold/Teef/Waaagh) as one module domain. | +| `CustomDialogs/` (+`ConversationTags/`) | FW | A shared "extra conversation lines" surface multiple modules hook into (framework role, similar to `CustomEvents/`) — but audit for module-specific dialog behaviors (e.g. `DuelBehavior`) that should move out. | +| `CustomDialogs/DuelBehavior` | MOD → `Tournaments/` (or its own `Modules/Duel/`) | Honor-duel is one coherent feature, currently colocated in `CustomDialogs/`. | +| `CustomEvents/` | FW mechanism | Generic scripted-event framework (`CustomEvent`, `CustomEventsCampaignBehavior`). | +| `CustomEvents/SimpleCareerQuestBehavior` | MOD → `Careers/` | Career-flavor content colocated in the framework folder today. | +| `MapNotifications/` | FW → `Framework/UI/` | Generic notification popup helper used by every module. | +| Root files: `CampaignEventHelpers`, `TorRecruitmentHelpers`/`TORAIRecruitmentCampaignBehavior`, `TORPartyUpgraderCampaignBehavior`, `TORCaptivityCampaignBehavior`, `TORFactionDiscontinuationCampaignBehavior`, `TORStartupBehavior`, `SkillTrainerBehavior`, `TorMapBarSpriteWidget`, `TORCampaignMusicHandler` | FW | Campaign-wide systems with no single owning feature. | +| Root files: `GreenskinAICampaignBehavior` | MOD → `CustomResources/` (Waaagh) or its own `Modules/Greenskins/` | Greenskin/Waaagh-flavored AI behavior — needs a look at what it actually touches before placing. | +| Root files: `TORSpecialSettlementBehavior` | MOD → `TORCustomSettlement/` | | + +### `CharacterDevelopment/` — split + +| Folder | Verdict | Notes | +|---|---|---| +| `TORSkills`, `TORSkillEffects`, `TORAttributes`, `TORCharacterTraits`, `TORPerks`, `TORPerkHandlerCampaignBehavior` | FW | Base progression scaffolding every module can add skills/perks/traits into. | +| `TORCareers`, `TORCareerChoices`, `TORCareerChoiceGroups`, `CareerAbilityChargeSupplier` | MOD → `Careers/` | See Careers entry above. | +| `CareerSystem/` (whole subfolder) | MOD → `Careers/` | | + +### `Extensions/`, `Items/`, `Models/`, `Quests/` — split + +| Folder | Verdict | Notes | +|---|---|---| +| `Items/` root (`ItemTrait`, `ItemTraitManager`, `ItemTraitAgentComponent`, `ExtendedItemObjectManager`/`Properties`) | FW | Generic item-enchantment/metadata engine. | +| `Items/` root (`TorEnchantingIngredients`, item-trait tooltip VMs/widgets) | MOD → `Crafting/` | Crafting-flavored UI colocated in `Items/` today. | +| `Items/InventoryUseScriptsCampaignBehavior` | FW | Generic dispatcher. | +| `Items/WeaponHitScripts/`, `Items/InventoryUseScripts/` | FW interface, **SPLIT** implementations | The `IWeaponHitScript`/`IInventoryUseScript` contracts stay FW; concrete scripts move with whichever module grants the item that uses them. | +| `Models/` (generic combat/party/settlement-economy formula overrides — the majority) | FW | Stays a registration surface, but each `AddModel` call should move to be issued by the owning module (Framework or the module registering itself), not centrally in `SubModule.OnGameStart`. | +| `Models/` — `TORFaithModel` | MOD → `Religion/` | | +| `Models/` — `TORCustomResourceModel` | MOD → `CustomResources/` | | +| `Models/` — `TOREnchantmentCraftingModel`, `TOREnchantmentIngredientsModel`, `TORSmithingModel` | MOD → `Crafting/` | | +| `Models/` — `TORCompanionHiringPriceCalculationModel`, `TORCompanionTrainingModel` | MOD → `Companions/` | | +| `Models/` — `TORHiringCompatibilityModel` | MOD → `ServeAsAHireling/` (verify against usage) | | +| `Models/` — `TORDiplomacyModel`, `TORAllianceModel`, `TORTradeAgreementModel`, `TORKingdomDecisionPermissionModel` | MOD → `Diplomacy/` | | +| `Models/` — `TORVillageProductionCalculatorModel` | MOD → `Villages/` | | +| `Models/` — `TORTournamentModel` | MOD → `Tournaments/` | | +| `Models/` — `TORAbilityModel` | FW → `AbilitySystem/` | Spell damage/radius/duration scaling is engine-level, not one module's. | +| `Models/CustomBattleModels/` | FW | Parallel model set for Custom Battle mode as a whole, not one feature. | +| `Quests/TORQuestHelper`, `QuestPartyComponent` | FW | Generic quest-launch infra used by many modules' content. | +| `Quests/EngineerQuest` | MOD → `MasterEngineer/` | | +| `Quests/SpecializeLoreQuest` | MOD → `SpellTrainers/` | | +| `Quests/HuntCultistsQuestCampaignBehavior` | MOD → `Chaos/` (verify) | | +| `Quests/PlaguedVillageQuestCampaignBehavior` | MOD → `Villages/` or `RaiseDead/` (verify — theme needs a quick read before placing) | | +| `Quests/Careers/` | MOD → `Careers/` | | + +## Migration strategy + +Doing this in one pass is high-risk on a codebase this size (2,600-line `SubModule.cs`, 90 game +models, `SaveGameSystem` compatibility constraints). Suggested phased order, each phase +independently shippable: + +1. **Introduce the mechanism, touch nothing else.** Add `ITORModule`/`TORModuleAttribute`/`TORModuleRegistry` under a new `Framework/` folder (which starts out mostly empty re-exports). No behavior moves yet. +2. **Move the uncontroversial pure-infrastructure folders** (`Utilities/`, `Audio/`, `GameManagers/`, `SaveGameSystem/`) into `Framework/` — pure `namespace`/`using` churn, zero registration risk, builds confidence in the move tooling. +3. **Convert 2–3 already-isolated `CampaignMechanics/` features** (good first candidates: `BountyMaster/`, `PostBattleLoot/`, `Villages/` — small, few cross-references per their CLAUDE.md summaries) to `Modules/` + `ITORModule`, removing their lines from `SubModule.cs`. Validate the registry-discovery approach end-to-end in a real play session before scaling up. +4. **Migrate the rest of the clearly-isolated `CampaignMechanics/*` and `BattleMechanics/*` content folders** module-by-module, each as its own PR (small diff, easy to bisect if something regresses). +5. **Tackle the split folders last** (`Models/`, `Items/`, `Quests/`, `Extensions/UI/`, `HarmonyPatches/`) — these require pulling individual files out of a shared folder rather than moving a whole folder, so they're more error-prone and benefit from the muscle memory built in steps 3–4. +6. **Tackle `Careers/` last of all** — it's the largest and most cross-cutting module (spans five current folders); do it once the pattern is well-proven elsewhere. + +Each phase: move files, update `namespace`s, remove the corresponding lines from `SubModule.cs`, +add the module's `ITORModule` implementation, build, and do a smoke playtest (Career/quest +mechanics and save/load in particular, given `SaveGameSystem`'s "never renumber" constraint). + +## Open questions before executing + +- **Naming**: `Modules/` vs. keeping `CampaignMechanics/`/`BattleMechanics/` as the module root and only carving out `Framework/`? (Renaming touches every file's `namespace`.) +- **Reflection-based discovery** mirrors the existing `ViewModelExtensionManager` pattern, but is a runtime cost/load-order change worth confirming against Bannerlord's startup profiling before committing, vs. an explicit (but still short) list of module types in `SubModule.cs`. +- A few placements above are flagged **"verify"** — `GreenskinAICampaignBehavior`, `TORHiringCompatibilityModel`, `HuntCultistsQuestCampaignBehavior`, `PlaguedVillageQuestCampaignBehavior` — their current CLAUDE.md summaries don't pin down which module they truly belong to; worth a quick source read before moving. +- Should `SaveGameSystem`'s central definer be split by module now, or only for *new* types going forward (leaving existing ids where they are, since renumbering breaks saves)? From 0eda363b413f9116308690e6844ffc231528d2e2 Mon Sep 17 00:00:00 2001 From: randychihuahua Date: Sat, 29 Aug 2026 21:48:02 +0200 Subject: [PATCH 2/6] Split EnchantmentHelper and EnchantmentShopHelper --- .../Crafting/EnchanterTownBehavior.cs | 2 +- .../Crafting/EnchantmentHelper.cs | 242 +----------------- .../Crafting/EnchantmentShopHelper.cs | 232 +++++++++++++++++ .../Crafting/PriestBehavior.cs | 2 +- CSharpSourceCode/TOR_Core.csproj | 1 + CSharpSourceCode/TOR_Core.sln | 8 +- 6 files changed, 251 insertions(+), 236 deletions(-) create mode 100644 CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/EnchanterTownBehavior.cs b/CSharpSourceCode/CampaignMechanics/Crafting/EnchanterTownBehavior.cs index a8e63ee3..74664526 100644 --- a/CSharpSourceCode/CampaignMechanics/Crafting/EnchanterTownBehavior.cs +++ b/CSharpSourceCode/CampaignMechanics/Crafting/EnchanterTownBehavior.cs @@ -772,7 +772,7 @@ bool EnchanterCondition(string culture) void OpenEnchantmentShop(List prefixList, string culture) { - EnchantmentHelper.OpenEnchantmentRecipeShop(prefixList, culture, false); + EnchantmentShopHelper.OpenEnchantmentRecipeShop(prefixList, culture, false); } } } diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentHelper.cs b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentHelper.cs index fded237e..05632964 100644 --- a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentHelper.cs +++ b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentHelper.cs @@ -1,22 +1,22 @@ using HarmonyLib; -using NLog; -using System; using System.Collections.Generic; using System.Linq; using TaleWorlds.CampaignSystem; using TaleWorlds.Core; -using TaleWorlds.Core.ImageIdentifiers; using TaleWorlds.LinQuick; using TaleWorlds.Localization; using TaleWorlds.ObjectSystem; -using TOR_Core.AbilitySystem.Spells; using TOR_Core.CharacterDevelopment; using TOR_Core.Extensions; -using TOR_Core.Items; using TOR_Core.Utilities; namespace TOR_Core.CampaignMechanics.Crafting; +/// +/// Enchantment blueprint data and item creation: what blueprints exist, who in the party +/// is eligible to learn one, and building the actual enchanted . +/// For the town-service shop UI built on top of this data, see . +/// public static class EnchantmentHelper { public static ItemObject CreateEnchantedItem(ItemObject original, List traits = null, string newName = null, bool playerCrafted = false, ItemModifier itemModifier = null) @@ -53,7 +53,7 @@ private static ItemObject CreateItemCopy(ItemObject copyFrom, string newId, stri return newItem; } - private static List GetBlueprintItems(List prefixList) + internal static List GetBlueprintItems(List prefixList) { return MBObjectManager.Instance.GetObjectTypeList() .Where(item => @@ -65,7 +65,7 @@ private static List GetBlueprintItems(List prefixList) .ToList(); } - private static bool TryGetBlueprintData(ItemObject item, out string blueprintId, out SkillObject requiredSkill, out int requiredSkillValue, out string restriction) + internal static bool TryGetBlueprintData(ItemObject item, out string blueprintId, out SkillObject requiredSkill, out int requiredSkillValue, out string restriction) { blueprintId = null; requiredSkill = null; @@ -104,19 +104,13 @@ private static bool TryGetBlueprintData(ItemObject item, out string blueprintId, return true; } - private static bool IsBlueprintCurrentlyApplicableToParty(string blueprintId) - { - if (Hero.MainHero.PartyBelongedTo.GetMemberHeroes().Any(hero => hero.HasKnownEnchantmentBlueprint(blueprintId))) - { - return true; - } + internal static bool IsBlueprintKnownByParty(string blueprintId) => Hero.MainHero.PartyBelongedTo.GetMemberHeroes().Any(hero => hero.HasKnownEnchantmentBlueprint(blueprintId)); - return Hero.MainHero.PartyBelongedTo.ItemRoster.Any(rosterElement => + internal static bool IsBlueprintInInventory(string blueprintId) => Hero.MainHero.PartyBelongedTo.ItemRoster.Any(rosterElement => TryGetBlueprintData(rosterElement.EquipmentElement.Item, out var inventoryBlueprintId, out _, out _, out _) && inventoryBlueprintId == blueprintId); - } - private static List GetEligibleHeroesForBlueprint(string blueprintId, SkillObject requiredSkill, int requiredSkillValue, string restriction, bool requireRequiredSkill) + internal static List GetEligibleHeroesForBlueprint(string blueprintId, SkillObject requiredSkill, int requiredSkillValue, string restriction, bool requireRequiredSkill) { var eligibleHeroes = new List(); @@ -158,7 +152,7 @@ public static bool HasAnyLearnableEnchantmentRecipe(List prefixList) continue; } - if (IsBlueprintCurrentlyApplicableToParty(blueprintId)) + if (IsBlueprintKnownByParty(blueprintId) || IsBlueprintInInventory(blueprintId)) { continue; } @@ -171,216 +165,4 @@ public static bool HasAnyLearnableEnchantmentRecipe(List prefixList) return false; } - - public static void OpenEnchantmentRecipeShop(List prefixList, string culture, bool blessings = false) - { - var blueprints = GetBlueprintItems(prefixList); - - var list = new List(); - foreach (var item in blueprints) - { - if (!TryGetBlueprintData(item, out var blueprintId, out var requiredSkill, out var requiredSkillValue, out var restriction)) - { - continue; - } - - if (IsBlueprintCurrentlyApplicableToParty(blueprintId)) - { - continue; - } - - if (GetEligibleHeroesForBlueprint(blueprintId, requiredSkill, requiredSkillValue, restriction, false).Any()) - { - list.Add(item); - } - } - - var selectableItems = new List(); - foreach (var item in list) - { - - var trait = item.GetTraits().FirstOrDefault(); - if (trait == null) - { - TORCommon.Log($"Enchantment blueprint {item.StringId} has no traits. Skipping this item.", LogLevel.Error); - continue; - } - - if (trait.OnInventoryUseScript == null) - { - TORCommon.Log($"Enchantment blueprint {item.StringId} has no inventory use script. Skipping this item.", LogLevel.Error); - continue; - } - - var arguments = trait.OnInventoryUseScript.InventoryScriptArguments; - if (arguments == null || arguments.Count < 3) - { - var argCount = arguments?.Count ?? 0; - TORCommon.Log($"Enchantment blueprint {item.StringId} has insufficient arguments (expected at least 3, got {argCount})", LogLevel.Error); - continue; - } - - var included = false; - - var hintText = new TextObject("{TRAIT_EFFECT}\n\n{REQUIREMENT_TEXT}\n\n{COMPLETE_COST}"); - - if (!TryGetBlueprintData(item, out var id, out var skill, out var skillValue, out var restriction)) - { - continue; - } - - var eligableHeroes = GetEligibleHeroesForBlueprint(id, skill, skillValue, restriction, false); - if (!eligableHeroes.Any()) - { - continue; - } - - var learnableHeroes = eligableHeroes.Where(hero => hero.GetSkillValue(skill) >= skillValue).ToList(); - var enabled = learnableHeroes.Any(); - - var requirementPrefix = ""; - - if (!string.IsNullOrEmpty(restriction)) - { - var lore = LoreObject.GetAll().FirstOrDefault(x => x.StringId == restriction); - if (lore != null) - { - requirementPrefix = "This enchantment is bound to the Lore of " + lore.Name + ". "; - } - else - { - requirementPrefix = "This enchantment requires " + restriction + ". "; - } - } - - if (!enabled) - { - if (eligableHeroes.Count == 1) - { - var hero = eligableHeroes[0]; - if (hero == Hero.MainHero) - { - hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + "You don't have enough " + skill.Name + ". Requires " + skillValue + "."); - } - else - { - hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + hero.Name + " doesn't have enough " + skill.Name + ". Requires " + skillValue + "."); - } - } - else - { - hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + "None of your eligible characters have enough " + skill.Name + ". Requires " + skillValue + "."); - } - } - else - { - hintText.SetTextVariable("REQUIREMENT_TEXT", ""); - } - - var crCost = 0; - var goldCost = 0; - var cr = Hero.MainHero.GetCultureSpecificCustomResource(); - var factor = cr.GetCustomResourceGeneralizedFactor(); - crCost = (int)factor * skillValue; - - goldCost = (int)item.Value; - - if (enabled) - { - if (!hintText.GetVariableValue("REQUIREMENT_TEXT", out var requirementText) || - requirementText != null && requirementText.ToString().IsEmpty()) - { - if (crCost >= Hero.MainHero.GetCultureSpecificCustomResourceValue()) - { - enabled = false; - - hintText.SetTextVariable("REQUIREMENT_TEXT", "Not enough {CUSTOMRESOURCE}"); - } - - if (goldCost >= Hero.MainHero.Gold) - { - enabled = false; - - hintText.SetTextVariable("REQUIREMENT_TEXT", "Not enough {GOLD_ICON}."); - } - } - - } - - - var underlyingTrait = ItemTrait.All.FirstOrDefault(x => x.ItemTraitStringId == id); - - if (underlyingTrait != null) - { - string typeRestriction = GameTexts.FindText("tor_enchantmentshop_restriction", underlyingTrait.ValidItemType.ToString()).ToString(); - GameTexts.SetVariable("VALIDTYPE_RESTRICTION", typeRestriction); - } - - - - if (enabled) - { - - hintText = new TextObject(trait.ItemTraitDescription + "\n {GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE},\n {VALIDTYPE_RESTRICTION}"); - } - hintText.SetTextVariable("TRAIT_EFFECT", trait.ItemTraitDescription); - hintText.SetTextVariable("COMPLETE_COST", "{GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE}"); - GameTexts.SetVariable("CR_VALUE", crCost); - GameTexts.SetVariable("CUSTOMRESOURCE", Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceIconAsText()); - GameTexts.SetVariable("GOLD_VALUE", item.Value); - - - selectableItems.Add(new InquiryElement(new Tuple, ItemObject>(eligableHeroes, item), item.Name.ToString(), new ItemImageIdentifier(item), enabled, hintText.ToString())); - } - - var shopvariation = ""; - if (blessings) - { - shopvariation = "blessings"; - } - else - { - shopvariation = culture; - } - - var title = GameTexts.FindText("tor_enchantmentshop_title", shopvariation).ToString(); - var description = GameTexts.FindText("tor_enchantmentshop_description", shopvariation).ToString(); - - var inquirydata = new MultiSelectionInquiryData(title, description, selectableItems, true, 1, 1, "Accept", "Cancel", - AddEnchantment, null, "", true); - MBInformationManager.ShowMultiSelectionInquiry(inquirydata, true); - } - - - private static void AddEnchantment(List inquiryElements) - { - var element = (Tuple, ItemObject>)inquiryElements.FirstOrDefault()?.Identifier; - if (element == null) return; - - var heroes = element.Item1; - var item = element.Item2; - var trait = item.GetTraits().FirstOrDefault(); - - var arguments = trait.OnInventoryUseScript.InventoryScriptArguments; - var skillValue = 0; - - int.TryParse(arguments[2], out skillValue); - var candidateHero = heroes.Count == 1 ? heroes[0] : heroes.FirstOrDefault(x => x == Hero.MainHero); - - if (candidateHero != null) - { - candidateHero.AddEnchantmentBlueprint(arguments[0], true); // convenience, only one character can learn it, so we instantly apply the trait - } - else - { - Hero.MainHero.PartyBelongedTo.ItemRoster.Add(new ItemRosterElement(item, 1)); // we dont know, so we just add it to the inventory - var itemAddedText = TORTextHelper.GetTextObject("tor_item_added_to_inventory_text", "{ITEM_NAME} was added to the inventory"); - itemAddedText.SetTextVariable("ITEM_NAME", item.Name); - MBInformationManager.AddQuickInformation(itemAddedText, 0); - } - - var crCost = skillValue * Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceGeneralizedFactor(); - Hero.MainHero.AddCultureSpecificCustomResource(-crCost); - Hero.MainHero.ChangeHeroGold(-item.Value); - } -} \ No newline at end of file +} diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs new file mode 100644 index 00000000..4d042ea9 --- /dev/null +++ b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs @@ -0,0 +1,232 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using TaleWorlds.CampaignSystem; +using TaleWorlds.Core; +using TaleWorlds.Core.ImageIdentifiers; +using TaleWorlds.Localization; +using TOR_Core.AbilitySystem.Spells; +using TOR_Core.Extensions; +using TOR_Core.Items; +using TOR_Core.Utilities; + +namespace TOR_Core.CampaignMechanics.Crafting; + +/// +/// The town-service enchantment shop: builds the inquiry listing eligible blueprints (via +/// ) and applies the chosen one on purchase. No blueprint +/// eligibility/data logic lives here - see for that. +/// +public static class EnchantmentShopHelper +{ + public static void OpenEnchantmentRecipeShop(List prefixList, string culture, bool blessings = false) + { + var blueprints = EnchantmentHelper.GetBlueprintItems(prefixList); + + var list = new List(); + foreach (var item in blueprints) + { + if (!EnchantmentHelper.TryGetBlueprintData(item, out var blueprintId, out var requiredSkill, out var requiredSkillValue, out var restriction)) + { + continue; + } + + if (EnchantmentHelper.IsBlueprintKnownByParty(blueprintId) || EnchantmentHelper.IsBlueprintInInventory(blueprintId)) + { + continue; + } + + if (EnchantmentHelper.GetEligibleHeroesForBlueprint(blueprintId, requiredSkill, requiredSkillValue, restriction, false).Any()) + { + list.Add(item); + } + } + + var selectableItems = new List(); + foreach (var item in list) + { + + var trait = item.GetTraits().FirstOrDefault(); + if (trait == null) + { + TORCommon.Log($"Enchantment blueprint {item.StringId} has no traits. Skipping this item.", LogLevel.Error); + continue; + } + + if (trait.OnInventoryUseScript == null) + { + TORCommon.Log($"Enchantment blueprint {item.StringId} has no inventory use script. Skipping this item.", LogLevel.Error); + continue; + } + + var arguments = trait.OnInventoryUseScript.InventoryScriptArguments; + if (arguments == null || arguments.Count < 3) + { + var argCount = arguments?.Count ?? 0; + TORCommon.Log($"Enchantment blueprint {item.StringId} has insufficient arguments (expected at least 3, got {argCount})", LogLevel.Error); + continue; + } + + var hintText = new TextObject("{TRAIT_EFFECT}\n\n{REQUIREMENT_TEXT}\n\n{COMPLETE_COST}"); + + if (!EnchantmentHelper.TryGetBlueprintData(item, out var id, out var skill, out var skillValue, out var restriction)) + { + continue; + } + + var eligableHeroes = EnchantmentHelper.GetEligibleHeroesForBlueprint(id, skill, skillValue, restriction, false); + if (!eligableHeroes.Any()) + { + continue; + } + + var learnableHeroes = eligableHeroes.Where(hero => hero.GetSkillValue(skill) >= skillValue).ToList(); + var enabled = learnableHeroes.Any(); + + var requirementPrefix = ""; + + if (!string.IsNullOrEmpty(restriction)) + { + var lore = LoreObject.GetAll().FirstOrDefault(x => x.StringId == restriction); + if (lore != null) + { + requirementPrefix = "This enchantment is bound to the Lore of " + lore.Name + ". "; + } + else + { + requirementPrefix = "This enchantment requires " + restriction + ". "; + } + } + + if (!enabled) + { + if (eligableHeroes.Count == 1) + { + var hero = eligableHeroes[0]; + if (hero == Hero.MainHero) + { + hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + "You don't have enough " + skill.Name + ". Requires " + skillValue + "."); + } + else + { + hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + hero.Name + " doesn't have enough " + skill.Name + ". Requires " + skillValue + "."); + } + } + else + { + hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + "None of your eligible characters have enough " + skill.Name + ". Requires " + skillValue + "."); + } + } + else + { + hintText.SetTextVariable("REQUIREMENT_TEXT", ""); + } + + var crCost = 0; + var goldCost = 0; + var cr = Hero.MainHero.GetCultureSpecificCustomResource(); + var factor = cr.GetCustomResourceGeneralizedFactor(); + crCost = (int)factor * skillValue; + + goldCost = (int)item.Value; + + if (enabled) + { + if (!hintText.GetVariableValue("REQUIREMENT_TEXT", out var requirementText) || + requirementText != null && requirementText.ToString().IsEmpty()) + { + if (crCost >= Hero.MainHero.GetCultureSpecificCustomResourceValue()) + { + enabled = false; + + hintText.SetTextVariable("REQUIREMENT_TEXT", "Not enough {CUSTOMRESOURCE}"); + } + + if (goldCost >= Hero.MainHero.Gold) + { + enabled = false; + + hintText.SetTextVariable("REQUIREMENT_TEXT", "Not enough {GOLD_ICON}."); + } + } + + } + + + var underlyingTrait = ItemTrait.All.FirstOrDefault(x => x.ItemTraitStringId == id); + + if (underlyingTrait != null) + { + string typeRestriction = GameTexts.FindText("tor_enchantmentshop_restriction", underlyingTrait.ValidItemType.ToString()).ToString(); + GameTexts.SetVariable("VALIDTYPE_RESTRICTION", typeRestriction); + } + + + + if (enabled) + { + + hintText = new TextObject(trait.ItemTraitDescription + "\n {GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE},\n {VALIDTYPE_RESTRICTION}"); + } + hintText.SetTextVariable("TRAIT_EFFECT", trait.ItemTraitDescription); + hintText.SetTextVariable("COMPLETE_COST", "{GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE}"); + GameTexts.SetVariable("CR_VALUE", crCost); + GameTexts.SetVariable("CUSTOMRESOURCE", Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceIconAsText()); + GameTexts.SetVariable("GOLD_VALUE", item.Value); + + + selectableItems.Add(new InquiryElement(new Tuple, ItemObject>(eligableHeroes, item), item.Name.ToString(), new ItemImageIdentifier(item), enabled, hintText.ToString())); + } + + var shopvariation = ""; + if (blessings) + { + shopvariation = "blessings"; + } + else + { + shopvariation = culture; + } + + var title = GameTexts.FindText("tor_enchantmentshop_title", shopvariation).ToString(); + var description = GameTexts.FindText("tor_enchantmentshop_description", shopvariation).ToString(); + + var inquirydata = new MultiSelectionInquiryData(title, description, selectableItems, true, 1, 1, "Accept", "Cancel", + AddEnchantment, null, "", true); + MBInformationManager.ShowMultiSelectionInquiry(inquirydata, true); + } + + + private static void AddEnchantment(List inquiryElements) + { + var element = (Tuple, ItemObject>)inquiryElements.FirstOrDefault()?.Identifier; + if (element == null) return; + + var heroes = element.Item1; + var item = element.Item2; + var trait = item.GetTraits().FirstOrDefault(); + + var arguments = trait.OnInventoryUseScript.InventoryScriptArguments; + var skillValue = 0; + + int.TryParse(arguments[2], out skillValue); + var candidateHero = heroes.Count == 1 ? heroes[0] : heroes.FirstOrDefault(x => x == Hero.MainHero); + + if (candidateHero != null) + { + candidateHero.AddEnchantmentBlueprint(arguments[0], true); // convenience, only one character can learn it, so we instantly apply the trait + } + else + { + Hero.MainHero.PartyBelongedTo.ItemRoster.Add(new ItemRosterElement(item, 1)); // we dont know, so we just add it to the inventory + var itemAddedText = TORTextHelper.GetTextObject("tor_item_added_to_inventory_text", "{ITEM_NAME} was added to the inventory"); + itemAddedText.SetTextVariable("ITEM_NAME", item.Name); + MBInformationManager.AddQuickInformation(itemAddedText, 0); + } + + var crCost = skillValue * Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceGeneralizedFactor(); + Hero.MainHero.AddCultureSpecificCustomResource(-crCost); + Hero.MainHero.ChangeHeroGold(-item.Value); + } +} diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/PriestBehavior.cs b/CSharpSourceCode/CampaignMechanics/Crafting/PriestBehavior.cs index f5c157aa..7ae59e33 100644 --- a/CSharpSourceCode/CampaignMechanics/Crafting/PriestBehavior.cs +++ b/CSharpSourceCode/CampaignMechanics/Crafting/PriestBehavior.cs @@ -273,7 +273,7 @@ void OpenBlessingRecipesShop(string prefix) { var partner = CharacterObject.OneToOneConversationCharacter; - EnchantmentHelper.OpenEnchantmentRecipeShop([prefix], partner.Culture.StringId, true); + EnchantmentShopHelper.OpenEnchantmentRecipeShop([prefix], partner.Culture.StringId, true); } void BlessParty(string cultId) diff --git a/CSharpSourceCode/TOR_Core.csproj b/CSharpSourceCode/TOR_Core.csproj index 8860968d..950f8581 100644 --- a/CSharpSourceCode/TOR_Core.csproj +++ b/CSharpSourceCode/TOR_Core.csproj @@ -516,6 +516,7 @@ + diff --git a/CSharpSourceCode/TOR_Core.sln b/CSharpSourceCode/TOR_Core.sln index b9b1a52e..79fc7bd6 100644 --- a/CSharpSourceCode/TOR_Core.sln +++ b/CSharpSourceCode/TOR_Core.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.2.32505.173 +# Visual Studio Version 18 +VisualStudioVersion = 18.9.12120.119 stable MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TOR_Core", "TOR_Core.csproj", "{80942161-02FB-4024-A1C2-22EF33DC8D1A}" EndProject @@ -13,8 +13,8 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {80942161-02FB-4024-A1C2-22EF33DC8D1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {80942161-02FB-4024-A1C2-22EF33DC8D1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80942161-02FB-4024-A1C2-22EF33DC8D1A}.Debug|Any CPU.ActiveCfg = Debug|x64 + {80942161-02FB-4024-A1C2-22EF33DC8D1A}.Debug|Any CPU.Build.0 = Debug|x64 {80942161-02FB-4024-A1C2-22EF33DC8D1A}.Debug|x64.ActiveCfg = Debug|x64 {80942161-02FB-4024-A1C2-22EF33DC8D1A}.Debug|x64.Build.0 = Debug|x64 {80942161-02FB-4024-A1C2-22EF33DC8D1A}.Release|Any CPU.ActiveCfg = Release|Any CPU From fc1b6aa80bc9c9ef9cf2b207939226516971820c Mon Sep 17 00:00:00 2001 From: randychihuahua Date: Sat, 29 Aug 2026 23:36:10 +0200 Subject: [PATCH 3/6] Changes proposed --- .../Crafting/EnchantmentShopHelper.cs | 279 ++++++++++-------- 1 file changed, 153 insertions(+), 126 deletions(-) diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs index 4d042ea9..c75e445a 100644 --- a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs +++ b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs @@ -21,10 +21,26 @@ namespace TOR_Core.CampaignMechanics.Crafting; public static class EnchantmentShopHelper { public static void OpenEnchantmentRecipeShop(List prefixList, string culture, bool blessings = false) + { + var purchasableBlueprints = GetPurchasableBlueprints(prefixList); + var selectableItems = BuildInquiryElements(purchasableBlueprints); + + var shopVariation = GetShopVariation(culture, blessings); + var title = GameTexts.FindText("tor_enchantmentshop_title", shopVariation).ToString(); + var description = GameTexts.FindText("tor_enchantmentshop_description", shopVariation).ToString(); + + var inquirydata = new MultiSelectionInquiryData(title, description, selectableItems, true, 1, 1, "Accept", "Cancel", + AddEnchantment, null, "", true); + MBInformationManager.ShowMultiSelectionInquiry(inquirydata, true); + } + + private readonly record struct PurchasableBlueprint(ItemObject Item, string BlueprintId, SkillObject RequiredSkill, int RequiredSkillValue, string Restriction, List EligibleHeroes); + + private static List GetPurchasableBlueprints(List prefixList) { var blueprints = EnchantmentHelper.GetBlueprintItems(prefixList); - var list = new List(); + var list = new List(); foreach (var item in blueprints) { if (!EnchantmentHelper.TryGetBlueprintData(item, out var blueprintId, out var requiredSkill, out var requiredSkillValue, out var restriction)) @@ -37,166 +53,167 @@ public static void OpenEnchantmentRecipeShop(List prefixList, string cul continue; } - if (EnchantmentHelper.GetEligibleHeroesForBlueprint(blueprintId, requiredSkill, requiredSkillValue, restriction, false).Any()) + var eligibleHeroes = EnchantmentHelper.GetEligibleHeroesForBlueprint(blueprintId, requiredSkill, requiredSkillValue, restriction, false); + if (eligibleHeroes.Any()) { - list.Add(item); + list.Add(new PurchasableBlueprint(item, blueprintId, requiredSkill, requiredSkillValue, restriction, eligibleHeroes)); } } + return list; + } + + private static List BuildInquiryElements(List blueprints) + { var selectableItems = new List(); - foreach (var item in list) + foreach(var blueprint in blueprints) { - - var trait = item.GetTraits().FirstOrDefault(); - if (trait == null) + if (!TryGetUsableTrait(blueprint.Item, out var trait)) { - TORCommon.Log($"Enchantment blueprint {item.StringId} has no traits. Skipping this item.", LogLevel.Error); continue; } - if (trait.OnInventoryUseScript == null) - { - TORCommon.Log($"Enchantment blueprint {item.StringId} has no inventory use script. Skipping this item.", LogLevel.Error); - continue; - } + selectableItems.Add(CreateInquiryElement(blueprint, trait)); + } - var arguments = trait.OnInventoryUseScript.InventoryScriptArguments; - if (arguments == null || arguments.Count < 3) - { - var argCount = arguments?.Count ?? 0; - TORCommon.Log($"Enchantment blueprint {item.StringId} has insufficient arguments (expected at least 3, got {argCount})", LogLevel.Error); - continue; - } + return selectableItems; + } - var hintText = new TextObject("{TRAIT_EFFECT}\n\n{REQUIREMENT_TEXT}\n\n{COMPLETE_COST}"); + private static InquiryElement CreateInquiryElement(PurchasableBlueprint blueprint, ItemTrait trait) + { + var item = blueprint.Item; + var skill = blueprint.RequiredSkill; + var skillValue = blueprint.RequiredSkillValue; + var eligibleHeroes = blueprint.EligibleHeroes; - if (!EnchantmentHelper.TryGetBlueprintData(item, out var id, out var skill, out var skillValue, out var restriction)) - { - continue; - } + var enabled = eligibleHeroes.Any(hero => hero.GetSkillValue(skill) >= skillValue); - var eligableHeroes = EnchantmentHelper.GetEligibleHeroesForBlueprint(id, skill, skillValue, restriction, false); - if (!eligableHeroes.Any()) - { - continue; - } + var hintText = new TextObject("{TRAIT_EFFECT}\n\n{REQUIREMENT_TEXT}\n\n{COMPLETE_COST}"); + hintText.SetTextVariable("REQUIREMENT_TEXT", enabled ? "" : BuildRequirementText(eligibleHeroes, skill, skillValue, blueprint.Restriction)); - var learnableHeroes = eligableHeroes.Where(hero => hero.GetSkillValue(skill) >= skillValue).ToList(); - var enabled = learnableHeroes.Any(); + var crCost = CalculateCustomResourceCost(skillValue); + var goldCost = item.Value; + enabled = ApplyAffordabilityCheck(hintText, enabled, crCost, goldCost); - var requirementPrefix = ""; + SetValidItemTypeRestrictionVariable(blueprint.BlueprintId); - if (!string.IsNullOrEmpty(restriction)) - { - var lore = LoreObject.GetAll().FirstOrDefault(x => x.StringId == restriction); - if (lore != null) - { - requirementPrefix = "This enchantment is bound to the Lore of " + lore.Name + ". "; - } - else - { - requirementPrefix = "This enchantment requires " + restriction + ". "; - } - } + if (enabled) + { + hintText = new TextObject(trait.ItemTraitDescription + "\n {GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE},\n {VALIDTYPE_RESTRICTION}"); + } - if (!enabled) - { - if (eligableHeroes.Count == 1) - { - var hero = eligableHeroes[0]; - if (hero == Hero.MainHero) - { - hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + "You don't have enough " + skill.Name + ". Requires " + skillValue + "."); - } - else - { - hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + hero.Name + " doesn't have enough " + skill.Name + ". Requires " + skillValue + "."); - } - } - else - { - hintText.SetTextVariable("REQUIREMENT_TEXT", requirementPrefix + "None of your eligible characters have enough " + skill.Name + ". Requires " + skillValue + "."); - } - } - else - { - hintText.SetTextVariable("REQUIREMENT_TEXT", ""); - } + hintText.SetTextVariable("TRAIT_EFFECT", trait.ItemTraitDescription); + hintText.SetTextVariable("COMPLETE_COST", "{GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE}"); + GameTexts.SetVariable("CR_VALUE", crCost); + GameTexts.SetVariable("CUSTOMRESOURCE", Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceIconAsText()); + GameTexts.SetVariable("GOLD_VALUE", item.Value); - var crCost = 0; - var goldCost = 0; - var cr = Hero.MainHero.GetCultureSpecificCustomResource(); - var factor = cr.GetCustomResourceGeneralizedFactor(); - crCost = (int)factor * skillValue; + return new InquiryElement(new Tuple, ItemObject>(eligibleHeroes, item), item.Name.ToString(), new ItemImageIdentifier(item), enabled, hintText.ToString()); + } - goldCost = (int)item.Value; + private static bool TryGetUsableTrait(ItemObject item, out ItemTrait trait) + { + trait = item.GetTraits().FirstOrDefault(); + if (trait == null) + { + TORCommon.Log($"Enchantment blueprint {item.StringId} has no traits. Skipping this item.", LogLevel.Error); + return false; + } - if (enabled) - { - if (!hintText.GetVariableValue("REQUIREMENT_TEXT", out var requirementText) || - requirementText != null && requirementText.ToString().IsEmpty()) - { - if (crCost >= Hero.MainHero.GetCultureSpecificCustomResourceValue()) - { - enabled = false; + if (trait.OnInventoryUseScript == null) + { + TORCommon.Log($"Enchantment blueprint {item.StringId} has no inventory use script. Skipping this item.", LogLevel.Error); + return false; + } - hintText.SetTextVariable("REQUIREMENT_TEXT", "Not enough {CUSTOMRESOURCE}"); - } + var arguments = trait.OnInventoryUseScript.InventoryScriptArguments; + if (arguments == null || arguments.Count < 3) + { + var argCount = arguments?.Count ?? 0; + TORCommon.Log($"Enchantment blueprint {item.StringId} has insufficient arguments (expected at least 3, got {argCount})", LogLevel.Error); + return false; + } - if (goldCost >= Hero.MainHero.Gold) - { - enabled = false; + return true; + } - hintText.SetTextVariable("REQUIREMENT_TEXT", "Not enough {GOLD_ICON}."); - } - } + private static string BuildRequirementText(List eligableHeroes, SkillObject skill, int skillValue, string restriction) + { + var requirementPrefix = GetRestrictionPrefix(restriction); - } + if (eligableHeroes.Count == 1) + { + var hero = eligableHeroes[0]; + return hero == Hero.MainHero + ? requirementPrefix + "You don't have enough " + skill.Name + ". Requires " + skillValue + "." + : requirementPrefix + hero.Name + " doesn't have enough " + skill.Name + ". Requires " + skillValue + "."; + } + return requirementPrefix + "None of your eligible characters have enough " + skill.Name + ". Requires " + skillValue + "."; + } - var underlyingTrait = ItemTrait.All.FirstOrDefault(x => x.ItemTraitStringId == id); + private static string GetRestrictionPrefix(string restriction) + { + if (string.IsNullOrEmpty(restriction)) + { + return ""; + } - if (underlyingTrait != null) - { - string typeRestriction = GameTexts.FindText("tor_enchantmentshop_restriction", underlyingTrait.ValidItemType.ToString()).ToString(); - GameTexts.SetVariable("VALIDTYPE_RESTRICTION", typeRestriction); - } + var lore = LoreObject.GetAll().FirstOrDefault(x => x.StringId == restriction); + return lore != null + ? "This enchantment is bound to the Lore of " + lore.Name + ". " + : "This enchantment requires " + restriction + ". "; + } + private static int CalculateCustomResourceCost(int skillValue) + { + var factor = Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceGeneralizedFactor(); + return (int)factor * skillValue; + } + private static bool ApplyAffordabilityCheck(TextObject hintText, bool enabled, int crCost, int goldCost) + { + if (!enabled) + { + return false; + } - if (enabled) - { + if (!hintText.GetVariableValue("REQUIREMENT_TEXT", out var requirementText) || + requirementText != null && requirementText.ToString().IsEmpty()) + { + var missing = new List(); - hintText = new TextObject(trait.ItemTraitDescription + "\n {GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE},\n {VALIDTYPE_RESTRICTION}"); + if (crCost >= Hero.MainHero.GetCultureSpecificCustomResourceValue()) + { + missing.Add("{CUSTOMRESOURCE}"); } - hintText.SetTextVariable("TRAIT_EFFECT", trait.ItemTraitDescription); - hintText.SetTextVariable("COMPLETE_COST", "{GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE}"); - GameTexts.SetVariable("CR_VALUE", crCost); - GameTexts.SetVariable("CUSTOMRESOURCE", Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceIconAsText()); - GameTexts.SetVariable("GOLD_VALUE", item.Value); + if (goldCost >= Hero.MainHero.Gold) + { + missing.Add("{GOLD_ICON}"); + } - selectableItems.Add(new InquiryElement(new Tuple, ItemObject>(eligableHeroes, item), item.Name.ToString(), new ItemImageIdentifier(item), enabled, hintText.ToString())); + if (missing.Any()) + { + enabled = false; + hintText.SetTextVariable("REQUIREMENT_TEXT", "Not enough " + string.Join(" and ", missing) + "."); + } } - var shopvariation = ""; - if (blessings) - { - shopvariation = "blessings"; - } - else + return enabled; + } + + private static void SetValidItemTypeRestrictionVariable(string blueprintId) + { + var underlyingTrait = ItemTrait.All.FirstOrDefault(x => x.ItemTraitStringId == blueprintId); + if (underlyingTrait != null) { - shopvariation = culture; + var typeRestriction = GameTexts.FindText("tor_enchantmentshop_restriction", underlyingTrait.ValidItemType.ToString()).ToString(); + GameTexts.SetVariable("VALIDTYPE_RESTRICTION", typeRestriction); } - - var title = GameTexts.FindText("tor_enchantmentshop_title", shopvariation).ToString(); - var description = GameTexts.FindText("tor_enchantmentshop_description", shopvariation).ToString(); - - var inquirydata = new MultiSelectionInquiryData(title, description, selectableItems, true, 1, 1, "Accept", "Cancel", - AddEnchantment, null, "", true); - MBInformationManager.ShowMultiSelectionInquiry(inquirydata, true); } + private static string GetShopVariation(string culture, bool blessings) => blessings ? "blessings" : culture; private static void AddEnchantment(List inquiryElements) { @@ -206,25 +223,35 @@ private static void AddEnchantment(List inquiryElements) var heroes = element.Item1; var item = element.Item2; var trait = item.GetTraits().FirstOrDefault(); - var arguments = trait.OnInventoryUseScript.InventoryScriptArguments; - var skillValue = 0; - int.TryParse(arguments[2], out skillValue); - var candidateHero = heroes.Count == 1 ? heroes[0] : heroes.FirstOrDefault(x => x == Hero.MainHero); + int.TryParse(arguments[2], out var skillValue); + + GrantBlueprintOrAddToInventory(heroes, item, arguments[0]); + ChargeForPurchase(skillValue, item); + } + + private static void GrantBlueprintOrAddToInventory(List heroes, ItemObject item, string blueprintId) + { + var candidateHero = SelectRecipientHero(heroes); if (candidateHero != null) { - candidateHero.AddEnchantmentBlueprint(arguments[0], true); // convenience, only one character can learn it, so we instantly apply the trait + candidateHero.AddEnchantmentBlueprint(blueprintId, true); } else { - Hero.MainHero.PartyBelongedTo.ItemRoster.Add(new ItemRosterElement(item, 1)); // we dont know, so we just add it to the inventory + Hero.MainHero.PartyBelongedTo.ItemRoster.Add(new ItemRosterElement(item, 1)); var itemAddedText = TORTextHelper.GetTextObject("tor_item_added_to_inventory_text", "{ITEM_NAME} was added to the inventory"); itemAddedText.SetTextVariable("ITEM_NAME", item.Name); MBInformationManager.AddQuickInformation(itemAddedText, 0); } + } + private static Hero SelectRecipientHero(List heroes) => heroes.Count == 1 ? heroes[0] : heroes.FirstOrDefault(x => x == Hero.MainHero); + + private static void ChargeForPurchase(int skillValue, ItemObject item) + { var crCost = skillValue * Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceGeneralizedFactor(); Hero.MainHero.AddCultureSpecificCustomResource(-crCost); Hero.MainHero.ChangeHeroGold(-item.Value); From d746d52b115d61eaf0bdedb785117f86436e38ed Mon Sep 17 00:00:00 2001 From: randychihuahua Date: Sat, 29 Aug 2026 23:46:59 +0200 Subject: [PATCH 4/6] Refactor EnchantmentShopHelper --- .../Crafting/EnchantmentShopHelper.cs | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs index c75e445a..f979c765 100644 --- a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs +++ b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs @@ -5,6 +5,7 @@ using TaleWorlds.CampaignSystem; using TaleWorlds.Core; using TaleWorlds.Core.ImageIdentifiers; +using TaleWorlds.LinQuick; using TaleWorlds.Localization; using TOR_Core.AbilitySystem.Spells; using TOR_Core.Extensions; @@ -63,36 +64,22 @@ private static List GetPurchasableBlueprints(List return list; } - private static List BuildInquiryElements(List blueprints) - { - var selectableItems = new List(); - foreach(var blueprint in blueprints) - { - if (!TryGetUsableTrait(blueprint.Item, out var trait)) - { - continue; - } - - selectableItems.Add(CreateInquiryElement(blueprint, trait)); - } + private static List BuildInquiryElements(List blueprints) => + blueprints.WhereQ(IsBlueprintDisplayable).SelectQ(CreateInquiryElement).ToListQ(); - return selectableItems; - } + private static bool IsBlueprintDisplayable(PurchasableBlueprint blueprint) => TryGetUsableTrait(blueprint.Item, out _); - private static InquiryElement CreateInquiryElement(PurchasableBlueprint blueprint, ItemTrait trait) + private static InquiryElement CreateInquiryElement(PurchasableBlueprint blueprint) { - var item = blueprint.Item; - var skill = blueprint.RequiredSkill; - var skillValue = blueprint.RequiredSkillValue; - var eligibleHeroes = blueprint.EligibleHeroes; + var trait = blueprint.Item.GetTraits().FirstOrDefault(); - var enabled = eligibleHeroes.Any(hero => hero.GetSkillValue(skill) >= skillValue); + var enabled = blueprint.EligibleHeroes.Any(hero => hero.GetSkillValue(blueprint.RequiredSkill) >= blueprint.RequiredSkillValue); var hintText = new TextObject("{TRAIT_EFFECT}\n\n{REQUIREMENT_TEXT}\n\n{COMPLETE_COST}"); - hintText.SetTextVariable("REQUIREMENT_TEXT", enabled ? "" : BuildRequirementText(eligibleHeroes, skill, skillValue, blueprint.Restriction)); + hintText.SetTextVariable("REQUIREMENT_TEXT", enabled ? "" : BuildRequirementText(blueprint.EligibleHeroes, blueprint.RequiredSkill, blueprint.RequiredSkillValue, blueprint.Restriction)); - var crCost = CalculateCustomResourceCost(skillValue); - var goldCost = item.Value; + var crCost = CalculateCustomResourceCost(blueprint.RequiredSkillValue); + var goldCost = blueprint.Item.Value; enabled = ApplyAffordabilityCheck(hintText, enabled, crCost, goldCost); SetValidItemTypeRestrictionVariable(blueprint.BlueprintId); @@ -106,9 +93,9 @@ private static InquiryElement CreateInquiryElement(PurchasableBlueprint blueprin hintText.SetTextVariable("COMPLETE_COST", "{GOLD_VALUE}{GOLD_ICON} , {CR_VALUE}{CUSTOMRESOURCE}"); GameTexts.SetVariable("CR_VALUE", crCost); GameTexts.SetVariable("CUSTOMRESOURCE", Hero.MainHero.GetCultureSpecificCustomResource().GetCustomResourceIconAsText()); - GameTexts.SetVariable("GOLD_VALUE", item.Value); + GameTexts.SetVariable("GOLD_VALUE", blueprint.Item.Value); - return new InquiryElement(new Tuple, ItemObject>(eligibleHeroes, item), item.Name.ToString(), new ItemImageIdentifier(item), enabled, hintText.ToString()); + return new InquiryElement(new Tuple, ItemObject>(blueprint.EligibleHeroes, blueprint.Item), blueprint.Item.Name.ToString(), new ItemImageIdentifier(blueprint.Item), enabled, hintText.ToString()); } private static bool TryGetUsableTrait(ItemObject item, out ItemTrait trait) From 1800525e2d3abd446c76d6ab5333f1abb6c260d7 Mon Sep 17 00:00:00 2001 From: randychihuahua Date: Sun, 30 Aug 2026 02:16:11 +0200 Subject: [PATCH 5/6] cleanup function --- .../CampaignMechanics/Crafting/EnchantmentShopHelper.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs index f979c765..1566d546 100644 --- a/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs +++ b/CSharpSourceCode/CampaignMechanics/Crafting/EnchantmentShopHelper.cs @@ -65,9 +65,7 @@ private static List GetPurchasableBlueprints(List } private static List BuildInquiryElements(List blueprints) => - blueprints.WhereQ(IsBlueprintDisplayable).SelectQ(CreateInquiryElement).ToListQ(); - - private static bool IsBlueprintDisplayable(PurchasableBlueprint blueprint) => TryGetUsableTrait(blueprint.Item, out _); + blueprints.WhereQ(b => IsUsableTrait(b.Item)).SelectQ(CreateInquiryElement).ToListQ(); private static InquiryElement CreateInquiryElement(PurchasableBlueprint blueprint) { @@ -98,9 +96,9 @@ private static InquiryElement CreateInquiryElement(PurchasableBlueprint blueprin return new InquiryElement(new Tuple, ItemObject>(blueprint.EligibleHeroes, blueprint.Item), blueprint.Item.Name.ToString(), new ItemImageIdentifier(blueprint.Item), enabled, hintText.ToString()); } - private static bool TryGetUsableTrait(ItemObject item, out ItemTrait trait) + private static bool IsUsableTrait(ItemObject item) { - trait = item.GetTraits().FirstOrDefault(); + var trait = item.GetTraits().FirstOrDefault(); if (trait == null) { TORCommon.Log($"Enchantment blueprint {item.StringId} has no traits. Skipping this item.", LogLevel.Error); From d954b0522916c1103d72c59ce3e81ed114243d83 Mon Sep 17 00:00:00 2001 From: randychihuahua Date: Sun, 30 Aug 2026 13:57:08 +0200 Subject: [PATCH 6/6] Untrack CLAUDE.md/INDEX.md doc files, keep locally via .gitignore These are local Claude Code context docs, not meant to ship in the PR. Removes them from git tracking (files remain on disk) and ignores CLAUDE.md/INDEX.md going forward. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0143sWrFVXpuj8SMbSSGNgft --- .gitignore | 2 + CSharpSourceCode/AbilitySystem/CLAUDE.md | 52 ------- .../AbilitySystem/CrossHairs/CLAUDE.md | 23 --- .../AbilitySystem/Scripts/CLAUDE.md | 46 ------ .../AbilitySystem/SpellCasting/CLAUDE.md | 10 -- .../AbilitySystem/Spells/CLAUDE.md | 24 ---- .../AbilitySystem/Spells/Prayers/CLAUDE.md | 11 -- .../AbilitySystem/Spells/SpellBook/CLAUDE.md | 14 -- CSharpSourceCode/Audio/CLAUDE.md | 20 --- .../BattleMechanics/AI/ArtilleryAI/CLAUDE.md | 5 - CSharpSourceCode/BattleMechanics/AI/CLAUDE.md | 84 ----------- .../CastingAI/AgentCastingBehavior/CLAUDE.md | 21 --- .../CastingAI/AgentTacticalBehavior/CLAUDE.md | 10 -- .../BattleMechanics/AI/CastingAI/CLAUDE.md | 12 -- .../AI/CastingAI/Components/CLAUDE.md | 8 -- .../CastingAI/SupportMissionLogic/CLAUDE.md | 6 - .../AI/CivilianMissionAI/CLAUDE.md | 10 -- .../AI/CommonAIFunctions/CLAUDE.md | 16 --- .../BattleMechanics/AI/TeamAI/CLAUDE.md | 11 -- .../AI/TeamAI/FormationBehavior/CLAUDE.md | 13 -- .../AI/TeamAI/TeamBehavior/CLAUDE.md | 7 - .../AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md | 6 - .../BattleMechanics/Artillery/CLAUDE.md | 19 --- .../BattleMechanics/Banners/CLAUDE.md | 13 -- CSharpSourceCode/BattleMechanics/CLAUDE.md | 59 -------- .../CustomArenaModes/CLAUDE.md | 17 --- .../BattleMechanics/DamageSystem/CLAUDE.md | 24 ---- .../BattleMechanics/Dismemberment/CLAUDE.md | 6 - .../BattleMechanics/Firearms/CLAUDE.md | 9 -- .../BattleMechanics/Morale/CLAUDE.md | 6 - .../BattleMechanics/SFX/CLAUDE.md | 12 -- .../BattleMechanics/SniperScope/CLAUDE.md | 6 - .../BattleMechanics/StatusEffect/CLAUDE.md | 35 ----- .../BattleMechanics/TriggeredEffect/CLAUDE.md | 33 ----- .../TriggeredEffect/Scripts/CLAUDE.md | 26 ---- .../BattleMechanics/Voice/CLAUDE.md | 15 -- .../CampaignMechanics/Assimilation/CLAUDE.md | 10 -- .../CampaignMechanics/BountyMaster/CLAUDE.md | 5 - CSharpSourceCode/CampaignMechanics/CLAUDE.md | 62 -------- .../CampaignMechanics/Careers/CLAUDE.md | 14 -- .../CampaignMechanics/Chaos/CLAUDE.md | 6 - .../CharacterCreation/CLAUDE.md | 35 ----- .../CampaignMechanics/Companions/CLAUDE.md | 7 - .../CampaignMechanics/Crafting/CLAUDE.md | 28 ---- .../CampaignMechanics/CustomDialogs/CLAUDE.md | 23 --- .../CustomDialogs/ConversationTags/CLAUDE.md | 18 --- .../CampaignMechanics/CustomEvents/CLAUDE.md | 14 -- .../CustomResourceBehavior/CLAUDE.md | 10 -- .../CustomResources/CLAUDE.md | 31 ---- .../CustomResources/WaaaghMeter/CLAUDE.md | 11 -- .../CampaignMechanics/Diplomacy/CLAUDE.md | 19 --- .../MapNotifications/CLAUDE.md | 5 - .../MasterEngineer/CLAUDE.md | 5 - .../PostBattleLoot/CLAUDE.md | 5 - .../RaidingParties/CLAUDE.md | 9 -- .../CampaignMechanics/RaiseDead/CLAUDE.md | 12 -- .../RegimentsOfRenown/CLAUDE.md | 11 -- .../CampaignMechanics/Religion/CLAUDE.md | 22 --- .../ServeAsAHireling/CLAUDE.md | 9 -- .../CampaignMechanics/SpellTrainers/CLAUDE.md | 7 - .../TORCustomSettlement/CLAUDE.md | 37 ----- .../TORCustomSettlement/Component/CLAUDE.md | 18 --- .../CustomSettlementMenus/CLAUDE.md | 17 --- .../CampaignMechanics/UniqueSpawns/CLAUDE.md | 11 -- .../CampaignMechanics/Villages/CLAUDE.md | 6 - .../CharacterDevelopment/CLAUDE.md | 36 ----- .../CareerSystem/CLAUDE.md | 40 ------ .../CareerSystem/CareerButton/CLAUDE.md | 27 ---- .../CareerSystem/Choices/CLAUDE.md | 19 --- CSharpSourceCode/Extensions/CLAUDE.md | 30 ---- .../Extensions/ExtendedInfoSystem/CLAUDE.md | 24 ---- CSharpSourceCode/Extensions/UI/CLAUDE.md | 36 ----- .../Extensions/UI/MainMenu/CLAUDE.md | 13 -- CSharpSourceCode/GameManagers/CLAUDE.md | 20 --- CSharpSourceCode/HarmonyPatches/CLAUDE.md | 46 ------ CSharpSourceCode/INDEX.md | 134 ------------------ CSharpSourceCode/Ink/CLAUDE.md | 23 --- CSharpSourceCode/Items/CLAUDE.md | 33 ----- .../Items/InventoryUseScripts/CLAUDE.md | 20 --- .../Items/WeaponHitScripts/CLAUDE.md | 22 --- CSharpSourceCode/Missions/CLAUDE.md | 38 ----- CSharpSourceCode/Models/CLAUDE.md | 53 ------- .../Models/CustomBattleModels/CLAUDE.md | 12 -- CSharpSourceCode/Properties/CLAUDE.md | 4 - CSharpSourceCode/Quests/CLAUDE.md | 23 --- CSharpSourceCode/Quests/Careers/CLAUDE.md | 10 -- CSharpSourceCode/SaveGameSystem/CLAUDE.md | 17 --- CSharpSourceCode/Utilities/CLAUDE.md | 59 -------- 88 files changed, 2 insertions(+), 1895 deletions(-) delete mode 100644 CSharpSourceCode/AbilitySystem/CLAUDE.md delete mode 100644 CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md delete mode 100644 CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md delete mode 100644 CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md delete mode 100644 CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md delete mode 100644 CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md delete mode 100644 CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md delete mode 100644 CSharpSourceCode/Audio/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md delete mode 100644 CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md delete mode 100644 CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md delete mode 100644 CSharpSourceCode/CharacterDevelopment/CLAUDE.md delete mode 100644 CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md delete mode 100644 CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md delete mode 100644 CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md delete mode 100644 CSharpSourceCode/Extensions/CLAUDE.md delete mode 100644 CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md delete mode 100644 CSharpSourceCode/Extensions/UI/CLAUDE.md delete mode 100644 CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md delete mode 100644 CSharpSourceCode/GameManagers/CLAUDE.md delete mode 100644 CSharpSourceCode/HarmonyPatches/CLAUDE.md delete mode 100644 CSharpSourceCode/INDEX.md delete mode 100644 CSharpSourceCode/Ink/CLAUDE.md delete mode 100644 CSharpSourceCode/Items/CLAUDE.md delete mode 100644 CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md delete mode 100644 CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md delete mode 100644 CSharpSourceCode/Missions/CLAUDE.md delete mode 100644 CSharpSourceCode/Models/CLAUDE.md delete mode 100644 CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md delete mode 100644 CSharpSourceCode/Properties/CLAUDE.md delete mode 100644 CSharpSourceCode/Quests/CLAUDE.md delete mode 100644 CSharpSourceCode/Quests/Careers/CLAUDE.md delete mode 100644 CSharpSourceCode/SaveGameSystem/CLAUDE.md delete mode 100644 CSharpSourceCode/Utilities/CLAUDE.md diff --git a/.gitignore b/.gitignore index 59513826..61e43d76 100644 --- a/.gitignore +++ b/.gitignore @@ -350,3 +350,5 @@ EmAssetPackages/ Tools/TranslationTool/translation_issues_report_* .claude tmpclaude-* +CLAUDE.md +INDEX.md diff --git a/CSharpSourceCode/AbilitySystem/CLAUDE.md b/CSharpSourceCode/AbilitySystem/CLAUDE.md deleted file mode 100644 index 65a66834..00000000 --- a/CSharpSourceCode/AbilitySystem/CLAUDE.md +++ /dev/null @@ -1,52 +0,0 @@ -# AbilitySystem - -The "magic" layer of TOR: Warhammer's Winds of Magic spells, priestly Prayers, and -per-Career signature abilities, all built on one shared runtime. - -## Core model - -- **`Ability`** (abstract, `Ability.cs`) — runtime instance wrapping an `AbilityTemplate`. - Handles cooldowns, cast validation (`CanCast`/`IsDisabled`), cast-frame calculation for - player/AI/quick-cast, spawning the effect `GameEntity`, and wiring up the right - `AbilityScript` subclass based on `AbilityEffectType` (Missile, Wind, Heal, Augment, - Summoning, Hex, Vortex, Blast, Bombardment, ArtilleryPlacement, TimeWarpEffect, etc.). - Three concrete subclasses: - - **`Spells/Spell.cs`** — Winds-of-Magic spells (costs Winds, has miscast chance, `SpellTier`, `BelongsToLoreID`). - - **`Prayer.cs`** — priest prayers (separate cooldown pool, `PrayerLevel` tier). - - **`CareerAbility.cs`** — each Career's unique active ability (see `CharacterDevelopment/CareerSystem`). - - **`ItemBoundAbility.cs`** — abilities granted by wielding a specific item. -- **`AbilityTemplate`** (`ITemplate`) — XML-serializable data definition (damage via - `TriggeredEffects`, visuals, cast type/time, crosshair type, target type, distances...). - Loaded/cloned via `AbilityFactory` from `AbilityTemplates.xml`-style data. -- **`AbilityFactory`** — loads and indexes all `AbilityTemplate`s at startup (`SubModule.OnSubModuleLoad`). -- **`AbilityComponent`** (`AgentComponent`) — attached to agents that can cast; tracks - known abilities (`KnownAbilitySystem`), Anvil-of-Doom state for Rune magic, prayer cooldown, quick-cast state. -- **`AbilityManagerMissionLogic`** — mission-level `MissionLogic` driving input → cast - requests, ticking cooldowns/wind-up casts, and mediating with the HUD. -- **`AbilityHUD_VM`** / **`CareerAbilityHUD_VM`** / **`AbilityRadialSelection_VM`** + - `AbilityRadialSelectionItemWidget` — in-mission UI (hotbar + radial ability picker). -- **`AbilityType`** / **`AbilityEffectType`** / **`AbilityTargetType`** / `CastType` / - `TriggerType` enums (in `AbilityType.cs`) drive most of the switch logic above. -- **`SeekerController`/`SeekerParameters`** — homing-missile behavior for seeker spells. -- **`SummonedAgentOrigin`/`SummonedCombatant`** — lets summoned troops (from Summoning abilities) - count as a proper battle combatant/origin for kill credit, banners, etc. - -## Subfolders - -- **`CrossHairs/`** — player aiming reticles per ability shape (see its CLAUDE.md). -- **`Scripts/`** — `AbilityScript` (`ScriptComponentBehavior`) implementations: the actual - mission-side visual/physics/timing logic for each `AbilityEffectType`, plus one - `CareerAbilityScript` subclass per Career signature ability (see its CLAUDE.md). -- **`SpellCasting/`** — `SpellCastSession`, tracks an in-progress multi-step cast (used for - Winds-of-Magic miscast rolls / windup UX outside the basic Ability flow). -- **`Spells/`** — `Spell`, `LoreObject` (a school/"Lore" of magic, e.g. Lore of Fire), - `SpellCastingLevel`; plus `SpellBook/` (in-mission spellbook screen: `SpellBookScreen`, - `SpellBookVM`, item/lore view-models) and `Prayers/` (battle prayer book equivalent: - `BattlePrayerScreen`, `BattlePrayersVM`, `PrayerItemVM`). - -## Notes - -- Loaded once at `SubModule.OnSubModuleLoad` via `AbilityFactory.LoadTemplates()`. -- AI casting decisions live outside this folder in - `BattleMechanics/AI/CastingAI` (`WizardAIComponent`, `AgentCastingBehavior`, - `AgentTacticalBehavior`) — this folder is the mechanism, that folder is the brain. diff --git a/CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md b/CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md deleted file mode 100644 index 94458008..00000000 --- a/CSharpSourceCode/AbilitySystem/CrossHairs/CLAUDE.md +++ /dev/null @@ -1,23 +0,0 @@ -# AbilitySystem/CrossHairs - -Player-facing aiming reticles shown while an ability is armed, one shape per -`CrosshairType` (set on `AbilityTemplate.CrosshairType`). - -- **`ICrosshair`** — `Show()/Hide()/Tick()/IsVisible`. -- **`Crosshair`** — plain default implementation of `ICrosshair`. -- **`AbilityCrosshair`** (abstract, `IDisposable, ICrosshair`) — base for ability-aware - crosshairs; exposes `Frame`/`Position` used by `Ability.CalculatePlayerCastMatrixFrame` - to place the spawned effect entity. - - `SelfCrosshair` — no aiming, centers on caster. - - `Pointer` — simple ground/world pointer (ability placement, e.g. Augment/Heal-on-ground). - - `MissileCrosshair` — aiming reticle for projectile/missile-type abilities. - - `SingleTargetCrosshair(AbilityTemplate)` — locks onto a single valid agent under the - reticle (`CachedTarget`), used for SingleAlly/SingleEnemy target types. - - `TargetedAOECrosshair` — ground-targeted area indicator. - - `WindCrosshair` — directional cone/line indicator for Wind-type abilities. -- **`ProjectileCrosshair_VM`** — view-model backing the crosshair widget's Gauntlet UI. -- **`CrosshairType`** enum — the switch key `AbilityTemplate`/`Ability` use to pick which - of the above to instantiate. - -Consumed by `Ability.GetSpawnFrame` (via `Ability.Crosshair`) and set up by whatever mission -UI arms the ability (`AbilityManagerMissionLogic` / `AbilityHUD_VM`). diff --git a/CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md deleted file mode 100644 index 21f1d6b9..00000000 --- a/CSharpSourceCode/AbilitySystem/Scripts/CLAUDE.md +++ /dev/null @@ -1,46 +0,0 @@ -# AbilitySystem/Scripts - -`AbilityScript` (`ScriptComponentBehavior`) and its subclasses — the mission-side entity -that actually flies/sits/pulses in the world while an `Ability` is active, and decides -when to trigger the ability's `TriggeredEffect`s (damage/heal/status/etc., from -`BattleMechanics/TriggeredEffect`). - -## Base class: `AbilityScript.cs` - -Owns the entity lifetime: ticking, movement (`ShouldMove`/`GetNextGlobalFrame`), lifetime -expiry vs `Template.Duration`, collision detection (`OnPhysicsCollision`/`CollidedWithAgent`), -sound looping, and `TriggerType`-driven firing (`OnCollision`, `EveryTick`, `TickOnce`, -`OnStop`). `TriggerEffects` opens/uses an `AbilityManagerMissionLogic` spell session -(`_castId`) so damage from this cast can be attributed for XP/kill-credit. Subclasses -override `GetNextGlobalFrame`, `ShouldMove`, `OnBeforeTick`/`OnAfterTick`, -`GetEffectsToTrigger`, `HandleCollision`. - -## Effect-type scripts (one per `AbilityEffectType`, picked by `Ability.AddBehaviour`) - -`ProjectileScript`, `MissileScript` (also serves SeekerMissile via `SeekerController`), -`WindScript`, `HealScript`, `AugmentScript` (also TacticalReposition), `SummoningScript`, -`HexScript`, `VortexScript`, `BlastScript`, `BombardmentScript`, `ArtilleryPlacementScript` -(also ItemPlacement), `TimeWarpScript`. - -## Career signature abilities - -**`CareerAbilityScript`** — base for `CareerAbility`'s effect: re-clones its -`TriggeredEffectTemplate` per cast and lets the caster's `CareerObject.MutateTriggeredEffect` -tweak numbers (perk-driven scaling), then follows the caster instead of flying free. -One subclass per Career ability (`CharacterDevelopment/CareerSystem/CareerObject` -wires these up by StringID): - -- `KnightlyChargeScript` / `KnightlyStrikeScript` (Grail Knight/Knight of the Old World) -- `AccusationScript`, `MindControlScript`, `ShadowStepScript` (Witch Hunter / Necrarch-adjacent) -- `TeleportScript` (+ `DamselTeleportScript`, `TeleportTriggeredScript`) (Grail Damsel) -- `ArcaneConduit`, `WisdomOfThungniScript` (Runelord/Runesmith — Dwarf rune magic) -- `ArmedToDaTeef`, `CallOfDaGreen`, `RedFuryScript`, `WrathOfTheWoodScript` (Greenskin careers) -- `AxeOfUlricScript`, `HawkEyeScript`, `LethalShotScript`, `DoomSeekingScript`, - `SummonChampionScript`, `ImpenetrableScript` (various human/elf careers) -- **`CareerAbilityMissleScript`** — missile variant base, subclassed by - `ArrowOfKurnousScript` (Waywatcher) and `BlastOfAgonyScript`. - -## Other - -- **`ITriggeredScript`** — separate lightweight interface (see - `BattleMechanics/TriggeredEffect/Scripts`) implemented by `TeleportTriggeredScript` here. diff --git a/CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md b/CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md deleted file mode 100644 index 868f7b81..00000000 --- a/CSharpSourceCode/AbilitySystem/SpellCasting/CLAUDE.md +++ /dev/null @@ -1,10 +0,0 @@ -# AbilitySystem/SpellCasting - -Single file: **`SpellCastSession`** — an accounting object for one ability cast, created by -`AbilityManagerMissionLogic.CreateSpellSession` when an `AbilityScript` first triggers and -collected once its effects (including any lingering `StatusEffect` durations) have played -out. Books damage/healing/kills/status-effects dealt by that cast, split into -friendly-fire vs. enemy buckets, and exposes totals (`TotalDamageDealt`, -`AgentsKilledCount`, `HasData`, etc.) used for post-cast feedback (kill credit, XP, -combat log/HUD numbers). Not persisted — purely an in-mission bookkeeping struct keyed by -`CastID`. diff --git a/CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md deleted file mode 100644 index 1ccfb7f8..00000000 --- a/CSharpSourceCode/AbilitySystem/Spells/CLAUDE.md +++ /dev/null @@ -1,24 +0,0 @@ -# AbilitySystem/Spells - -Winds-of-Magic spell layer on top of the generic `Ability`/`AbilityTemplate` system. - -- **`Spell`** (`: Ability`) — a castable Winds-of-Magic spell instance. -- **`SpellCastingLevel`** enum — spell tier labels used in UI (mirrors `AbilityTemplate.SpellTier`). -- **`LoreObject`** — one "Lore" of magic (school), e.g. `LoreOfFire`, `LoreOfLife`, - `HighMagic`, `DarkMagic`, `Necromancy`, `RuneMagic`, `BigWaaagh`, `MinorMagic`. - Hardcoded static list (`GetAll`/`GetLore`) encodes lore-vs-culture eligibility - (`DisabledForCultures`) and `IsRestrictedToVampires` — this is where "which races can - learn which magic" is defined (see `Utilities/TORConstants.Cultures` for the culture IDs: - Empire, Bretonnia, Mousillon, Sylvania, Asrai, Eonir, Dawi/Dwarfs, Greenskin...). - Note the in-code caveat: Spellsingers (Asrai) get a special-cased bypass of the - High/Dark Magic culture lock via `CampaignMechanics/SpellTrainers/SpellTrainerInTownBehavior`. - -## Subfolders - -- **`SpellBook/`** — the campaign-map spellbook screen for learning/viewing spells: - `SpellBookScreen`/`SpellBookState` (game state + screen), `SpellBookVM` (root VM), - `AbilityItemVM` (abstract row VM) → `SpellItemVM`, `LoreObjectVM`, - `SpellBookMapIconVM`, `StatItemVM` (stat-line rows shown via `AbilityTemplate.GetStats`). -- **`Prayers/`** — the equivalent in-mission book for battle Prayers: - `BattlePrayerScreen`/`BattlePrayerBookState`, `BattlePrayersVM`, - `PrayerItemVM` (`: AbilityItemVM`), `PrayerLoreObjectVM`. diff --git a/CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md deleted file mode 100644 index a3790dcf..00000000 --- a/CSharpSourceCode/AbilitySystem/Spells/Prayers/CLAUDE.md +++ /dev/null @@ -1,11 +0,0 @@ -# AbilitySystem/Spells/Prayers - -In-mission "Prayer book" UI — the Prayer equivalent of `../SpellBook`, but opened during a -battle rather than on the campaign map: - -- **`BattlePrayerScreen`** (`ScreenBase, IGameStateListener`) + **`BattlePrayerBookState`** - (`GameState`) — screen/state pair. -- **`BattlePrayersVM`** — root view-model listing the caster's known `Prayer`s. -- **`PrayerItemVM`** (`: AbilityItemVM`, base defined in `../SpellBook`) — one prayer row. -- **`PrayerLoreObjectVM`** — grouping VM analogous to `LoreObjectVM`, but for prayer - "lores"/deities rather than Winds-of-Magic lores. diff --git a/CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md b/CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md deleted file mode 100644 index 8eac9136..00000000 --- a/CSharpSourceCode/AbilitySystem/Spells/SpellBook/CLAUDE.md +++ /dev/null @@ -1,14 +0,0 @@ -# AbilitySystem/Spells/SpellBook - -Campaign-map "Spellbook" screen UI (a `ScreenBase` + `GameState`, Gauntlet-based, not a -mission behavior): - -- **`SpellBookScreen`** (`ScreenBase, IGameStateListener`) + **`SpellBookState`** (`GameState`) - — screen/state pair pushed onto the game state stack to open the spellbook. -- **`SpellBookVM`** — root view-model: lists known/learnable spells grouped by `LoreObject`. -- **`AbilityItemVM`** (abstract `ViewModel`) — shared row VM for a single ability entry; - base for `SpellItemVM` here and `PrayerItemVM` in `../Prayers`. -- **`LoreObjectVM`** — VM wrapper around a `LoreObject` (lore icon/name/unlock state). -- **`SpellBookMapIconVM`** — the map-bar icon/button that opens the spellbook. -- **`StatItemVM`** — one label/value stat row (cooldown, Winds cost, tier, type), built from - `AbilityTemplate.GetStats`. diff --git a/CSharpSourceCode/Audio/CLAUDE.md b/CSharpSourceCode/Audio/CLAUDE.md deleted file mode 100644 index 292232f5..00000000 --- a/CSharpSourceCode/Audio/CLAUDE.md +++ /dev/null @@ -1,20 +0,0 @@ -# Audio - -Small standalone audio subsystem for playing sound files that live outside the game's -FMOD sound-bank pipeline (loaded directly from disk as .ogg/.wav under the TOR_Armory -module's `ModuleSounds/` folder). - -- **`TORAudioManager`** (static) — loads a file into a `TORModuleSound` via - `CreateSoundInstance` (tries `.ogg` then falls back to `.wav`), plays it through a native - `SoundEvent.CreateEventFromExternalFile` using a dummy FMOD event - (`event:/Extra/voiceover`) as the carrier, and ticks all `_activeSounds` every frame - (`SubModule.OnApplicationTick`) to handle looping (`RestartsWhenFinished`) and cleanup. - `StopAll()` is called on `SubModule.OnGameEnd`. -- **`TORModuleSound`** — handle for one loaded sound: play/remove, 3D position + falloff - range (`SetPosition`), restart-on-finish behavior. -- **`TORAudioAmbientSoundEmitter`** (`ScriptComponentBehavior`) — a scene-prop/entity script - (also usable in the level editor via `OnEditorInit`/`OnEditorVariableChanged`) that plays - a looping 3D ambient sound from `AudioName` when the camera is within `Range`, using the - manager above. Drop this on a prop in a scene to give it ambient audio. - -Distinct from voice lines / battle shouts, which live in `BattleMechanics/Voice`. diff --git a/CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md deleted file mode 100644 index 1a602c3c..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/ArtilleryAI/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# BattleMechanics/AI/ArtilleryAI - -**`FieldSiegeWeaponAI`** (`: UsableMachineAIBase`) — AI crew behavior for the field siege -weapons defined in `BattleMechanics/Artillery` (trebuchets etc.): aim, reload, and fire -decision loop for an AI-controlled operator. diff --git a/CSharpSourceCode/BattleMechanics/AI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CLAUDE.md deleted file mode 100644 index ae410f6e..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CLAUDE.md +++ /dev/null @@ -1,84 +0,0 @@ -# BattleMechanics/AI - -Custom battlefield AI, layered on top of TaleWorlds' `HumanAIComponent`/`BehaviorComponent`/ -`TeamAIGeneral` framework. Three broad concerns: - -1. **Spellcaster ("wizard") AI** — `CastingAI/` — utility-scored decisions about when/what - to cast and how to stay safe while doing it. -2. **Formation/team AI overrides** — `TeamAI/` — TOR replacements for vanilla formation - behaviors (charge/retreat/skirmish/defend/aggressive-melee) and the team general. -3. **Misc battlefield AI** — artillery crew AI (`ArtilleryAI/`), non-combatant/civilian - mission AI (`CivilianMissionAI/`), and shared scoring/utility helpers (`CommonAIFunctions/`). - -Root file: **`TORCultureBattleSettings`** (static) — per-culture tuning knobs for battle AI -(aggression, formation spacing, etc. — used to give e.g. Greenskins vs. Empire different -"feel"). **`AIKickAgentComponent`** — lets AI-controlled agents throw kick attacks. - -## `CommonAIFunctions/` — shared utility-AI building blocks - -Used by both `CastingAI` and (indirectly) `TeamAI`: - -- **`IAgentBehavior`** — interface every scoreable per-agent behavior implements - (`Execute`, `Terminate`, `CalculateUtility`). -- **`BehaviorOption`** — a `(Behavior, Target, UtilityValue)` tuple candidate. -- **`Target` : `Threat`** — a scoring target: an enemy `Formation`, a `TacticalPosition`, etc. -- **`Axis`/`AxisExtensions`** — named utility curves ("axes") that get combined via - `GeometricMean` into one utility score per candidate (classic utility-AI pattern). -- **`ScoringFunctions`** — the actual curve functions (distance falloff, density, etc.) - that `Axis`es wrap. -- **`DecisionManager`** — `EvaluateCastingBehaviors`: flattens all behaviors' scored - options and picks the single best (`MaxBy` utility). -- **`CommonAIFunctions`** (`CommonAIDecisionFunctions`/`CommonAIStateFunctions`/ - `CommonAIFunctions`) — grab-bag of static helpers reused across behaviors (formation - queries, positioning math). - -## `CastingAI/` — spellcasters - -- **`Components/WizardAIComponent`** (`: HumanAIComponent`) — replaces the agent's stock - `HumanAIComponent` entirely. Every ~3s (`EvalInterval`, jittered) it re-evaluates - `AvailableCastingBehaviors` via `DecisionManager` and picks the best-scoring - `AbstractAgentCastingBehavior`; every tick it runs that behavior's `TacticalBehavior` - (positioning/safety) then the casting behavior itself, unless the formation is on - Hold Fire. -- **`AgentCastingBehaviorConfiguration`** (static) — registers, per ability-effect-type, - which `Axis`es feed its utility score (`UtilityByType`) and builds the list of available - behaviors for an agent from its known abilities (`PrepareCastingBehaviors`). -- **`AgentCastingBehavior/`** — one class per casting "shape", all `: AbstractAgentCastingBehavior` - (`IAgentBehavior`): `MissileCastingBehavior` (base for aimed-projectile spells), - `AoETargetedCastingBehavior` → `SelectSingleTargetCastingBehavior`/`SelectMultiTargetCastingBehavior`, - `AoEAdjacentCastingBehavior`, `AoEDirectionalCastingBehavior`, `SummoningCastingBehavior`, - `ArtilleryPlacementCastingBehavior`, `PreserveWindsCastingBehavior` (chooses not to cast, - conserving Winds of Magic), `TacticalTeleportCastingBehavior`. `AbstractAgentCastingBehavior` - itself owns cooldown/range/line-of-sight checks, target updating, and the - utility-score calc (`CalculateUtility` = geometric mean of its `Axis` list + target - hysteresis to avoid target-flip-flopping). -- **`AgentTacticalBehavior/`** — `AbstractAgentTacticalBehavior` (`IAgentBehavior`) and - concrete positioning behaviors run alongside casting: `KeepSafeTacticalBehavior` - (kite away from danger), `AoEAdjacentTacticalBehavior`/`AoEDirectionalTacticalBehavior` - (reposition to land AoE shapes). -- **`SupportMissionLogic/`** — `QuerySystemExtensions`/`QuerySystemExtensionsMissionLogic`, - extends TaleWorlds' formation `QuerySystem` (tactical position queries) for the above. - -## `TeamAI/` - -- **`FormationBehavior/`** — TOR subclasses of vanilla `BehaviorComponent`s: - `TORBehaviorBase` (abstract shared base), `TORBehaviorCharge`, `TORBehaviorDefend`, - `TORBehaviorRetreat`, `TORBehaviorSkirmish`, `TORBehaviorAggressiveMelee`, - `TORBehaviorProtectArtillery` (new), `TORFormationClass`. -- **`TeamBehavior/TORTeamAIGeneral`** (`: TeamAIGeneral`) — top-level team AI override. - - **`TeamBehavior/Tactics/TORTacticPositionalArtillery`** (`: TacticDefensiveLine`) — - a tactic that keeps a defensive line while positioning artillery. -- **`TORMissionCombatantsLogic`** (`: MissionCombatantsLogic`) — replaces the vanilla - combatants logic (see `SubModule.OnBeforeMissionBehaviorInitialize`, - `CreateFromInstance`). - -## `ArtilleryAI/` - -- **`FieldSiegeWeaponAI`** (`: UsableMachineAIBase`) — AI crew behavior for the field - siege weapons in `BattleMechanics/Artillery` (aim/reload/fire loop). - -## `CivilianMissionAI/` - -Non-combat town/village mission AI (townsfolk going about their day, reacting to trouble): -`TORDailyBehaviorGroup`/`TORAlarmedBehaviorGroup` (`AgentBehaviorGroup`), -`TORWalkingBehavior`/`TORFightBehavior` (`AgentBehavior`). diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md deleted file mode 100644 index f800b0c0..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentCastingBehavior/CLAUDE.md +++ /dev/null @@ -1,21 +0,0 @@ -# BattleMechanics/AI/CastingAI/AgentCastingBehavior - -One `AbstractAgentCastingBehavior` (`: IAgentBehavior`) subclass per spell-casting "shape". -Each wraps cooldown/range/line-of-sight checks and a utility score -(`CalculateUtility` = geometric mean of registered `Axis`es, see -`../../CommonAIFunctions`), and on `Execute()` selects the ability and calls -`Agent.TryCastCurrentAbility`. - -- **`AbstractAgentCastingBehavior`** — shared base (see class doc in parent CLAUDE.md). -- **`MissileCastingBehavior`** — base for aimed single-projectile spells. - - **`AoETargetedCastingBehavior`** — aims at a scored ground/formation target. - - **`SelectSingleTargetCastingBehavior`**, **`SelectMultiTargetCastingBehavior`** — - single- vs. multi-target variants. -- **`AoEAdjacentCastingBehavior`** / **`AoEDirectionalCastingBehavior`** — self-centered or - directional area spells (cones/lines), paired with the matching `AgentTacticalBehavior`. -- **`SummoningCastingBehavior`** — casts summon-type abilities. -- **`ArtilleryPlacementCastingBehavior`** — places artillery/item-placement abilities; - cooperates with `WizardAIComponent.UpdateArtilleryTargetPosition`. -- **`PreserveWindsCastingBehavior`** — a "do nothing, conserve Winds of Magic" option so the - utility system can prefer not casting when nothing scores well. -- **`TacticalTeleportCastingBehavior`** — casts reposition/teleport-type abilities. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md deleted file mode 100644 index 1197d214..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CastingAI/AgentTacticalBehavior/CLAUDE.md +++ /dev/null @@ -1,10 +0,0 @@ -# BattleMechanics/AI/CastingAI/AgentTacticalBehavior - -Positioning/safety behaviors run every tick alongside a caster's chosen -`AgentCastingBehavior` (see `WizardAIComponent.OnTick`), all `: AbstractAgentTacticalBehavior` -(`IAgentBehavior`). - -- **`AbstractAgentTacticalBehavior`** — shared base. -- **`KeepSafeTacticalBehavior`** — kite away from nearby danger/melee threats. -- **`AoEAdjacentTacticalBehavior`** / **`AoEDirectionalTacticalBehavior`** — reposition to - land the caster's adjacent/directional AoE shape on its target. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md deleted file mode 100644 index 9a733ef0..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CastingAI/CLAUDE.md +++ /dev/null @@ -1,12 +0,0 @@ -# BattleMechanics/AI/CastingAI - -Utility-AI for agents that can cast spells/prayers/career abilities in battle. See -`../CLAUDE.md` ("CastingAI") for the full picture. Quick map: - -- **`AgentCastingBehaviorConfiguration`** (this folder, root) — registers which `Axis`es - score each casting-behavior type and builds an agent's `PrepareCastingBehaviors` list - from its known abilities. -- **`Components/WizardAIComponent`** — the `HumanAIComponent` replacement driving it all. -- **`AgentCastingBehavior/`** — the actual cast decisions (one class per spell "shape"). -- **`AgentTacticalBehavior/`** — positioning/safety run alongside casting. -- **`SupportMissionLogic/`** — `QuerySystem` extensions the above rely on for formation queries. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md deleted file mode 100644 index f50dfbf5..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CastingAI/Components/CLAUDE.md +++ /dev/null @@ -1,8 +0,0 @@ -# BattleMechanics/AI/CastingAI/Components - -**`WizardAIComponent`** (`: HumanAIComponent`) — replaces a spellcasting agent's stock -`HumanAIComponent` (removes it via `agent.RemoveComponent` in its ctor). Every ~3 seconds -(jittered per-agent) it re-evaluates `AvailableCastingBehaviors` through -`DecisionManager.EvaluateCastingBehaviors` and adopts the best-scoring -`AbstractAgentCastingBehavior`; every tick (unless the formation is on Hold Fire) it runs -that behavior's `TacticalBehavior` then the behavior itself. See parent `../CLAUDE.md`. diff --git a/CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md deleted file mode 100644 index 3ab80e3a..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CastingAI/SupportMissionLogic/CLAUDE.md +++ /dev/null @@ -1,6 +0,0 @@ -# BattleMechanics/AI/CastingAI/SupportMissionLogic - -**`FormationQuerySystemExtensions`** (`QuerySystemExtensions.cs`) + -**`QuerySystemExtensionsMissionLogic`** — extend TaleWorlds' formation `QuerySystem` with -extra tactical-position queries that the casting/tactical behaviors in the sibling folders -rely on for finding safe spots and AoE landing positions. diff --git a/CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md deleted file mode 100644 index ff0e2637..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CivilianMissionAI/CLAUDE.md +++ /dev/null @@ -1,10 +0,0 @@ -# BattleMechanics/AI/CivilianMissionAI - -Non-combat AI for town/village scenes — NPCs going about their day and reacting to trouble. - -- **`TORDailyBehaviorGroup`** (`: AgentBehaviorGroup`) — normal daytime routine group. -- **`TORAlarmedBehaviorGroup`** (`: AgentBehaviorGroup`) — takes over when something alarms - the civilian population (a fight breaks out, a crime is witnessed). -- **`TORWalkingBehavior`** (`: AgentBehavior`) — idle wandering/walking-to-destination. -- **`TORFightBehavior`** (`: SandBox.Missions.AgentBehaviors.AgentBehavior`) — a civilian - joining/reacting to a brawl. diff --git a/CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md deleted file mode 100644 index 93d514a4..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/CommonAIFunctions/CLAUDE.md +++ /dev/null @@ -1,16 +0,0 @@ -# BattleMechanics/AI/CommonAIFunctions - -Shared utility-AI primitives used by `CastingAI` (and available to `TeamAI`): - -- **`IAgentBehavior`** — interface every scoreable behavior implements (`Execute`, - `Terminate`, `CalculateUtility`). -- **`BehaviorOption`** — `(Behavior, Target, UtilityValue)` candidate tuple. -- **`Target : Threat`** — a scoring target (enemy `Formation`, `TacticalPosition`, etc.). -- **`Axis` / `AxisExtensions`** — named utility curves combined via `GeometricMean` into one - score per candidate — the core "utility AI" mechanism. -- **`ScoringFunctions`** — the actual curve functions (distance falloff, density, etc.). -- **`DecisionManager`** — `EvaluateCastingBehaviors`: flattens every behavior's scored - options and picks the single best via `MaxBy`. -- **`CommonAIDecisionFunctions` / `CommonAIStateFunctions` / `CommonAIFunctions`** - (`CommonAIFunctions.cs`) — grab-bag of static formation/positioning helpers reused across - behaviors. diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md deleted file mode 100644 index a752621c..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/TeamAI/CLAUDE.md +++ /dev/null @@ -1,11 +0,0 @@ -# BattleMechanics/AI/TeamAI - -TOR's replacements for vanilla team/formation-level battle AI. - -- **`TORMissionCombatantsLogic`** (`: MissionCombatantsLogic`) — swaps in for the vanilla - combatants logic; installed via `SubModule.OnBeforeMissionBehaviorInitialize` - (`TORMissionCombatantsLogic.CreateFromInstance`). -- **`FormationBehavior/`** — per-formation behavior overrides (charge/defend/retreat/ - skirmish/aggressive-melee + a new protect-artillery behavior). -- **`TeamBehavior/`** — `TORTeamAIGeneral` (`: TeamAIGeneral`) and, under `Tactics/`, - `TORTacticPositionalArtillery` (`: TacticDefensiveLine`). diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md deleted file mode 100644 index abe1f153..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/TeamAI/FormationBehavior/CLAUDE.md +++ /dev/null @@ -1,13 +0,0 @@ -# BattleMechanics/AI/TeamAI/FormationBehavior - -TOR subclasses of vanilla `BehaviorComponent`s, registered wherever formations pick their -AI behavior set (culture settings in `../../TORCultureBattleSettings` feed into this): - -- **`TORBehaviorBase`** (abstract) — shared base for the overrides below. -- **`TORBehaviorCharge`** (`: BehaviorCharge`), **`TORBehaviorDefend`** (`: BehaviorDefend`), - **`TORBehaviorRetreat`** (`: BehaviorRetreat`), **`TORBehaviorSkirmish`** - (`: BehaviorSkirmish`), **`TORBehaviorAggressiveMelee`** (`: BehaviorComponent`) — tuned/ - patched versions of the matching vanilla formation behavior. -- **`TORBehaviorProtectArtillery`** (`: BehaviorComponent`) — new behavior: keeps a - formation screening friendly artillery pieces. -- **`TORFormationClass`** — formation classification helper used to pick behaviors. diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md deleted file mode 100644 index 852b9662..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/CLAUDE.md +++ /dev/null @@ -1,7 +0,0 @@ -# BattleMechanics/AI/TeamAI/TeamBehavior - -**`TORTeamAIGeneral`** (`: TeamAIGeneral`) — top-level per-team AI override deciding -overall tactics/formation assignment for a side in battle. - -- **`Tactics/TORTacticPositionalArtillery`** (`: TacticDefensiveLine`) — a battle-wide tactic - that holds a defensive line while positioning artillery pieces for effective fire. diff --git a/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md b/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md deleted file mode 100644 index 70435eaf..00000000 --- a/CSharpSourceCode/BattleMechanics/AI/TeamAI/TeamBehavior/Tactics/CLAUDE.md +++ /dev/null @@ -1,6 +0,0 @@ -# BattleMechanics/AI/TeamAI/TeamBehavior/Tactics - -**`TORTacticPositionalArtillery`** (`: TacticDefensiveLine`) — battle-wide tactic variant -that holds a defensive line formation while positioning/protecting friendly artillery -pieces so they can keep firing. Selected by `TORTeamAIGeneral` for sides that have -artillery on the field. diff --git a/CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md deleted file mode 100644 index d2fbf4b8..00000000 --- a/CSharpSourceCode/BattleMechanics/Artillery/CLAUDE.md +++ /dev/null @@ -1,19 +0,0 @@ -# BattleMechanics/Artillery - -Field (non-siege-only) artillery pieces usable in open battles, extending TaleWorlds' -`RangedSiegeWeapon`/`StandingPoint` machinery. AI crew logic lives separately in -`BattleMechanics/AI/ArtilleryAI`; team-level protection behavior in -`BattleMechanics/AI/TeamAI` (`TORBehaviorProtectArtillery`, `TORTacticPositionalArtillery`). - -- **`BaseFieldSiegeWeapon`** (abstract `: RangedSiegeWeapon`) — shared base for field - artillery: ammo, aiming, firing. - - **`FieldTrebuchet`** — concrete field trebuchet usable outside sieges. - - **`ArtilleryRangedSiegeWeapon`** — general field artillery piece (cannon-type). -- **`ArtilleryStandingPoint`** / **`TrebuchetStandingPoint`** (`: StandingPoint`) and - **`AmmoPickUpStandingPoint`** (`: StandingPointWithWeaponRequirement`) — the usable - positions troops interact with to crew/reload the weapon. -- **`CannonBallPile`** (`: SiegeMachineStonePile`) — ammo pile prop for cannon-type weapons. -- **`Ballistics`** (static) — trajectory/aiming math shared by the weapons above. - -Placement in battle is driven by `AbilitySystem`'s `ArtilleryPlacementScript`/ -`ArtilleryPlacementCastingBehavior` for player/AI-called artillery abilities. diff --git a/CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md deleted file mode 100644 index 822e7e93..00000000 --- a/CSharpSourceCode/BattleMechanics/Banners/CLAUDE.md +++ /dev/null @@ -1,13 +0,0 @@ -# BattleMechanics/Banners - -Custom faction/unit banners usable in missions (beyond the game's per-clan banner system). - -- **`CustomBannerManager`** (static) — loads banner definitions from XML - (`LoadXML`, called in `SubModule.OnSubModuleLoad`); **`FactionBannerOverride`** — - per-faction override entry (lets a Warhammer faction/culture use a specific custom - banner texture instead of the generated vanilla one). -- **`CustomBannerMissionLogic`** (`: MissionLogic`) — applies the overrides to banner-bearer - agents/props during a mission; added in `SubModule.OnMissionBehaviorInitialize`. - -Also see `Models/TORBattleBannerBearersModel` (which agents get banners) and -`HarmonyPatches/FactionBannerPatches.cs`. diff --git a/CSharpSourceCode/BattleMechanics/CLAUDE.md b/CSharpSourceCode/BattleMechanics/CLAUDE.md deleted file mode 100644 index 419cbf94..00000000 --- a/CSharpSourceCode/BattleMechanics/CLAUDE.md +++ /dev/null @@ -1,59 +0,0 @@ -# BattleMechanics - -Everything that runs inside a `Mission` (battles, sieges, tournaments, arena fights): -custom AI, status effects, damage/triggered-effect resolution, siege artillery, banners, -dismemberment, firearms, monster-siege support, and misc SFX/voice mission logics. This is -the largest and most mission-behavior-heavy folder in the mod; most classes are either a -`MissionLogic`/`MissionView` registered in `SubModule.OnMissionBehaviorInitialize`, or an -`AgentComponent`/`ScriptComponentBehavior` attached per-agent or per-prop. - -## Root-level mission logics - -- **`TORBattleAgentLogic`** (`: BattleAgentLogic`) — replaces the vanilla per-agent battle - logic (kill credit, morale-on-death, etc.) to route through TOR's own systems. -- **`AddAgentComponentsMissionLogic`** — attaches TOR's custom `AgentComponent`s - (`AbilityComponent`, `StatusEffectComponent`, `AgentVoiceComponent`, AI components) to - every spawned agent. -- **`CareerPerkMissionBehavior`** — applies/reacts to Career perks during missions. -- **`CinematicCameraMissionView`** — scripted camera moves (cutscene-style shots). -- **`CustomCrosshairMissionBehavior`** — swaps in TOR ability/weapon crosshairs, replacing - `MissionGauntletCrosshair` (removed in `SubModule`). -- **`SiegeEarlyVictoryMissionLogic`** — lets a siege end early under custom conditions. -- **`TORMonsterSiegeLogic`** — large file; lets giant-monster troops (trolls, etc.) act as - their own siege "detachment" (ladders/gates), with several internal Harmony patch classes - (`TORMonsterSiegeLadderQueueConditionsPatch`, `...GateDamagePatch`, etc.) colocated here - rather than in `HarmonyPatches/`. - -## Subfolders - -- **`AI/`** — custom battlefield AI: formation behaviors, team AI, spellcaster AI, - civilian mission AI, artillery AI, and shared decision-making helpers (own CLAUDE.md tree). -- **`Artillery/`** — field siege weapons (trebuchets etc.) beyond the vanilla siege-only ones. -- **`Banners/`** — custom faction banner assets/overrides usable in missions. -- **`CustomArenaModes/`** — archery contest and joust tournament game modes for the arena. -- **`DamageSystem/`** — `DamageType` enum + `TORDamageHelper`, shared damage-type/resistance - math used by both spell damage (`Models/TORAbilityModel`) and physical damage - (`Models/TORAgentApplyDamageModel`). -- **`Dismemberment/`** — `DismembermentMissionLogic` (gore/limb-loss on kill). -- **`Firearms/`** — black-powder weapon mechanics (Empire handguns/cannons — reload, - misfire, continuous-fire tracking). -- **`Morale/`** — `UndeadMoraleAgentComponent` (undead troops ignore/are immune to morale). -- **`SFX/`** — small standalone `ScriptComponentBehavior`s for scene dressing - (light dampening, object spinning/animating, face-toward-target, flyable objects). -- **`SniperScope/`** — a zoom/scope `ICrosshair` implementation for long-range weapons. -- **`StatusEffect/`** — the buff/debuff (DOT/HOT/stat-mod) system applied by spells, items, - and prayers. -- **`TriggeredEffect/`** — the data-driven "what happens on hit/cast" system: damage, - healing, status application, summoning, script triggers — the payload `Ability`/item - scripts fire off. -- **`Voice/`** — custom battle shouts and per-agent voice-over component. - -## Key shared types - -- **`TORDamageHelper`** — routes spell/melee/ranged damage through the same - per-`DamageType` proportion/amplification/resistance math, and folds in Career-passive - bonuses (`CareerHelper.AddCareerPassivesForDamageValues`) when the main party is involved. -- **`TriggeredEffect`/`TriggeredEffectTemplate`/`TriggeredEffectManager`** — XML-defined - "effect packages" (damage, heal, status effects, summon, spawn prefab, run a named - `ITriggeredScript`) resolved by AoE/target-type against nearby agents; used by both - Ability scripts and item weapon-hit scripts. diff --git a/CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md b/CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md deleted file mode 100644 index 871217bb..00000000 --- a/CSharpSourceCode/BattleMechanics/CustomArenaModes/CLAUDE.md +++ /dev/null @@ -1,17 +0,0 @@ -# BattleMechanics/CustomArenaModes - -New arena/tournament game modes beyond vanilla melee tournaments. - -- **`ArcheryContestTournamentGame`** (`: FightTournamentGame`) + - **`ArcheryContestTournamentBehavior`** (`: TournamentBehavior`, in - `CustomTournamentBehaviors.cs`) + **`ArcheryContestAgentController`** (`: AgentController`) - — a ranged-only archery contest mode. Driven in the campaign layer by - `Missions/ArcheryContestMissionController`. -- **`JoustTournamentGame`** (`: FightTournamentGame`) + - **`JoustTournamentBehavior`** (`: TournamentBehavior`, in `CustomTournamentBehaviors.cs`) - + **`JoustLaneEndVolumeBox`** (`: MissionObject`) — a mounted joust mode with dedicated - lanes; the volume box marks/triggers lane-end turnaround. Driven by - `Missions/JoustFightMissionController`. - -See `Missions/` for the campaign-facing controllers that set these modes up, and -`CharacterCreation`/settlement menus for how a player enters them. diff --git a/CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md b/CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md deleted file mode 100644 index 92cdf725..00000000 --- a/CSharpSourceCode/BattleMechanics/DamageSystem/CLAUDE.md +++ /dev/null @@ -1,24 +0,0 @@ -# BattleMechanics/DamageSystem - -The shared damage-type/resistance math used by every damage source in the mod (melee, -ranged, spells). - -- **`DamageType`** enum — TOR's extended damage typing (beyond vanilla Cut/Pierce/Blunt), - e.g. Fire/Physical/etc. (see `TriggeredEffectTemplate.DamageType`, - `StatusEffectTemplate.DamageType`), plus an `All` sentinel used for array sizing. -- **`TORDamageHelper`** (static) — the actual formulas: - - `CalculateDamageWithProportions` — splits one base damage value across multiple - `DamageType`s by proportion, applies per-type amplification minus resistance - (used for melee/ranged where `TORAgentApplyDamageModel` blends types). - - `CalculateSingleTypeDamage` — single-`DamageType` version (used for spells, - `TORAbilityModel`). - - `ApplyCareerPassives` — folds `CharacterDevelopment/CareerSystem` `CareerHelper` - passive bonuses into the attack/defense percentage arrays when the main party is - involved in the hit. - - `DetermineMask(Blow/KillingBlow)` — classifies a hit as Spell/Ranged/Melee - (`AttackTypeMask`), checking `Utilities/TORSpellBlowHelper` first so spell damage isn't - misclassified as a normal ranged/melee hit. - -Consumed by `Models/TORAgentApplyDamageModel`, `Models/TORAbilityModel`, -`BattleMechanics/StatusEffect` (amplification/resistance aggregation), and -`BattleMechanics/TriggeredEffect`. diff --git a/CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md deleted file mode 100644 index cc11cdc3..00000000 --- a/CSharpSourceCode/BattleMechanics/Dismemberment/CLAUDE.md +++ /dev/null @@ -1,6 +0,0 @@ -# BattleMechanics/Dismemberment - -**`DismembermentMissionLogic`** (`: MissionLogic`) — gore mechanic: on a sufficiently heavy -killing blow, detaches/replaces limb meshes on the corpse instead of (or alongside) the -normal ragdoll, matching Warhammer's more brutal combat tone. Added in -`SubModule.OnMissionBehaviorInitialize`. diff --git a/CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md deleted file mode 100644 index 3a8ce64b..00000000 --- a/CSharpSourceCode/BattleMechanics/Firearms/CLAUDE.md +++ /dev/null @@ -1,9 +0,0 @@ -# BattleMechanics/Firearms - -**`FirearmsMissionLogic`** (`: MissionLogic`) — black-powder weapon mechanics (Empire -handguns/pistols, grenades, the Dwarf "Trollhammer torpedo", cannon-type explosions): -custom explosion damage/radius per weapon type (`_explosionDamage`/`_explosionRadius`, -torpedo variant sized 30% smaller), continuous-fire tracking per agent -(`ContinousFiringData`, `_continousFiringAgents`) for sustained-fire weapons, and managed -gunshot/grenade sound events (validated once, played/cleaned up per shot). Added in -`SubModule.OnMissionBehaviorInitialize`. diff --git a/CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md deleted file mode 100644 index 702a40b6..00000000 --- a/CSharpSourceCode/BattleMechanics/Morale/CLAUDE.md +++ /dev/null @@ -1,6 +0,0 @@ -# BattleMechanics/Morale - -**`UndeadMoraleAgentComponent`** (`: AgentComponent`) — attached to undead troops -(Vampire Counts/Mousillon/Sylvania factions) to make them ignore or heavily resist morale -loss/routing, matching tabletop Warhammer's undead "unbreakable/immune to psychology" -theme. Complements `Models/TORBattleMoraleModel` and `Models/TORPartyMoraleModel`. diff --git a/CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md b/CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md deleted file mode 100644 index 0133c998..00000000 --- a/CSharpSourceCode/BattleMechanics/SFX/CLAUDE.md +++ /dev/null @@ -1,12 +0,0 @@ -# BattleMechanics/SFX - -Small, reusable `ScriptComponentBehavior`s for scene-prop dressing, usable from the scene -editor as well as spawned at runtime (e.g. by `AbilitySystem`/`StatusEffect` visuals): - -- **`TORSpinner`** — continuously rotates its entity (`RotationSpeed`); used by - `StatusEffectComponent` for effects flagged `Template.Rotation`. -- **`TORFaceArmy`** (in `TORFaceEnemy.cs`) — orients an entity to face a target/enemy. -- **`TORLightDampener`** — attenuates a light source's intensity over time/conditions. -- **`TORSimpleObjectAnimator`** — plays a simple keyframe/transform animation on an entity. -- **`PlayerFlyableObjectScript`** — lets the player fly/ride an otherwise-static object - (used for spectacle set-pieces, e.g. mounts summoned by abilities). diff --git a/CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md b/CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md deleted file mode 100644 index d29f64b3..00000000 --- a/CSharpSourceCode/BattleMechanics/SniperScope/CLAUDE.md +++ /dev/null @@ -1,6 +0,0 @@ -# BattleMechanics/SniperScope - -**`SniperScope`** (`: ICrosshair`) — a zoom/scope-style aiming reticle for long-range -weapons (e.g. Empire long rifles from `BattleMechanics/Firearms`), separate from the -`AbilitySystem/CrossHairs` family since it's a weapon-aiming aid rather than an -ability-targeting reticle. diff --git a/CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md b/CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md deleted file mode 100644 index d6a5b56c..00000000 --- a/CSharpSourceCode/BattleMechanics/StatusEffect/CLAUDE.md +++ /dev/null @@ -1,35 +0,0 @@ -# BattleMechanics/StatusEffect - -The buff/debuff system: DOTs/HOTs, damage amplification/resistance, movement/attack/reload -speed mods, lance steadiness, temporary character attributes — applied by spells, prayers, -items, and terrain. - -- **`StatusEffectTemplate`** (`ITemplate, IEquatable`) — XML-defined effect data: - `EffectType` (`DamageOverTime`, `HealthOverTime`, `WindsOverTime`, `DamageAmplification`, - `Resistance`, `MovementManipulation`, `AttackSpeedManipulation`, `ReloadSpeedManipulation`, - `LanceSteadiness`, `TemporaryAttributeOnly`), `BaseEffectValue`, target `DamageType`/ - `AttackTypeMask` (for amplification/resistance types), particle/visual config - (`ParticleId`, `ParticleIntensity`, `ApplyToRootBoneOnly`, `Rotation`). -- **`StatusEffectManager`** (static) — loads/indexes all templates - (`LoadStatusEffects`, called from `SubModule.OnSubModuleLoad`) and creates runtime - `StatusEffect` instances (`CreateNewStatusEffect`, handles cloning for career-mutated effects). -- **`StatusEffect`** (`IDisposable, IEquatable`) — one active instance on an agent: - template + applier + remaining duration + `CastId` (links back to the - `AbilitySystem/SpellCasting/SpellCastSession` that applied it, for kill/XP credit). -- **`StatusEffectComponent`** (`: AgentComponent, IDisposable`) — attached per-agent - (via `AddAgentComponentsMissionLogic`); the real engine of the system: - - Ticks every ~1s (`OnElapsed`), decrementing durations and removing expired effects. - - Aggregates all active effects into one `EffectAggregate` per tick (sum of DoT/HoT/Winds- - over-time/speed mods/resistances/amplifications across `AttackTypeMask`×`DamageType`), - exposed via `GetAmplifiers`/`GetResistances`/`GetMovementSpeedModifier`/etc. for other - systems (damage models, agent driven properties) to query. - - Owns a pooled particle-visual system (`StatusParticleVisualPoolEntry`) so repeated - stacking/refreshing of the same effect on the same agent reuses particle systems - instead of recreating them, with a dormant-pool cleanup timer. - - Restores/resynchronizes `AgentDrivenProperties` (speed, swing/reload speed, mount stats) - when effects apply or expire (`SynchronizeBaseValues`/`RefreshStatusStateAfterRemoval`). -- **`StatusEffectMissionLogic`** (`: MissionLogic`) — mission-level driver that ticks every - agent's `StatusEffectComponent` (added in `SubModule.OnMissionBehaviorInitialize`). - -Consumed by `AbilitySystem` (spell/prayer effects), `BattleMechanics/TriggeredEffect` -(`AssociatedStatusEffects`), and item enchantments (`Items/ItemTrait`). diff --git a/CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md b/CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md deleted file mode 100644 index 9cf53373..00000000 --- a/CSharpSourceCode/BattleMechanics/TriggeredEffect/CLAUDE.md +++ /dev/null @@ -1,33 +0,0 @@ -# BattleMechanics/TriggeredEffect - -The data-driven "payload" system for what happens when a spell/weapon/trap fires: damage, -healing, status-effect application, unit summoning, prefab spawning, or running a named -custom script. Both `AbilitySystem` (via `Ability.Template.TriggeredEffects`) and item -weapon-hit scripts (`Items/WeaponHitScripts`) resolve their actual effects through this. - -- **`TriggeredEffectTemplate`** (`ITemplate`) — XML data: `DamageType`/`DamageAmount`/ - `DamageVariance`, `Radius`/`HasShockWave`, `TargetType` (Self/Enemy/Friendly/All), - `ImbuedStatusEffects` (→ resolved to `StatusEffectTemplate`s), particle/sound feedback, - and optional `ScriptNameToTrigger` (reflection-instantiated `ITriggeredScript`), - `SpawnPrefabName`, or `TroopIdToSummon`/`NumberToSummon` for summon effects. -- **`TriggeredEffectManager`** (static) — loads/indexes templates - (`LoadTemplates`, from `SubModule.OnSubModuleLoad`), `GetTemplateWithId`/ - `GetTemplatesWithIds` used everywhere a `TriggeredEffects` string list needs resolving. -- **`TriggeredEffect`** (`IDisposable`) — runtime `Trigger(...)` call: resolves targets by - `TargetType` + radius, applies the `TORAbilityModel`'s skill/perk scaling - (`GetSkillEffectivenessForAbilityDamage`, radius/duration scaling) when in campaign, - routes damage/heal through `TORMissionHelper.DamageAgents`/`HealAgents`, queues status - effects (batches through `AbilityManagerMissionLogic` when present, for correct - visual/sound sequencing and spell-session bookkeeping), spawns burst - particles/sound, and finally reflection-invokes the configured `ITriggeredScript`. - Uses a small time-delayed disposal queue (`ProcessPendingDisposals`) to avoid - disposing sound handles mid-tick. -- **`AnimationTrigger`/`AnimationTriggerManager`/`AnimationTriggerMissionLogic`** — - separate, simpler system: named triggers fired from animation events (e.g. a weapon - swing keyframe) rather than ability/weapon-hit code; `AnimationTriggerTuple` pairs a - trigger name with its handler. - -## Subfolder - -- **`Scripts/`** — `ITriggeredScript` implementations invoked via `ScriptNameToTrigger` - (see its CLAUDE.md). diff --git a/CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md b/CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md deleted file mode 100644 index c9656422..00000000 --- a/CSharpSourceCode/BattleMechanics/TriggeredEffect/Scripts/CLAUDE.md +++ /dev/null @@ -1,26 +0,0 @@ -# BattleMechanics/TriggeredEffect/Scripts - -`ITriggeredScript` (`OnTrigger(position, triggerer, targets, duration)`) implementations, -reflection-instantiated by `TriggeredEffect.TriggerScript` via -`TriggeredEffectTemplate.ScriptNameToTrigger`. One-off bespoke behaviors too specific to -generalize into template fields. - -- **`DynamicItemTraitScripts.cs`** — largest file; one class per weapon/item enchantment - proc effect (Lore-of-Magic flavored): `ApplySwiftShiverTrait`, `ApplyHagbaneTrait`, - `ApplyStarFireTrait`, `ApplyFlamingItemTraitScript`/`ApplyLesserFlamingItemTraitScript`, - `ApplyLightItemTraitScript`/`ApplyLesserLightItemTraitScript`, - `ApplyHeavensItemTraitScript`/`ApplyLesserHeavensItemTraitScript`/`ApplyGreaterHeavensItemTraitScript`/`ApplyMightyHeavensItemTraitScript`, - `ApplyDeathDamageItemTraitScript`, `ApplyMetalItemTraitScript`, - `ApplyQuickSilverWeaponItemTraitScript`, `ApplyHolyItemTraitScript`, - `ApplyAzyrForesightScript`, `EnchantWeaponScript`, `ApplyTranquillityCadaiTrait`, - `SpiritLeech` — each applies a specific `Items/ItemTrait` / status effect on hit. -- **`RuneMagicScripts.cs`** — Dwarf Rune Magic procs: `OathAndSteelScript`, - `HearthAndHome`, `SpellbreakerRuneScript`, `WrathAndRuinScript`. -- **`AnvilOfDoomSpawnerScript`** — spawns the Anvil of Doom prop (Runelord/Runesmith - ability prerequisite, see `AbilitySystem/Ability.IsDisabled`). -- **`PrefabSpawnerScript`** — generic "spawn this prefab" trigger. -- **`SummonScript`** — spawns `TroopIdToSummon` × `NumberToSummon` (Summoning abilities). -- **`KnockDownScript`** — knocks affected agents down. -- **`TraitHelper`** (static) — shared helpers for the trait scripts above. -- **`ITriggeredScript`** — the interface itself (also implemented by - `AbilitySystem/Scripts/TeleportScript.TeleportTriggeredScript`). diff --git a/CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md b/CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md deleted file mode 100644 index 581fc8e2..00000000 --- a/CSharpSourceCode/BattleMechanics/Voice/CLAUDE.md +++ /dev/null @@ -1,15 +0,0 @@ -# BattleMechanics/Voice - -Custom voice-over playback that bypasses the native `Agent.MakeVoice` (which the comments -note can crash for TOR's custom races/monsters). - -- **`TORVoiceManager`** (singleton) — loads `tor_voice_definitions.xml` (from the - TOR_Armory module's data folder) mapping a race/monster name to a `VoiceDefinition` - (internal class) of sound file names; `GetVoiceToPlay(agent, voiceType)` picks the right - line for that agent's race (human/vampire/skeleton/spirit_host/wraith/etc.) and - `SkinVoiceType`. Played back through `Audio/TORAudioManager`, not native FMOD voice events. - Initialized in `SubModule.OnSubModuleLoad`. -- **`AgentVoiceComponent(agent)`** (`: AgentComponent`) — per-agent component that requests - voice lines (hurt/death/battle cries) from the manager at the right moments. -- **`BattleShoutsMissionLogic`** (`: MissionLogic`) — mission-level trigger for battle-cry - style shouts (charge, morale events), added in `SubModule.OnMissionBehaviorInitialize`. diff --git a/CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md deleted file mode 100644 index ffb950ba..00000000 --- a/CSharpSourceCode/CampaignMechanics/Assimilation/CLAUDE.md +++ /dev/null @@ -1,10 +0,0 @@ -# CampaignMechanics/Assimilation - -Handles what happens to a settlement's population/culture when it changes hands between -very different factions (e.g. Greenskins sacking an Empire town) — Warhammer factions don't -peacefully "convert" the way vanilla Calradia cultures do. - -- **`AssimilationCampaignBehavior`** (`: CampaignBehaviorBase`) — the assimilation - mechanic itself (loyalty/culture drift, or replacement, after conquest). -- **`RaceFixCampaignBehavior`** — corrects/normalizes character race data that can drift - or mismatch after culture/faction changes (also see `HarmonyPatches/RaceFixPatches.cs`). diff --git a/CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md deleted file mode 100644 index 66055576..00000000 --- a/CSharpSourceCode/CampaignMechanics/BountyMaster/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# CampaignMechanics/BountyMaster - -**`BountyMasterCampaignBehavior`** (`: CampaignBehaviorBase`) — a settlement service that -issues bounty-hunting contracts against enemies/criminals, rewarding the player for -tracking down and defeating the target. diff --git a/CSharpSourceCode/CampaignMechanics/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CLAUDE.md deleted file mode 100644 index 9a128333..00000000 --- a/CSharpSourceCode/CampaignMechanics/CLAUDE.md +++ /dev/null @@ -1,62 +0,0 @@ -# CampaignMechanics - -The largest folder: every `CampaignBehaviorBase` (registered in -`SubModule.InitializeGameStarter`) plus its supporting helpers/VMs/screens. This is where -Warhammer's setting gets expressed on the campaign map — factions, careers, religion, -custom resources (Waaagh, Teef, Oath Gold, Chivalry, Forest Harmony, Favor), diplomacy, -crafting/enchanting, and unique named characters/settlements. - -Most files follow one of these shapes: -- **`XyzCampaignBehavior` / `XyzTownBehavior`** (`: CampaignBehaviorBase`) — registers game - events (`AddBehaviors`) and reacts to them; one per mechanic, added individually in - `SubModule.cs`. -- **`XyzHelper`** (static) — pure logic/queries a behavior or UI delegates to. -- **`XyzVM` / `XyzScreen`** — Gauntlet view-model/screen pairs for a dedicated UI (crafting, - spellbook-adjacent, religion encyclopedia, etc.). - -## Root-level files - -- **`CampaignEventHelpers`** (static) — shared helpers for wiring up `CampaignEvents`. -- **`TorRecruitmentHelpers`/`TORAIRecruitmentCampaignBehavior`** — custom troop recruitment - rules (including AI lord recruitment). -- **`TORPartyUpgraderCampaignBehavior`** — custom troop-upgrade-path logic per party. -- **`TORCaptivityCampaignBehavior`** — custom prisoner/captivity handling. -- **`TORSpecialSettlementBehavior`** — hooks for TOR's special settlement types. -- **`TORFactionDiscontinuationCampaignBehavior`** — handles a faction ceasing to exist - (Warhammer factions can be wiped out/disabled, unlike vanilla's always-present kingdoms). -- **`TORStartupBehavior`** — first-run/new-campaign setup. -- **`GreenskinAICampaignBehavior`** — Waaagh-flavored AI behavior for Greenskin lords. -- **`SkillTrainerBehavior`** (+ `HeroTrainingData`) — companion/hero skill training over time. -- **`TorMapBarSpriteWidget`** (`: IconBrushWidget`) — custom map-bar icon widget. -- **`TORCampaignMusicHandler`** (`: IMusicHandler`) — custom campaign music selection. - -## Subfolders (one mechanic each — see each folder's own CLAUDE.md) - -- **`Assimilation/`** — race/culture "fixing" and assimilation of captured settlements. -- **`BountyMaster/`** — bounty-hunting contracts. -- **`Careers/`** — campaign-side glue for the Career system (dialogs, perks) — the core - Career data model itself lives in `CharacterDevelopment/CareerSystem`. -- **`Chaos/`** — the Chaos faction/invasion mechanic. -- **`CharacterCreation/`** — TOR's custom character-creation flow (race/culture specializations). -- **`Companions/`** — companion recruitment/AI companion behavior. -- **`Crafting/`** — weapon/armor enchanting system (screen, VMs, ingredients, loot). -- **`CustomDialogs/`** — extra conversation lines/behaviors + culture-specific - `ConversationTags/`. -- **`CustomEvents/`** — generic scripted campaign events framework. -- **`CustomResourceBehavior/`** — town/campaign behaviors that grant/spend custom resources. -- **`CustomResources/`** — the custom resource system itself (Waaagh, Teef, Oath Gold, - Chivalry, Forest Harmony, Favor) + `WaaaghMeter/` UI. -- **`Diplomacy/`** — alliances, trade agreements, kingdom decisions. -- **`MapNotifications/`** — custom map notification popups. -- **`MasterEngineer/`** — Dwarf Master Engineer town service. -- **`PostBattleLoot/`** — post-battle looted-troop bookkeeping. -- **`RaidingParties/`** — raider war-party AI/component. -- **`RaiseDead/`** — Vampire Counts/Necromancy raise-dead mechanics, graveyards, tree spirits. -- **`RegimentsOfRenown/`** — named elite unit regiments recruitable at settlements. -- **`Religion/`** — the religion/deity system and its encyclopedia page. -- **`ServeAsAHireling/`** — player-as-hireling activity. -- **`SpellTrainers/`** — trainers who teach spells/lores in town. -- **`TORCustomSettlement/`** — TOR's bespoke settlement types (Troll Cave, Chaos Portal, - Shrine, Herdstone, Cursed Site, Oak of Ages, World Roots, Slaver Camp) + their menus/components. -- **`UniqueSpawns/`** — named unique heroes/monsters spawned into the world (e.g. Orion). -- **`Villages/`** — custom village types. diff --git a/CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md deleted file mode 100644 index 7a7e5a86..00000000 --- a/CSharpSourceCode/CampaignMechanics/Careers/CLAUDE.md +++ /dev/null @@ -1,14 +0,0 @@ -# CampaignMechanics/Careers - -Campaign-map glue for the Career system (the core data model — `CareerObject`, -`CareerChoiceObject`, perks — lives in `CharacterDevelopment/CareerSystem`; this folder is -the campaign-behavior/dialog layer on top of it). - -- **`TORCareerPerkCampaignBehavior`** (`: CampaignBehaviorBase`) — applies/reacts to - career perk effects at the campaign level (companion in - `BattleMechanics/CareerPerkMissionBehavior` for missions). -- **`CareerDialogOptionsCampaignBehavior`** — registers career-specific dialog lines/options. -- **`CareerButtonDialogs`** (static) — dialog text/logic backing the in-mission "career - button" special actions (see `CharacterDevelopment/CareerSystem/CareerButton`). -- **`GrailDamselEnvoyOfTheLadyPerkDialog`** — a specific perk-triggered dialog for the - Grail Damsel career's "Envoy of the Lady" perk. diff --git a/CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md deleted file mode 100644 index 8be93030..00000000 --- a/CSharpSourceCode/CampaignMechanics/Chaos/CLAUDE.md +++ /dev/null @@ -1,6 +0,0 @@ -# CampaignMechanics/Chaos - -**`ChaosCampaignBehavior`** (`: CampaignBehaviorBase`) — the Chaos faction/invasion -mechanic: escalating incursions from Chaos-aligned forces (spawned via -`CampaignMechanics/TORCustomSettlement/Component/ChaosPortalComponent` portals), -independent of the normal kingdom-war system. Added in `SubModule.InitializeGameStarter`. diff --git a/CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md deleted file mode 100644 index e2921e9e..00000000 --- a/CSharpSourceCode/CampaignMechanics/CharacterCreation/CLAUDE.md +++ /dev/null @@ -1,35 +0,0 @@ -# CampaignMechanics/CharacterCreation - -TOR's replacement character-creation flow: race/culture-specific narrative stages plus a -custom final "Specialization" stage (pick a starting profession/background per race). - -- **`TORCharacterCreationContentHandler`** (`: ICharacterCreationContentHandler`, singleton - `Instance`) — the central driver: builds `CharacterCreationOption`/`SpecializationOption` - lists, tracks stage navigation (`LastStageIndex`, per-stage selections e.g. Wood Elf gods - / Dwarf grudges / profession), applies the final race/equipment/religion/specialization - choice on finish. Has an in-code TODO noting it needs rework for the 1.3.1 native - `ICharacterCreationContentHandler` pattern (replaced the older `CharacterCreationContentBase`). -- **`CharacterCreationOption`** / **`SpecializationOption`** — XML-loadable option data for - the generic stages and the custom specialization stage respectively. -- **`TORSpecializationStage`** (`: CharacterCreationStageBase`) — the custom final stage. - - **`TORSpecializationStageView`** (`: CharacterCreationStageViewBase`) — its Gauntlet view. - - **`TORSpecializationStageVM`** (+ `SpecializationOptionVM`, - `TORSpecializationGainedPropertiesVM`, `SpecializationAttributeGroupVM`, - `SpecializationAttributeVM`, `SpecializationSkillItemVM`, `FocusIconVM`, all in the same - file) — the stage's view-model tree, showing attribute/skill/focus gains per option. -- **`FaceGenHelper`** (static) — face-generation helpers per race (pairs with - `HarmonyPatches/FaceGenPatches.cs`). -- **`TORCharacterCreationException`** (+ `TORCCXmlLoadException`, - `TORCCSpecializationStageLoadException`, `TORCCReflectionException`, - `TORCCEquipmentUpdateException`, `TORCCInvalidOptionTypeException`) — a small exception - hierarchy for reporting specific character-creation data/loading failures. - -## TODO - -- **`TORSpecializationStageView`** used to track an instance `_wasVisited` flag (set true - on affirmative action, reset false when backing out to jump to the Profession stage), - deliberately instance-scoped rather than static "to prevent cross-session contamination - when creating multiple characters" per its own comment — but nothing ever read it, so it - was removed as dead code (see the TODO comment left at its old declaration site). Restore - it if visited-state still needs tracking; likely related to the class's other in-code TODO - about needing a full rework for the 1.3.1 `ICharacterCreationContentHandler` pattern. diff --git a/CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md deleted file mode 100644 index 4a304df5..00000000 --- a/CSharpSourceCode/CampaignMechanics/Companions/CLAUDE.md +++ /dev/null @@ -1,7 +0,0 @@ -# CampaignMechanics/Companions - -- **`TORCompanionsCampaignBehavior`** (`: CampaignBehaviorBase`) — custom companion - recruitment/management rules (companion pools likely skewed by culture/race, matching - Warhammer factions). -- **`TORAICompanionCampaignBehavior`** — AI-side companion behavior (how AI lords use/hire - companions). diff --git a/CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md deleted file mode 100644 index 906069b1..00000000 --- a/CSharpSourceCode/CampaignMechanics/Crafting/CLAUDE.md +++ /dev/null @@ -1,28 +0,0 @@ -# CampaignMechanics/Crafting - -TOR's item-enchanting system: a full Gauntlet screen (separate from vanilla smithing) that -applies magical `Items/ItemTrait`s to weapons/armor using ingredients and priest/artisan -services. - -- **`EnchantmentHelper`** (static) — `CreateEnchantedItem`: clones an `ItemObject` with a - fresh generated id and applies the chosen traits/`ItemModifier`, optionally flagged - player-crafted. -- **`EnchantingScreen`** (`: ScreenBase, IGameStateListener`) + **`EnchantingState`** - (`: GameState`) — the screen/state pair that opens the enchanting UI. -- **`EnchantingVM`** (root view-model) with supporting VMs: **`EnchantableItemVM`** - (an item eligible for enchanting), **`EnchantableTraitVM`** (a selectable trait/effect), - **`EnchantingIngredientVM`** (+ **`EnchantingIngredientWidget`** `: RichTextWidget`, - internal), **`EnchantingItemTableauVM`** (3D item preview tableau). -- **`EnchanterTownBehavior`** (`: CampaignBehaviorBase`) — the town service entry point - that opens `EnchantingScreen`. -- **`PriestBehavior`** (`: CampaignBehaviorBase`) — a related town service (priest-blessed - enchantments/holy traits, ties into `CampaignMechanics/Religion`). -- **`TORArtisanDistrictCampaignBehavior`** (+ `TorItemDuplicationData`, - `TorItemBeingCraftedData`) — an artisan-district crafting service (queued item - crafting/duplication over time). -- **`LootCampaignBehavior`** / **`EnchantmentIngredientLootCampaignBehavior`** — adds - enchanting ingredients and enchanted items to post-battle/dungeon loot tables. - -See `Items/TorEnchantingIngredients`, `Items/ItemTrait`, and -`Models/TOREnchantmentCraftingModel`/`TOREnchantmentIngredientsModel` for the underlying -data/cost models this UI drives. diff --git a/CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md deleted file mode 100644 index bd57fa6e..00000000 --- a/CSharpSourceCode/CampaignMechanics/CustomDialogs/CLAUDE.md +++ /dev/null @@ -1,23 +0,0 @@ -# CampaignMechanics/CustomDialogs - -Extra conversation content: new dialog flows/behaviors plus (in `ConversationTags/`) the -`ConversationTag`s that gate culture/race-specific lines in both vanilla and TOR dialogs. - -- **`CustomDialogCampaignBehavior`** (`: CampaignBehaviorBase`) — registers TOR's general - additional dialog lines/flows. -- **`TORCompanionDialogBehavior`** — companion-specific conversation content. -- **`CareerSwitchCampaignBehavior`** — the dialog/flow for changing a hero's Career. -- **`DuelBehavior`** — dialog-triggered honor duels (see also - `Missions/DuelFightMissionController`). -- **`BloodKissSceneNotificationItem`** (`: SceneNotificationData`) — a scripted scene - notification for the Vampire "Blood Kiss" (turning a companion into a vampire) narrative - moment. - -## Subfolder - -- **`ConversationTags/`** — `ConversationTag` (`IsApplicableTo(CharacterObject)`) - implementations used as dialog conditions, one file per race/culture family: - `CommonTags` (`PlayerIsRenownedTag`), `HumanTags` (Bretonnian/Empire/Warrior - Priest/Grail Knight checks), `DwarfTags`, `AsraiTag` (+ elf/player-is-elf variants), - `EonirTag`, `GreenskinTags` (orc/goblin), `VampireTags` (male/female), `BloodDragonTag`, - `MousillonTag`. diff --git a/CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md deleted file mode 100644 index 225cff56..00000000 --- a/CSharpSourceCode/CampaignMechanics/CustomDialogs/ConversationTags/CLAUDE.md +++ /dev/null @@ -1,18 +0,0 @@ -# CampaignMechanics/CustomDialogs/ConversationTags - -`ConversationTag` implementations (`IsApplicableTo(CharacterObject character)`) used as -dialog line conditions/filters, so a conversation line can be written once and -automatically apply only to characters of the right race/culture/background. - -- **`CommonTags.cs`** — `PlayerIsRenownedTag` (player clan tier > 2). -- **`HumanTags.cs`** — `IsBretonnianTag`/`IsEmpireTag` and their `PlayerIs...` variants, - `IsWarriorPriestTag`/`PlayerIsWarriorPriestTag`, `PlayerIsGrailKnightTag`. -- **`DwarfTags.cs`** — `IsDwarfTag`, `PlayerIsDwarfTag`. -- **`AsraiTag.cs`** — `AsraiTag`, `ElfMaleTag`, `PlayerIsElfTag`, `PlayerIsAsraiTag`. -- **`EonirTag.cs`** — `EonirTag`, `PlayerIsEonirTag`. -- **`GreenskinTags.cs`** — `IsOrcTag`, `IsGoblinTag`, `PlayerIsOrcTag`. -- **`VampireTags.cs`** — `VampireMaleTag`, `VampireFemaleTag`. -- **`BloodDragonTag.cs`** / **`MousillonTag.cs`** — specific vampire bloodline/culture tags. - -Referenced from dialog registration code in `../CustomDialogCampaignBehavior` and other -`CampaignBehaviorBase`s that add conversation lines via `CampaignGameStarter.AddDialogLine`. diff --git a/CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md deleted file mode 100644 index f3f9b198..00000000 --- a/CSharpSourceCode/CampaignMechanics/CustomEvents/CLAUDE.md +++ /dev/null @@ -1,14 +0,0 @@ -# CampaignMechanics/CustomEvents - -A generic scripted-event framework: named events with a frequency tier, cooldown, a -condition predicate, and a consequence action — a lightweight alternative to writing a -full `CampaignBehaviorBase` for every one-off flavor event. - -- **`CustomEvent`** — `(StringId, CustomEventFrequency, Cooldown, Func condition, - Action consequence)`; `DoesConditionHold()`/`Trigger()`. `CustomEventFrequency`: - Rare/Uncommon/Common/Abundant/Special. -- **`CustomEventsCampaignBehavior`** (`: CampaignBehaviorBase`) — periodically rolls - registered `CustomEvent`s against their frequency/cooldown and fires the ones whose - condition holds. -- **`SimpleCareerQuestBehavior`** (`: CampaignBehaviorBase`) — lightweight one-off - Career-flavor quests built on this same event pattern rather than a full `Quests/` quest class. diff --git a/CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md deleted file mode 100644 index c0074a42..00000000 --- a/CSharpSourceCode/CampaignMechanics/CustomResourceBehavior/CLAUDE.md +++ /dev/null @@ -1,10 +0,0 @@ -# CampaignMechanics/CustomResourceBehavior - -Campaign/town behaviors that actually grant or spend the resources defined in -`../CustomResources`, keyed to specific settlement services: - -- **`OathGoldBehavior`** (+ `ExpeditionReward`) — Dwarf Oath Gold: expeditions and their - rewards (large file — the most developed of these systems). -- **`TeefBehavior`** — Greenskin Teef gain/spend hooks. -- **`PrestigeNobleTownBehavior`** — Empire Prestige gained via noble/town interactions. -- **`EonirFavorEnvoyTownBehavior`** — Eonir Council Favor via an envoy town service. diff --git a/CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md deleted file mode 100644 index e5507f83..00000000 --- a/CSharpSourceCode/CampaignMechanics/CustomResources/CLAUDE.md +++ /dev/null @@ -1,31 +0,0 @@ -# CampaignMechanics/CustomResources - -TOR's per-culture "second currency" system — each major culture has its own thematic -resource tracked alongside gold/influence. - -- **`CustomResource`** — definition: `StringId`, localized name/description - (`tor_custom_resource_name/description` game texts), icon, which culture(s) it belongs to, - and an optional custom tooltip function. `GetCustomResourceIconAsText` renders it as an - inline `` tag for use in UI text. -- **`CustomResourceManager`** (singleton) — registers all resources on `Initialize()` - (called from `SubModule.InitializeGameStarter`): - - Empire → **Prestige** - - Bretonnia → **Chivalry** (`ChivalryHelper`) - - Sylvania/Mousillon (Vampire factions) → **DarkEnergy** - - Asrai (Wood Elves) → **ForestHarmony** (`ForestHarmonyHelper`) - - Eonir (Wood Elves) → **CouncilFavor** (`FavorHelper`) - - Dawi (Dwarfs) → **OathGold** (`OathGoldHelper`) - - Greenskin → **Teef**/**Waaagh** (see `TeefHelper`, `WaaaghMeter/`) - - Also tracks a `_massBudget`/`_resourceChanges` and hooks the party screen - (`ScreenManager.OnPushScreen/OnPopScreen`) to show resource changes in the party UI. -- **`ChivalryHelper` / `ForestHarmonyHelper` / `FavorHelper` / `OathGoldHelper` / `TeefHelper`** - (static) — per-resource gain/spend rules and tooltip info providers. - -Actual gain/spend triggers live in the sibling `CustomResourceBehavior/` folder; -`Models/TORCustomResourceModel` governs generalized cost scaling -(`CustomResource.GetCustomResourceGeneralizedFactor`). - -## Subfolder - -- **`WaaaghMeter/`** — Greenskin-specific Waaagh resource UI (map view + VM) and behavior. diff --git a/CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md deleted file mode 100644 index 7a4f7e16..00000000 --- a/CSharpSourceCode/CampaignMechanics/CustomResources/WaaaghMeter/CLAUDE.md +++ /dev/null @@ -1,11 +0,0 @@ -# CampaignMechanics/CustomResources/WaaaghMeter - -Greenskin "Waaagh" meter — a mass-momentum resource that grows as Greenskin factions -win battles/raid, unlocking benefits at thresholds ("Big Waaagh"). - -- **`WaaaghBehavior`** (`: CampaignBehaviorBase`) — accrues/decays the meter based on - campaign events; ties into `WaaaghHelper` for the actual math and - `AbilitySystem/Spells/LoreObject` ("BigWaaagh" lore unlock). -- **`WaaaghHelper`** (static) — gain/threshold calculations. -- **`WaaaghMeterMapView`** (`: MapView`) — the on-map meter widget. -- **`WaaaghMeterVM`** — its view-model. diff --git a/CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md deleted file mode 100644 index 4855879b..00000000 --- a/CSharpSourceCode/CampaignMechanics/Diplomacy/CLAUDE.md +++ /dev/null @@ -1,19 +0,0 @@ -# CampaignMechanics/Diplomacy - -Alliance/war/trade-agreement mechanics beyond vanilla kingdom diplomacy. - -- **`HonorAllianceDecision`** (`: KingdomDecision`, + nested `HonorAllianceOutcome`, - + `HonorAllianceDecisionTypeDefiner : SaveableTypeDefiner`) — a Total-War-style forced - choice: when an ally is attacked, the kingdom must vote within 24h to either join the war - or break the alliance — no "do nothing and stay allied" option. -- **`TORAllianceWarBehavior`** (`: CampaignBehaviorBase`, + - `TORAllianceWarBehaviorTypeDefiner : SaveableTypeDefiner`) — tracks alliances and raises - `HonorAllianceDecision`s when one is tested; persists alliance state via the type definer. -- **`TORKingdomDecisionsCampaignBehavior`** — registers/manages TOR's custom kingdom - decisions generally. -- **`TORTradeAgreementAIBehavior`** — AI logic for proposing/accepting trade agreements - (see `Models/TORTradeAgreementModel`, `Models/DiplomacyHelpers`). - -See `Models/TORAllianceModel`, `Models/TORDiplomacyModel`, -`Models/TORKingdomDecisionPermissionModel` for the scoring/permission rules these behaviors -call into. diff --git a/CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md deleted file mode 100644 index 954ebbf7..00000000 --- a/CSharpSourceCode/CampaignMechanics/MapNotifications/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# CampaignMechanics/MapNotifications - -- **`TORMapNotification`** (`: InformationData`) — a custom map notification payload - (icon/text for TOR-specific events not covered by vanilla notification types). -- **`TORMapNotificationView`** (`: MapNotificationView`) — its Gauntlet view. diff --git a/CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md deleted file mode 100644 index 9fb8e2c0..00000000 --- a/CSharpSourceCode/CampaignMechanics/MasterEngineer/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# CampaignMechanics/MasterEngineer - -**`MasterEngineerTownBehaviour`** (`: CampaignBehaviorBase`) — a Dwarf-flavored town -service where a Master Engineer NPC offers engineering-related interactions (likely -artillery/equipment crafting or upgrades — pairs with `Quests/EngineerQuest`). diff --git a/CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md deleted file mode 100644 index 66b8a9d1..00000000 --- a/CSharpSourceCode/CampaignMechanics/PostBattleLoot/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -# CampaignMechanics/PostBattleLoot - -**`PendingLootedTroopManager`** (static) — tracks troops/items looted from a battle that -are pending resolution (e.g. captured troops or gear to be claimed after the post-battle -screen), decoupling the moment of victory from when loot is actually granted. diff --git a/CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md deleted file mode 100644 index e81c5412..00000000 --- a/CSharpSourceCode/CampaignMechanics/RaidingParties/CLAUDE.md +++ /dev/null @@ -1,9 +0,0 @@ -# CampaignMechanics/RaidingParties - -Raider-type war parties (Greenskin/Chaos/Beastmen war-bands that raid rather than hold territory). - -- **`IRaidingParty`** — marker/contract interface for a raiding party component. -- **`RaidingPartyComponent`** (`: WarPartyComponent, IRaidingParty`) — the party component - itself: identifies a `MobileParty` as a raider band with raiding-specific AI/lifecycle. -- **`RaidingPartyCampaignBehavior`** (`: CampaignBehaviorBase`) — spawns/manages raiding - parties campaign-wide (from `../TORCustomSettlement` raider-spawner settlements, etc.). diff --git a/CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md deleted file mode 100644 index a2599c6e..00000000 --- a/CSharpSourceCode/CampaignMechanics/RaiseDead/CLAUDE.md +++ /dev/null @@ -1,12 +0,0 @@ -# CampaignMechanics/RaiseDead - -Vampire Counts / Mousillon (undead) and Asrai (tree spirit) resurrection-flavored mechanics. - -- **`RaiseDeadInTownBehavior`** (`: CampaignBehaviorBase`) — a town service letting an - undead-aligned player raise fallen troops as undead reinforcements. -- **`PostBattleCampaignBehavior`** — post-battle hook that ties into raising the dead after - a fight (corpses available to raise scale with the battle just fought). -- **`GraveyardNightWatchPartyComponent`** (`: PartyComponent`) — a party that guards a - graveyard at night (tied to `BattleMechanics` graveyard fight content in `Missions/`). -- **`TreeSpiritHelpers`** (static) — Wood Elf tree-spirit summoning/raising helpers - (parallel mechanic for Asrai, thematically similar to undead raising). diff --git a/CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md deleted file mode 100644 index 55dd229e..00000000 --- a/CSharpSourceCode/CampaignMechanics/RegimentsOfRenown/CLAUDE.md +++ /dev/null @@ -1,11 +0,0 @@ -# CampaignMechanics/RegimentsOfRenown - -Named elite "Regiment of Renown" units (a tabletop Warhammer concept: unique, upgraded -unit templates) recruitable from specific settlements. - -- **`RORManager`** (static) — loads/indexes ROR templates (`LoadTemplates`, called from - `SubModule.OnSubModuleLoad`). -- **`RORSettlementTemplate`** — links a settlement to the regiment(s) it can recruit. -- **`RORCampaignBehavior`** (`: CampaignBehaviorBase`) — availability/recruitment logic. -- **`ToRSettlementNameplateVM`** (`: SettlementNameplateVM`) — extends the map settlement - nameplate VM, presumably to flag settlements offering a Regiment of Renown. diff --git a/CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md deleted file mode 100644 index 499b3950..00000000 --- a/CSharpSourceCode/CampaignMechanics/Religion/CLAUDE.md +++ /dev/null @@ -1,22 +0,0 @@ -# CampaignMechanics/Religion - -Warhammer deity/pantheon system layered onto heroes and settlements. - -- **`ReligionObject`** (`: MBObjectBase`, XML-defined via `MBObjectManager`) — a deity/faith: - name, deity name, lore/blessing text, associated `CultureObject`, `Pantheon` enum, - `HostileReligions` (feeds `GetHostilityFactor`, used by diplomacy/relations math), - religious troops/elite units/artifacts, `InitialClans`. `FillAll()` loads the full list - from `Religions.xml` (`SubModule.BeginGameStart`). Has an encyclopedia link. -- **`ReligionObjectHelper`** (static) — queries/helpers (e.g. a hero's dominant religion, - compatibility scoring between religions/pantheons). -- **`ReligionCampaignBehavior`** (`: CampaignBehaviorBase, IDisposable`) — the runtime - mechanic: heroes gain/lose faith, blessings apply, hostility affects relations. -- **`ReligionEncyclopediaPage`** (`: EncyclopediaPage, IPublicEncyclopediaPage`) + - **`TorEncyclopediaModel`** (`: OverrideEncyclopediaModel`) + - **`TorEncyclopediaListItemNameComparer`** — adds a Religion category/page to the game's - encyclopedia. -- **`EncyclopediaReligionObjectVM`** (`: EncyclopediaContentPageVM`) — the page's view-model. - -Settlements can be tied to a religion via `ReligionObject` on -`CampaignMechanics/TORCustomSettlement/Component/TORBaseSettlementComponent` (shrines, etc.). -Also see `Models/TORFaithModel`. diff --git a/CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md deleted file mode 100644 index a4b078ae..00000000 --- a/CSharpSourceCode/CampaignMechanics/ServeAsAHireling/CLAUDE.md +++ /dev/null @@ -1,9 +0,0 @@ -# CampaignMechanics/ServeAsAHireling - -Lets the player take service as a hireling under an AI lord/faction instead of leading -their own party. - -- **`ServeAsAHirelingCampaignBehavior`** (`: CampaignBehaviorBase`) — entry/exit points and - state management for the activity. -- **`ServeAsAHirelingActivities`** — the day-to-day activities/tasks performed while serving. -- **`ServeAsAHirelingHelpers`** (static) — shared query/eligibility helpers. diff --git a/CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md deleted file mode 100644 index 2d15b6e6..00000000 --- a/CSharpSourceCode/CampaignMechanics/SpellTrainers/CLAUDE.md +++ /dev/null @@ -1,7 +0,0 @@ -# CampaignMechanics/SpellTrainers - -**`SpellTrainerInTownBehavior`** (`: CampaignBehaviorBase`) — a town service where an NPC -trainer teaches the player/companions spells from a `LoreObject` (see -`AbilitySystem/Spells/LoreObject`), gated by culture eligibility — including the special -Spellweaver dialog bypass that lets Asrai Spellsingers learn High/Dark Magic despite the -normal culture lock (see the note in `AbilitySystem/Spells/CLAUDE.md`). diff --git a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md deleted file mode 100644 index 6bd0d019..00000000 --- a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CLAUDE.md +++ /dev/null @@ -1,37 +0,0 @@ -# CampaignMechanics/TORCustomSettlement - -TOR's bespoke settlement/world-object types — special map locations beyond -towns/castles/villages, each with its own component, menu, and (usually) a -`CampaignBehaviorBase`. Registered as engine object types in `SubModule.BeginGameStart` -(`game.ObjectManager.RegisterType<...Component>(...)`). - -- **`TORCustomSettlementCampaignBehavior`** — umbrella behavior wiring the custom - settlement types into the campaign (spawning, menus, persistence). -- **`TrollCaveCampaignBehavior`** — Troll Cave lair: spawns defending trolls - (`TrollCaveDefenderPartyComponent`), raidable by the player. -- **`GreenskinBrawlBehavior`** (+ `BrawlMissionResult`) — Greenskin settlement brawl - mini-game (scored mission result feeding back into the campaign). -- **`GoblinRecruitmentBehavior`** — goblin troop recruitment from custom settlements. -- **`TORSettlementMenuHelpers`** (static) — shared menu-building helpers for the - `CustomSettlementMenus/` logic classes. - -## Subfolders - -- **`Component/`** — `SettlementComponent` subclasses, one per settlement type (see its - CLAUDE.md): `TORBaseSettlementComponent` (abstract base: owner clan, `ReligionObject`, - active flag) → `BaseRaiderSpawnerComponent` (abstract, spawns raiders periodically) → - `ChaosPortalComponent`, `HerdStoneComponent`, `SlaverCampComponent`, `TrollCaveComponent`; - plus `CursedSiteComponent`, `OakOfAgesComponent`, `ShrineComponent`, `WorldRootsComponent`. -- **`CustomSettlementMenus/`** — `TORBaseSettlementMenuLogic` (abstract) and its concrete - per-settlement-type menu builders (Troll Cave, Cursed Site, Oak of Ages, Shrine, - Raiding Site). - -## TODO - -- **`TORCustomSettlementCampaignBehavior`**'s victory-loot item selection has a stray - `continue;` right after the first line of its enchanting loop (near the - `unmodifiedItems`/`enchantedItems` split), which skips the ~90 lines of "lesser_loot" - item-trait selection entirely. Victory loot from Chaos Portal/Troll Cave/etc. currently - never receives enchantments — every item passes through unmodified. The dead code is - still there (warning-suppressed, not deleted), pending a decision on whether to - re-enable it or remove it for good — found while enabling `TreatWarningsAsErrors`. diff --git a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md deleted file mode 100644 index b454339a..00000000 --- a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/Component/CLAUDE.md +++ /dev/null @@ -1,18 +0,0 @@ -# CampaignMechanics/TORCustomSettlement/Component - -`SettlementComponent` subclasses, one per bespoke settlement/world-object type registered -in `SubModule.BeginGameStart`. - -- **`TORBaseSettlementComponent`** (abstract `: SettlementComponent`) — shared base: parses - common XML attrs (`background_mesh`, `wait_mesh`, `background_crop_position`, `religion`), - resolves `Religion` (`CampaignMechanics/Religion`), tracks `OwnerClan`/`IsActive`. - - **`BaseRaiderSpawnerComponent`** (abstract) — adds periodic raider-troop spawning; base - for the "hostile lair" settlement types: - - **`ChaosPortalComponent`** — Chaos incursion portal. - - **`HerdStoneComponent`** — Beastmen herdstone. - - **`SlaverCampComponent`** — Dark Elf/Norscan-style slaver camp. - - **`TrollCaveComponent`** — troll lair (pairs with `../TrollCaveCampaignBehavior`). - - **`CursedSiteComponent`** (`IDisposable`) — a cursed/haunted site (Vampire-flavored). - - **`OakOfAgesComponent`** — Wood Elf sacred site. - - **`ShrineComponent`** — a religious shrine tied to a `ReligionObject`. - - **`WorldRootsComponent`** — Wood Elf world-roots network site. diff --git a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md deleted file mode 100644 index cac00cf8..00000000 --- a/CSharpSourceCode/CampaignMechanics/TORCustomSettlement/CustomSettlementMenus/CLAUDE.md +++ /dev/null @@ -1,17 +0,0 @@ -# CampaignMechanics/TORCustomSettlement/CustomSettlementMenus - -Settlement-menu ("wait menu") builders for the custom settlement types in `../Component`. - -- **`TORBaseSettlementMenuLogic`** (abstract) — shared menu-registration scaffolding - (takes a `CampaignGameStarter`). -- **`TrollCaveMenuLogic`**, **`CursedSiteMenuLogic`**, **`OakOfAgesMenuLogic`**, - **`ShrineMenuLogic`**, **`RaidingSiteMenuLogic`** — one concrete menu per settlement type, - built with `../TORSettlementMenuHelpers`. - -## TODO - -- **`TrollCaveMenuLogic`** used to track an `_isClearingCave` flag (true when clearing the - cave, false when a luring attempt goes wrong) but nothing downstream ever read it, so it - was removed as dead code (see the TODO comment left at its old declaration site). If - `StartClearCave`/`StartTrollBattle` are meant to diverge on outcome (different - loot/message/etc.), that distinction still needs implementing. diff --git a/CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md deleted file mode 100644 index 5a2362da..00000000 --- a/CSharpSourceCode/CampaignMechanics/UniqueSpawns/CLAUDE.md +++ /dev/null @@ -1,11 +0,0 @@ -# CampaignMechanics/UniqueSpawns - -Named unique heroes/monsters spawned into the campaign world (lore characters/creatures -rather than generic troops). - -- **`UniqueSpawnCampaignBehavior`** (`: CampaignBehaviorBase`) — generic framework for - spawning and tracking unique named entities. -- **`UniqueSpawnPartyComponent`** (`: WarPartyComponent`) — party component marking a - unique spawn's war party. -- **`OrionCampaignBehavior`** — a specific named unique spawn (Orion, the Wood Elf King in - the Wood — a Warhammer lore character), its own dedicated behavior. diff --git a/CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md b/CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md deleted file mode 100644 index 12ed1a57..00000000 --- a/CSharpSourceCode/CampaignMechanics/Villages/CLAUDE.md +++ /dev/null @@ -1,6 +0,0 @@ -# CampaignMechanics/Villages - -- **`TORVillageTypes`** (`: DefaultVillageTypes`) — TOR's replacement/extension of the - vanilla village-type list (per-culture village flavors matching Warhammer factions). -- **`TORTownManagementVillageItemVM`** — view-model for a village row in the town - management screen, extended for TOR's village data. diff --git a/CSharpSourceCode/CharacterDevelopment/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CLAUDE.md deleted file mode 100644 index 38162005..00000000 --- a/CSharpSourceCode/CharacterDevelopment/CLAUDE.md +++ /dev/null @@ -1,36 +0,0 @@ -# CharacterDevelopment - -Character progression data: skills, attributes, perks, traits, and the Career system -(Warhammer-flavored "prestige classes" like Grail Knight, Witch Hunter, Runelord, Slayer, -Orc Boss). Most root-level files are static-ish registries initialized once at startup -(`SubModule.BeginGameStart`/game object registration) mirroring vanilla's -`DefaultSkills`/`DefaultTraits` pattern. - -## Root-level registries - -- **`TORSkills`** — TOR's additional skill definitions. -- **`TORSkillEffects`** — skill-driven passive effects. -- **`TORAttributes`** — additional character attributes. -- **`TORCharacterTraits`** — additional personality/character traits. -- **`TORPerks`** (+ nested static `Spellcraft`, `GunPowder`, `Faith` groups) — TOR's extra - perks, grouped by theme (e.g. `TORPerks.Spellcraft.ArcaneLink`, referenced by - `BattleMechanics/TriggeredEffect/TriggeredEffect`). -- **`TORPerkHandlerCampaignBehavior`** (`: CampaignBehaviorBase`) — applies perk effects - campaign-side. -- **`TORCareers`** — registry of every `CareerObject` (Blood Knight, Grail Damsel, Grail - Knight, Mercenary, Minor Vampire, Necromancer, Warrior Priest [+ Ulric variant], Witch - Hunter, Black Grail Knight, Necrarch, Imperial Magister, Waywatcher, Spellsinger, Warden, - Grey Lord, Knight of the Old World, Ironbreaker, Slayer, Runelord, Orc Boss, Orc Shaman). -- **`TORCareerChoices`** (+ `CareerHasNoChoicesException`) — registry of all - `CareerChoiceObject`s (the perk-tree nodes within a career). -- **`TORCareerChoiceGroups`** — registry of `CareerChoiceGroupObject`s (tiers/branches - grouping choices within a career tree). -- **`CareerAbilityChargeSupplier`** (static) — supplies charge-gain hooks for careers whose - signature ability builds "charge" from combat actions rather than a plain cooldown - (`ChargeType.Custom` on `CareerObject`). - -## Subfolder - -- **`CareerSystem/`** — the Career data model itself (`CareerObject`, `CareerChoiceObject`, - `CareerChoiceGroupObject`), its screen/VMs, and the perk-tree "special button" + - per-career choice-effect implementations (see its CLAUDE.md). diff --git a/CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md deleted file mode 100644 index 82e06db7..00000000 --- a/CSharpSourceCode/CharacterDevelopment/CareerSystem/CLAUDE.md +++ /dev/null @@ -1,40 +0,0 @@ -# CharacterDevelopment/CareerSystem - -The Career data model — Warhammer "prestige class" progression (Grail Knight, Witch -Hunter, Runelord, Slayer, Orc Boss, etc.), each with a signature `CareerAbility` -(see `AbilitySystem/CareerAbility` + `AbilitySystem/Scripts/CareerAbilityScript`), a perk -tree, and often a special right-click "career button" action. - -## Core model - -- **`CareerObject`** (`: PropertyObject`, XML-defined via `MBObjectManager`) — one career: - `AbilityTemplateID`/`AbilityScriptType` (its signature ability), `ChargeType` - (`CooldownOnly` vs `Custom`, the latter driven by a `ChargeFunction` computing charge from - combat hits — see `CareerAbilityChargeSupplier`), `RootNode`/`ChoiceGroups` (the perk tree), - an eligibility `Predicate`. `MutateAbility`/`MutateTriggeredEffect`/ - `MutateStatusEffect` let unlocked choices numerically tweak the career's ability/effects - at cast time (called from `AbilitySystem/Scripts/CareerAbilityScript`, - `BattleMechanics/StatusEffect/StatusEffectComponent`). -- **`CareerChoiceObject`** (`: PropertyObject`, + nested `MutationObject`, `PassiveEffect`) - — one perk-tree node: a `PassiveEffect` (flat/percentage stat bonus, - `PassiveEffectType`-keyed, consumed by `CareerHelper.ApplyBasicCareerPassives`/ - `AddCareerPassivesForDamageValues`) and/or a `MutationObject` (numeric tweak applied to - the career's ability/triggered-effect/status-effect). -- **`CareerChoiceGroupObject`** (`: PropertyObject`) — groups/tiers of `CareerChoiceObject`s - forming the tree structure. -- **`CareerHelper`** (static) — the query/application layer used everywhere else in the - codebase: `ApplyBasicCareerPassives`, `AddCareerPassivesForDamageValues` (feeds - `BattleMechanics/DamageSystem/TORDamageHelper`), `IsValidCareerMissionInteractionBetweenAgents`, - `PrayerCooldownIsNotShared`. -- **`CareerObjectVM`/`CareerChoiceObjectVM`/`CareerChoiceGroupObjectVM`** — view-models for - the tree UI; **`CareerAbilityEffectVM`** — shows the ability's current numeric effect. -- **`CareerScreen`** (`: ScreenBase, IGameStateListener`) + **`CareerScreenGameState`** - (`: GameState`) + **`CareerScreenVM`** — the dedicated Career screen (pick/respec choices). - -## Subfolders - -- **`Choices/`** — one `TORCareerChoicesBase` subclass per career, registering that - career's actual `CareerChoiceObject`/`PassiveEffect`/`MutationObject` data - (see its CLAUDE.md). -- **`CareerButton/`** — right-click "special action" buttons some careers add to the - party/prisoner screen (see its CLAUDE.md). diff --git a/CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md deleted file mode 100644 index 71eb61f2..00000000 --- a/CSharpSourceCode/CharacterDevelopment/CareerSystem/CareerButton/CLAUDE.md +++ /dev/null @@ -1,27 +0,0 @@ -# CharacterDevelopment/CareerSystem/CareerButton - -Right-click "special action" buttons that some careers add to the party-roster/prisoner -screen (e.g. sacrificing a prisoner, converting a troop, using a career resource on a unit) -— distinct from the in-mission `CareerAbility`. - -- **`CareerButtonBehaviorBase`** (abstract, ctor takes the owning `CareerObject`) — contract: - `ButtonClickedEvent`, `ShouldButtonBeVisible`, `ShouldButtonBeActive` (+ disable reason - text), `CareerButtonIcon`; registers itself with - `SpecialbuttonEventManagerHandler.Instance` via `Register()`. -- **`SpecialbuttonHandler.cs`** — **`SpecialbuttonEventManagerHandler`** (singleton) — the - registry/dispatcher all button behaviors register into; routed to from wherever the - roster screen fires its click event (see `HarmonyPatches`/`Extensions/UI`). -- **`CareerButtons`** — static list/lookup of all registered button behaviors. -- **`GreenskinCareerButton`** (abstract `: CareerButtonBehaviorBase`) — shared base for - Greenskin careers' buttons: - - **`OrcBossCareerButton`**, **`OrcShamanCareerButton`**. -- Per-career concrete behaviors: **`BlackGrailKnightCareerButtonBehavior`**, - **`GrailKnightCareerButtonBehavior`** (+ `KnightPuritySeal` in - `KnightOldWorldCareerButtonBehavior.cs`... see below), **`ImperialMagisterCareerButtonBehavior`** - (+ `PowerstoneHelper`/`PowerStone` — a resource-stone mechanic), **`IronbreakerCareerButton`** - (→ `IronbreakerCareerButtonBehavior`), **`KnightOldWorldCareerButtonBehavior`** - (+ `KnightPuritySeal`), **`MercenaryCareerButtonBehavior`**, **`NecrarchCareerButtonBehavior`**, - **`RunelordCareerButtonBehavior`** (+ `UnitRune`), **`SlayerCareerButtonBehavior`**, - **`WaywatcherCareerButtonBehavior`** (+ `ArrowType`), **`WitchHunterCareerButtonBehavior`**. -- **`CareerButtonHelper`** (static) — shared query/action helpers used across the concrete - behaviors above. diff --git a/CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md b/CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md deleted file mode 100644 index d5cf41fb..00000000 --- a/CSharpSourceCode/CharacterDevelopment/CareerSystem/Choices/CLAUDE.md +++ /dev/null @@ -1,19 +0,0 @@ -# CharacterDevelopment/CareerSystem/Choices - -One `TORCareerChoicesBase` (abstract, ctor takes the owning `CareerObject`) subclass per -Career, registering that career's `CareerChoiceGroupObject`/`CareerChoiceObject` tree -(passives + ability mutations). `CareerChoicesHelper` (static) holds shared construction -helpers used by all of them. - -Subclasses (one per `CharacterDevelopment.TORCareers` entry): -`BlackGrailKnightCareerChoices`, `BloodKnightCareerChoices`, `GrailDamselCareerChoices`, -`GrailKnightCareerChoices`, `GreyLordCareerChoices`, `ImperialMagisterCareerChoices`, -`IronbreakerCareerChoices`, `KnightOldWorldCareerChoices`, `MercenaryCareerChoices`, -`NecrarchCareerChoices`, `NecromancerCareerChoices`, `OrcBossCareerChoices`, -`OrcShamanCareerChoices`, `RunelordCareerChoices`, `SlayerCareerChoices`, -`SpellsingerCareerChoices`, `VampireCountCareerChoices`, `WardenCareerChoices`, -`WarriorPriestCareerChoices`, `WarriorPriestUlricCareerChoices`, -`WaywatcherCareerChoices`, `WitchHunterCareerChoices`. - -Consumed by `CharacterDevelopment/TORCareerChoices`/`TORCareerChoiceGroups` at startup and -rendered by `../CareerScreenVM`/`CareerChoiceObjectVM`. diff --git a/CSharpSourceCode/Extensions/CLAUDE.md b/CSharpSourceCode/Extensions/CLAUDE.md deleted file mode 100644 index a690938d..00000000 --- a/CSharpSourceCode/Extensions/CLAUDE.md +++ /dev/null @@ -1,30 +0,0 @@ -# Extensions - -Grab-bag of C# extension methods on vanilla TaleWorlds types, plus two more structured -sub-frameworks: the "extended info" side-data system and the "view-model extension" UI -injection system. - -## Root-level extension method classes - -One static class per extended type, all in `TOR_Core.Extensions`: -`AgentExtensions`, `AgentDrivenPropertiesExtensions`, `BannerExtensions`, -`CharacterObjectExtensions`, `ClanExtensions`, `CollectionExtensions`, -`ConversationManagerExtensions`, `FormationExtensions`, `GameMenuExtensions`, -`GameModelsExtensions` (shortcuts to `Campaign.Current.Models.GetXyzModel()`), -`HeroExtensions`, `ItemObjectExtensions`, `KingdomExtension`, `MissionExtensions`, -`MobilePartyExtensions`, `SettlementExtensions`, `SkillExtensions`, `TeamExtensions`, -`ViewModelExtensions`. Also **`DebugMethods`** (static) — misc debug/diagnostic helpers. -These are the mod's "everywhere" utility layer — e.g. `AgentExtensions.GetHero()`, -`GetCareer()`, `GetAbility()`, `IsSpellCaster()`, `HasCareer()` used throughout -`AbilitySystem`/`BattleMechanics`/`CharacterDevelopment`. - -## `ExtendedInfoSystem/` - -TOR needs to attach extra runtime/persisted data to vanilla objects -(`CharacterObject`, `Hero`, `MobileParty`) without subclassing them — see its CLAUDE.md. - -## `UI/` - -The "view-model extension" pattern: attaches extra bindable properties/commands onto -vanilla Gauntlet `ViewModel`s (party screen, character developer, encyclopedia, crafting, -conversation, etc.) without needing a full custom screen — see its CLAUDE.md. diff --git a/CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md b/CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md deleted file mode 100644 index 01fd99c4..00000000 --- a/CSharpSourceCode/Extensions/ExtendedInfoSystem/CLAUDE.md +++ /dev/null @@ -1,24 +0,0 @@ -# Extensions/ExtendedInfoSystem - -Side-table data attached to vanilla `CharacterObject`/`Hero`/`MobileParty` instances (keyed -by string id) since those types can't be subclassed with extra fields. - -- **`ExtendedInfoManager`** (`: CampaignBehaviorBase`, singleton `Instance`) — owns the - dictionaries (`_characterInfos`, `_heroInfos`, `_partyInfos`, plus banner-resource and - settlement-info tables), loads static per-troop data from - `tor_extendedunitproperties.xml` (TOR_Core's ExtendedData folder), and hooks nearly every - relevant `CampaignEvents` (session launch, new game, hourly/daily/quarter-daily ticks, - hero created/killed, party created/destroyed, troop upgrades, battle end) to keep the - side-tables in sync. For `CustomGame` (non-campaign), `CreateDefaultInstanceAndLoad()` is - used instead (see `SubModule.InitializeGameStarter`). -- **`CharacterExtendedInfo`** (+ `ResourceCostTuple`, `ResistanceTuple`, `AmplifierTuple`, - `DamageProportionTuple`, all `IEquatable`) — per-`CharacterObject` extra data: resource - costs, damage-type resistances/amplifications/proportions (feeds - `BattleMechanics/DamageSystem/TORDamageHelper`), race/culture-driven combat traits. -- **`HeroExtendedInfo(character)`** — per-`Hero` data (e.g. `CareerID` — see - `AbilitySystem/Scripts/CareerAbilityScript.GetEffectsToTrigger`, — Winds of Magic pool, - religion/faith state). -- **`MobilePartyExtendedInfo`** — per-party data. - -Accessed via extension methods in `../HeroExtensions`/`../CharacterObjectExtensions`/ -`../MobilePartyExtensions` (e.g. `hero.GetExtendedInfo()`) rather than directly. diff --git a/CSharpSourceCode/Extensions/UI/CLAUDE.md b/CSharpSourceCode/Extensions/UI/CLAUDE.md deleted file mode 100644 index a9b970e4..00000000 --- a/CSharpSourceCode/Extensions/UI/CLAUDE.md +++ /dev/null @@ -1,36 +0,0 @@ -# Extensions/UI - -A reflection-based "view-model extension" framework that bolts extra bindable -properties/commands onto vanilla Gauntlet `ViewModel`s, so TOR can add UI hooks to native -screens (party, character developer, encyclopedia, crafting/refinement, conversation, map -info, SP item tooltip) without subclassing or fully replacing them. - -- **`IViewModelExtension`** / **`BaseViewModelExtension`** (abstract, `IDisposable`) — base - for every extension: wraps a target `ViewModel` (`_vm`), and via reflection forwards - property/method access (`GetPropertyValue`/`SetPropertyValue`/`ExecuteCommand`/ - `GetViewModelAtPath`) to either the extension's own members (if declared on an - `IViewModelExtension`-derived type) or the wrapped VM's — letting Gauntlet's XML/Prefab - data-binding address extension properties as if they were on the original VM. Registers - itself with the manager on construction. -- **`ViewModelExtensionManager`** (singleton) — `CollectViewModelExtensions()` scans for - `[ViewModelExtension]`-attributed types at startup - (`SubModule.OnSubModuleLoad` calls `Initialize()` before Harmony patches, since patches - reroute vanilla VM construction to also construct/register the matching extension); holds - a `ConditionalWeakTable` so extensions are GC'd with their VM. -- **`ViewModelExtensionAttribute`** — marks a `BaseViewModelExtension` subclass and the - vanilla `ViewModel` type it targets. - -## Concrete extensions (one per extended vanilla VM) - -`PartyVMExtension` (+ `PendingResourceCostVM`), `PartyCharacterVMExtension`, -`CharacterDeveloperVMExtension`, `CraftingVMExtension`, `RefinementVMExtension`, -`ConversationItemVMExtension`, `MissionConversationVMExtension`, -`HeroEncyclopediaVMExtension`, `UnitEncyclopediaVMExtension`, `SPItemVMExtension`, -`TORMapInfoVMExtension`. - -## Other - -- **`TORInitialScreen`** (`: ScreenBase, IGameStateListener`) — TOR's replacement initial - loading/splash screen. -- **`MainMenu/`** — main-menu-specific VMs/services (welcome popup, recommended-settings - warning, shader-cache warning, extra main-menu links) — see its CLAUDE.md. diff --git a/CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md b/CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md deleted file mode 100644 index 2f5b0664..00000000 --- a/CSharpSourceCode/Extensions/UI/MainMenu/CLAUDE.md +++ /dev/null @@ -1,13 +0,0 @@ -# Extensions/UI/MainMenu - -Main-menu screen additions/warnings, shown before a campaign is loaded. - -- **`TORWelcomePopupVM`** — a first-run/update welcome popup. -- **`TORRecommendedSettingsWarningVM`** (+ **`TORRecommendedSettingsService`**, internal - static) — warns the player if their graphics/game settings don't match TOR's recommended - configuration (this mod adds heavy shader/particle content). -- **`TORShaderCacheWarning`** (internal static) — warns about/handles shader-cache-related - first-launch stutter (pairs with `Utilities/ShaderSourceManager` and - `SubModule`'s shader-compilation tracking in `OnApplicationTick`). -- **`TORMainMenuLinksVM`** (+ **`TORMainMenuLinkLauncher`**, internal static) — extra - main-menu links (e.g. Discord/wiki/mod page) opened via the launcher helper. diff --git a/CSharpSourceCode/GameManagers/CLAUDE.md b/CSharpSourceCode/GameManagers/CLAUDE.md deleted file mode 100644 index 7b5691c8..00000000 --- a/CSharpSourceCode/GameManagers/CLAUDE.md +++ /dev/null @@ -1,20 +0,0 @@ -# GameManagers - -Low-level game/campaign bootstrapping that has to run very early, outside the normal -`CampaignBehaviorBase` lifecycle. - -- **`TorCampaignGameManager`** (`: SandBoxGameManager`) — TOR's replacement campaign game - manager. On load finish it pushes `CharacterCreationState` and registers - `TORCharacterCreationContentHandler` (see `CampaignMechanics/CharacterCreation`) via the - 1.3.1-era `OnCharacterCreationInitializedEvent`, replacing the older direct-constructor - handler registration pattern. -- **`TORKeyInputManager`** (static) — registers TOR's custom hotkey category - (`TORGameKeyContext`, "The Old Realms") and its key bindings (e.g. Quick Cast, Quick Cast - Selection Menu) with `HotKeyManager`. Must use hardcoded text, not - `Utilities/TORTextHelper`, since it runs before the game text manager exists. Initialized - in `SubModule.OnSubModuleLoad`. -- **`TORGameKeyContext`** (`: GameKeyContext`) — the custom key-binding category itself, - including the `TorKeyMap` key indices (`QuickCast`, `QuickCastSelectionMenu`, etc.). -- **`TORShaderGameManager`** — game-manager variant used to drive/track shader compilation - state (pairs with `Utilities/ShaderSourceManager` and the shader-cache warning in - `Extensions/UI/MainMenu`). diff --git a/CSharpSourceCode/HarmonyPatches/CLAUDE.md b/CSharpSourceCode/HarmonyPatches/CLAUDE.md deleted file mode 100644 index 5622a52f..00000000 --- a/CSharpSourceCode/HarmonyPatches/CLAUDE.md +++ /dev/null @@ -1,46 +0,0 @@ -# HarmonyPatches - -Every Harmony patch in the mod (one static class per patched vanilla system, using -`[HarmonyPatch]` attributes — prefix/postfix/transpiler methods named `...Patch`). -Applied via `SubModule.HarmonyInstance.PatchAllUncategorized()` at `OnSubModuleLoad`, except -classes tagged `[HarmonyPatchCategory("LatePatches")]` (e.g. `AgentPatches`), which are -applied later in `SubModule.OnGameInitializationFinished` — after the campaign's text -manager exists, needed for patches that touch localized strings (see the `SubModule` -remarks on `InitializeGameStarter`). Some monster/siege-specific patches live outside this -folder, colocated in `BattleMechanics/TORMonsterSiegeLogic.cs` instead. - -Grouped by what they patch (not exhaustive — see individual files for exact target methods): - -- **Agents/combat**: `AgentPatches` (custom voice routing via - `BattleMechanics/Voice/AgentVoiceComponent`), `MissionCombatMechanicsHelpers`, - `MissionPatches`, `RetreatPatches` (`TORAutoResolveRetreatPatches`), - `AnimationSystemDataPatches`, `MountCreationPatches`. -- **Custom battle / arena / tournaments**: `CustomBattlePatches`, `ArenaPracticePatch`, - `TournamentPatches`, `ArtilleryPatches`. -- **Items/inventory/crafting**: `ItemPatches`, `InventoryPatches`, `InventoryResetPatch`, - `FastTradeInventoryPatch`, `CraftingPatches`, `VeterinarianPatch`. -- **Characters/creation/race**: `CharacterObjectPatches` (+ townsfolk/villager spawn-rate - sub-patches), `CharacterCreationPatches` (positive-effect text, narrative stage start, - gained-attribute population), `RaceFixPatches`, `FaceGenPatches`. -- **Campaign map/world**: `SettlementPatches`, `HideoutPatches`, `MobilePartyPatches`, - `MapEventJoinRestrictionsPatch` (+ `StartBattleActionJoinRestrictionsPatch`), - `EncounterPatches` (+ `EncounterGameMenuBehaviorPatches`), `CustomWorldMapPatch` - (+ `QuestPartyMapTrackerProviderPatches`), `NotablesCampaignBehaviorPatches`, - `ObjectManagerPatches`, `CaravanVisualPatch`. -- **Diplomacy/factions**: `FactionBannerPatches`. -- **Custom resources**: `CustomResourcePatches`. -- **Models**: `ModelPatches` (+ `ClampTroopsLeftToGarrisonCapacityPatch`). -- **UI/VM**: `ViewModelPatches` (+ `ScoreboardBaseVMPatches`, - `RefinementVMOnSelectActionPatch`), `ViewModelRefreshPatch`, `PartyScreenPerformancePatches` - (`PartyVM_TransferAllTroops_PerformancePatch`), `EncyclopediaPatches` (+ unit - property/tooltip sub-patches), `TableauRenderPatches`, `GameTextPatches`, - `LogEntryNotificationPatches`, `MainMenuOptionsPatches`, `MainMenuCrashPatch` - (`MainMenuDeferredClearAllCleanup`, `ToMainMenuClearAllFix`), `LoadingScreenPatches`, - `GameKeyOptionsCategoryPatch`. -- **Dialogue**: `ConversationPatches`. -- **Perks/skills**: `PerkResetRelatedPatch`. -- **Music**: `MBMusicManagerPatches`. -- **Debug**: `BaseGameDebugPatches`. - -Consult `Utilities/TORConfig`/`TORConstants` and the target class's file for the exact -method signatures being patched before modifying one of these. diff --git a/CSharpSourceCode/INDEX.md b/CSharpSourceCode/INDEX.md deleted file mode 100644 index 8ad305cf..00000000 --- a/CSharpSourceCode/INDEX.md +++ /dev/null @@ -1,134 +0,0 @@ -# TOR_Core — Index - -**The Old Realms** is a Mount & Blade II: Bannerlord total-conversion mod bringing Games -Workshop's *Warhammer Fantasy Battles* setting to Bannerlord. This is `TOR_Core`, the main -C# gameplay-logic module (there are sibling modules — `TOR_Armory` for art/data assets, -`TOR_Environment`, and Bannerlord's own `Native`/`SandBox`/`StoryMode`/`CustomBattle` — -referenced by the launch args in `TOR_Core.csproj`, but not present in this source tree). - -Every folder in this tree (down to leaf subfolders) has its own `CLAUDE.md` with details; -this file is the map of how they fit together. Start here, then drill into the folder that -owns the system you're touching. - -## Orientation - -- **Entry point**: `SubModule.cs` (`TOR_Core.SubModule : MBSubModuleBase`). Read this file - first when you need to know "where does X get registered/initialized" — it is the single - place that lists every `CampaignBehaviorBase`, `GameModel`, and mission behavior the mod - adds, plus Harmony setup and startup ordering. If a system isn't wired up, it starts here. -- **Project file**: `TOR_Core.csproj` — old-style (non-SDK) .NET Framework 4.8 project; - every source file must be listed in a `` element or it won't build. - References are DLLs from the installed game (`../../../bin/Win64_Shipping_Client/`) and - sibling modules (`Native`, `SandBox`, `StoryMode`, `CustomBattle`) — this is a Bannerlord - mod, not a standalone app; you cannot build/run it without a Bannerlord installation. -- **`lib/`** — two vendored DLLs (`ink-engine-runtime.dll`, `ink_compiler.dll`) for the - `Ink/` narrative-scripting integration. **`obj/`**/**`bin/`** — build output, ignore. -- **`Properties/`** — just `AssemblyInfo.cs`. - -## Architectural patterns you'll see everywhere - -- **`CampaignBehaviorBase` per mechanic** — almost every gameplay system in - `CampaignMechanics/` is one behavior class registered in `SubModule.InitializeGameStarter`. - To find how a mechanic starts, grep its behavior class name in `SubModule.cs`. -- **`GameModel` overrides** — `Models/` replaces vanilla formulas one at a time - (`TORXyzModel : DefaultXyzModel`), registered in `SubModule.OnGameStart`. To change a - formula, find the matching model here before writing a Harmony patch. -- **Harmony patches** (`HarmonyPatches/`) are the fallback for anything vanilla doesn't - expose a model/behavior/virtual method for. Most patch at `OnSubModuleLoad`; a few need - `[HarmonyPatchCategory("LatePatches")]` to run after `Game.Current`'s text manager exists. -- **XML-defined template data + a static loader/factory**: `AbilityTemplate` - (`AbilitySystem/AbilityFactory`), `TriggeredEffectTemplate` - (`BattleMechanics/TriggeredEffect/TriggeredEffectManager`), `StatusEffectTemplate` - (`BattleMechanics/StatusEffect/StatusEffectManager`), `ItemTrait` - (`Items/ItemTraitManager`), `ReligionObject`/`CareerObject`/`CareerChoiceObject` - (native `MBObjectManager` + XML). All loaded once in `SubModule.OnSubModuleLoad`/ - `BeginGameStart`. If you need to add a new spell/effect/trait/career-choice, you're - almost always adding a data entry + maybe one script class, not new infrastructure. -- **Utility-AI** (`BattleMechanics/AI`) — behaviors implement `IAgentBehavior` and score - themselves via `Axis`/`ScoringFunctions`; `DecisionManager` picks the best score. This - pattern is specific to spellcaster AI (`CastingAI/`) but the primitives - (`CommonAIFunctions/`) are reusable. -- **Extension methods over subclassing** — `Extensions/` adds behavior to vanilla types - (`Agent`, `Hero`, `CharacterObject`, ...) as static extension methods rather than wrapper - classes, since most vanilla types aren't designed to be subclassed. -- **Two ways to attach "extra data" to a vanilla object**: - - Runtime/campaign side data → `Extensions/ExtendedInfoSystem` (side dictionaries keyed - by string id, e.g. `hero.GetExtendedInfo()`). - - Extra bindable UI properties on a vanilla `ViewModel` → `Extensions/UI`'s - `BaseViewModelExtension`/`ViewModelExtensionManager` (reflection-based property/command - forwarding, registered via `[ViewModelExtension]`). -- **Save compatibility**: every persisted custom type must be registered in a - `SaveableTypeDefiner` (mainly `SaveGameSystem/TORSaveableTypeDefiner`, but a few - behaviors define their own inline) with a **stable, never-reused** numeric id — see that - file's own warning before adding or renumbering one. - -## The Warhammer domain model (so the folder docs make sense) - -- **Cultures** (`Utilities/TORConstants.Cultures`) map onto (and often reuse the game-object - slot of) vanilla Bannerlord cultures: Empire (`empire`), Bretonnia (`vlandia`), Sylvania - (`khuzait`), Mousillon (`mousillon`), Asrai/Wood Elves (`battania`), Eonir/Wood Elves - (`eonir`), Dawi/Dwarfs (`sturgia`), Greenskin (`aserai`) — plus Druchii, Beastmen, Chaos, - and several bandit-culture reskins. `Cultures.All` lists the 8 main playable ones. -- **Magic**: Winds-of-Magic **Spells** (Lores: Fire/Light/Heavens/Life/Metal/Beasts/Death, - High Magic, Dark Magic, Necromancy, Big Waaagh) and Dwarf **Rune Magic** are one system - (`AbilitySystem`); priestly **Prayers** are a parallel system tied to - `CampaignMechanics/Religion`; each **Career** has its own unique signature - `CareerAbility`. All three share the same `Ability`/`AbilityTemplate` runtime. -- **Careers** (`CharacterDevelopment/CareerSystem`) are Warhammer-flavored "prestige - classes" — Grail Knight, Black Grail Knight, Grail Damsel, Knight of the Old World, - Witch Hunter, Warrior Priest (+ of Ulric), Blood Knight, Vampire Count, Necromancer, - Necrarch, Imperial Magister, Waywatcher, Spellsinger, Warden, Grey Lord, Mercenary, - Ironbreaker, Runelord, Slayer, Orc Boss, Orc Shaman — each with a perk tree - (`CareerSystem/Choices`), a signature ability, and sometimes a special roster-screen - button (`CareerSystem/CareerButton`). -- **Per-culture "second currency"** (`CampaignMechanics/CustomResources`): Prestige - (Empire), Chivalry (Bretonnia), DarkEnergy (Sylvania/Mousillon), ForestHarmony (Asrai), - CouncilFavor (Eonir), OathGold (Dawi), Teef/Waaagh (Greenskin). -- **Bespoke settlement types** (`CampaignMechanics/TORCustomSettlement`): Chaos Portal, - Herdstone, Slaver Camp, Troll Cave (all raider-spawning lairs), Cursed Site, Oak of Ages, - Shrine, World Roots. -- **Damage/effects pipeline**: an `Ability`/weapon-hit fires a - `BattleMechanics/TriggeredEffect` → resolves target set → applies damage via - `BattleMechanics/DamageSystem/TORDamageHelper` and/or a - `BattleMechanics/StatusEffect` → both get scaled by `Models/TORAbilityModel` - (skill/perk effectiveness) and `CharacterDevelopment/CareerSystem/CareerHelper` - (career passives) along the way. - -## Top-level folder map - -| Folder | What it owns | -|---|---| -| `AbilitySystem/` | Spells, prayers, career abilities: the shared casting/effect runtime. | -| `Audio/` | Standalone file-based sound playback (ambient sounds). | -| `BattleMechanics/` | In-mission mechanics: AI, status effects, triggered effects, artillery, banners, firearms, dismemberment, voice, arena modes. | -| `CampaignMechanics/` | Every campaign-map mechanic (largest folder): factions, careers, religion, custom resources, diplomacy, crafting, custom settlements, quests-adjacent behaviors. | -| `CharacterDevelopment/` | Skills, perks, traits, attributes, and the Career data model. | -| `Extensions/` | Extension methods on vanilla types; the ExtendedInfo side-data system; the ViewModel-extension UI injection system. | -| `GameManagers/` | Early campaign bootstrapping, hotkeys, shader-related game managers. | -| `HarmonyPatches/` | Every Harmony patch, grouped by what vanilla system they touch. | -| `Ink/` | Branching-narrative integration (Inkle's Ink language). | -| `Items/` | Item traits/enchantments, weapon on-hit scripts, inventory-use scripts. | -| `Missions/` | Mission-open factory methods + scripted one-off fight controllers. | -| `Models/` | `GameModel` overrides (vanilla formula replacements) + Custom Battle variants. | -| `Quests/` | `QuestBase` quest classes, including Career storyline quests. | -| `SaveGameSystem/` | Save-type registration (`SaveableTypeDefiner`). | -| `Utilities/` | Cross-cutting static helpers (config, paths, constants, math, logging). | - -## Where to look for a given task - -- **"Add/tune a spell or prayer"** → `AbilitySystem/` (template + maybe a new - `AbilityScript`), `AbilitySystem/Spells/LoreObject` if it's a new Lore. -- **"Add a new status effect / DOT / buff"** → `BattleMechanics/StatusEffect`. -- **"A weapon should do something special on hit"** → `Items/WeaponHitScripts` + - `Items/ItemTrait`. -- **"Add/tune a Career perk or its passive"** → `CharacterDevelopment/CareerSystem/Choices`. -- **"Change how damage/resistance math works"** → `BattleMechanics/DamageSystem` + - `Models/TORAgentApplyDamageModel`/`TORAbilityModel`. -- **"Add a new campaign mechanic/town service"** → a new `CampaignBehaviorBase` under - `CampaignMechanics/`, registered in `SubModule.InitializeGameStarter`. -- **"Vanilla formula needs to behave differently"** → check `Models/` first; only reach for - `HarmonyPatches/` if there's no model hook for it. -- **"AI isn't casting/behaving right"** → `BattleMechanics/AI/CastingAI` (spellcasters) or - `BattleMechanics/AI/TeamAI` (formation/team AI). -- **"Add UI to an existing vanilla screen"** → `Extensions/UI` (`BaseViewModelExtension`) - rather than a Harmony patch on the screen class, if at all possible. diff --git a/CSharpSourceCode/Ink/CLAUDE.md b/CSharpSourceCode/Ink/CLAUDE.md deleted file mode 100644 index f0d365cc..00000000 --- a/CSharpSourceCode/Ink/CLAUDE.md +++ /dev/null @@ -1,23 +0,0 @@ -# Ink - -Integration of Inkle's [Ink](https://www.inklestudios.com/ink/) narrative scripting -language (via `lib/ink-engine-runtime.dll` + `lib/ink_compiler.dll`, referenced in -`TOR_Core.csproj`) for branching story content — used for narrative events/quests too -complex for simple dialog trees. - -- **`InkStoryManager`** (singleton) — loads every `*.ink` file from the module's - `InkStories/` folder into an `InkStory` (`Initialize()`, called from - `SubModule.OnSubModuleLoad`); `AllStories`/`LastStoryId` track loaded/most-recent story. -- **`InkStory`** — wraps a compiled Ink `Story` runtime instance and bridges it to game - state: exposes choices/continue-text, and lets Ink script "external functions" reach into - the campaign (spawning items via `Items`, custom settlements via - `CampaignMechanics/TORCustomSettlement`, custom events, quests, missions, audio) so a - story file can trigger real game effects, not just show text. -- **`InkFileHandler`** — file I/O helper for locating/reading `.ink`/compiled story assets. -- **`InkFakeMarketData`** — mock market data used when an Ink story needs to reference - prices/trade without a real market context. -- **`InkStoryCampaignBehavior`** (`: CampaignBehaviorBase`) — campaign-level hook that - starts/advances stories (also see `Items/InventoryUseScripts/StartInkStoryScript`, an - item that launches a story when used). -- **`InkStoryVM`** / **`InkStoryChoiceVM`** — Gauntlet view-models for presenting the - current story text and its choices to the player. diff --git a/CSharpSourceCode/Items/CLAUDE.md b/CSharpSourceCode/Items/CLAUDE.md deleted file mode 100644 index 54fb37b0..00000000 --- a/CSharpSourceCode/Items/CLAUDE.md +++ /dev/null @@ -1,33 +0,0 @@ -# Items - -Item-level extensions: magical weapon/armor traits (enchantments), custom item metadata, -and inventory-item "use" scripts (right-click a campaign item to trigger an effect). - -- **`ItemTrait`** (`IEquatable`, XML-defined) — a magical trait/enchantment - definition: `ResistanceTuple`/`AmplifierTuple`/`AdditionalDamageTuple` - (from `Extensions/ExtendedInfoSystem/CharacterExtendedInfo`'s tuple types, reused here for - items), an `OnWeaponHitScript`/`OnInventoryUseScript` reference (by name, resolved to a - script class), `ImbuedStatusEffectId`/`ImbuedEffectChance`, crafting cost - (`IsCraftable`, `IngredientItem`/`IngredientAmount`), valid item type, and a `StatsTuple` - for flat stat bonuses. This is the data half of `CampaignMechanics/Crafting`'s enchanting - system and of pre-enchanted unique items. -- **`ItemTraitManager`** (static) — loads/indexes all `ItemTrait`s (`LoadItemTraits`, - called from `SubModule.OnSubModuleLoad`). -- **`ItemTraitAgentComponent`** (`: AgentComponent`) — tracks which traits are active on an - agent's equipped gear during a mission. -- **`ExtendedItemObjectManager`** / **`ExtendedItemObjectProperties`** — extra per-`ItemObject` - metadata beyond what `ItemTrait` covers (loaded via `ExtendedItemObjectManager.LoadXML` - in `SubModule.OnSubModuleLoad`). -- **`TorEnchantingIngredients`** — ingredient item definitions used by the crafting UI. -- **`TorItemMenuVM`** / **`TorItemTraitVM`** / **`TorInventoryItemTupleWidget`** / - **`TorImageIdentifierWidget`** — inventory/tooltip UI showing an item's traits. -- **`InventoryUseScriptsCampaignBehavior`** (`: CampaignBehaviorBase`) — dispatches - "use this item" actions from the inventory screen to the matching - `InventoryUseScripts/` script. - -## Subfolders - -- **`WeaponHitScripts/`** — `IWeaponHitScript` implementations: on-hit weapon procs - (see its CLAUDE.md). -- **`InventoryUseScripts/`** — `IInventoryUseScript` implementations: right-click item-use - effects on the campaign map (see its CLAUDE.md). diff --git a/CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md b/CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md deleted file mode 100644 index 9ca25616..00000000 --- a/CSharpSourceCode/Items/InventoryUseScripts/CLAUDE.md +++ /dev/null @@ -1,20 +0,0 @@ -# Items/InventoryUseScripts - -Right-click "use this item" effects on the campaign map, referenced by name from -`Items/ItemTrait.OnInventoryUseScript` and dispatched by -`Items/InventoryUseScriptsCampaignBehavior`. - -- **`IInventoryUseScript`** — `OnUse(userParty, item)`, `OnHourlyTick`/`OnDailyTick` - (for items with a recurring effect while carried, not just a one-shot use). -- **`BaseInventoryUseScript(string[] arguments)`** (`IEquatable`, `[SaveableField]` - arguments — persisted with the save) — default base; `UseScript` wraps `OnUse` and fires - `Utilities/TORCampaignEvents.Instance.OnUseInventoryUseScriptObject` for other systems to - react to. Equality is by type + arguments, so save/load can match instances back up. - Also defines **`TORUseScriptArgumentException`** and **`ScriptUseData`** (a small - saveable record of who used what item, when, and how many times). -- **`StartInkStoryScript`** — using the item launches an `Ink/` narrative story. -- **`SkillBookScript`** — grants skill XP/unlocks when read. -- **`CustomResourceContainerScript`** — using the item grants/converts a - `CampaignMechanics/CustomResources` resource. -- **`EnchantmentBlueprintScript`** — teaches/unlocks an enchantment recipe for - `CampaignMechanics/Crafting`. diff --git a/CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md b/CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md deleted file mode 100644 index c2c91326..00000000 --- a/CSharpSourceCode/Items/WeaponHitScripts/CLAUDE.md +++ /dev/null @@ -1,22 +0,0 @@ -# Items/WeaponHitScripts - -On-hit weapon proc effects, referenced by name from `Items/ItemTrait.OnWeaponHitScript` -and instantiated per hit. - -- **`IWeaponHitScript`** — `OnHit(attackingAgent, attackedAgent, blow, missionWeapon, - collisionData)`. -- **`BaseWeaponHitScript(string[] arguments)`** — default base implementing the interface; - `ApplyWeaponTraitDamage` routes secondary/bonus damage through - `AbilitySystem/AbilityManagerMissionLogic.QueueOnHitSecondaryDamage` when available - (deferred outside the original hit callback to avoid mutating agent state mid-resolution), - else falls back to `Extensions/AgentExtensions.ApplyDamage` directly. -- **`WeaponScripts.cs`** — the bulk of concrete on-hit procs (elemental/magical weapon - effects triggered on a successful hit). -- **`DefenseScripts.cs`** — on-hit scripts that trigger from the defender's side (e.g. - reactive/retaliation effects, damage reduction procs). -- **`KnightlyStrikeHitScript`** — the on-hit effect tied to the Grail Knight/Knight career - "Knightly Strike" ability (see `AbilitySystem/Scripts/KnightlyStrikeScript`). - -Dispatched via **`WeaponHitScriptsMissionLogic`** (root `Items/` folder, -`: MissionLogic`), added in `SubModule.OnMissionBehaviorInitialize`, which listens for hit -events and looks up the attacker's weapon's `ItemTrait.OnWeaponHitScript` to invoke. diff --git a/CSharpSourceCode/Missions/CLAUDE.md b/CSharpSourceCode/Missions/CLAUDE.md deleted file mode 100644 index 92e1f3d1..00000000 --- a/CSharpSourceCode/Missions/CLAUDE.md +++ /dev/null @@ -1,38 +0,0 @@ -# Missions - -Campaign-facing "how do we open a mission scene and what runs it" layer — factory methods -for launching a mission scene plus small `MissionLogic` controllers for scripted one-off -fights (as opposed to `BattleMechanics/`, which is the in-mission mechanics that run once -inside any mission). - -- **`TorMissionManager`** (static, `[MissionManager]`) — `[MissionMethod]`-attributed - factory methods (the same pattern as vanilla's `MissionManager`/`CampaignMissionManager`) - that build and open a `Mission` for a given scene: e.g. - `OpenArcheryContestMission(scene, ArcheryContestTournamentGame, settlement, culture, - isPlayerParticipating)`. This is the entry point `CampaignMechanics`/`Quests` code calls - to actually start one of TOR's custom mission types. -- **`TORMissionAgentHandler`** — shared agent-spawning logic reused by several of the - scripted-fight controllers below. -- **`MissionExperienceBehavior`** — custom XP granting rules for missions. - -## Scripted fight controllers (one per special encounter type, all `: MissionLogic`) - -- **`QuestFightMissionController(enemyPartyTemplate, enemyCount, onMissionEnd, ...)`** — - generic "fight this templated enemy party, then run a callback" controller used by quests. -- **`DuelFightMissionController`** — 1v1 honor duel (see - `CampaignMechanics/CustomDialogs/DuelBehavior`). -- **`BrawlMissionController`** — settlement brawl mini-game (see - `CampaignMechanics/TORCustomSettlement/GreenskinBrawlBehavior`). -- **`GraveyardFightMissionController`** — graveyard night-watch fight (see - `CampaignMechanics/RaiseDead`). -- **`TrollCaveMissionController`** — Troll Cave raid mission. -- **`ArcheryContestMissionController`** / **`JoustFightMissionController`** — wrap the - `BattleMechanics/CustomArenaModes` archery/joust tournament games for campaign use. - -## TODO - -- **`TrollCaveMissionController`** used to set a `_playerCanLeave` flag on victory but - nothing ever read it (the real "let the mission end" signal is - `_battleEndLogic.ChangeCanCheckForEndCondition(true)`, called right alongside it), so it - was removed as dead code. Restore it (see the TODO comment left at its old declaration - site) if a leave-mission check still needs it. diff --git a/CSharpSourceCode/Models/CLAUDE.md b/CSharpSourceCode/Models/CLAUDE.md deleted file mode 100644 index 90b3055f..00000000 --- a/CSharpSourceCode/Models/CLAUDE.md +++ /dev/null @@ -1,53 +0,0 @@ -# Models - -TaleWorlds `GameModel` overrides — the game's standard "swap out the formula" extension -point. Almost every file here is `TORXyzModel : DefaultXyzModel` (or `SandboxXyzModel`), -overriding one or more virtual calculation methods while calling `base.Xyz(...)` for the -rest. All are registered in `SubModule.OnGameStart` via `gameStarterObject.AddModel(new -TORXyzModel())` — that method is the authoritative list of which vanilla model each -replaces. A few (`TORAbilityModel`, `TORFaithModel`, `TORCustomResourceModel`, -`TOREnchantmentCraftingModel`, `TOREnchantmentIngredientsModel`, -`TORHiringCompatibilityModel`, `TORCompanionTrainingModel`, `TORReinforcementRestrictionModel`) -extend `GameModel` directly — new mechanics vanilla has no equivalent formula for. - -## By theme - -- **Combat/agent stats**: `TORAgentStatCalculateModel` (`: SandboxAgentStatCalculateModel`), - `TORAgentApplyDamageModel` (`: SandboxAgentApplyDamageModel` — routes through - `BattleMechanics/DamageSystem/TORDamageHelper`), `TORStrikeMagnitudeModel` - (`: SandboxStrikeMagnitudeModel`), `TORCombatSimulationModel`, `TORCombatXpModel`, - `TORBattleMoraleModel` (`: SandboxBattleMoraleModel`), `TORBattleBannerBearersModel` - (`: SandboxBattleBannerBearersModel`), `TORBattleRewardModel`, `TORDamageParticleModel`. -- **Abilities/magic**: `TORAbilityModel` (`: GameModel` — spell damage/radius/duration - scaling by skill/perk, called from `BattleMechanics/TriggeredEffect`), `TORFaithModel` - (`: GameModel` — prayer/religion mechanics). -- **Party**: `TORPartySizeModel`, `TORPartySpeedCalculatingModel`, `TORPartyWageModel`, - `TORPartyHealingModel`, `TORPartyMoraleModel`, `TORPartyDesertionModel`, - `TORPartyTrainingModel`, `TORPartyTroopUpgradeModel`, `TORMobilePartyAIModel`, - `TORMobilePartyFoodConsumptionModel`, `TORReinforcementRestrictionModel` (`: GameModel`). -- **Character/skills**: `TORCharacterDevelopmentModel`, `TORCharacterStatsModel`, - `TORCompanionTrainingModel` (`: GameModel`), `TORCompanionHiringPriceCalculationModel`, - `TORPrisonerRecruitmentCalculationModel`, `TORHiringCompatibilityModel` (`: GameModel`). -- **Clan/kingdom/diplomacy**: `TORClanFinanceModel`, `TORClanTierModel`, - `TORClanPoliticsModel`, `TORDiplomacyModel`, `TORAllianceModel`, `TORTradeAgreementModel`, - `TORKingdomDecisionPermissionModel` (`: KingdomDecisionPermissionModel`), - `TORMinorFactionsModel`, `TORMarriageModel`, `TORPersuasionModel`. -- **Settlement/economy**: `TORSettlementFoodModel`, `TORSettlementLoyaltyModel`, - `TORSettlementMilitiaModel`, `TORSettlementProsperityModel` (sealed), - `TORVillageProductionCalculatorModel`, `TORTradeItemPriceFactorModel` (sealed), - `TORTroopSupplierModel`, `TORBuildingEffectModel`, `TORAlleyModel`, - `TORBanditDensityModel`, `TORInventoryCapacityModel`. -- **Crafting/smithing**: `TORSmithingModel`, `TOREnchantmentCraftingModel` (`: GameModel`), - `TOREnchantmentIngredientsModel` (`: GameModel`), `TOREquipmentSelectionModel`. -- **Custom resources**: `TORCustomResourceModel` (`: GameModel` — generalized cost scaling, - see `CampaignMechanics/CustomResources/CustomResource.GetCustomResourceGeneralizedFactor`). -- **Encounters/map/raids**: `TOREncounterModel`, `TOREncounterGameMenuModel`, - `TORMapVisibilityModel`, `TORRaidModel`, `TORVoiceOverModel`. -- **Siege/tournament**: `TORSiegeEngineCalculationModel`, `TORTournamentModel`. -- **Misc**: `TORVolunteerModel`, `DiplomacyHelpers` (static — shared math for - `TORDiplomacyModel`/`TORAllianceModel`/`TORTradeAgreementModel`). - -## Subfolder - -- **`CustomBattleModels/`** — the parallel model set used for the game's Custom Battle mode - (`Game.Current.GameType is CustomGame`) instead of a real campaign — see its CLAUDE.md. diff --git a/CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md b/CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md deleted file mode 100644 index aef263c2..00000000 --- a/CSharpSourceCode/Models/CustomBattleModels/CLAUDE.md +++ /dev/null @@ -1,12 +0,0 @@ -# Models/CustomBattleModels - -Model overrides used specifically in TaleWorlds' Custom Battle mode -(`Game.Current.GameType is CustomGame`), registered in `SubModule.OnGameStart`'s -`else if (Game.Current.GameType is CustomGame ...)` branch instead of the campaign branch. - -- **`TORCustomBattleMoraleModel`** (`: CustomBattleMoraleModel`). -- **`TORCustomBattleAgentStatCalculateModel`** (`: CustomBattleAgentStatCalculateModel`). - -Both mirror their campaign counterparts (`../TORBattleMoraleModel`, -`../TORAgentStatCalculateModel`) but against the Custom Battle base classes, since Custom -Battle mode has no `Campaign`/`Hero`/career context to draw on. diff --git a/CSharpSourceCode/Properties/CLAUDE.md b/CSharpSourceCode/Properties/CLAUDE.md deleted file mode 100644 index c8983391..00000000 --- a/CSharpSourceCode/Properties/CLAUDE.md +++ /dev/null @@ -1,4 +0,0 @@ -# Properties - -Standard .NET project metadata folder — contains only `AssemblyInfo.cs` -(assembly title/version/GUID attributes generated by Visual Studio). No TOR-specific logic. diff --git a/CSharpSourceCode/Quests/CLAUDE.md b/CSharpSourceCode/Quests/CLAUDE.md deleted file mode 100644 index 1932ff19..00000000 --- a/CSharpSourceCode/Quests/CLAUDE.md +++ /dev/null @@ -1,23 +0,0 @@ -# Quests - -`QuestBase`-derived campaign quests, plus generic quest infrastructure. (Career-flavor -one-off scripted events use the lighter `CampaignMechanics/CustomEvents` framework instead -of a full quest class.) - -- **`TORQuestHelper`** (static) — `StartCareerQuest(questPath)`: generic quest-launcher - used by Career content — resolves a `TOR_Core.` type name via reflection and - starts it if not already ongoing (guards against duplicate quest instances by `StringId`). -- **`QuestPartyComponent`** — party component marking a `MobileParty` as belonging to an - active quest (e.g. an escort or hunted target). -- **`EngineerQuest`** — a Dwarf-engineering-flavored quest (pairs with - `CampaignMechanics/MasterEngineer`). -- **`SpecializeLoreQuest`** — quest for specializing into a Winds-of-Magic Lore - (`AbilitySystem/Spells/LoreObject`) beyond the basic trainer interaction. -- **`HuntCultistsQuestCampaignBehavior`** / **`PlaguedVillageQuestCampaignBehavior`** - (`: CampaignBehaviorBase`) — self-contained quest-line behaviors (issue, track, and - resolve their quest without needing a separate `QuestBase` subclass registered elsewhere). - -## Subfolder - -- **`Careers/`** — one `QuestBase` subclass per Career-specific storyline quest, launched - via `TORQuestHelper.StartCareerQuest` (see its CLAUDE.md). diff --git a/CSharpSourceCode/Quests/Careers/CLAUDE.md b/CSharpSourceCode/Quests/Careers/CLAUDE.md deleted file mode 100644 index 28ddaa49..00000000 --- a/CSharpSourceCode/Quests/Careers/CLAUDE.md +++ /dev/null @@ -1,10 +0,0 @@ -# Quests/Careers - -One `QuestBase` subclass per Career-specific storyline quest (multi-stage, `JournalLog` -tasks saved via `[SaveableField]`), launched through `../TORQuestHelper.StartCareerQuest` -with a `questPath` like `"Quests.Careers.RunesmithQuest"`. - -- **`RunesmithQuest`** / **`RunelordQuest`** — Dwarf Runelord career questline (crafting - runes, tied to `CampaignMechanics/Menagery`/`Crafting`). -- **`OrcBossQuest1`** / **`OrcBossQuest2`** — Orc Boss career questline (sequential parts). -- **`OrcShamanQuest1`** / **`OrcShamanQuest2`** — Orc Shaman career questline. diff --git a/CSharpSourceCode/SaveGameSystem/CLAUDE.md b/CSharpSourceCode/SaveGameSystem/CLAUDE.md deleted file mode 100644 index 95459e48..00000000 --- a/CSharpSourceCode/SaveGameSystem/CLAUDE.md +++ /dev/null @@ -1,17 +0,0 @@ -# SaveGameSystem - -Single file: **`TORSaveableTypeDefiner`** (`: SaveableTypeDefiner`, base id `771000`) — -registers every custom class/interface that needs to be persisted in save games (party -components, settlement components, quest data, inventory-use-script data, custom-battle -tournament games, notification types, etc.) with a stable numeric id via -`AddClassDefinition`/`AddInterfaceDefinition`. - -**Critical constraint (called out in the file's own remarks):** never change an existing -type's id once players have saves using it — old saves will crash on load when the game -scans the save folder. Only ever append new ids; only renumber if you're deliberately -breaking save compatibility and know players will need to clear their saves. - -Other `SaveableTypeDefiner`s exist too, colocated with what they define (e.g. -`CampaignMechanics/Diplomacy/TORAllianceWarBehavior.TORAllianceWarBehaviorTypeDefiner`, -`HonorAllianceDecision.HonorAllianceDecisionTypeDefiner`) — check for those before assuming -this file is the only place a type gets registered. diff --git a/CSharpSourceCode/Utilities/CLAUDE.md b/CSharpSourceCode/Utilities/CLAUDE.md deleted file mode 100644 index a0b47aeb..00000000 --- a/CSharpSourceCode/Utilities/CLAUDE.md +++ /dev/null @@ -1,59 +0,0 @@ -# Utilities - -Cross-cutting static helpers used from every other folder. No campaign-behavior/mission -logic of its own — pure infrastructure. - -- **`TORConstants`** — every magic number/id string in one place, including the important - **`Cultures`** struct mapping Warhammer culture names to the underlying vanilla - `CultureObject.StringId` they're built on/reuse: `EMPIRE="empire"`, - `BRETONNIA="vlandia"`, `SYLVANIA="khuzait"`, `MOUSILLON="mousillon"`, - `ASRAI="battania"`, `DRUCHII="druchii"`, `BEASTMEN="steppe_bandits"`, - `CHAOS="chaos_culture"`, `EONIR="eonir"`, `DAWI="sturgia"` (Dwarfs), `GREENSKIN="aserai"`, - plus bandit/deserter variant cultures. `Cultures.All` is the 8 "main" playable cultures. - Also has a **`Factions`** struct (Empire provinces: Reikland, Middenland, Ostland, - Ostermark, Stirland, Hochland, Averland, Wissenland, Talabecland, Nordland, Moot, - Wasteland, ...) and religion/devotion/voice-index constants. -- **`TORCommon`** (static) — grab-bag: `Say`/`Log` (message + NLog wrappers), - `GetRandomDirection`/`GetRandomOrientation`, `FindNearestSettlement`/ - `FindSettlementsAroundPosition`/`FindPartiesAroundPosition` (spatial queries via - `Locatable` search), `CopyEquipmentToClipBoard` (debug helper). -- **`TORConfig`** — loads `TORConfiguration` from an XML config file (`ReadConfig`, called - from `SubModule.OnSubModuleLoad`) exposing tunable campaign constants (kingdom war - cadence, bandit party caps, career perk point cap, declare-war score weights, - `UseAlternativeVoiceManager`, `DisableMinstrelEvent`) plus a password-gated - `EnableFreeRaceSelection` debug toggle. -- **`TORPaths`** — module root/data/log path resolution (`TORCoreModuleRootPath`, - `TORArmoryModuleRootPath`, `TORLogPath`, etc.) — everything else that reads XML/assets - goes through this rather than hardcoding relative paths. -- **`TORCampaignEvents`** — TOR's own custom `CampaignEvent` definitions (beyond vanilla - `CampaignEvents`), e.g. `OnUseInventoryUseScriptObject` (see `Items/InventoryUseScripts`). -- **`TORConsoleCommands`** — debug console commands. -- **`TORTests`** — in-game smoke tests, likely surfaced via console commands. -- **`CTBlog`** — a debug/telemetry logging helper (separate from NLog, per its name — check - before assuming it's dead code). -- **`TORNotificationHelper`** — builds/shows `CampaignMechanics/MapNotifications`. -- **`TORTextHelper`** / **`TextObjectExtension`** / **`StringExtensions`** / - **`DictionaryExtensions`** — localization text lookup wrappers and small generic - extensions. -- **`TORDamageDisplay`** — floating combat-text style damage number display. -- **`TORSpellBlowHelper`** — classifies whether a `Blow`/`KillingBlow` originated from a - spell (used by `BattleMechanics/DamageSystem/TORDamageHelper.DetermineMask`). -- **`TORSummonHelper`** — mission agent-limit checks for summon-type abilities - (`AbilitySystem/Ability.IsDisabled` calls `CanSummon()`). -- **`TORMissionHelper`** — mission-side damage/heal/status-effect - application entry points used by `BattleMechanics/TriggeredEffect` - (`DamageAgents`/`HealAgents`/`ApplyStatusEffectToAgent`). -- **`TORHireHelper`** — hiring-cost/eligibility helpers. -- **`TOREquipmentHelper`** — equipment set resolution helpers (character creation, troops). -- **`TORExtendedInfoHelper`** — query helpers over `Extensions/ExtendedInfoSystem` data. -- **`TORGameStarterHelper`** — startup wiring helpers (`CleanCampaignStarter`, - `AddVerifiedIssueBehaviors`, called from `SubModule.InitializeGameStarter`). -- **`TORGameMenuBackgroundSwitcher`** — swaps settlement menu background art by context. -- **`TORMassMaterialSwitcher`** — bulk material/shader swapping on entities (visual variants). -- **`TOREntityRotator`** — simple entity rotation helper (scene/prop tool). -- **`TORParticleSystem`** (+ `ParticleIntensity` enum) — attaches/pools particle effects - on agents/entities; used heavily by `BattleMechanics/StatusEffect/StatusEffectComponent`. -- **`TORAnimationLogger`** — debug mission behavior logging animation events (added only - when a debugger is attached, see `SubModule.OnMissionBehaviorInitialize`). -- **`ShaderSourceManager`** — copies TOR_Armory shader sources into the game folder before - shader compilation (`SubModule.OnSubModuleLoad`, gated by `ENABLECOPYSHADERS`).