1+ using System . Collections . ObjectModel ;
2+ using System . Diagnostics . CodeAnalysis ;
3+ using System . Runtime . CompilerServices ;
4+ using DiskCardGame ;
5+ using HarmonyLib ;
6+ using InscryptionAPI . Guid ;
7+ using UnityEngine ;
8+
9+ namespace InscryptionAPI . Encounters ;
10+
11+ [ HarmonyPatch ]
12+ public static class OpponentManager
13+ {
14+ public class FullOpponent
15+ {
16+ public readonly Opponent . Type Id ;
17+ public Type Opponent ;
18+ public string SpecialSequencerId ;
19+
20+ public FullOpponent ( Opponent . Type id , Type opponent , string specialSequencerId )
21+ {
22+ Id = id ;
23+ SpecialSequencerId = specialSequencerId ;
24+ Opponent = opponent ;
25+ }
26+ }
27+
28+ public static readonly ReadOnlyCollection < FullOpponent > BaseGameOpponents = new ( GenBaseGameOpponents ( ) ) ;
29+ private static readonly ObservableCollection < FullOpponent > NewOpponents = new ( ) ;
30+
31+ private static List < FullOpponent > GenBaseGameOpponents ( )
32+ {
33+ bool useReversePatch = true ;
34+ try
35+ {
36+ OriginalGetSequencerIdForBoss ( Opponent . Type . ProspectorBoss ) ;
37+ }
38+ catch ( NotImplementedException )
39+ {
40+ useReversePatch = false ;
41+ }
42+
43+ List < FullOpponent > baseGame = new ( ) ;
44+ var gameAsm = typeof ( Opponent ) . Assembly ;
45+ foreach ( Opponent . Type opponent in Enum . GetValues ( typeof ( Opponent . Type ) ) )
46+ {
47+ string specialSequencerId = useReversePatch ? OriginalGetSequencerIdForBoss ( opponent ) : BossBattleSequencer . GetSequencerIdForBoss ( opponent ) ;
48+ Type opponentType = gameAsm . GetType ( $ "DiskCardGame.{ opponent . ToString ( ) } Opponent") ;
49+
50+ baseGame . Add ( new FullOpponent ( opponent , opponentType , specialSequencerId ) ) ;
51+ }
52+ return baseGame ;
53+ }
54+
55+ static OpponentManager ( )
56+ {
57+ NewOpponents . CollectionChanged += static ( _ , _ ) =>
58+ {
59+ AllOpponents = BaseGameOpponents . Concat ( NewOpponents ) . ToList ( ) ;
60+ } ;
61+ }
62+
63+ public static List < FullOpponent > AllOpponents { get ; private set ; } = BaseGameOpponents . ToList ( ) ;
64+
65+ public static FullOpponent Add ( string guid , string opponentName , string sequencerID , Type opponentType )
66+ {
67+ Opponent . Type opponentId = GuidManager . GetEnumValue < Opponent . Type > ( guid , opponentName ) ;
68+ FullOpponent opp = new ( opponentId , opponentType , sequencerID ) ;
69+ NewOpponents . Add ( opp ) ;
70+ return opp ;
71+ }
72+
73+ [ HarmonyPatch ( typeof ( Opponent ) , nameof ( Opponent . SpawnOpponent ) ) ]
74+ [ HarmonyPrefix ]
75+ public static bool ReplaceSpawnOpponent ( EncounterData encounterData , ref Opponent __result )
76+ {
77+ if ( encounterData . opponentType == Opponent . Type . Default || ! ProgressionData . LearnedMechanic ( MechanicsConcept . OpponentQueue ) )
78+ return true ; // For default opponents or if we're in the tutorial, just let the base game logic flow
79+
80+ // This mostly just follows the logic of the base game, other than the fact that the
81+ // opponent gets instantiated by looking up the type from the list
82+
83+ GameObject gameObject = new GameObject ( ) ;
84+ gameObject . name = "Opponent" ;
85+
86+ __result = gameObject . AddComponent ( AllOpponents . First ( o => o . Id == encounterData . opponentType ) . Opponent ) as Opponent ;
87+
88+ __result . AI = Activator . CreateInstance ( CustomType . GetType ( "DiskCardGame" , encounterData . aiId ?? "AI" ) ) as AI ;
89+ __result . NumLives = __result . StartingLives ;
90+ __result . OpponentType = encounterData . opponentType ;
91+ __result . TurnPlan = __result . ModifyTurnPlan ( encounterData . opponentTurnPlan ) ;
92+ __result . Blueprint = encounterData . Blueprint ;
93+ __result . Difficulty = encounterData . Difficulty ;
94+ __result . ExtraTurnsToSurrender = SeededRandom . Range ( 0 , 3 , SaveManager . SaveFile . GetCurrentRandomSeed ( ) ) ;
95+ return false ;
96+ }
97+
98+ [ HarmonyReversePatch ( HarmonyReversePatchType . Original ) ]
99+ [ HarmonyPatch ( typeof ( BossBattleSequencer ) , nameof ( BossBattleSequencer . GetSequencerIdForBoss ) ) ]
100+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
101+ public static string OriginalGetSequencerIdForBoss ( Opponent . Type bossType ) { throw new NotImplementedException ( ) ; }
102+
103+ [ HarmonyPatch ( typeof ( BossBattleSequencer ) , nameof ( BossBattleSequencer . GetSequencerIdForBoss ) ) ]
104+ [ HarmonyPrefix ]
105+ public static bool ReplaceGetSequencerId ( Opponent . Type bossType , ref string __result )
106+ {
107+ __result = AllOpponents . First ( o => o . Id == bossType ) . SpecialSequencerId ;
108+ return false ;
109+ }
110+ }
0 commit comments