Skip to content

Commit 215e2ab

Browse files
authored
Merge pull request #28 from divisionbyz0rro/challenges-ui-api
Challenges, User Interface, Saves, and GUID Manager
2 parents 49f6a64 + a73bc1d commit 215e2ab

11 files changed

Lines changed: 1210 additions & 0 deletions

InscryptionAPI/AscensionScreens/AscensionRunSetupScreenBase.cs

Lines changed: 433 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
using DiskCardGame;
2+
using HarmonyLib;
3+
using UnityEngine;
4+
using System.Collections;
5+
6+
namespace InscryptionAPI.AscensionScreens
7+
{
8+
[HarmonyPatch]
9+
public static class AscensionScreenManager
10+
{
11+
internal static List<Type> registeredScreens = new List<Type>();
12+
13+
internal static Dictionary<AscensionMenuScreens.Screen, AscensionRunSetupScreenBase> screens;
14+
15+
internal static AscensionMenuScreens.Screen initialScreen = AscensionMenuScreens.Screen.JournalSummary;
16+
17+
internal const int CUSTOM_SCREEN_START = 100;
18+
19+
private static string challengeScreenHoverText = "START RUN";
20+
21+
public static void RegisterScreen<T>() where T : AscensionRunSetupScreenBase
22+
{
23+
registeredScreens.Add(typeof(T));
24+
}
25+
26+
private static AscensionScreenSort.Direction GetPreferredDirection(Type t)
27+
{
28+
AscensionScreenSort sortAttr = Attribute.GetCustomAttribute(t, typeof(AscensionScreenSort)) as AscensionScreenSort;
29+
if (sortAttr == null)
30+
return AscensionScreenSort.Direction.NoPreference;
31+
else
32+
return sortAttr.preferredDirection;
33+
}
34+
35+
public static void InitializeAllScreens()
36+
{
37+
// Sort the screens
38+
registeredScreens.Sort((a, b) => (int)GetPreferredDirection(a) - (int)GetPreferredDirection(b));
39+
40+
// Build screens
41+
screens = new Dictionary<AscensionMenuScreens.Screen, AscensionRunSetupScreenBase>();
42+
43+
AscensionMenuScreens.Screen previousScreen = AscensionMenuScreens.Screen.SelectChallenges;
44+
AscensionMenuScreens.Screen currentScreen = (AscensionMenuScreens.Screen)CUSTOM_SCREEN_START;
45+
AscensionMenuScreens.Screen nextScreen = (AscensionMenuScreens.Screen)(CUSTOM_SCREEN_START + 1);
46+
initialScreen = currentScreen;
47+
for (int i = 0; i < registeredScreens.Count; i++)
48+
{
49+
Type screenType = registeredScreens[i];
50+
51+
if (i == registeredScreens.Count - 1) // the last one
52+
nextScreen = AscensionMenuScreens.Screen.SelectChallengesConfirm;
53+
54+
try
55+
{
56+
AscensionRunSetupScreenBase screen = AscensionRunSetupScreenBase.BuildScreen(screenType, previousScreen, nextScreen);
57+
58+
screens.Add(currentScreen, screen);
59+
60+
previousScreen = currentScreen;
61+
currentScreen = nextScreen;
62+
nextScreen = (AscensionMenuScreens.Screen)((int)nextScreen + 1);
63+
} catch (Exception ex)
64+
{
65+
InscryptionAPIPlugin.Log.LogError(ex);
66+
}
67+
}
68+
69+
if (screens.Count == 0)
70+
return;
71+
72+
// Now make another pass through the screens and set the behavior of hovering over the continue and back buttons
73+
74+
previousScreen = AscensionMenuScreens.Screen.SelectChallenges;
75+
currentScreen = (AscensionMenuScreens.Screen)CUSTOM_SCREEN_START;
76+
nextScreen = (AscensionMenuScreens.Screen)(CUSTOM_SCREEN_START + 1);
77+
78+
// Set the hover text of the challenge screen to be the title of the first custom screen
79+
challengeScreenHoverText = screens[currentScreen].headerText;
80+
81+
for (int i = 0; i < screens.Count; i++)
82+
{
83+
AscensionRunSetupScreenBase cur = screens[currentScreen];
84+
85+
string prevText = screens.ContainsKey(previousScreen) ? screens[previousScreen].headerText : "SELECT CHALLENGES";
86+
string nextText = screens.ContainsKey(nextScreen) ? screens[nextScreen].headerText : "START RUN";
87+
88+
Action<MainInputInteractable> prevHoverAction = (MainInputInteractable i) => cur.DisplayMessage(Localization.ToUpper(Localization.Translate(prevText)));
89+
Action<MainInputInteractable> nextHoverAction = (MainInputInteractable i) => cur.DisplayMessage(Localization.ToUpper(Localization.Translate(nextText)));
90+
Action<MainInputInteractable> unHoverAction = (MainInputInteractable i) => cur.ClearMessage();
91+
92+
cur.backButton.CursorEntered = (Action<MainInputInteractable>)Delegate.Combine(cur.backButton.CursorEntered, prevHoverAction);
93+
cur.backButton.CursorExited = (Action<MainInputInteractable>)Delegate.Combine(cur.backButton.CursorExited, unHoverAction);
94+
cur.continueButton.CursorEntered = (Action<MainInputInteractable>)Delegate.Combine(cur.continueButton.CursorEntered, nextHoverAction);
95+
cur.continueButton.CursorExited = (Action<MainInputInteractable>)Delegate.Combine(cur.continueButton.CursorExited, unHoverAction);
96+
97+
previousScreen = currentScreen;
98+
currentScreen = nextScreen;
99+
nextScreen = (AscensionMenuScreens.Screen)((int)nextScreen + 1);
100+
}
101+
}
102+
103+
// This patches the confirmation button of the challenge screen to ensure it starts the queue
104+
[HarmonyPatch(typeof(AscensionChallengeScreen), "OnContinuePressed")]
105+
[HarmonyPrefix]
106+
public static bool TransitionToSideDeckScreen(ref AscensionChallengeScreen __instance)
107+
{
108+
if (screens == null || screens.Count == 0)
109+
return true; // No custom screens; execute the original method
110+
111+
AscensionMenuScreens.Instance.SwitchToScreen(initialScreen);
112+
return false;
113+
}
114+
115+
[HarmonyPatch(typeof(AscensionMenuScreens), "ScreenSwitchSequence")]
116+
[HarmonyPostfix]
117+
public static IEnumerator SwitchToScreen(IEnumerator sequenceEvent, AscensionMenuScreens.Screen screen)
118+
{
119+
while (sequenceEvent.MoveNext())
120+
yield return sequenceEvent.Current;
121+
122+
yield return new WaitForSeconds(0.05f);
123+
124+
if (AscensionScreenManager.screens.ContainsKey(screen))
125+
AscensionScreenManager.screens[screen].gameObject.SetActive(true);
126+
127+
yield break;
128+
}
129+
130+
[HarmonyPatch(typeof(AscensionMenuScreens), "ConfigurePostGameScreens")]
131+
[HarmonyPostfix]
132+
public static void InitializeScreensOnStart()
133+
{
134+
InitializeAllScreens();
135+
}
136+
137+
[HarmonyPatch(typeof(AscensionMenuScreens), "DeactivateAllScreens")]
138+
[HarmonyPostfix]
139+
public static void DeactivateAllCustomScreens()
140+
{
141+
if (screens != null && screens.Count > 0)
142+
foreach (AscensionRunSetupScreenBase screenbase in screens.Values)
143+
if (screenbase != null && screenbase.gameObject != null)
144+
screenbase.gameObject.SetActive(false);
145+
}
146+
147+
[HarmonyPatch(typeof(AscensionChallengeScreen), "OnContinueCursorEnter")]
148+
[HarmonyPrefix]
149+
public static bool HoverTextFirstCustomScreen(ref AscensionChallengeScreen __instance)
150+
{
151+
string line = Localization.Translate(challengeScreenHoverText);
152+
__instance.challengeDisplayer.DisplayText("", line, "", false);
153+
return false;
154+
}
155+
}
156+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace InscryptionAPI.AscensionScreens
2+
{
3+
// Decorates a custom screen and marks how it should be sorted
4+
public class AscensionScreenSort : System.Attribute
5+
{
6+
public enum Direction : int
7+
{
8+
RequiresStart = 1,
9+
PrefersStart = 2,
10+
NoPreference = 3,
11+
PrefersEnd = 4,
12+
RequiresEnd = 5,
13+
}
14+
15+
public Direction preferredDirection;
16+
17+
public AscensionScreenSort(Direction preferredDirection = Direction.NoPreference)
18+
{
19+
this.preferredDirection = preferredDirection;
20+
}
21+
}
22+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using DiskCardGame;
2+
using UnityEngine;
3+
4+
namespace InscryptionAPI.Challenges
5+
{
6+
public class AscensionChallengePaginator : MonoBehaviour
7+
{
8+
public int challengePageIndex = 0;
9+
10+
public readonly static int CHALLENGES_PER_ROW = 7;
11+
12+
public List<AscensionChallengeInfo> availableChallenges;
13+
14+
public List<AscensionIconInteractable> topRow;
15+
16+
public List<AscensionIconInteractable> bottomRow;
17+
18+
public List<List<AscensionChallengeInfo>> pages = new();
19+
20+
public List<List<bool>> pageStates = new();
21+
22+
private void PageBuilder(List<AscensionChallengeInfo> challenges, int startIdx)
23+
{
24+
List<AscensionChallengeInfo> curPage = new List<AscensionChallengeInfo>();
25+
for (int i = startIdx; i < challenges.Count; i++)
26+
{
27+
// Check to see if we need a new page
28+
if (curPage.Count == 14)
29+
{
30+
pages.Add(curPage);
31+
curPage = new List<AscensionChallengeInfo>();
32+
}
33+
34+
// Check to see if we need a blank buffer
35+
// This happens if the next icon is the same as the current, and the
36+
// current icon would be on the bottom row
37+
if (i < challenges.Count - 1 && challenges[i + 1].challengeType == challenges[i].challengeType && curPage.Count % 2 == 1)
38+
curPage.Add(null);
39+
40+
curPage.Add(challenges[i]);
41+
}
42+
pages.Add(curPage);
43+
}
44+
45+
public void GeneratePages()
46+
{
47+
// The first page is nice and easy
48+
List<AscensionChallengeInfo> pageOne = new List<AscensionChallengeInfo>();
49+
pageOne.AddRange(availableChallenges.GetRange(0, 14));
50+
pages.Add(pageOne);
51+
52+
// Do the challenges first:
53+
List<AscensionChallengeInfo> challenges = availableChallenges.Where(i => i.pointValue > 0).ToList();
54+
List<AscensionChallengeInfo> assists = availableChallenges.Where(i => i.pointValue < 0).ToList();
55+
56+
// Do the challenges
57+
if (challenges.Count > 14)
58+
PageBuilder(challenges, 14);
59+
60+
if (assists.Count > 0)
61+
PageBuilder(assists, 0);
62+
63+
while (pageStates.Count < pages.Count)
64+
{
65+
pageStates.Add(new List<bool>());
66+
for (int i = 0; i < 14; i++)
67+
pageStates[pageStates.Count - 1].Add(false);
68+
}
69+
}
70+
71+
private void SavePageState()
72+
{
73+
for (int i = 0; i < 7; i++)
74+
{
75+
pageStates[challengePageIndex][i * 2] = topRow[i].activatedRenderer.enabled;
76+
pageStates[challengePageIndex][i * 2 + 1] = bottomRow[i].activatedRenderer.enabled;
77+
}
78+
}
79+
80+
public void ShowVisibleChallenges()
81+
{
82+
// Sort out which list of challenges are the visible ones
83+
List<AscensionChallengeInfo> visibleChallenges = pages[challengePageIndex];
84+
List<bool> selectedChallenges = pageStates[challengePageIndex];
85+
86+
// Make all challenge icons inactive
87+
foreach (AscensionIconInteractable icon in topRow.Concat(bottomRow))
88+
icon.gameObject.SetActive(false);
89+
90+
// Start going through and setting the icons
91+
for (int i = 0; i < visibleChallenges.Count; i++)
92+
{
93+
if (visibleChallenges[i] == null) // this is a spacer
94+
continue;
95+
AscensionIconInteractable targetIcon = (i % 2 == 0) ? this.topRow[i / 2] : this.bottomRow[i / 2];
96+
targetIcon.AssignInfo(visibleChallenges[i]);
97+
targetIcon.activatedRenderer.enabled = selectedChallenges[i];
98+
targetIcon.gameObject.SetActive(true);
99+
}
100+
}
101+
102+
public void ChallengePageLeft(MainInputInteractable button)
103+
{
104+
if (!AscensionMenuScreens.Instance.selectChallengesScreen.activeSelf)
105+
return;
106+
107+
if (challengePageIndex > 0)
108+
{
109+
SavePageState();
110+
challengePageIndex -= 1;
111+
ShowVisibleChallenges();
112+
}
113+
}
114+
115+
public void ChallengePageRight(MainInputInteractable button)
116+
{
117+
if (!AscensionMenuScreens.Instance.selectChallengesScreen.activeSelf)
118+
return;
119+
120+
if (challengePageIndex < pages.Count - 1)
121+
{
122+
SavePageState();
123+
challengePageIndex += 1;
124+
ShowVisibleChallenges();
125+
}
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)