Skip to content

Commit e8dd50d

Browse files
challenge and ui api implementation
1 parent d0ec338 commit e8dd50d

7 files changed

Lines changed: 964 additions & 0 deletions

File tree

InscryptionAPI/AscensionScreens/AscensionRunSetupScreenBase.cs

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

0 commit comments

Comments
 (0)