Files
bansonic_beta_main/Assets/idolsDisplay/UI_Idols.cs
T
2026-06-25 11:48:56 +08:00

1037 lines
31 KiB
C#

using System;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class UI_Idols : MonoBehaviour
{
[Header("quit")]
public Button quitButton;
[Header("prefabs")]
public GameObject idolCardPrefab;
public Transform idolCardParent;
[Header("sprites")]
public Sprite[] idolLevelIcons;
public Sprite[] idolBtm;
[Header("colors")]
public Color[] idolSliderColors;
[Header("paths")]
public string idolSOpath_runtime;
public string idolSOpath_editor;
[Header("scan")]
public bool includeLockedHeroes = false;
[Header("middleParts")]
public Image idolHDimage;
public Text idolBackNameText;
public idolMaterialController imc;
[Header("rightPanel")]
public GameObject rightPanel;
public Text idol_chenghaoText;
public Text idol_nameText;
public Slider idol_expBar;
public Text idol_expText;
public Image levelIcon;
public Image btmIdolProfile;
public Text finishGameTimes;
public Text mvpGetTimes;
public Text joinTeamTimes;
[Header("special Skills")]
public GameObject ssPrefab;
public Transform ssParent;
public int maxSSDisplay = 3;
[Header("down panels")]
public idolLevels il;
public idolVoices iv;
public idolDocument ido;
public idolSkillsHub ish;
public idolSkins isk;
public idolEquipments ieqpmt;
public idolUpgrade iu;
[Header("left toggles")]
public Toggle idolLevelsToggle;
public Toggle idolVoicesToggle;
public Toggle idolDetailPassageToggle;
public Toggle idolSkillsToggle;
public Toggle idolSkinsToggle;
public Toggle idolWeaponToggle;
[Header("objects")]
public GameObject levelsObj;
public GameObject voicesObj;
public GameObject detailPassageObj;
public GameObject skillsObj;
public GameObject skinsObj;
public GameObject weaponObj;
private readonly List<GameObject> spawnedCards = new List<GameObject>();
private readonly List<GameObject> spawnedSpecialSkillEntries = new List<GameObject>();
private AllyHero_SO currentSelectedHero;
private bool suppressToggleCallbacks;
private int pendingGrowthAnimationHeroId = -1;
private Tween idolExpBarTween;
private void Start()
{
BindQuitButton();
InitializeSectionToggles();
RebuildCards();
}
private void OnEnable()
{
BindQuitButton();
btmandtopController.GlobalOverlayPanelVisibilityChanged += HandleOverlayPanelsVisibilityChanged;
AllyHeroDeployLedger.EnsureInstance().OnHeroGrowthChanged += HandleHeroGrowthChanged;
InitializeSectionToggles();
RebuildCards();
HandleOverlayPanelsVisibilityChanged(btmandtopController.CurrentOverlayPanelsVisible);
}
private void OnDisable()
{
UnbindQuitButton();
btmandtopController.GlobalOverlayPanelVisibilityChanged -= HandleOverlayPanelsVisibilityChanged;
if (AllyHeroDeployLedger.Instance != null)
{
AllyHeroDeployLedger.Instance.OnHeroGrowthChanged -= HandleHeroGrowthChanged;
}
if (idolExpBarTween != null && idolExpBarTween.IsActive())
{
idolExpBarTween.Kill();
idolExpBarTween = null;
}
UnbindSectionToggles();
}
private void BindQuitButton()
{
if (quitButton == null)
{
return;
}
quitButton.onClick.RemoveListener(HandleQuitClicked);
quitButton.onClick.AddListener(HandleQuitClicked);
}
private void UnbindQuitButton()
{
if (quitButton == null)
{
return;
}
quitButton.onClick.RemoveListener(HandleQuitClicked);
}
private void HandleQuitClicked()
{
gameObject.SetActive(false);
}
private void InitializeSectionToggles()
{
BindSectionToggles();
ApplySectionSelection(idolLevelsToggle != null ? idolLevelsToggle : GetFirstAvailableToggle());
}
private void BindSectionToggles()
{
UnbindSectionToggles();
BindSectionToggle(idolLevelsToggle);
BindSectionToggle(idolVoicesToggle);
BindSectionToggle(idolDetailPassageToggle);
BindSectionToggle(idolSkillsToggle);
BindSectionToggle(idolSkinsToggle);
BindSectionToggle(idolWeaponToggle);
}
private void UnbindSectionToggles()
{
UnbindSectionToggle(idolLevelsToggle);
UnbindSectionToggle(idolVoicesToggle);
UnbindSectionToggle(idolDetailPassageToggle);
UnbindSectionToggle(idolSkillsToggle);
UnbindSectionToggle(idolSkinsToggle);
UnbindSectionToggle(idolWeaponToggle);
}
private void BindSectionToggle(Toggle toggle)
{
if (toggle == null)
{
return;
}
if (toggle == idolLevelsToggle) toggle.onValueChanged.AddListener(OnLevelsToggleChanged);
if (toggle == idolVoicesToggle) toggle.onValueChanged.AddListener(OnVoicesToggleChanged);
if (toggle == idolDetailPassageToggle) toggle.onValueChanged.AddListener(OnDetailPassageToggleChanged);
if (toggle == idolSkillsToggle) toggle.onValueChanged.AddListener(OnSkillsToggleChanged);
if (toggle == idolSkinsToggle) toggle.onValueChanged.AddListener(OnSkinsToggleChanged);
if (toggle == idolWeaponToggle) toggle.onValueChanged.AddListener(OnWeaponToggleChanged);
}
private void UnbindSectionToggle(Toggle toggle)
{
if (toggle == null)
{
return;
}
if (toggle == idolLevelsToggle) toggle.onValueChanged.RemoveListener(OnLevelsToggleChanged);
if (toggle == idolVoicesToggle) toggle.onValueChanged.RemoveListener(OnVoicesToggleChanged);
if (toggle == idolDetailPassageToggle) toggle.onValueChanged.RemoveListener(OnDetailPassageToggleChanged);
if (toggle == idolSkillsToggle) toggle.onValueChanged.RemoveListener(OnSkillsToggleChanged);
if (toggle == idolSkinsToggle) toggle.onValueChanged.RemoveListener(OnSkinsToggleChanged);
if (toggle == idolWeaponToggle) toggle.onValueChanged.RemoveListener(OnWeaponToggleChanged);
}
private void OnLevelsToggleChanged(bool isOn) => HandleSectionToggleChanged(idolLevelsToggle, isOn);
private void OnVoicesToggleChanged(bool isOn) => HandleSectionToggleChanged(idolVoicesToggle, isOn);
private void OnDetailPassageToggleChanged(bool isOn) => HandleSectionToggleChanged(idolDetailPassageToggle, isOn);
private void OnSkillsToggleChanged(bool isOn) => HandleSectionToggleChanged(idolSkillsToggle, isOn);
private void OnSkinsToggleChanged(bool isOn) => HandleSectionToggleChanged(idolSkinsToggle, isOn);
private void OnWeaponToggleChanged(bool isOn) => HandleSectionToggleChanged(idolWeaponToggle, isOn);
private void HandleSectionToggleChanged(Toggle source, bool isOn)
{
if (suppressToggleCallbacks || source == null)
{
return;
}
if (isOn)
{
ApplySectionSelection(source);
return;
}
if (!AnySectionToggleOn())
{
ApplySectionSelection(idolLevelsToggle != null ? idolLevelsToggle : GetFirstAvailableToggle());
}
else
{
RefreshSectionObjects();
}
}
private void ApplySectionSelection(Toggle activeToggle)
{
Toggle resolved = activeToggle != null ? activeToggle : (idolLevelsToggle != null ? idolLevelsToggle : GetFirstAvailableToggle());
suppressToggleCallbacks = true;
SetToggleState(idolLevelsToggle, resolved == idolLevelsToggle);
SetToggleState(idolVoicesToggle, resolved == idolVoicesToggle);
SetToggleState(idolDetailPassageToggle, resolved == idolDetailPassageToggle);
SetToggleState(idolSkillsToggle, resolved == idolSkillsToggle);
SetToggleState(idolSkinsToggle, resolved == idolSkinsToggle);
SetToggleState(idolWeaponToggle, resolved == idolWeaponToggle);
suppressToggleCallbacks = false;
RefreshSectionObjects();
}
private void RefreshSectionObjects()
{
SetObjectState(levelsObj, idolLevelsToggle != null && idolLevelsToggle.isOn);
SetObjectState(voicesObj, idolVoicesToggle != null && idolVoicesToggle.isOn);
SetObjectState(detailPassageObj, idolDetailPassageToggle != null && idolDetailPassageToggle.isOn);
SetObjectState(skillsObj, idolSkillsToggle != null && idolSkillsToggle.isOn);
SetObjectState(skinsObj, idolSkinsToggle != null && idolSkinsToggle.isOn);
SetObjectState(weaponObj, idolWeaponToggle != null && idolWeaponToggle.isOn);
}
private bool AnySectionToggleOn()
{
return (idolLevelsToggle != null && idolLevelsToggle.isOn)
|| (idolVoicesToggle != null && idolVoicesToggle.isOn)
|| (idolDetailPassageToggle != null && idolDetailPassageToggle.isOn)
|| (idolSkillsToggle != null && idolSkillsToggle.isOn)
|| (idolSkinsToggle != null && idolSkinsToggle.isOn)
|| (idolWeaponToggle != null && idolWeaponToggle.isOn);
}
private Toggle GetFirstAvailableToggle()
{
if (idolLevelsToggle != null) return idolLevelsToggle;
if (idolVoicesToggle != null) return idolVoicesToggle;
if (idolDetailPassageToggle != null) return idolDetailPassageToggle;
if (idolSkillsToggle != null) return idolSkillsToggle;
if (idolSkinsToggle != null) return idolSkinsToggle;
if (idolWeaponToggle != null) return idolWeaponToggle;
return null;
}
private static void SetToggleState(Toggle toggle, bool isOn)
{
if (toggle == null)
{
return;
}
toggle.SetIsOnWithoutNotify(isOn);
}
private static void SetObjectState(GameObject target, bool active)
{
if (target != null && target.activeSelf != active)
{
target.SetActive(active);
}
}
[ContextMenu("Rebuild Idols")]
public void RebuildCards()
{
RebuildCards(true);
}
private void RebuildCards(bool animateSelectedHero)
{
if (idolCardPrefab == null || idolCardParent == null)
{
return;
}
AllyHeroDeployLedger.EnsureInstance().InitializeIfNeeded();
ClearCards();
ClearSpecialSkillEntries();
List<AllyHero_SO> heroes = LoadHeroAssets();
if (heroes.Count == 0)
{
ApplyHeroDetails(null, animateSelectedHero);
return;
}
heroes.Sort((left, right) => left.ally_heroID.CompareTo(right.ally_heroID));
AllyHero_SO firstDisplayedHero = null;
AllyHero_SO preferredHero = currentSelectedHero;
bool preferredHeroDisplayed = false;
for (int i = 0; i < heroes.Count; i++)
{
AllyHero_SO hero = heroes[i];
if (hero == null)
{
continue;
}
if (!includeLockedHeroes && !hero.isUnlocked)
{
continue;
}
IdolLevelSnapshot snapshot = BuildLevelSnapshot(hero);
GameObject instance = Instantiate(idolCardPrefab, idolCardParent);
spawnedCards.Add(instance);
idolCardPrefab card = instance.GetComponent<idolCardPrefab>();
if (card == null)
{
continue;
}
if (firstDisplayedHero == null)
{
firstDisplayedHero = hero;
}
if (preferredHero != null && preferredHero.ally_heroID == hero.ally_heroID)
{
preferredHeroDisplayed = true;
}
AllyHero_SO capturedHero = hero;
card.Setup(
hero.ally_hero_squareProfile,
hero.ally_heroDesignation,
hero.ally_heroName,
snapshot.sliderValue,
snapshot.cardXpText,
snapshot.levelIcon,
snapshot.bottomSprite,
snapshot.sliderColor,
() => ApplyHeroDetails(capturedHero, true));
}
ApplyHeroDetails(preferredHeroDisplayed ? preferredHero : firstDisplayedHero, animateSelectedHero);
}
private List<AllyHero_SO> LoadHeroAssets()
{
List<AllyHero_SO> heroes = new List<AllyHero_SO>();
#if UNITY_EDITOR
if (!Application.isPlaying && !string.IsNullOrWhiteSpace(idolSOpath_editor))
{
string[] searchFolders = { idolSOpath_editor };
string[] guids = AssetDatabase.FindAssets("t:AllyHero_SO", searchFolders);
for (int i = 0; i < guids.Length; i++)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
AllyHero_SO hero = AssetDatabase.LoadAssetAtPath<AllyHero_SO>(assetPath);
if (hero != null)
{
heroes.Add(hero);
}
}
return heroes;
}
#endif
AllyHero_SO[] loadedHeroes = Resources.LoadAll<AllyHero_SO>(string.IsNullOrWhiteSpace(idolSOpath_runtime) ? string.Empty : idolSOpath_runtime);
for (int i = 0; i < loadedHeroes.Length; i++)
{
if (loadedHeroes[i] != null)
{
heroes.Add(loadedHeroes[i]);
}
}
return heroes;
}
private void ApplyHeroDetails(AllyHero_SO hero)
{
ApplyHeroDetails(hero, true);
}
private void ApplyHeroDetails(AllyHero_SO hero, bool animatePortrait)
{
currentSelectedHero = hero;
ClearSpecialSkillEntries();
if (iu != null)
{
iu.SetHero(hero);
}
if (ish != null)
{
ish.SetHero(hero);
}
if (ieqpmt != null)
{
ieqpmt.SetHero(hero);
}
if (isk != null)
{
isk.SetHero(hero);
}
if (rightPanel != null)
{
rightPanel.SetActive(hero != null);
}
if (hero == null)
{
SetText(idolBackNameText, string.Empty);
SetText(idol_chenghaoText, string.Empty);
SetText(idol_nameText, string.Empty);
SetText(idol_expText, string.Empty);
SetIdolDocumentText(string.Empty);
SetText(finishGameTimes, "0000000");
SetText(mvpGetTimes, "0000000");
SetText(joinTeamTimes, "00000000");
ApplyHeroImage(null, animatePortrait);
SetImageSprite(levelIcon, null);
SetImageSpritePreserveAlpha(btmIdolProfile, null);
SetSliderVisual(idol_expBar, 0f, Color.white);
ApplyLevelDetails(null);
ApplyBehaviourRadar(null);
return;
}
IdolLevelSnapshot snapshot = BuildLevelSnapshot(hero);
ApplyHeroImage(hero.ally_hero_HD_image, animatePortrait);
SetText(idolBackNameText, hero.ally_heroName);
SetText(idol_chenghaoText, hero.ally_heroDesignation);
SetText(idol_nameText, hero.ally_heroName);
SetIdolDocumentText(hero.ally_heroDescription);
bool animateExpBar = pendingGrowthAnimationHeroId > 0 && hero.ally_heroID == pendingGrowthAnimationHeroId;
SetSliderVisual(idol_expBar, snapshot.sliderValue, snapshot.sliderColor, animateExpBar);
if (animateExpBar)
{
pendingGrowthAnimationHeroId = -1;
}
SetText(idol_expText, snapshot.detailXpText);
SetImageSprite(levelIcon, snapshot.levelIcon);
SetImageSpritePreserveAlpha(btmIdolProfile, hero.ally_hero_squareProfile);
SetText(finishGameTimes, FormatSevenDigitCount(hero.ally_finishCount));
SetText(mvpGetTimes, FormatSevenDigitCount(hero.ally_mvpCount));
SetText(joinTeamTimes, FormatJoinDate(hero.ally_joinDateUtcTicks));
ApplyLevelDetails(hero.GetEffectiveLevelInfoWithEquipment(hero.GetEffectiveLevelForCurrentEXP()));
ApplyBehaviourRadar(hero);
PopulateSpecialSkills(hero);
}
private void SetIdolDocumentText(string value)
{
if (ido != null && ido.idol_documentText != null)
{
ido.idol_documentText.text = value ?? string.Empty;
}
}
private void ApplyHeroImage(Sprite sprite)
{
ApplyHeroImage(sprite, true);
}
private void ApplyHeroImage(Sprite sprite, bool animate)
{
if (imc != null)
{
if (animate)
{
imc.TransitionToSprite(sprite);
}
else
{
imc.SetSpriteImmediate(sprite);
}
return;
}
SetImageSprite(idolHDimage, sprite);
}
private IdolLevelSnapshot BuildLevelSnapshot(AllyHero_SO hero)
{
IdolLevelSnapshot snapshot = new IdolLevelSnapshot
{
sliderValue = 0f,
cardXpText = "UNKNOWN",
detailXpText = "UNKNOWN",
levelIcon = GetLevelIconByIndex(4),
bottomSprite = GetBottomSpriteByIndex(4),
sliderColor = GetSliderColorByIndex(4)
};
if (hero == null)
{
return snapshot;
}
List<AllyHero_SO.AllyLevelInfo> levels = new List<AllyHero_SO.AllyLevelInfo>();
if (hero.levelStats != null)
{
for (int i = 0; i < hero.levelStats.Count; i++)
{
if (hero.levelStats[i] != null)
{
levels.Add(hero.levelStats[i]);
}
}
}
if (levels.Count == 0)
{
return snapshot;
}
levels.Sort((left, right) => left.requiredEXP.CompareTo(right.requiredEXP));
int currentExp = Mathf.Max(0, hero.ally_currentEXP);
int unlockedTierIndex = Mathf.Clamp(hero.ally_growthUnlockedTierIndex, 0, levels.Count - 1);
int displayIndex = unlockedTierIndex;
AllyHero_SO.AllyLevelInfo currentLevel = levels[displayIndex];
int tierIndex = ResolveTierIndex(currentLevel, displayIndex, levels.Count);
snapshot.levelIcon = GetLevelIconByIndex(tierIndex);
snapshot.bottomSprite = GetBottomSpriteByIndex(tierIndex);
snapshot.sliderColor = GetSliderColorByIndex(tierIndex);
if (displayIndex >= levels.Count - 1)
{
snapshot.sliderValue = 1f;
snapshot.cardXpText = "MAX";
snapshot.detailXpText = "MAX";
return snapshot;
}
int floorExp = currentLevel.requiredEXP;
int nextLevelIndex = Mathf.Clamp(displayIndex + 1, 0, levels.Count - 1);
int nextExp = levels[nextLevelIndex].requiredEXP;
int range = Mathf.Max(1, nextExp - floorExp);
int gained = Mathf.Clamp(currentExp - floorExp, 0, range);
snapshot.sliderValue = Mathf.Clamp01(gained / (float)range);
int neededExp = nextExp - currentExp;
if (neededExp > 0)
{
snapshot.cardXpText = "NEED " + neededExp + " EXP";
snapshot.detailXpText = gained + "/" + range;
}
else
{
snapshot.cardXpText = "READY";
snapshot.detailXpText = range + "/" + range;
}
return snapshot;
}
private void PopulateSpecialSkills(AllyHero_SO hero)
{
if (hero == null || ssPrefab == null || ssParent == null || maxSSDisplay <= 0 || hero.skillGroups == null)
{
return;
}
int shown = 0;
for (int i = 0; i < hero.skillGroups.Length; i++)
{
SkillGroup group = hero.skillGroups[i];
if (group == null || !group.isSpecialSkill)
{
continue;
}
GameObject instance = Instantiate(ssPrefab, ssParent);
spawnedSpecialSkillEntries.Add(instance);
ssPrefab display = instance.GetComponent<ssPrefab>();
if (display != null)
{
display.Setup(group.groupIcon, group.groupName);
}
shown++;
if (shown >= maxSSDisplay)
{
break;
}
}
}
private int ResolveTierIndex(AllyHero_SO.AllyLevelInfo levelInfo, int levelIndex, int levelCount)
{
if (levelInfo != null && !string.IsNullOrWhiteSpace(levelInfo.levelName))
{
string normalized = levelInfo.levelName.Trim().ToUpperInvariant();
if (normalized.Contains("S")) return 3;
if (normalized.Contains("A")) return 2;
if (normalized.Contains("B")) return 1;
if (normalized.Contains("C")) return 0;
}
if (levelCount <= 1)
{
return 0;
}
float normalizedIndex = levelIndex / (float)Mathf.Max(1, levelCount - 1);
if (normalizedIndex >= 0.99f) return 3;
if (normalizedIndex >= 0.66f) return 2;
if (normalizedIndex >= 0.33f) return 1;
return 0;
}
private Sprite GetLevelIconByIndex(int index)
{
if (idolLevelIcons == null || idolLevelIcons.Length == 0)
{
return null;
}
return idolLevelIcons[Mathf.Clamp(index, 0, idolLevelIcons.Length - 1)];
}
private Sprite GetBottomSpriteByIndex(int index)
{
if (idolBtm == null || idolBtm.Length == 0)
{
return null;
}
return idolBtm[Mathf.Clamp(index, 0, idolBtm.Length - 1)];
}
private Color GetSliderColorByIndex(int index)
{
if (idolSliderColors == null || idolSliderColors.Length == 0)
{
return Color.white;
}
return idolSliderColors[Mathf.Clamp(index, 0, idolSliderColors.Length - 1)];
}
private void ClearCards()
{
for (int i = spawnedCards.Count - 1; i >= 0; i--)
{
if (spawnedCards[i] == null)
{
continue;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(spawnedCards[i]);
}
else
#endif
{
Destroy(spawnedCards[i]);
}
}
spawnedCards.Clear();
if (idolCardParent == null)
{
return;
}
for (int i = idolCardParent.childCount - 1; i >= 0; i--)
{
Transform child = idolCardParent.GetChild(i);
if (child == null || child.GetComponent<idolCardPrefab>() == null)
{
continue;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(child.gameObject);
}
else
#endif
{
Destroy(child.gameObject);
}
}
}
private void ClearSpecialSkillEntries()
{
for (int i = spawnedSpecialSkillEntries.Count - 1; i >= 0; i--)
{
if (spawnedSpecialSkillEntries[i] == null)
{
continue;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(spawnedSpecialSkillEntries[i]);
}
else
#endif
{
Destroy(spawnedSpecialSkillEntries[i]);
}
}
spawnedSpecialSkillEntries.Clear();
if (ssParent == null)
{
return;
}
for (int i = ssParent.childCount - 1; i >= 0; i--)
{
Transform child = ssParent.GetChild(i);
if (child == null || child.GetComponent<ssPrefab>() == null)
{
continue;
}
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(child.gameObject);
}
else
#endif
{
Destroy(child.gameObject);
}
}
}
private static void SetText(Text target, string value)
{
if (target != null)
{
target.text = value ?? string.Empty;
}
}
private static void SetImageSprite(Image target, Sprite sprite)
{
if (target == null)
{
return;
}
target.sprite = sprite;
target.color = sprite != null ? new Color(target.color.r, target.color.g, target.color.b, 1f) : new Color(target.color.r, target.color.g, target.color.b, 0f);
}
private static void SetImageSpritePreserveAlpha(Image target, Sprite sprite)
{
if (target == null)
{
return;
}
target.sprite = sprite;
}
private void SetSliderVisual(Slider slider, float normalizedValue, Color fillColor, bool animate = false)
{
if (slider == null)
{
return;
}
float targetValue = Mathf.Clamp01(normalizedValue);
if (slider.fillRect == null)
{
slider.normalizedValue = targetValue;
return;
}
Image fillImage = slider.fillRect.GetComponent<Image>();
if (fillImage != null)
{
fillImage.color = fillColor;
}
if (animate)
{
if (idolExpBarTween != null && idolExpBarTween.IsActive())
{
idolExpBarTween.Kill();
}
float fromValue = slider.normalizedValue;
slider.normalizedValue = fromValue;
idolExpBarTween = DOTween.To(() => slider.normalizedValue, value => slider.normalizedValue = value, targetValue, 0.25f)
.SetEase(Ease.OutCubic)
.SetUpdate(true);
return;
}
slider.normalizedValue = targetValue;
}
private void ApplyLevelDetails(AllyHero_SO.AllyLevelInfo levelInfo)
{
if (il == null)
{
return;
}
if (levelInfo == null)
{
SetText(il.hp, "0");
SetText(il.attack, "0");
SetText(il.mana, "0");
SetText(il.damageResistant, "0%");
SetText(il.scoreEfficency, "0%");
SetText(il.slotAmount, "0");
SetText(il.miss_mr, "0");
SetText(il.good_mr, "0");
SetText(il.great_mr, "0");
SetText(il.perfect_mr, "0");
SetText(il.good_dm, "0%");
SetText(il.great_dm, "0%");
SetText(il.perfect_dm, "0%");
SetText(il.miss_hl, "0");
return;
}
AllyHero_SO.AllyLevelInfo baseLevelInfo = currentSelectedHero != null ? currentSelectedHero.GetEffectiveLevelForCurrentEXP() : levelInfo;
SetText(il.hp, FormatGrowthInt(baseLevelInfo != null ? baseLevelInfo.maxHP : levelInfo.maxHP, levelInfo.maxHP));
SetText(il.attack, FormatGrowthInt(baseLevelInfo != null ? baseLevelInfo.attack : levelInfo.attack, levelInfo.attack));
SetText(il.mana, FormatGrowthInt(baseLevelInfo != null ? baseLevelInfo.maxMana : levelInfo.maxMana, levelInfo.maxMana));
SetText(il.damageResistant, FormatGrowthPercent(baseLevelInfo != null ? baseLevelInfo.damageResistance : levelInfo.damageResistance, levelInfo.damageResistance));
SetText(il.scoreEfficency, FormatGrowthPercent(baseLevelInfo != null ? baseLevelInfo.scoreEfficiency : levelInfo.scoreEfficiency, levelInfo.scoreEfficiency));
int baseSlotAmount = baseLevelInfo != null ? baseLevelInfo.skill_slot_limited : levelInfo.skill_slot_limited;
int effectiveSlotAmount = currentSelectedHero != null ? currentSelectedHero.GetEffectiveSkillSlotLimit() : levelInfo.skill_slot_limited;
SetText(il.slotAmount, FormatGrowthInt(baseSlotAmount, effectiveSlotAmount));
SetText(il.miss_mr, levelInfo.manaGainOnMiss.ToString());
SetText(il.good_mr, levelInfo.manaGainGood.ToString());
SetText(il.great_mr, levelInfo.manaGainGreat.ToString());
SetText(il.perfect_mr, levelInfo.manaGainPerfect.ToString());
SetText(il.good_dm, FormatPercent(levelInfo.damageMultiplierGood));
SetText(il.great_dm, FormatPercent(levelInfo.damageMultiplierGreat));
SetText(il.perfect_dm, FormatPercent(levelInfo.damageMultiplierPerfect));
SetText(il.miss_hl, FormatNumber(levelInfo.missHpLossBase));
}
public void RefreshCurrentHeroDetails()
{
ApplyHeroDetails(currentSelectedHero, false);
}
private void ApplyBehaviourRadar(AllyHero_SO hero)
{
if (ido == null || ido.idol_rader == null)
{
return;
}
idolRadarController radarController = ido.idol_rader.GetComponent<idolRadarController>();
if (radarController == null)
{
radarController = ido.idol_rader.GetComponentInChildren<idolRadarController>(true);
}
if (radarController != null)
{
radarController.ApplyHero(hero);
}
}
private void HandleOverlayPanelsVisibilityChanged(bool visible)
{
if (ido == null || ido.idol_rader == null)
{
return;
}
ido.idol_rader.SetActive(!visible);
if (!visible)
{
ApplyBehaviourRadar(currentSelectedHero);
}
}
private void HandleHeroGrowthChanged(int heroId)
{
if (heroId <= 0)
{
return;
}
if (currentSelectedHero != null && currentSelectedHero.ally_heroID == heroId)
{
pendingGrowthAnimationHeroId = heroId;
}
RebuildCards(false);
}
private static string FormatSevenDigitCount(int value)
{
if (value <= 0)
{
return "0000000";
}
if (value >= 9999999)
{
return "9999999";
}
return value.ToString("D7");
}
private static string FormatJoinDate(long utcTicks)
{
if (utcTicks <= 0L)
{
return "--------";
}
try
{
DateTime date = new DateTime(utcTicks, DateTimeKind.Utc);
if (date.Year <= 1 && date.Month <= 1 && date.Day <= 1)
{
return "--------";
}
return date.ToString("yyyyMMdd");
}
catch
{
return "--------";
}
}
private static string FormatPercent(float value)
{
return Mathf.RoundToInt(value * 100f) + "%";
}
private static string FormatGrowthInt(int baseValue, int effectiveValue)
{
int growth = effectiveValue - baseValue;
if (growth == 0)
{
return baseValue.ToString();
}
string sign = growth > 0 ? "+" : "-";
string color = growth > 0 ? "#7CFF6B" : "#FF5A5A";
return $"{baseValue} <color={color}>{sign} {Mathf.Abs(growth)}</color>";
}
private static string FormatGrowthPercent(float baseValue, float effectiveValue)
{
float growth = effectiveValue - baseValue;
string baseText = FormatPercent(baseValue);
if (Mathf.Approximately(growth, 0f))
{
return baseText;
}
string sign = growth > 0f ? "+" : "-";
string color = growth > 0f ? "#7CFF6B" : "#FF5A5A";
return $"{baseText} <color={color}>{sign} {FormatPercent(Mathf.Abs(growth))}</color>";
}
private static string FormatNumber(float value)
{
if (Mathf.Approximately(value, Mathf.Round(value)))
{
return Mathf.RoundToInt(value).ToString();
}
return value.ToString("0.##");
}
private struct IdolLevelSnapshot
{
public float sliderValue;
public string cardXpText;
public string detailXpText;
public Sprite levelIcon;
public Sprite bottomSprite;
public Color sliderColor;
}
}