Skip to content

Commit 1919e57

Browse files
authored
Merge pull request #33 from divisionbyz0rro/ability-defect-fix
Boss, special sequencer, and AI managers
2 parents 2c5a9c5 + 257f67d commit 1919e57

9 files changed

Lines changed: 437 additions & 65 deletions

File tree

InscryptionAPI/Ascension/AscensionChallengeScreen.cs

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -35,78 +35,81 @@ public static void ReassignableIconFixes(ref AscensionIconInteractable __instanc
3535
[HarmonyPostfix]
3636
public static void AddPaginationToChallengeScreen()
3737
{
38-
if (ChallengeManager.newInfos.Count > 0)
39-
{
40-
InscryptionAPIPlugin.Logger.LogDebug($"Creating Paginator");
38+
InscryptionAPIPlugin.Logger.LogDebug($"Creating Paginator");
4139

42-
AscensionChallengePaginator paginator = AscensionMenuScreens.Instance.selectChallengesScreen.GetComponent<AscensionChallengePaginator>();
43-
if (paginator == null)
44-
paginator = AscensionMenuScreens.Instance.selectChallengesScreen.AddComponent<AscensionChallengePaginator>();
40+
AscensionChallengePaginator paginator = AscensionMenuScreens.Instance.selectChallengesScreen.GetComponent<AscensionChallengePaginator>();
41+
if (paginator == null)
42+
paginator = AscensionMenuScreens.Instance.selectChallengesScreen.AddComponent<AscensionChallengePaginator>();
4543

46-
InscryptionAPIPlugin.Logger.LogDebug($"Getting pseudo prefabs");
44+
InscryptionAPIPlugin.Logger.LogDebug($"Getting pseudo prefabs");
4745

48-
GameObject leftPseudoPrefab = AscensionMenuScreens.Instance.cardUnlockSummaryScreen.transform.Find("Unlocks/ScreenAnchor/PageLeftButton").gameObject;
49-
GameObject rightPseudoPrefab = AscensionMenuScreens.Instance.cardUnlockSummaryScreen.transform.Find("Unlocks/ScreenAnchor/PageRightButton").gameObject;
46+
GameObject leftPseudoPrefab = AscensionMenuScreens.Instance.cardUnlockSummaryScreen.transform.Find("Unlocks/ScreenAnchor/PageLeftButton").gameObject;
47+
GameObject rightPseudoPrefab = AscensionMenuScreens.Instance.cardUnlockSummaryScreen.transform.Find("Unlocks/ScreenAnchor/PageRightButton").gameObject;
5048

51-
InscryptionAPIPlugin.Logger.LogDebug($"Getting icon grid");
49+
InscryptionAPIPlugin.Logger.LogDebug($"Getting icon grid");
5250

53-
GameObject challengeIconGrid = AscensionMenuScreens.Instance.selectChallengesScreen.transform.Find("Icons/ChallengeIconGrid").gameObject;
51+
GameObject challengeIconGrid = AscensionMenuScreens.Instance.selectChallengesScreen.transform.Find("Icons/ChallengeIconGrid").gameObject;
5452

55-
GameObject topRow = challengeIconGrid.transform.Find("TopRow").gameObject;
56-
GameObject bottomRow = challengeIconGrid.transform.Find("BottomRow").gameObject;
53+
GameObject topRow = challengeIconGrid.transform.Find("TopRow").gameObject;
54+
GameObject bottomRow = challengeIconGrid.transform.Find("BottomRow").gameObject;
5755

58-
InscryptionAPIPlugin.Logger.LogDebug($"Initializing data");
56+
InscryptionAPIPlugin.Logger.LogDebug($"Initializing data");
5957

60-
paginator.topRow = new List<AscensionIconInteractable>();
61-
paginator.bottomRow = new List<AscensionIconInteractable>();
62-
for (int i = 1; i <= 7; i++)
63-
{
64-
paginator.topRow.Add(topRow.transform.Find($"Icon_{i}").gameObject.GetComponent<AscensionIconInteractable>());
65-
paginator.bottomRow.Add(bottomRow.transform.Find($"Icon_{i+7}").gameObject.GetComponent<AscensionIconInteractable>());
66-
}
58+
paginator.topRow = new List<AscensionIconInteractable>();
59+
paginator.bottomRow = new List<AscensionIconInteractable>();
60+
for (int i = 1; i <= 7; i++)
61+
{
62+
paginator.topRow.Add(topRow.transform.Find($"Icon_{i}").gameObject.GetComponent<AscensionIconInteractable>());
63+
paginator.bottomRow.Add(bottomRow.transform.Find($"Icon_{i+7}").gameObject.GetComponent<AscensionIconInteractable>());
64+
}
6765

68-
InscryptionAPIPlugin.Logger.LogDebug($"Original challenge info");
69-
paginator.availableChallenges = new List<AscensionChallengeInfo>();
70-
for (int i = 0; i < 7; i++)
71-
{
72-
paginator.availableChallenges.Add(paginator.topRow[i].challengeInfo);
73-
paginator.availableChallenges.Add(paginator.bottomRow[i].challengeInfo);
74-
}
66+
InscryptionAPIPlugin.Logger.LogDebug($"Original challenge info");
67+
paginator.availableChallenges = new List<AscensionChallengeInfo>();
68+
for (int i = 0; i < 7; i++)
69+
{
70+
paginator.availableChallenges.Add(paginator.topRow[i].challengeInfo);
71+
paginator.availableChallenges.Add(paginator.bottomRow[i].challengeInfo);
72+
}
7573

76-
InscryptionAPIPlugin.Logger.LogDebug($"Custom challenge info");
77-
foreach (AscensionChallengeInfo info in ChallengeManager.newInfos.Where(i => ChallengeManager.IsStackable(i.challengeType)))
78-
{
79-
paginator.availableChallenges.Add(info); // Add stackables twice
80-
paginator.availableChallenges.Add(info); // Do them first so they stack nice
81-
}
74+
InscryptionAPIPlugin.Logger.LogDebug($"Custom challenge info");
75+
foreach (AscensionChallengeInfo info in ChallengeManager.newInfos.Where(i => ChallengeManager.IsStackable(i.challengeType)))
76+
{
77+
paginator.availableChallenges.Add(info); // Add stackables twice
78+
paginator.availableChallenges.Add(info); // Do them first so they stack nice
79+
}
8280

83-
foreach (AscensionChallengeInfo info in ChallengeManager.newInfos.Where(i => !ChallengeManager.IsStackable(i.challengeType)))
84-
{
85-
paginator.availableChallenges.Add(info);
86-
}
81+
foreach (AscensionChallengeInfo info in ChallengeManager.newInfos.Where(i => !ChallengeManager.IsStackable(i.challengeType)))
82+
{
83+
paginator.availableChallenges.Add(info);
84+
}
8785

88-
paginator.GeneratePages();
86+
paginator.GeneratePages();
8987

90-
InscryptionAPIPlugin.Logger.LogDebug($"Creating page turners");
91-
GameObject leftIcon = GameObject.Instantiate(leftPseudoPrefab, challengeIconGrid.transform);
92-
GameObject rightIcon = GameObject.Instantiate(rightPseudoPrefab, challengeIconGrid.transform);
88+
InscryptionAPIPlugin.Logger.LogDebug($"Creating page turners");
89+
GameObject leftIcon = GameObject.Instantiate(leftPseudoPrefab, challengeIconGrid.transform);
90+
GameObject rightIcon = GameObject.Instantiate(rightPseudoPrefab, challengeIconGrid.transform);
9391

94-
InscryptionAPIPlugin.Logger.LogDebug($"Positioning page turners");
95-
leftIcon.transform.localPosition = leftIcon.transform.localPosition + (Vector3)(new Vector2(-0.75f, 0.25f));
96-
rightIcon.transform.localPosition = rightIcon.transform.localPosition + (Vector3)(new Vector2(0.75f, 0.25f));;
92+
InscryptionAPIPlugin.Logger.LogDebug($"Positioning page turners");
93+
leftIcon.transform.localPosition = leftIcon.transform.localPosition + (Vector3)(new Vector2(-0.75f, 0.25f));
94+
rightIcon.transform.localPosition = rightIcon.transform.localPosition + (Vector3)(new Vector2(0.75f, 0.25f));;
9795

98-
InscryptionAPIPlugin.Logger.LogDebug($"Getting pagination controllers");
99-
AscensionMenuInteractable leftController = leftIcon.GetComponent<AscensionMenuInteractable>();
100-
AscensionMenuInteractable rightController = rightIcon.GetComponent<AscensionMenuInteractable>();
96+
InscryptionAPIPlugin.Logger.LogDebug($"Getting pagination controllers");
97+
AscensionMenuInteractable leftController = leftIcon.GetComponent<AscensionMenuInteractable>();
98+
AscensionMenuInteractable rightController = rightIcon.GetComponent<AscensionMenuInteractable>();
10199

102-
Action<MainInputInteractable> leftClickAction = (MainInputInteractable i) => paginator.ChallengePageLeft(i);
103-
Action<MainInputInteractable> rightClickAction = (MainInputInteractable i) => paginator.ChallengePageRight(i);
100+
Action<MainInputInteractable> leftClickAction = (MainInputInteractable i) => paginator.ChallengePageLeft(i);
101+
Action<MainInputInteractable> rightClickAction = (MainInputInteractable i) => paginator.ChallengePageRight(i);
104102

105-
InscryptionAPIPlugin.Logger.LogDebug($"Setting click actions");
106-
leftController.CursorSelectStarted = (Action<MainInputInteractable>)Delegate.Combine(leftController.CursorSelectStarted, leftClickAction);
107-
rightController.CursorSelectStarted = (Action<MainInputInteractable>)Delegate.Combine(rightController.CursorSelectStarted, rightClickAction);
103+
InscryptionAPIPlugin.Logger.LogDebug($"Setting click actions");
104+
leftController.CursorSelectStarted = (Action<MainInputInteractable>)Delegate.Combine(leftController.CursorSelectStarted, leftClickAction);
105+
rightController.CursorSelectStarted = (Action<MainInputInteractable>)Delegate.Combine(rightController.CursorSelectStarted, rightClickAction);
108106

109-
paginator.challengePageIndex = 0;
107+
paginator.challengePageIndex = 0;
108+
109+
if (ChallengeManager.newInfos.Count == 0)
110+
{
111+
GameObject.Destroy(leftController.gameObject);
112+
GameObject.Destroy(rightController.gameObject);
110113
}
111114
}
112115
}

InscryptionAPI/Ascension/AscensionRunSetupScreenBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public static AscensionRunSetupScreenBase BuildScreen(Type screenType, Ascension
234234
InscryptionAPIPlugin.Logger.LogDebug($"Adding continue button");
235235
GameObject continuePrefab = Resources.Load<GameObject>("prefabs/ui/ascension/ascensionmenucontinuebutton");
236236
GameObject continueButton = GameObject.Instantiate(continuePrefab, screenObject.transform);
237-
continueButton.transform.localPosition = new Vector3(2.08f, 1.15f, 0f);
237+
continueButton.transform.localPosition = new Vector3(2.15f, 1.13f, 0f);
238238

239239
controller.continueButton = continueButton.GetComponent<AscensionMenuInteractable>();
240240

InscryptionAPI/Card/AbilityExtensions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ public static class AbilityExtensions
88
{
99
public static AbilityInfo AbilityByID(this List<AbilityInfo> abilities, Ability id) => abilities.FirstOrDefault(x => x.ability == id);
1010

11+
public static AbilityManager.FullAbility AbilityByID(this List<AbilityManager.FullAbility> abilities, Ability id) => abilities.FirstOrDefault(x => x.Id == id);
12+
13+
public static AbilityInfo SetIcon(this AbilityInfo info, Texture2D icon)
14+
{
15+
AbilityManager.FullAbility ability = AbilityManager.AllAbilities.FirstOrDefault(fab => fab.Id == info.ability);
16+
if (ability == default(AbilityManager.FullAbility))
17+
throw new InvalidOperationException("Cannot set custom texture directly on AbilityInfo unless it has been added via AbilityManager.Add");
18+
19+
ability.SetIcon(icon);
20+
return info;
21+
}
22+
1123
public static AbilityInfo SetCustomFlippedTexture(this AbilityInfo info, Texture2D icon)
1224
{
1325
AbilityManager.FullAbility ability = AbilityManager.AllAbilities.FirstOrDefault(fab => fab.Id == info.ability);
@@ -18,6 +30,11 @@ public static AbilityInfo SetCustomFlippedTexture(this AbilityInfo info, Texture
1830
return info;
1931
}
2032

33+
public static void SetIcon(this AbilityManager.FullAbility info, Texture2D icon)
34+
{
35+
info.Texture = icon;
36+
}
37+
2138
public static void SetCustomFlippedTexture(this AbilityManager.FullAbility info, Texture2D icon)
2239
{
2340
info.CustomFlippedTexture = icon;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System.Collections.ObjectModel;
2+
using DiskCardGame;
3+
using HarmonyLib;
4+
using InscryptionAPI.Guid;
5+
6+
namespace InscryptionAPI.Encounters;
7+
8+
[HarmonyPatch]
9+
public static class AIManager
10+
{
11+
public class FullAI
12+
{
13+
public readonly string Id;
14+
public readonly Type AI;
15+
16+
public FullAI(string id, Type aiType)
17+
{
18+
Id = id;
19+
AI = aiType;
20+
21+
TypeManager.Add(Id.ToString(), AI);
22+
}
23+
}
24+
25+
public readonly static ReadOnlyCollection<FullAI> BaseGameAIs = new(GenBaseGameAIsList());
26+
private readonly static ObservableCollection<FullAI> NewAIs = new();
27+
28+
public static List<FullAI> AllAIs { get; private set; } = BaseGameAIs.ToList();
29+
30+
static AIManager()
31+
{
32+
NewAIs.CollectionChanged += static (_, _) =>
33+
{
34+
AllAIs = BaseGameAIs.Concat(NewAIs).ToList();
35+
};
36+
}
37+
38+
private static List<FullAI> GenBaseGameAIsList()
39+
{
40+
List<FullAI> baseGame = new();
41+
var gameAsm = typeof(AI).Assembly;
42+
foreach (Type aiType in gameAsm.GetTypes().Where(type => type.IsSubclassOf(typeof(AI))))
43+
{
44+
baseGame.Add(new(aiType.Name, aiType));
45+
}
46+
return baseGame;
47+
}
48+
49+
public static FullAI Add(string guid, string aiName, Type sequencer)
50+
{
51+
FullAI full = new("AI_" + GuidManager.GetFullyQualifiedName(guid, aiName), sequencer);
52+
NewAIs.Add(full);
53+
return full;
54+
}
55+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using DiskCardGame;
2+
3+
namespace InscryptionAPI.Encounters;
4+
5+
public static class EncounterExtensions
6+
{
7+
public static OpponentManager.FullOpponent OpponentById(this IEnumerable<OpponentManager.FullOpponent> opponents, Opponent.Type id)
8+
{
9+
return opponents.FirstOrDefault(o => o.Id == id);
10+
}
11+
12+
public static OpponentManager.FullOpponent SetOpponent(this OpponentManager.FullOpponent opp, Type opponentType)
13+
{
14+
opp.Opponent = opponentType;
15+
return opp;
16+
}
17+
18+
public static OpponentManager.FullOpponent SetSequencer(this OpponentManager.FullOpponent opp, string sequenceId)
19+
{
20+
opp.SpecialSequencerId = sequenceId;
21+
return opp;
22+
}
23+
24+
public static OpponentManager.FullOpponent SetNewSequencer(this OpponentManager.FullOpponent opp, string pluginGuid, string sequencerName, Type sequencerType)
25+
{
26+
var newSequencer = SpecialSequenceManager.Add(pluginGuid, sequencerName, sequencerType);
27+
opp.SpecialSequencerId = newSequencer.Id;
28+
return opp;
29+
}
30+
}

0 commit comments

Comments
 (0)