1212using STS2RitsuLib . Content ;
1313using STS2RitsuLib . Patching . Models ;
1414using STS2RitsuLib . Scaffolding . Characters ;
15+ using STS2RitsuLib . Timeline ;
1516using SerializableRun = MegaCrit . Sts2 . Core . Saves . SerializableRun ;
1617
1718namespace STS2RitsuLib . Unlocks . Patches
@@ -96,8 +97,8 @@ public static bool Prefix(SerializablePlayer serializablePlayer, SerializableRun
9697 }
9798
9899 /// <summary>
99- /// Replaces vanilla post-run character-unlock epoch checks for mod characters with registry-driven grants.
100- /// 将 mod 角色的原版跑局后角色解锁纪元检查替换为由注册表驱动的授予 。
100+ /// Extends vanilla post-run character-unlock epoch checks with registered and template-derived mod grants.
101+ /// 用已注册和模板推导出的 mod 授予扩展原版跑局后角色解锁纪元检查 。
101102 /// </summary>
102103 public class PostRunCharacterUnlockEpochCompatibilityPatch : IPatchMethod
103104 {
@@ -106,7 +107,7 @@ public class PostRunCharacterUnlockEpochCompatibilityPatch : IPatchMethod
106107
107108 /// <inheritdoc />
108109 public static string Description =>
109- "Handle post-run character unlock epochs for mod characters via registered RitsuLib unlock rules " ;
110+ "Handle registered or template-derived post-run character unlock epochs without blocking vanilla chains " ;
110111
111112 /// <inheritdoc />
112113 public static bool IsCritical => false ;
@@ -123,8 +124,8 @@ public static ModPatchTarget[] GetTargets()
123124 }
124125
125126 /// <summary>
126- /// Obtains the registered post-run character-unlock epoch when appropriate; skips vanilla when handled .
127- /// 在适当时获得已注册的跑局后角色解锁纪元;已处理时跳过原版逻辑 。
127+ /// Obtains registered or template-derived post-run character-unlock epochs when appropriate.
128+ /// 在适当时获得已注册或模板推导出的跑局后角色解锁纪元 。
128129 /// </summary>
129130 public static bool Prefix ( SerializablePlayer serializablePlayer , SerializableRun serializableRun )
130131 {
@@ -133,41 +134,48 @@ public static bool Prefix(SerializablePlayer serializablePlayer, SerializableRun
133134
134135 ArgumentNullException . ThrowIfNull ( serializablePlayer . CharacterId ) ;
135136 var character = ModelDb . GetById < CharacterModel > ( serializablePlayer . CharacterId ) ;
136- if ( ! ModContentRegistry . TryGetOwnerModId ( character . GetType ( ) , out _ ) )
137- return true ;
137+ var isModCharacter = ModContentRegistry . TryGetOwnerModId ( character . GetType ( ) , out _ ) ;
138138
139139 if ( ! Sts2RunGameModeCompat . IsStandardSerializableRunForEpochUnlocks ( serializableRun ) )
140140 return true ;
141141
142- if ( ! ModUnlockRegistry . TryGetPostRunCharacterUnlockEpoch ( character . Id , out var epochId ) )
142+ var epochIds = new HashSet < string > ( StringComparer . Ordinal ) ;
143+ foreach ( var epochId in ModUnlockRegistry . GetPostRunCharacterUnlockEpochs ( character . Id ) )
144+ epochIds . Add ( epochId ) ;
145+ foreach ( var epochId in ModTimelineNeowCoExpansion . GetModCharacterRootEpochIdsUnlockedAfterRunAs (
146+ character . Id ) )
147+ epochIds . Add ( epochId ) ;
148+
149+ if ( epochIds . Count == 0 )
143150 {
151+ if ( ! isModCharacter )
152+ return true ;
153+
144154 if ( character is IModCharacterEpochTimelineRequirement { RequiresEpochAndTimeline : false } )
145155 return false ;
146156
147157 ModUnlockMissingRuleWarnings . WarnOnce (
148158 $ "postrun_char_unlock_epoch:{ character . Id } ",
149- $ "[Unlocks] Mod character '{ character . Id } ' has no registered post-run character-unlock epoch (UnlockCharacterAfterRunAs / RegisterPostRunCharacterUnlockEpoch). " +
159+ $ "[Unlocks] Mod character '{ character . Id } ' has no registered post-run character-unlock epoch (UnlocksAfterRunAsType / UnlockCharacterAfterRunAs / RegisterPostRunCharacterUnlockEpoch). " +
150160 "Leaving vanilla post-run check in place (no-op for this character)." ) ;
151161 return true ;
152162 }
153163
154- if ( SaveManager . Instance . Progress . IsEpochObtained ( epochId ) )
155- return false ;
156-
157- if ( ! EpochRuntimeCompatibility . CanUseEpochId (
158- epochId ,
159- $ "post-run character unlock epoch rule for mod character '{ character . Id } '") )
160- return false ;
161-
162- SaveManager . Instance . ObtainEpoch ( epochId ) ;
163- NGame . Instance ? . AddChildSafely ( NGainEpochVfx . Create ( EpochModel . Get ( epochId ) ) ) ;
164- if ( ! serializablePlayer . DiscoveredEpochs . Contains ( epochId , StringComparer . Ordinal ) )
165- serializablePlayer . DiscoveredEpochs . Add ( epochId ) ;
164+ foreach ( var epochId in epochIds . Where ( epochId => ! SaveManager . Instance . Progress . IsEpochObtained ( epochId ) )
165+ . Where ( epochId => EpochRuntimeCompatibility . CanUseEpochId (
166+ epochId ,
167+ $ "post-run character unlock epoch rule after run as '{ character . Id } '") ) )
168+ {
169+ SaveManager . Instance . ObtainEpoch ( epochId ) ;
170+ NGame . Instance ? . AddChildSafely ( NGainEpochVfx . Create ( EpochModel . Get ( epochId ) ) ) ;
171+ if ( ! serializablePlayer . DiscoveredEpochs . Contains ( epochId , StringComparer . Ordinal ) )
172+ serializablePlayer . DiscoveredEpochs . Add ( epochId ) ;
166173
167- RitsuLibFramework . Logger . Info (
168- $ "[Unlocks] Obtained post-run character unlock epoch '{ epochId } ' for mod character '{ character . Id } '.") ;
174+ RitsuLibFramework . Logger . Info (
175+ $ "[Unlocks] Obtained post-run character unlock epoch '{ epochId } ' after run as '{ character . Id } '.") ;
176+ }
169177
170- return false ;
178+ return ! isModCharacter ;
171179 }
172180 }
173181
0 commit comments