r2mods/ilspy_dump/ror2_csproj/RoR2.UI/DifficultyBarController.cs

443 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace RoR2.UI;
[ExecuteAlways]
public class DifficultyBarController : MonoBehaviour
{
[Serializable]
public struct SegmentDef
{
[Tooltip("The default English string to use for the element at design time.")]
public string debugString;
[Tooltip("The final language token to use for this element at runtime.")]
public string token;
[Tooltip("The color to use for the panel.")]
public Color color;
}
private class SegmentImageAnimation
{
public Image segmentImage;
public float age;
public float duration;
public AnimationCurve colorCurve;
public Color color0;
public Color color1;
public void Update(float t)
{
segmentImage.color = Color.Lerp(color0, color1, colorCurve.Evaluate(t));
}
}
[Header("Component References")]
public RectTransform viewPort;
public RectTransform segmentContainer;
public Image difficultyBarBackdrop;
[Tooltip("How wide each segment should be.")]
[Header("Layout")]
public float elementWidth;
public float levelsPerSegment;
public float debugTime;
[Header("Segment Parameters")]
public SegmentDef[] segmentDefs;
[Tooltip("The prefab to instantiate for each segment.")]
public GameObject segmentPrefab;
[Header("Colors")]
public float pastSaturationMultiplier;
public float pastValueMultiplier;
public Color pastLabelColor;
public float currentSaturationMultiplier;
public float currentValueMultiplier;
public Color currentLabelColor;
public float upcomingSaturationMultiplier;
public float upcomingValueMultiplier;
public Color upcomingLabelColor;
[Tooltip("If the increasedDifficultyBarFX user setting is enabled and the next difficulty color's value is below this, flash white instead.")]
public float backdropFlashWhiteThreshold = 0.43f;
[Header("Animations")]
public AnimationCurve fadeAnimationCurve;
public float fadeAnimationDuration = 1f;
public AnimationCurve flashAnimationCurve;
public float flashAnimationDuration = 0.5f;
private int currentSegmentIndex = -1;
private static readonly Color labelFadedColor = Color.Lerp(Color.gray, Color.white, 0.5f);
[SerializeField]
private string onDifficultyChangeSoundString = "Play_wDifficulty_New";
[Header("Final Segment")]
public Sprite finalSegmentSprite;
private HUD hud;
private float scrollX;
private float scrollXRaw;
private float lastSegmentScroll;
[Tooltip("Do not set this manually. Regenerate the children instead.")]
public Image[] images;
[Tooltip("Do not set this manually. Regenerate the children instead.")]
public TextMeshProUGUI[] labels;
public RawImage[] wormGearImages;
public float UVScaleToScrollX;
public float gearUVOffset;
private readonly List<SegmentImageAnimation> playingAnimations = new List<SegmentImageAnimation>();
private static Color ColorMultiplySaturationAndValue(ref Color col, float saturationMultiplier, float valueMultiplier)
{
Color.RGBToHSV(col, out var H, out var S, out var V);
return Color.HSVToRGB(H, S * saturationMultiplier, V * valueMultiplier);
}
private void OnCurrentSegmentIndexChanged(int newSegmentIndex)
{
if (!Application.isPlaying)
{
return;
}
int num = newSegmentIndex - 1;
float width = viewPort.rect.width;
int i = 0;
for (int num2 = images.Length - 1; i < num2; i++)
{
Image obj = images[i];
TextMeshProUGUI textMeshProUGUI = labels[i];
RectTransform rectTransform = obj.rectTransform;
bool flag2 = (obj.enabled = rectTransform.offsetMax.x + scrollX >= 0f && rectTransform.offsetMin.x + scrollX <= width);
textMeshProUGUI.enabled = flag2;
}
int num3 = images.Length - 1;
Image obj2 = images[num3];
TextMeshProUGUI textMeshProUGUI2 = labels[num3];
bool flag4 = (obj2.enabled = obj2.rectTransform.offsetMax.x + scrollX >= 0f);
textMeshProUGUI2.enabled = flag4;
for (int j = 0; j <= num; j++)
{
images[j].color = ColorMultiplySaturationAndValue(ref segmentDefs[j].color, pastSaturationMultiplier, pastValueMultiplier);
labels[j].color = pastLabelColor;
}
for (int k = newSegmentIndex + 1; k < images.Length; k++)
{
images[k].color = ColorMultiplySaturationAndValue(ref segmentDefs[k].color, upcomingSaturationMultiplier, upcomingValueMultiplier);
labels[k].color = upcomingLabelColor;
}
Image image = ((num != -1) ? images[num] : null);
Image image2 = ((newSegmentIndex != -1) ? images[newSegmentIndex] : null);
TextMeshProUGUI textMeshProUGUI3 = ((newSegmentIndex != -1) ? labels[newSegmentIndex] : null);
if ((bool)image)
{
playingAnimations.Add(new SegmentImageAnimation
{
age = 0f,
duration = fadeAnimationDuration,
segmentImage = image,
colorCurve = fadeAnimationCurve,
color0 = segmentDefs[num].color,
color1 = ColorMultiplySaturationAndValue(ref segmentDefs[num].color, pastSaturationMultiplier, pastValueMultiplier)
});
}
Color color = ColorMultiplySaturationAndValue(ref segmentDefs[newSegmentIndex].color, currentSaturationMultiplier, currentValueMultiplier);
if ((bool)image2)
{
playingAnimations.Add(new SegmentImageAnimation
{
age = 0f,
duration = flashAnimationDuration,
segmentImage = image2,
colorCurve = flashAnimationCurve,
color0 = color,
color1 = Color.white
});
}
if ((bool)hud && (bool)difficultyBarBackdrop)
{
UserProfile userProfile = hud.localUserViewer.userProfile;
if (userProfile != null && userProfile.increasedDifficultyBarFX)
{
Color.RGBToHSV(segmentDefs[newSegmentIndex].color, out var _, out var _, out var V);
playingAnimations.Add(new SegmentImageAnimation
{
age = 0f,
duration = flashAnimationDuration,
segmentImage = difficultyBarBackdrop,
colorCurve = flashAnimationCurve,
color0 = difficultyBarBackdrop.color,
color1 = ((V < backdropFlashWhiteThreshold) ? Color.white : color)
});
if (newSegmentIndex > 0)
{
Util.PlaySound(onDifficultyChangeSoundString, RoR2Application.instance.gameObject);
}
}
}
if ((bool)textMeshProUGUI3)
{
textMeshProUGUI3.color = currentLabelColor;
}
}
private void SetSegmentScroll(float segmentScroll)
{
if (segmentScroll == lastSegmentScroll)
{
return;
}
lastSegmentScroll = segmentScroll;
float num = segmentDefs.Length + 2;
if (segmentScroll > num)
{
segmentScroll = num - 1f + (segmentScroll - Mathf.Floor(segmentScroll));
}
scrollXRaw = (segmentScroll - 1f) * (0f - elementWidth);
scrollX = Mathf.Floor(scrollXRaw);
int num2 = currentSegmentIndex;
currentSegmentIndex = Mathf.Clamp(Mathf.FloorToInt(segmentScroll), 0, segmentContainer.childCount - 1);
if (num2 != currentSegmentIndex)
{
OnCurrentSegmentIndexChanged(currentSegmentIndex);
}
Vector2 offsetMin = segmentContainer.offsetMin;
offsetMin.x = scrollX;
segmentContainer.offsetMin = offsetMin;
if ((bool)segmentContainer && segmentContainer.childCount > 0)
{
int num3 = segmentContainer.childCount - 1;
RectTransform rectTransform = (RectTransform)segmentContainer.GetChild(num3);
RectTransform rectTransform2 = (RectTransform)rectTransform.Find("Label");
_ = labels[num3];
if (segmentScroll >= (float)(num3 - 1))
{
float num4 = elementWidth;
Vector2 offsetMin2 = rectTransform.offsetMin;
offsetMin2.x = CalcSegmentStartX(num3);
rectTransform.offsetMin = offsetMin2;
Vector2 offsetMax = rectTransform.offsetMax;
offsetMax.x = offsetMin2.x + num4;
rectTransform.offsetMax = offsetMax;
rectTransform2.anchorMin = new Vector2(0f, 0f);
rectTransform2.anchorMax = new Vector2(0f, 1f);
rectTransform2.offsetMin = new Vector2(0f, 0f);
rectTransform2.offsetMax = new Vector2(elementWidth, 0f);
}
else
{
rectTransform.offsetMax = rectTransform.offsetMin + new Vector2(elementWidth, 0f);
SetLabelDefaultDimensions(rectTransform2);
}
}
}
private float CalcSegmentStartX(int i)
{
return (float)i * elementWidth;
}
private float CalcSegmentEndX(int i)
{
return (float)(i + 1) * elementWidth;
}
private void SetLabelDefaultDimensions(RectTransform labelRectTransform)
{
labelRectTransform.anchorMin = new Vector2(0f, 0f);
labelRectTransform.anchorMax = new Vector2(1f, 1f);
labelRectTransform.pivot = new Vector2(0.5f, 0.5f);
labelRectTransform.offsetMin = new Vector2(0f, 0f);
labelRectTransform.offsetMax = new Vector2(0f, 0f);
}
private void SetSegmentCount(uint desiredCount)
{
if ((bool)segmentContainer && (bool)segmentPrefab)
{
uint num = (uint)segmentContainer.childCount;
if (images == null || images.Length != desiredCount)
{
images = new Image[desiredCount];
labels = new TextMeshProUGUI[desiredCount];
}
int i = 0;
for (int num2 = Mathf.Min(images.Length, segmentContainer.childCount); i < num2; i++)
{
Transform child = segmentContainer.GetChild(i);
images[i] = child.GetComponent<Image>();
labels[i] = child.Find("Label").GetComponent<TextMeshProUGUI>();
}
while (num > desiredCount)
{
UnityEngine.Object.DestroyImmediate(segmentContainer.GetChild((int)(num - 1)).gameObject);
num--;
}
for (; num < desiredCount; num++)
{
GameObject gameObject = UnityEngine.Object.Instantiate(segmentPrefab, segmentContainer);
gameObject.SetActive(value: true);
images[i] = gameObject.GetComponent<Image>();
labels[i] = gameObject.transform.Find("Label").GetComponent<TextMeshProUGUI>();
i++;
}
}
}
private void SetupSegments()
{
if ((bool)segmentContainer && (bool)segmentPrefab)
{
SetSegmentCount((uint)segmentDefs.Length);
for (int i = 0; i < segmentContainer.childCount; i++)
{
SetupSegment((RectTransform)segmentContainer.GetChild(i), ref segmentDefs[i], i);
}
SetupFinalSegment((RectTransform)segmentContainer.GetChild(segmentContainer.childCount - 1));
}
}
private static void ScaleLabelToWidth(TextMeshProUGUI label, float width)
{
RectTransform obj = (RectTransform)label.transform;
float x = label.textBounds.size.x;
Vector3 localScale = obj.localScale;
localScale.x = width / x;
obj.localScale = localScale;
}
private void SetupFinalSegment(RectTransform segmentTransform)
{
TextMeshProUGUI[] array = segmentTransform.GetComponentsInChildren<TextMeshProUGUI>();
int num = 4;
if (array.Length < num)
{
TextMeshProUGUI[] array2 = new TextMeshProUGUI[num];
for (int i = 0; i < array.Length; i++)
{
array2[i] = array[i];
}
for (int j = array.Length; j < num; j++)
{
array2[j] = UnityEngine.Object.Instantiate(array[0].gameObject, segmentTransform).GetComponent<TextMeshProUGUI>();
}
array = array2;
}
int k = 0;
for (int num2 = array.Length; k < num2; k++)
{
TextMeshProUGUI obj = array[k];
obj.enableWordWrapping = false;
obj.overflowMode = TextOverflowModes.Overflow;
obj.alignment = TextAlignmentOptions.MidlineLeft;
obj.text = Language.GetString(segmentDefs[segmentDefs.Length - 1].token);
obj.enableAutoSizing = true;
Vector3 localPosition = obj.transform.localPosition;
localPosition.x = (float)k * elementWidth;
obj.transform.localPosition = localPosition;
}
segmentTransform.GetComponent<Image>().sprite = finalSegmentSprite;
}
private void SetupSegment(RectTransform segmentTransform, ref SegmentDef segmentDef, int i)
{
Vector2 offsetMin = segmentTransform.offsetMin;
Vector2 offsetMax = segmentTransform.offsetMax;
offsetMin.x = CalcSegmentStartX(i);
offsetMax.x = CalcSegmentEndX(i);
segmentTransform.offsetMin = offsetMin;
segmentTransform.offsetMax = offsetMax;
segmentTransform.GetComponent<Image>().color = segmentDef.color;
((RectTransform)segmentTransform.Find("Label")).GetComponent<LanguageTextMeshController>().token = segmentDef.token;
}
private void Awake()
{
hud = GetComponentInParent<HUD>();
SetupSegments();
}
private void DoBarUpdates(float deltaTime)
{
if ((bool)Run.instance)
{
SetSegmentScroll((Run.instance.ambientLevel - 1f) / levelsPerSegment);
}
if (Application.isPlaying)
{
RunAnimations(deltaTime);
}
}
private void Update()
{
DoBarUpdates(Time.deltaTime);
UpdateGears();
}
private void UpdateGears()
{
RawImage[] array = wormGearImages;
foreach (RawImage obj in array)
{
Rect uvRect = obj.uvRect;
float num = Mathf.Sign(uvRect.width);
uvRect.x = scrollXRaw * UVScaleToScrollX * num + ((num < 0f) ? gearUVOffset : 0f);
obj.uvRect = uvRect;
}
}
private void RunAnimations(float deltaTime)
{
for (int num = playingAnimations.Count - 1; num >= 0; num--)
{
SegmentImageAnimation segmentImageAnimation = playingAnimations[num];
segmentImageAnimation.age += deltaTime;
float num2 = Mathf.Clamp01(segmentImageAnimation.age / segmentImageAnimation.duration);
segmentImageAnimation.Update(num2);
if (num2 >= 1f)
{
playingAnimations.RemoveAt(num);
}
}
}
}